学习Haskell,我正在尝试编写一个给定条件的函数takeIf
,并且列表返回满足条件的所有列表元素。
所需输出的示例:
takeIf (>0) [] --> []
takeIf (>0) [-1, 0, 1, 2] --> [1,2]
我尝试了这个定义:
takeIf cond [] = []
takeIf cond (x:xs) = if (cond x)
then x:(takeIf cond xs)
else []:(takeIf cond xs)
但它不起作用。
我的第一个问题是:我有
:t takeIf --> ([a] -> Bool) -> [[a]] -> [[a]]
为什么呢?为什么不:
:t takeIf --> (a -> Bool) -> [a] -> [a]
如何让这段代码生效?
这是我得到的错误:
如果有帮助,我正在使用ghci
答案 0 :(得分:10)
[]:(takeIf cond xs)
在这里,您尝试将[]作为takeIf cond xs
结果的新第一个元素。由于[]
是一个列表,因此GHC推断takeIf cond xs
的结果必须是列表。由于takeIf的结果与其参数的类型相同,这意味着xs
也必须是列表列表。由于x
是xs
的元素,因此x
必须是列表。
好像你打算[]:
意味着“不在列表中添加任何内容”,但是[]
并不是什么,它是空列表。 [] : []
,不会向您[]
提供[[]]
。同样地,[] : [1,2,3]
会给你[[], 1, 2, 3]
- 除了那个类型不好,所以它真正给你的是一个类型错误。
如果您不想在列表中添加任何内容,请不要在列表中添加任何内容,即只使用someList
代替[] : someList
。
答案 1 :(得分:3)
因为sepp2k比我快 - 我只想补充一点,你可能想看看filter
及其来源,这正是你尝试重新实现的功能。
这是实际的来源
filter :: (a -> Bool) -> [a] -> [a]
filter _pred [] = []
filter pred (x:xs)
| pred x = x : filter pred xs
| otherwise = filter pred xs
答案 2 :(得分:0)
替代方案是折叠,例如
filter' f = foldr go [] where
go x xs = if f x then x:xs else xs