當Haskell確定某個類型變量(由程序員顯式給出或由Haskell隱式引入)必須滿足一個條件時,它將需要遞歸地發生錯誤「發生檢查:無法構造[無限]類型」按照自身的方式定義,這將導致無限的「深度」類型(即,在其自身定義中「發生」的類型變量)。
它通常從任一對有關在程序混淆兩個不同的「結構的水平」程序員的一部分的錯字或概念上的錯誤造成的。
作爲一個簡單的例子,整數(類型[Int]
)的列表是一個有效的Haskell類型,所以是整數([[Int]]
)或整數的列表的列表的列表的列表的列表的列表的列表([[[[[Int]]]]]
),但只允許有限數量的列表級別。你不可能擁有列表清單等列表,一路下來 - 這將是一個無限的類型。如果Haskell認爲你想要它構造這樣的類型,它會給你一個「發生檢查」的錯誤。
如下定義:
yuck (x:xs) = x == xs
給出了這樣的錯誤正是這個原因。 Haskell從左側知道yuck
取一些未知元素類型的列表a
其中變量x
是類型a
的頭和變量xs
是類型[a]
的尾部。從RHS,操作(==)
力量x
和xs
具有相同類型 - 換句話說,它意味着約束a ~ [a]
其中波浪線表示「式的平等」。沒有有限型(無類型與數量有限列表級別)有這個特性,只有無效無限類型[[[[...forever...]]]]
可以讓您免除外列表級別,仍然有剩下的相同類型的,所以你的錯誤。
這裏的問題是程序員混淆了兩層結構:列表xs
和元素x
。
在你的具體的例子,對錯誤的原因是相似的,但難以解釋。操作者:
(<*>) :: (Applicative f) => f (a -> b) -> f a -> f b
採取與不同的基本類型2個應用性操作:左手側有一個類型通過施加到底層類型a -> b
的適用函子f
給出右手側有一個類型通過施加到底層類型b
相同適用函子f
給出。
你還沒告訴哈斯克爾其適用函子f
你想用的,所以哈斯克爾試圖推斷出它。因爲LHS具有類型:
(+4) :: (Num n) => n -> n
哈斯克爾嘗試與f (a -> b)
匹配類型n -> n
。使用(->)
類型運算符的前綴形式來編寫這些類型可能會更清楚:Haskell試圖匹配(->) n n
與f ((->) a b)
,其中f
是一個應用函子。
幸運的是,對於任何類型的(->) t
都有一個應用仿函數實例t
。所以,Haskell的理由是你想要的應用仿函數是f = (->) n
,並且它成功匹配(->) n n = f n
到f ((->) a b)
。這意味着n
等於((->) a b)
。然後,Haskell嘗試匹配RHS上的類型,匹配(->) n n = f n
與(->) n a = f a
。這工作,它意味着n
等於a
。
現在我們有一個問題。 n
同時等於a -> b
(來自LHS)和a
(來自RHS)。這意味着創造無限功能型的,這東西看起來像:
(((... forever ...)->b)->b)->b)->b
這是你可以排除在外...->b
,並留下與同類型的唯一途徑。這是一個不可能的無限類型,所以你會得到錯誤。
底層問題在於您犯了概念性錯誤。鑑於您正在使用ReaderExample
,我認爲您打算使用(->) n
應用仿函數實例,所以您和Haskell在這一點上達成了一致。在這種情況下:
(+4) :: (Num n) -> n -> n
是讀者的行動,從閱讀器讀取數,並增加了四到它。同樣,(+3)
是一個閱讀器操作,它從閱讀器中讀取一個數字,並向其中添加三個數字。
然而,(<*>)
是發生在從所述讀取器讀取以產生函數(非數字!)的LHS讀取器動作的操作者,然後將其應用於使用RHS從讀取的結果讀者產生一個數字。例如,如果你定義:
multiplyByReader :: (Num n) -> n -> n -> n
multiplyByReader readerNum input = readerNum * input
則:
multiplyByReader <*> (+4)
或簡單的版本:
(*) <*> (+4)
纔有意義。意圖的含義是:構建一個閱讀器動作,(1)使用LHS從閱讀器中讀取一個數字,以創建一個函數,該函數與閱讀器相乘;然後(2)將此函數應用於將RHS應用於讀者的數字。
這將相當於\r -> r * (r + 4)
,你可以看到:
> ((*) <*> (+4)) 5 -- same a 5 * (5 + 4)
45
>
當你寫(+3) <*> (+4)
,你是混合了兩種不同結構層次:LHS讀者產生了一些而應該得到功能可以應用於一個數字。
我最好的猜測是你想要創建一個閱讀器動作,將(+4)
應用於讀者以獲取一個數字,然後將(+3)
應用於該結果。在這種情況下,(+3)
不是讀者操作;它只是你要應用到讀者動作(+4)
,這相當於fmap
平在讀取器操作的結果的函數:
(+3) <$> (+4)
當然,你能等效它直接寫爲:
(+3) . (+4)
兩者都是增加7閱讀次數複合讀寫操作:
> ((+3) <$> (+4)) 5
12
> ((+3) . (+4)) 5
12
>
但是''<*>有類型'(<*> ):: Applicative f => f(a - > b) - > fa - > fb' ...由於在左邊你寫了'(+4)',Haskell的理由是'Num n => a〜b〜 N'。但是這意味着'(+3)'應該有'n'類型...... –
即使它起作用,它也意味着像'\ x - >(+)x 4((+)x 3)'這裏的第一個'(+)'有太多爭論。 – chi
就目前而言,由於您沒有勾勒出您的想法,因此要解釋您的思維錯誤在哪裏有點困難。以下是關於如何幫助我們幫助你的一些提示:你爲什麼期望這個函數返回一個參數?由於類型'(<*>)::應用型F => F(A - > B) - >發 - > fb',你能指望什麼每種類型的變量獲得專門到'(+4)<*>(+3) '(什麼是'f'?'a'?'b'?)?在這個表達式中,你認爲什麼具體類型對'4'有效? '(+4)'? '(+3)'? –