簡體   English   中英

無法演繹(a〜[a])

[英]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.

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