【问题标题】:Haskell isMember function errorHaskell isMember 函数错误
【发布时间】:2017-10-26 19:13:21
【问题描述】:
isMember:: a -> [a] -> Bool
isMember y [] = False
isMember y (x:xs) =
 if y == x then
  True
 else
  isMember y xs

尝试创建一个函数来识别某物是否是列表的成员。例如:

isMember 6 [1,2,3,4,5,6]
>True

但是,我不断收到编译器错误,指出“使用 '==' 导致 (Eq a) 没有实例”

不胜感激(我是函数式语言中 Haskell 和递归的新手,所以像我五岁一样解释。)

【问题讨论】:

    标签: list haskell functional-programming


    【解决方案1】:

    你快到了

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

    编译器告诉你你承诺接受任何类型的列表成员 - 但后来你使用了函数==,它不适用于所有类型(例如函数)。

    通过添加Eq a =>,您表示我接受所有具有 equals 方法的输入。

    一些补充说明

    你可以(重新)把最后一行写成

    isMember y (x:xs) = (y == x) || isMember y xs
    

    这相当于您的实现(感谢@chi 的评论)。 您的版本的优点在于它是尾递归的。

    另外一点需要注意——模式:

    • 为空列表案例返回一些东西 (isMember _ [] = False)
    • 并使用此值遍历列表 (isMember y (x:xs) = ...)

    碰巧出现了很多,并已被抽象为fold 函数家族(foldlfoldr ...)。把它放在你的用例中看起来像

    isMember y xs = foldl False (\x b -> (x == y) || b) xs
    

    【讨论】:

    • 由于|| 是懒惰的,我认为替代方案在除语法之外的所有方面都是尾递归的。它的执行与尾递归具有基本相同的空间和时间。
    • 为什么将foldl中的||改为&&
    • @4castle - 因为我在我的 ghci 会话中从错误的部分复制了它,所以我对其进行了测试以确保没有不正确的代码 - 但随后复制了错误的部分。 - 更新
    • 我认为以“Alternatively”开头的第二部分可能有点令人困惑,因为听起来您是在说重写最后一行是解决 OP 问题的另一种方法。这实际上只是额外的建议;无论如何,他们都需要添加Eq a。像“另外”这样的内容会更好吗?
    猜你喜欢
    • 2021-01-24
    • 1970-01-01
    • 1970-01-01
    • 2014-11-13
    • 1970-01-01
    • 1970-01-01
    • 2013-03-29
    • 2018-04-14
    • 2011-05-21
    相关资源
    最近更新 更多