【问题标题】:Could not deduce (a ~ [a])无法推断(a ~ [a])
【发布时间】:2013-01-08 20:13:13
【问题描述】:

我尝试编写一个函数,它接受子列表的列表,反转子列表并返回串联的反转子列表。这是我的尝试:

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]

我做错了什么?第二个问题是 - 类型签名可以更通用吗?我必须尽可能写得通俗一点。

【问题讨论】:

  • 据我所知,你不需要 Ord a =>
  • 这边:conrev :: [[]] -> []?我收到一个错误,Expecting one more argument to '[]'
  • 尝试 conrev :: [[a]] -> [a]
  • Couldn't match expected type 'a' with actual type '[a]' 'a' is a rigid type variable bound by the type signature for conrev :: [[a]] -> [a] at 3.hs:1:11

标签: list haskell reverse signature type-deduction


【解决方案1】:

在等式中

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 ~ [b]。所以总的来说,这个等式需要a ~ [a]

如果你没有编写(不必要的)Ord a 约束,你会得到更少的不透明

Couldn't construct infinite type a = [a]

错误。

如果您删除了一些外部[],您的实现将起作用:

conrev :: Ord a => [[a]] -> [a]
conrev [] = []
conrev [a] = reverse a
conrev (x:xs) = reverse x ++ conrev xs

但更好的实现应该是

conrev = concat . map reverse

【讨论】:

    【解决方案2】:

    您的第二个模式与您想要的不匹配,看起来您将类型的结构误认为值的结构。

    [[a]] 作为类型表示“某种类型的列表列表a

    [[a]] 作为模式表示“匹配包含 single 列表的列表,该列表包含 将绑定到名称的 single 元素 a.

    编辑: 如果我了解您要执行的操作,则中间情况实际上是多余的。第三种情况将处理非空列表,第一种情况将处理空列表。没有必要为单例列表创建另一个案例。

    编辑 2:

    第三种情况的实现还有一个问题。

    conrev :: Ord a => [[a]] -> [a]
    conrev [(x:xs)] = reverse x ++ conrev [xs]
    

    鉴于您看到的类型,x 必须是 [a] 类型,xs 必须是 [[a]] 类型。所以写conrev [xs] 是将[[[a]]] 类型的值传递给conrev。这是您的类型错误的来源。您通过调用convrev [xs] 隐含地声明[a]a 的类型相同。

    【讨论】:

    • 这正是我的想法。我有一个包含某种类型的子列表列表(在这种情况下我推送整数)。在模式匹配中,当我只有一个子列表时,我想处理这种情况。
    • 是的,但是您将类型语法与匹配值的模式混为一谈。考虑一下你的中间情况在列表[[1,2]] 上做了什么,你会得到一个模式匹配错误。在[[1]]a 绑定到1 的情况下,然后您执行reverse [1],这在技术上是正确的,但没有用。
    • 嗯...好的,我删除了它。但我还有一个Could not deduce (a ~ [a]) 的问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-19
    • 1970-01-01
    • 2013-10-05
    • 2021-07-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多