[英]Could not deduce (a ~ [a])
我嘗試編寫一個函數,它接受一個子列表列表,反轉子列表並返回連接的反向子列表。 這是我的嘗試:
conrev :: Ord a => [[a]] -> [a]
conrev [[]] = []
conrev [[a]] = reverse [a]
conrev [(x:xs)] = reverse x ++ conrev [xs]
main = putStrLn (show (conrev [[1,2],[],[3,4]]))
我收到此錯誤:
3.hs:4:27:
Could not deduce (a ~ [a])
from the context (Ord a)
bound by the type signature for conrev :: Ord a => [[a]] -> [a]
at 3.hs:1:11-31
`a' is a rigid type variable bound by
the type signature for conrev :: Ord a => [[a]] -> [a] at 3.hs:1:11
In the first argument of `reverse', namely `x'
In the first argument of `(++)', namely `reverse x'
In the expression: reverse x ++ conrev [xs]
我究竟做錯了什么? 第二個問題是 - 類型簽名可能更通用嗎? 我必須寫得盡可能通用。
在等式中
conrev [(x:xs)] = reverse x ++ conrev [xs]
您匹配包含單個元素的列表,該列表是非空列表x:xs
。 所以,給定類型
conrev :: Ord a => [[a]] -> [a]
列表x:xs
必須具有類型[a]
,因此x :: a
。
現在,你調用reverse x
,這意味着x
必須是一個列表, x :: [b]
。 然后你連接起來
reverse x :: [b]
同
conrev [xs] :: [a]
從中可以得出b
必須與a
類型相同。 但早先確定a〜 a ~ [b]
。 總而言之,這個等式需要a ~ [a]
。
如果你沒有寫出(不必要的) Ord a
約束,你就會得到不那么不透明的東西
Couldn't construct infinite type a = [a]
錯誤。
如果你刪除了一些outer []
你的實現會有效:
conrev :: Ord a => [[a]] -> [a]
conrev [] = []
conrev [a] = reverse a
conrev (x:xs) = reverse x ++ conrev xs
但更好的實施將是
conrev = concat . map reverse
您的第二個模式與您想要的不匹配,看起來您錯誤地認為值的結構類型的結構。
[[a]]
作為一種類型意味着“某種類型a
列表列表”
[[a]]
作為模式意味着“匹配包含單個列表的列表,該列表包含將綁定到名稱 a
的單個元素。
編輯:如果我理解你要做什么,中間案例實際上是多余的。 第三種情況將處理非空列表,第一種情況將處理空列表。 為單身人士名單制作另一個案例是不必要的。
編輯2:
第三種情況的實施還存在另一個問題。
conrev :: Ord a => [[a]] -> [a]
conrev [(x:xs)] = reverse x ++ conrev [xs]
給定類型,您看到x
必須是[a]
類型, xs
必須是[[a]]
類型。 所以寫conrev [xs]
類型[[[a]]]
的值傳遞給conrev
。 這是您的類型錯誤來自的地方。 你含蓄地指出, [a]
是同類型的a
通過調用convrev [xs]
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.