【问题标题】:Could not deduce (Eq a) from the context (...)无法从上下文中推断出 (Eq a) (...)
【发布时间】:2023-03-19 00:48:01
【问题描述】:

我是 Haskell 的新手。我写了这段代码:

deleteDuplicates :: [a] -> [a]
deleteDuplicates [] = []
deleteDuplicates (x:xs)
        | x == (head xs)        = x : (deleteDuplicates (tail xs))
        | otherwise             = x : (head xs) : (deleteDuplicates (tail xs))

这个错误是什么意思,为什么会发生?我是不是不小心比较了两种不同的类型?

set2.hs:10:3:
    Could not deduce (Eq a) from the context ()
      arising from a use of `==' at set2.hs:10:3-16
    Possible fix:
      add (Eq a) to the context of
        the type signature for `deleteDuplicates'
    In the expression: x == (head xs)
        In a stmt of a pattern guard for
                 the definition of `deleteDuplicates':
          x == (head xs)
    In the definition of `deleteDuplicates':
        deleteDuplicates (x : xs)
                           | x == (head xs) = x : (deleteDuplicates (tail xs))
                           | otherwise = x : (head xs) : (deleteDuplicates (tail xs))

【问题讨论】:

    标签: haskell types typeclass


    【解决方案1】:

    你的类型签名错误:

    deleteDuplicates :: [a] -> [a]
    

    这表示您的函数可以在任何类型的列表上工作,a,但事实并非如此!您稍后调用:

    x == (head xs)
    

    所以你必须能够比较你的类型是否相等。意味着签名必须是:

    deleteDuplicates :: Eq a => [a] -> [a]
    

    在这种情况下,最好删除显式类型签名,在 GHCi 中加载函数并发现解释器认为它应该具有的类型(通过:t deleteDuplicates)。

    更多错误

    此外,您使用head 是一个坏主意。 head 是一个偏函数,当xs == [] 时会失败。我建议你扩展模式匹配:

    deleteDuplicates (x1:x2:xs)
        | x1 == x2 = ...
        | otherwise = x1 : deleteDuplicates (x2:xs)
    

    还要注意otherwise 案例的修复。您正在跳过 x2,但是如果 x2 匹配列表中的下一个元素怎么办?像[1,2,2,3] 这样的东西会发现1 /= 2,然后递归会得到列表[2,3] - 哎呀!

    【讨论】:

    • 对于[1, 2, 2, 3] 无法生成删除所有重复项的列表,您是完全正确的。我的错。 Eq a => 对我来说是新事物......所以唯一要做的就是强制 a 类型的元素应该具有可比性?
    • 彼得:基本上,是的。这是一个“类型类约束”。函数== 声明在Eq 类型类中,因此它只能用于Eq 的实例。
    • @Pieter:可比较的平等,是的。 Eq a => 表示 a 必须是类型类 Eq 的实例。类型类指定实例实现的接口。 Eq 类提供了两个函数,(==)(/=),它们的类型都是 a -> a -> Bool。其他类型类将提供其他功能,例如Ord 提供小于、大于和类似的排序测试。
    【解决方案2】:

    编译器告诉你,如果aEq 的实例,仅从类型签名中是无法解决的。

    deleteDuplicates :: Eq a => [a] -> [a]
    

    您需要通过在签名中提及aEq 类型类的实例来告诉编译器。

    【讨论】:

      【解决方案3】:

      表达式

      x == (head xs)
      

      要求在xs 的成员上定义==,这意味着a 必须是类型类Eq 的实例。将函数的类型签名更改为

      deleteDuplicates :: Eq a => [a] -> [a]
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-02-01
        相关资源
        最近更新 更多