我尝试过这样:
member e [] = False
member e xs = foldr (==) e xs
然后:
member 3 [1,2,3,4,5]
我收到此错误消息:
No instance for (Num Bool) arising from the literal `3'
In the first argument of `memb', namely `3'
我不知道这意味着什么......有人可以帮助我吗?
PS:member是一个函数,给定元素和元素列表,返回元素是否属于该列表。通常的实施是:
member a [] = False
member a (x:xs) | (a == x) = True
| otherwise = member a xs
PS2:完整代码
-- member:: Int -> [Int] -> Bool (Not necessary)
member e [] = False
member e xs = foldr (==) e xs
main = do
putStrLn (show( member 3 [1,2,3] ) )
答案 0 :(得分:7)
你几乎就在那里,但是你可以看到你的类型没有排队。如果你给member
一个明确的类型签名本来会更好,我猜你想要像
member :: (Eq a) => a -> [a] -> Bool
这会让编译器抱怨当你试图使用它时,它不会进行类型检查而不是失败。问题是foldr (==)
的类型为Bool -> [Bool] -> Bool
,与您期望的不完全相同。
相反,你想要的更像是
member e xs
= foldr (||)
False
(map (e ==) xs)
我已经将参数拆分为不同的行,以便更容易看到foldr
的参数究竟是什么。这里的主要想法是将值列表转换为Bool
列表,然后使用或运算符(||
)将列表缩减为单个Bool
。由于Haskell默认是惰性的,map (e ==) xs
实际上不会计算任何内容,直到foldr
需要元素,因此您不必将列表中的每个元素都与{{1}进行比较}。
你可以直接用e
和更复杂的累加器(foldr
的第一个参数)直接实现这个:
foldr
可以等同地写为
member e xs = foldr (\x acc -> if acc then x else e == x) False xs
请注意,在这种情况下,我们必须对member e xs = foldr (\x acc -> acc || e == x) False xs
中的每个e == x
执行x
,直到找到xs
为acc
的情况为止。这就是我之前选择True
的原因,我只是将累加值的步骤与执行比较分开。
要记住map (e ==)
(以及大多数其他折叠)的一件事是,第二个参数(也称为初始值)必须与foldr
的最终结果具有相同的类型。在这种情况下,您希望foldr
返回foldr
,因此第二个参数也必须是Bool
。
解决这些问题的一个技巧,只要你有一个足够新的GHC版本,就是打字孔。这些允许你放入"洞"在表达式中,编译器会告诉你该洞应该是什么类型,所以如果你做了
Bool
GHC将打印出来
member :: Eq a => a -> [a] -> Bool
member e xs = foldr _1 _2 xs
这告诉您给Found hole `_1` with type: a -> Bool -> Bool
...
Relevant bindings include
xs :: [a]
e :: a
Found hole `_2` with type: Bool
...
Relevant bindings include
xs :: [a]
e :: a
的函数必须具有foldr
类型,并且初始值必须具有类型a -> Bool -> Bool
。由于Bool
的类型为e
,因此您无法将其置于该洞中。这种技术可以帮助指导您定义函数,特别是当您不确定所有类型时,编译器会告诉您每个参数的用途。
答案 1 :(得分:0)
我们知道,使用伪代码语法,
foldr g z [] = z
foldr g z [a,b,c,...,n] = g a (foldr g z [b,c,...,n])
我们知道我们希望它成为
member x [] = False
member x [a,b,c,...,n] = (x==a) || member x [b,c,...,n]
= foldr g z [a,b,c,...,n]
= g a (foldr g z [b,c,...,n])
------------------------ r
= (x==a) || (foldr g z [b,c,...,n])
= foldr g z [a,b,c,...,n]
where
{ z = False ;
g a r = (x==a) || r } --- r
因此使用我们定义的常规 Haskell 语法
member x = foldr g False where { g a r = (x==a) || r }