簡體   English   中英

為什么這個Haskell代碼編譯?

[英]Why does this Haskell code compile?

鑒於:

uncurry :: (a-> b -> c) -> (a,b) -> c    
id :: a -> a

調用uncurry id產生類型為的函數: (b -> c, b) -> c

我們如何得到這個結果?

如何使用id(a - > a)作為第一個參數來表示,這需要一個(a - > b - > c)函數?

如果我們從制作類型的角度來看它,就會更容易理解弄清楚我們需要對id的類型做些什么才能使它適合uncurry所需的形狀。 既然我們有:

id :: a -> a

我們還有:

id :: (b -> c) -> (b -> c)

這可以通過替換可以看出b -> ca在原始類型的id ,就像你可以替代Int搞清楚的類型時,而不是id 42 然后我們可以將括號放在右側,因為(->)是右關聯的:

id :: (b -> c) -> b -> c

表明id的類型適合形式a -> b -> c ,其中ab -> c 換句話說,我們可以通過專門化它已經擁有的一般類型來重塑id的類型以適應所需的形式。

理解這一點的另一種方法是看到uncurry ($)也有類型(b -> c, b) -> c 比較id($)的定義:

id :: a -> a
id a = a

($) :: (a -> b) -> a -> b
($) f x = f x

我們可以使后一個定義更加無點:

($) f = f

在這一點上, ($)只是對特定類型的id ,這一事實變得清晰。

如何使用id(a - > a)作為第一個參數來表示,這需要一個(a - > b - > c)函數?

實際上, uncurry需要(a -> (b -> c))函數。 您看得出來差別嗎? :)

省略括號是邪惡的(有時候)。 這使得新手無法破譯Haskell。 當然,在你收集了一些語言經驗之后,你覺得你根本不需要它們了。

在這里,一旦我們明確地寫出所有省略的括號,一切都變得清晰了:

uncurry :: (a -> (b -> c)) -> ((a,b) -> c)
id      ::  a ->    a

現在,編寫uncurry id調用a1 -> a1a2 -> (b -> c)的類型統一。 這很簡單, a1 ~ a2a1 ~ (b -> c) 只是機械的東西,這里沒有創造性思維 所以問題中的id實際上有類型a -> a where a ~ (b -> c) ,因此uncurry id具有類型(b -> c,b) -> c ,通過簡單替換a ~ (b -> c)進入(a,b) -> c 也就是說,它需要一對b -> c函數和一個b值,並且必須產生一個c值。

由於類型是最通用的(即沒有任何關於它們的知識,因此沒有特定的函數來調用可能以某種特殊方式執行該技巧),這里生成c值的唯一方法調用 b -> c使用b值作為參數。 當然,這就是($)作用。 所以uncurry id == uncurry ($) ,雖然id肯定不是 ($)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM