Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/list/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/csharp-4.0/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
List 用Haskell中的HoF实现滤波器_List_Haskell - Fatal编程技术网

List 用Haskell中的HoF实现滤波器

List 用Haskell中的HoF实现滤波器,list,haskell,List,Haskell,我正在尝试编写一个函数,它接受一个谓词f和一个列表,并返回一个列表,该列表包含满足f且保持顺序的所有项。诀窍是只使用高阶函数(HoF),不使用递归,不使用理解,当然也不使用过滤器。我建议您查看foldr我认为您可以这样使用map: filter' :: (a -> Bool) -> [a] -> [a] filter' p xs = concat (map (\x -> if (p x) then [x] else []) xs) 看到了吗?在列表列表中转换列表,如果您

我正在尝试编写一个函数,它接受一个谓词f和一个列表,并返回一个列表,该列表包含满足f且保持顺序的所有项。诀窍是只使用高阶函数(HoF),不使用递归,不使用理解,当然也不使用过滤器。

我建议您查看
foldr
我认为您可以这样使用
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]

在这里有
concatMap
使代码更简单:p

代码应该如下所示:

filter' :: (a -> Bool) -> [a] -> [a]
filter' p xs = concatMap (\x -> if (p x) then [x] else []) xs
按照sclv的建议,使用foldr可以通过以下方式完成:

filter'' :: (a -> Bool) -> [a] -> [a]
filter'' p xs = foldr (\x y -> if p x then (x:y) else y) [] xs

那么,是否允许使用ifs和空列表

filter = (\f -> (>>= (\x -> if (f x) then return x else [])))

您可以用
foldr
表示
filter

filter p = foldr (\x xs-> if p x then x:xs else xs) []
对于整数列表

filter2::(Int->Bool)->[Int]->[Int]
filter2 f []=[]
filter2 f (hd:tl) = if f hd then hd:filter2 f tl
                else filter2 f tl

你这么做显然是为了学习,所以让我给你看一些很酷的东西。首先,为了让我们耳目一新,过滤器的类型是:

filter :: (a -> Bool) -> [a] -> [a]
有趣的是最后一位
[a]->[a]
。它分解一个列表,然后建立一个新列表

递归模式在Haskell(和其他函数式语言)中非常常见,人们已经为其中一些模式命名。最简单的是变形,它是变形的对偶。最后,我将向您展示这与您当前的问题之间的关系

固定点 先决知识FTW

什么类型的
Nothing
?启动GHCI,它会说
什么都没有::也许是一个
,我不会不同意。什么都不做怎么样?再次使用GHCI,它说的是
Just Nothing::Maybe(Maybe a)
,这也是非常有效的,但是这个
Nothing
嵌入在
Just
s的任意数甚至无限数中的值呢。即,此值的类型是什么:

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)))
旁白:有人吗

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
这种
修复方式可能有点无聊。以下是一种固定点为列表的类型:

data L a r = Nil | Cons a r
type List a = Fix (L a)
这种数据类型将有助于演示一些递归模式

有用的事实:
consar
中的
r
称为递归站点

变形 变形是一种分解结构的操作。列表的反同构更为人所知的是折叠。现在,一个亚同态的类型可以这样表示:

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)
    转换为
    ta
    ,我们可以通过一厢情愿,使用
    fmap(cata f)
    ;我们假设我们能够构建
    cata
  • 最后,我们有一个
    ta
    ,我们想要一个
    a
    ,所以我们只使用
    f
前面我说过列表的反同构称为fold,但是
cata
目前看起来不太像fold。让我们根据
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 :: (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)
好的,反变形一次分解一层数据结构

变形 列表上的同构是展开。展开比折叠对偶更不常见,它们的类型如下:

unfoldr :: (b -> Maybe (a, b)) -> b -> [a]
正如您可以看到的那样,变形构建了数据结构。以下是更通用的类型:

ana :: Functor a => (a -> t a) -> a -> Fix t
这看起来应该很熟悉。这个定义也让人联想到反同构

ana f = In . fmap (ana f) . f
这是同样的事情。从
ana
构造
explode
比从
cata
构造
fold
更简单。注意
Maybe(a,b)
lab
之间的结构相似性

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)
把理论付诸实践 过滤器是一个有趣的函数,因为它可以从一个反同态或从一个反同态构造。这个问题的其他答案(到目前为止)也使用了反射,但我将用两种方式来定义它:

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

是的,是的,我知道我在“展开”版本中使用了递归定义,但请原谅,我教了你很多理论,而且过滤器不是递归的。

我忍不住用另一种方式回答这个问题,这次根本没有递归

-- 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

还有其他的方法,我对haskell有点不了解:除了使用
concat
,你可以更严格地使用
catMaybes::[maybea]->[a]
。这正是我的答案,只是它使用了列表单子。。或者还有其他区别吗?另外,它非常不清楚,也很难阅读..好吧,如果您使用mzero和import Control.Monad更改[],您将在任何Monad中得到一个过滤器,而不仅仅是在列表中。然而,这不是filterM