簡體   English   中英

為什么 `fx = xx` 和 `gx = xxxxx` 具有相同的類型

[英]Why `f x = x x` and `g x = x x x x x` have the same type

我正在玩 Rank-N-type 並嘗試輸入xx 但是我發現這兩個函數可以以相同的方式輸入是違反直覺的。

f :: (forall a b. a -> b) -> c
f x = x x

g :: (forall a b. a -> b) -> c
g x = x x x x x

我還注意到fx = xx ... xx (many x s) 之類的東西仍然具有相同的類型。 誰能解釋為什么會這樣?

關鍵是x :: a -> b是一個可以提供任何類型值的函數,無論給出什么參數。 這意味着x可以應用於自身,結果可以再次應用於x ,依此類推。

至少,這就是它承諾的類型檢查器可以做的事情。 類型檢查器不關心是否存在任何這樣的值,只關心類型是否對齊。 fg實際上都不能被調用,因為不存在a -> b類型a -> b值(忽略 bottom 和unsafeCoerce )。

這不應該比以下事實更令人驚訝

m :: (∀ a . a) -> (∀ a . a) -> (Int, Bool)
m p q = (p, q)

具有相同的類型

n :: (∀ a . a) -> (∀ a . a) -> (Int, Bool)
n p q = (q, p)

就像在您的示例中一樣,這是有效的,因為通用量化參數可以以多種不同的方式使用,編譯器在每種情況下都會選擇適當的類型並強制x充當具有該類型的角色。

這實際上是一個相當人為的情況,因為像∀ a . a這樣的類型∀ a . a ∀ a . a∀ ab . a->b ∀ ab . a->b是無人居住的(模⊥),因此您實際上永遠無法使用帶有此類參數的 RankN 函數; 實際上,那時你甚至不會它!

實用的 RankN 函數通常會在其參數中強加一些額外的結構或類型類約束,例如

foo :: (∀ a . [a] -> [a]) -> ...

或者

qua :: (∀ n . Num n -> Int -> n -> n) -> ...

一個更簡單的例子

每當我們使用具有多態類型的變量(例如您的x )時,都可以觀察到這種現象。 身份函數id可能是最著名的例子。

id :: forall a . a -> a

在這里,所有這些表達式都進行類型檢查,並且類型為Int -> Int

id :: Int -> Int
id id :: Int -> Int
id id id :: Int -> Int
id id id id :: Int -> Int
...

這怎么可能? 好吧,關鍵是每次我們寫id我們實際上是指“應該從上下文中推斷出的某個未知類型a上的身份函數”。 至關重要的是,每次使用id都有自己的a

讓我們寫id @T來表示類型T上的特定標識函數。

寫作

id :: Int -> Int

實際上是指

id @Int :: Int -> Int

這很簡單。 相反,寫

id id :: Int -> Int

實際上是指

id @(Int -> Int) (id @Int) :: Int -> Int

其中第一個id現在指的是函數空間Int -> Int 而且當然,

id id id :: Int -> Int

方法

(id @((Int -> Int) -> (Int -> Int))) (id @(Int -> Int)) (id @Int) :: Int -> Int

等等。 我們沒有意識到類型會變得如此混亂,因為 Haskell 會為我們推斷這些類型。

具體案例

在您的具體情況下,

g :: (forall a b. a -> b) -> c
g x = x x x x x

我們可以通過多種方式進行類型檢查。 一種可能的方法是定義A ~ Int , B ~ Bool , T ~ (A -> B)然后推斷:

g x = x @T @(T -> T -> T -> c) (x @A @B) (x @A @B) (x @A @B) (x @A @B)

我建議花一些時間來了解所有類型的檢查。 (此外,我們對AB選擇是完全任意的,我們可以在那里使用任何其他類型。我們甚至可以為每個x使用不同的A s 和B s,只要第一個x被適當地實例化!)

很明顯,即使當xxx ...是一個更長的序列時,這種推斷也是可能的。

暫無
暫無

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

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