Haskell:具有多态相等函数的递归

时间:2010-09-14 10:49:26

标签: haskell polymorphism

好的,所以我们还没有学过多态函数,但我们仍然需要编写这段代码。

Given:
nameEQ (a,_) (b,_) = a == b
numberEQ (_,a) (_,b) = a == b
intEQ a b = a == b
member :: (a -> a -> Bool) -> a -> [a] -> Bool

我补充说:

member eq x ys | length ys < 1 = False
               | head(ys) == x = True
            | otherwise = member(x,tail(ys))

但我得到的错误是不正确的类型以及其他一些东西。我们必须查看某个类型中是否存在元素。所以我们有以上两种类型。给出了一些例子:

phoneDB = [("Jenny","867-5309"), ("Alice","555-1212"), ("Bob","621-6613")]

> member nameEQ ("Alice","") phoneDB
True
> member nameEQ ("Jenny","") phoneDB
True
> member nameEQ ("Erica","") phoneDB
False
> member numberEQ ("","867-5309") phoneDB
True
> member numberEQ ("","111-2222") phoneDB
False
> member intEQ 4 [1,2,3,4]
True
> member intEQ 4 [1,2,3,5]
False 

不完全确定我需要在这做什么。任何关于此的帮助或文档都会很棒。谢谢!

3 个答案:

答案 0 :(得分:7)

各种各样的事情(我不会写出完整的答案,因为这是家庭作业):

  1. length ys < 1可以更简单地表达为null ys
  2. 您不需要在函数参数周围使用括号。 head(ys)更常见的是head ys
  3. 如果需要,您可以将顶部案例和其他两个案例转换为模式匹配而不是警卫。 member eq x [] = ...将匹配空案例,member eq x (y:ys) = ...将匹配非空案例。
  4. 您正在使用==进行比较。但是你打算使用你给的eq函数。
  5. 您正在将成员的参数包括在内,就好像这是Java或类似的一样。在Haskell中,参数由空格分隔,因此member(x,(tail(ys))应为member x (tail ys)

答案 1 :(得分:5)

你忽略的那些错误“关于不是正确的类型以及其他一些东西”很重要。他们告诉你什么是错的。

例如,我第一次将您的代码放入ghc我得到了:

Couldn't match expected type `a -> a -> Bool'
       against inferred type `(a1, [a1])'
In the first argument of `member', namely `(x, tail (ys))'
In the expression: member (x, tail (ys))
In the definition of `member':
    member eq x ys
             | length ys < 1 = False
             | head (ys) == x = True
             | otherwise = member (x, tail (ys))

好吧,当我看到它很简单时 - 你输入了

member(x,tail(ys))

当你明确表示:

member x (tail ys)

Commas在Haskell中意味着你不打算在那里。

一旦我做出更改,它再次抱怨您已将eq参数留给member

如果您还没有了解Haskell类型类,那么之后的错误会更加困难,但只需说明您需要使用传入的eq函数进行比较,而不是==

答案 2 :(得分:2)

由于a中的参数member :: (a -> a -> Bool) -> a -> [a] -> Bool 不要派生Eq,你不能用==来比较它们, 但是必须使用给定的函数eq

因此,您的代码可能如下所示:

member :: (a -> a -> Bool) -> a -> [a] -> Bool
member eq x ys
 | length ys < 1 = False
 | eq x (head ys) = True
 | otherwise = member eq x (tail ys)

唯一的问题是,该长度仍需要评估整个List, 所以你可以写一篇更好的写作:

member' :: (a -> a -> Bool) -> a -> [a] -> Bool
member' eq x (y:ys)
 | eq x y = True
 | otherwise = member' eq x ys
member' _ _ [] = False

使用任何你可以进一步简化它:

member'' :: (a -> a -> Bool) -> a -> [a] -> Bool
member'' f a = any (f a)