這個問題相當廣泛 - 我只會談到幾點。
proxy
類型變量只是類型變量* -> *
,即類型構造函數的類型。實際上,如果你有一個功能
foo :: proxy a -> ...
你可以傳遞給它的值例如選擇proxy = Maybe
和a = Int
。您也可以傳遞[] Char
(也寫爲[Char]
)的值。或者,更常見的是,Proxy Int
類型的值,其中Proxy
是被定義爲
data Proxy a = Proxy
即不攜帶任何運行信息的數據類型的數據類型(有它的單個值!),但其中攜帶編譯時信息(幻像類型變量a
)。
假設N
是一種類型Nat
- 一個編譯時自然。我們可以寫一個函數
bar :: N -> ...
但調用這需要我們建立N
類型的值 - 這是無關緊要的。類型N
的目的僅僅是攜帶編譯時信息,其運行時間值不是我們真正想要使用的。實際上,N
根本沒有值,除了底部。我們可能呼叫
bar (undefined :: N)
但是這看起來奇怪。讀這個,我們必須認識到bar
它的第一個參數是懶惰的,它不會導致嘗試使用它的分歧。問題在於bar :: N -> ...
類型的簽名具有誤導性:它聲稱結果可能取決於類型爲N
的參數的值,但實際情況並非如此。相反,如果我們使用
baz :: Proxy N -> ...
的意圖是明確的 - 有隻有一個運行時間值是:Proxy :: Proxy N
。同樣清楚的是,N
值僅在編譯時存在。
有時候,而是採用了特定Proxy N
,代碼稍微推廣到
foo :: proxy N -> ...
其達到同樣的目的,但也允許不同類型的Proxy
。 (就我個人而言,我不是非常興奮的這種推廣。)
回到問題:natVal
是一個函數,它只將編譯時自然轉換爲運行時值。即它將Proxy N
轉換爲Int
,只返回常量。
如果您使用類型模板參數來模擬編譯時自然,那麼您與C++模板的類比可能會更接近。例如。
template <typename N> struct S { using pred = N; };
struct Z {};
template <typename N> int natVal();
template <typename N> int natVal() { return 1 + natVal<typename N::pred>(); }
template <> int natVal<Z>() { return 0; }
int main() {
cout << natVal<S<S<Z>>>() << endl; // outputs 2
return 0;
}
只是假裝有用於S
和Z
沒有公共構造:它們的運行時間值是不重要的,只是他們的編譯時間信息的事項。
來源
2015-06-01 22:32:31
chi
不,編譯時不需要知道類型。例如,編譯'id'時不知道所有可能的參數是什麼。 – augustss
@augustss好點,但是'SomeNat'的目的是什麼? – Alec
這是一種存在量化類型。你知道這是Nat,但不是確切的類型。 – augustss