2010-12-14 81 views
2

「無法創建無限型」 的錯誤,我想知道爲什麼哈斯克爾接受這個在Haskell

perms xs = [ x:y | i <- [0..(length xs - 1)], x <- [xs!!i], y <- perms (takeOut i xs)] 

,但不會接受:

perms xs = [ x:(perms y) | i <- [0..(length xs - 1)], x <- [xs!!i], y <- (takeOut i xs)] 

它抱怨

[1的1]編譯主(abc.hs,解釋)

Occurs check: cannot construct the infinite type: t = [t] 
    Expected type: t -> [t] 
    Inferred type: [t] -> [[a]] 
In the second argument of `(:)', namely `(perms y)' 
In the expression: x : (perms y) 

我能理解它說什麼,我只是不能說爲什麼第一個是好的,第二個不是!

編輯:嗯,當然我也有

perms [] = [[]] 

在頂部。

由於

+2

'(x,i)< - zip xs [0 ..]'而不是'i < - [0 ..(length xs - 1)],x < - [xs !! i]'好得多 – 2010-12-14 09:01:57

+0

是的!謝謝! – 2010-12-15 01:43:41

回答

3

在列表解析,x <- ys結合在ysx每個元件。從本質上講,你想轉換:

[ f foo | foo <- bar ] 

進入

[ f bar ] 

短語

y <- perms (takeOut i xs) 

意思是 「每個排列的takeOut i xsy」。所以[ x:y | ... ]預先x到每個排列。

相應地,短語

y <- takeOut i xs 

手段 「爲各元素的takeOut i xsy」。因此,[ x:perms y | ... ]正試圖找到元素的所有排列y(甚至不是一個列表),然後將x預先添加到該排列列表。東西的排列是列表的列表,所以x必須是一個列表來做到這一點,事實並非如此。所以,基本上,第二個是沒有意義的。

我可以看到你爲什麼會被拋棄。請記住,<-let不同,這意味着每個

8

在第一個表達式必須x:y這意味着,如果x :: a然後y :: [a]x : perms y如果x :: a那麼它必須是perms y :: [a],但perms y :: [[a]](排列列表)。 Typechecker試圖統一[a][[a]]並失敗。

+0

這個答案過於技術性,並沒有給出任何直覺來源的錯誤。 – luqui 2010-12-14 22:34:39

4

我的大腦傷害,我不是專家,但我認爲:

perms xs = [ x:y | i <- [0..(length xs - 1)], x <- [xs!!i], y <- perms (takeOut i xs)] 

燙髮(外賣我的xs)是一個列表的列表。 x是consent到該列表的每個元素上。 Perms在整個列表中被調用,因此perms是一個函數列表。

perms xs = [ x:(perms y) | i <- [0..(length xs - 1)], x <- [xs!!i], y <- (takeOut i xs)] 

(取出我XS)是一個列表,並且該列表x的每個元件被consed到該元素的燙髮。 Perms在列表的每個元素上被調用,所以perms是一個函數。

只有前一種情況是內部一致的,類型分析儀愛你。