【问题标题】:Determine if value is an element of a list in Haskell确定值是否是 Haskell 中列表的元素
【发布时间】:2017-09-19 05:37:21
【问题描述】:

我正在尝试编写一个函数来确定一个元素是否存在于列表中,这两者都是由用户提供的。我认为递归解决方案是最好的。这就是我所拥有的:

isElement :: a -> [b] -> Bool
isElement a [] = False
isElement a (x:xs) = if a == x then True
                     else isElement a xs

但它无法编译。错误是“无法将预期类型 -a' 与实际类型 -b' 匹配”。我不知道这意味着什么或如何解决问题。

【问题讨论】:

  • 您的类型签名错误。 == 要求其操作数具有相同的类型,但您有 a :: ax :: b
  • 不只是任何类型; a 需要是 Eq 类型类的实例:isElement :: Eq a => a -> [a] -> Bool
  • if 附近使用TrueFalse 时,您应该始终保持警惕。通常这意味着逻辑可以在没有if 的情况下更直接地表达。在这种情况下,这是真的。您可以将第二个等式的主体写为(a == x) || isElement a xs
  • 我猜这个问题是为了学习,否则elem是一个很好的功能。

标签: haskell recursion


【解决方案1】:

您的代码在技术上有效。在这里给你带来麻烦的是类型签名。

首先,这是工作代码:

isElement :: (Eq a) => a -> [a] -> Bool
isElement a [] = False
isElement a (x:xs) = if a == x then True
                     else isElement a xs

我改变了两件事:

  1. 使用 Haskell 的链表(使用 [] 的数据类型)时要记住的第一件事是它们只能包含相同类型的元素。但是,在您的类型签名中,a ➞ [b] 您指定您的第一个元素的类型为 a,而列表中的元素类型为 b,与 a 不同。
  2. 第二件事是“启用”泛型类型ab 的相等性检查,GHC 会给出警告,提示您需要遵循的步骤来解决这个问题:

    • No instance for (Eq a) arising from a use of ‘=='
      Possible fix:
        add (Eq a) to the context of
          the type signature for:
            isElement :: a -> [a] -> Bool
    

    所以它告诉我们的是指定a 类型可以进行比较!
    这太棒了,因为我们完全可以通过在代码中使用 (Eq a) => 部分向编译器提供该线索来做到这一点,大致翻译为“给定数据类型 a 的此属性(Eq),[在此处插入类型签名] ”。 (请随时在这里纠正我,StackOverflow 的人!)

您的代码有效,并且使用这种显式递归重新实现函数是我首先了解它的工作原理的方式,所以不要犹豫,通过重写您使用的东西来学习,然后在 Hackage 上查看它们的来源以查看现实世界的haskellers是如何做到的。

学习愉快!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-02-07
    • 2011-06-09
    • 1970-01-01
    • 2018-01-10
    • 1970-01-01
    • 2016-12-07
    • 2018-08-03
    • 2016-02-07
    相关资源
    最近更新 更多