我正在尝试编写一个带谓词f和列表的函数,并返回一个列表,该列表包含满足保留顺序的f的所有项。诀窍是只使用更高阶函数(HoF),没有递归,没有理解,当然也没有过滤器。
答案 0 :(得分:7)
您可以filter
:
foldr
filter p = foldr (\x xs-> if p x then x:xs else xs) []
答案 1 :(得分:6)
我认为您可以这样使用 map
:
filter' :: (a -> Bool) -> [a] -> [a]
filter' p xs = concat (map (\x -> if (p x) then [x] else []) xs)
你知道吗?转换列表列表中的列表,如果您想要的元素不通过p,则转为空列表
filter' (> 1) [1 , 2, 3 ]
将是:concat [ [], [2], [3]] = [2,3]
在prelude中, concatMap
可使代码更简单:P
代码应如下所示:
filter' :: (a -> Bool) -> [a] -> [a]
filter' p xs = concatMap (\x -> if (p x) then [x] else []) xs
使用foldr,如sclv所建议,可以使用以下内容完成:
filter'' :: (a -> Bool) -> [a] -> [a]
filter'' p xs = foldr (\x y -> if p x then (x:y) else y) [] xs
答案 2 :(得分:6)
你显然要这样做才能学习,所以让我向你展示一些很酷的东西。首先,为了刷新我们的想法,过滤器的类型是:
filter :: (a -> Bool) -> [a] -> [a]
这个有趣的部分是最后一位[a] -> [a]
。它分解了一个列表并构建了一个新列表。
递归模式在Haskell(和其他函数语言)中非常常见,人们已经为这些模式中的某些模式提出了名称。最简单的是变形,它是变形的双重性。我会告诉你最后这与你眼前的问题有什么关系。
必备知识FTW!
Nothing
的类型是什么?解雇GHCI,它说Nothing :: Maybe a
我不会反对。那么Just Nothing
呢?再次使用GHCI,它说Just Nothing :: Maybe (Maybe a)
也是完全有效的,但是这个Nothing
嵌入Just
的任意数字,甚至是无限数字的价值如何呢?即,这个值的类型是什么:
foo = Just foo
Haskell实际上并没有允许这样的定义,但稍微调整一下我们可以做出这样的类型:
data Fix a = In { out :: a (Fix a) }
just :: Fix Maybe -> Fix Maybe
just = In . Just
nothing :: Fix Maybe
nothing = In Nothing
foo :: Fix Maybe
foo = just foo
哇,足够近!使用相同的类型,我们可以创建任意嵌套的nothing
s:
bar :: Fix Maybe
bar = just (just (just (just nothing)))
除此之外:Peano算术吗?
fromInt :: Int -> Fix Maybe
fromInt 0 = nothing
fromInt n = just $ fromInt (n - 1)
toInt :: Fix Maybe -> Int
toInt (In Nothing) = 0
toInt (In (Just x)) = 1 + toInt x
这个Fix Maybe
类型有点无聊。这是一个固定点是列表的类型:
data L a r = Nil | Cons a r
type List a = Fix (L a)
这种数据类型将有助于演示一些递归模式。
实用信息:r
中的Cons a r
称为递归网站
catamorphism是一种破坏结构的操作。列表的catamorphism更好地称为折叠。现在,变形的类型可以这样表达:
cata :: (T a -> a) -> Fix T -> a
可以等同地写成:
cata :: (T a -> a) -> (Fix T -> a)
或者用英语作为:
你给我一个将数据类型减少到一个值的函数,我会给你一个函数,将它的固定点减少到一个值。
实际上,我说谎,这种类型真的是:
cata :: Functor T => (T a -> a) -> Fix T -> a
但原则是一样的。请注意,T
仅针对递归网站的类型进行参数化,因此Functor
部分实际上是在说“给我一种操纵所有递归网站的方法”。
然后cata
可以定义为:
cata f = f . fmap (cata f) . out
这是非常密集的,让我详细说明。这是一个三步过程:
Fix t
,这是一种难以使用的类型,我们可以通过应用out
(来自Fix
的定义)让我们更轻松t (Fix t)
。t (Fix t)
,通过一厢情愿的想法,将t a
转换为fmap (cata f)
我们可以做的事情。我们假设我们能够构建cata
。t a
,我们需要a
,因此我们只使用f
。之前我曾说过,列表的变形被称为折叠,但cata
看起来并不像折叠。让我们用cata
来定义折叠函数。
重新封装,列表类型为:
data L a r = Nil | Cons a r
type List a = Fix (L a)
这需要是一个有用的仿函数,这是直截了当的:
instance Functor (L a) where
fmap _ Nil = Nil
fmap f (Cons a r) = Cons a (f r)
如此专业化cata
我们得到:
cata :: (L x a -> a) -> List x -> a
我们几乎在那里:
construct :: (a -> b -> b) -> b -> L a b -> b
construct _ x (In Nil) = x
construct f _ (In (Cons e n)) = f e n
fold :: (a -> b -> b) -> b -> List a -> b
fold f m = cata (construct f m)
好的,catamorphisms一次打破一层数据结构。
列表上的Anamorphisms正在展开。与折叠双重相比,展开不太常见,它们的类型如下:
unfoldr :: (b -> Maybe (a, b)) -> b -> [a]
正如您所看到的,anamorphisms构建了数据结构。这是更一般的类型:
ana :: Functor a => (a -> t a) -> a -> Fix t
这应该立即看起来很熟悉。这个定义也让人想起了这种变形。
ana f = In . fmap (ana f) . f
这是相反的事情。从unfold
构建ana
甚至比从fold
构建cata
更简单。请注意Maybe (a, b)
和L a b
之间的结构相似性。
convert :: Maybe (a, b) -> L a b
convert Nothing = Nil
convert (Just (a, b)) = Cons a b
unfold :: (b -> Maybe (a, b)) -> b -> List a
unfold f = ana (convert . f)
过滤器是一个有趣的功能,因为它可以从一个变形或变形构造。这个问题的其他答案(迄今为止)也使用了catamorphisms,但我将两种方式定义:
filter p = foldr (\x xs -> if p x then x:xs else xs) []
filter p =
unfoldr (f p)
where
f _ [] =
Nothing
f p (x:xs) =
if p x then
Just (x, xs)
else
f p xs
是的,是的,我知道我在展开版本中使用了递归定义,但请原谅我,我教你很多理论,无论如何 filter 不是递归的。
答案 3 :(得分:3)
我建议您查看foldr
。
答案 4 :(得分:2)
嗯,是否允许使用ifs和空列表?
filter = (\f -> (>>= (\x -> if (f x) then return x else [])))
答案 5 :(得分:1)
获取整数列表
filter2::(Int->Bool)->[Int]->[Int]
filter2 f []=[]
filter2 f (hd:tl) = if f hd then hd:filter2 f tl
else filter2 f tl
答案 6 :(得分:1)
我无法抗拒以另一种方式回答这个问题,这一次没有任何递归。
-- This is a type hack to allow the y combinator to be represented
newtype Mu a = Roll { unroll :: Mu a -> a }
-- This is the y combinator
fix f = (\x -> f ((unroll x) x))(Roll (\x -> f ((unroll x) x)))
filter :: (a -> Bool) -> [a] -> [a]
filter =
fix filter'
where
-- This is essentially a recursive definition of filter
-- except instead of calling itself, it calls f, a function that's passed in
filter' _ _ [] = []
filter' f p (x:xs) =
if p x then
(x:f p xs)
else
f p xs