我正在做些运动以练习Haskell技能。我的任务是自己使用find
函数来实现Haskell函数filter
。
我已经实现了没有find
函数的filter
函数(请参见下面的代码块),但是现在我的问题是要使用filter
函数来实现它。
-- This is the `find` function without `filter` and it's working for me.
find1 e (x:xs)= if e x then x
else find1 e xs
-- This is the find function with the filter function
find2 e xs = filter e xs
find1
的结果正确
*Main> find1(>4)[1..10] Output : [5].
但是我写过滤器的实际任务是给我
*Main> find2(>4)[1..10] Output : [5,6,7,8,9,10].
我想要的find2
结果是find1
的结果。
答案 0 :(得分:2)
要将“剪切列表”仅包含一个head元素,请使用take 1
:
> take 1 [1..]
[1]
> take 1 []
[]
> take 1 $ find2 (> 4) [1..10]
[5]
> take 1 $ find2 (> 14) [1..10]
[]
如果您需要实现自己的take 1
函数,只需根据每种可能的输入情况写下其方程式:
take1 [] = []
take1 (x:xs) = [x]
或者使用filter
findWithFilter p xs = take1 $ filter p xs
您的find1
定义与您显示的输出不对应。相反,以下定义将:
find1 e (x:xs) = if e x then [x] -- you had `x`
else find1 e xs
find1 _ [] = [] -- the missing clause
习惯上将谓词p
而不是e
称为助记符设备。强烈建议将类型签名添加到所有顶级定义中。
如果您自己编写困难,可以先不使用签名,然后询问GHCi推断出哪种类型,而不是使用该签名如果它确实表达了您的意图 –否则就意味着您已经编码了不同的内容:
> :t find1
find1 :: (t -> Bool) -> [t] -> [t]
第一次尝试似乎不错。
除了,您实际上希望输出列表中的元素永远不超过1个:对于某些[]
,它是[x]
或x
,永远不超过一个。
列表[]
的类型在这里太宽容了,因此不完美。
虽然确实存在这种类型。它称为Maybe
:对于某些Maybe t
,类型Nothing
的值可以是Just x
或x :: t
(读:x
的类型是{{ 1}}):
t
我们甚至不必在这里import Data.Maybe (listToMaybe)
find22 p xs = listToMaybe $ filter p xs
:函数take 1
(读:具有一种类型的函数,在listToMaybe :: [a] -> Maybe a
中输入,在[a]
中输出)从输入列表中最多获取一个元素,因为结果类型不允许有多个元素-它根本没有更多空间。因此,它正确表达了我们的意图:最多生成一个元素(如果有):
Maybe a
在确定确实需要时,在其定义上方添加完整签名:
> find22 (> 4) [1..10]
Just 5
> find22 (> 14) [1..10]
Nothing
接下来,自己实施find22 :: (a -> Bool) -> [a] -> Maybe a
。为此,只需遵循类型,然后编写方程式枚举可能的输入情况,就可以在每种情况下产生适当的输出类型值,就像我们上面对listToMaybe
所做的那样。