Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.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
Haskell 编写此函数(通常称为filterA)的惯用方法是什么?_Haskell_Applicative - Fatal编程技术网

Haskell 编写此函数(通常称为filterA)的惯用方法是什么?

Haskell 编写此函数(通常称为filterA)的惯用方法是什么?,haskell,applicative,Haskell,Applicative,我正在修这门课 这里有一个关于应用程序的部分,我被要求实现一个具有以下行为和类型的函数 -- | Filter a list with a predicate that produces an effect. -- -- >>> filtering (ExactlyOne . even) (4 :. 5 :. 6 :. Nil) -- ExactlyOne [4,6] -- -- >>> filtering (\a -> if a > 13 the

我正在修这门课

这里有一个关于应用程序的部分,我被要求实现一个具有以下行为和类型的函数

-- | Filter a list with a predicate that produces an effect.
--
-- >>> filtering (ExactlyOne . even) (4 :. 5 :. 6 :. Nil)
-- ExactlyOne [4,6]
--
-- >>> filtering (\a -> if a > 13 then Empty else Full (a <= 7)) (4 :. 5 :. 6 :. Nil)
-- Full [4,5,6]
--
-- >>> filtering (\a -> if a > 13 then Empty else Full (a <= 7)) (4 :. 5 :. 6 :. 7 :. 8 :. 9 :. Nil)
-- Full [4,5,6,7]
--
-- >>> filtering (\a -> if a > 13 then Empty else Full (a <= 7)) (4 :. 5 :. 6 :. 13 :. 14 :. Nil)
-- Empty
--
-- >>> filtering (>) (4 :. 5 :. 6 :. 7 :. 8 :. 9 :. 10 :. 11 :. 12 :. Nil) 8
-- [9,10,11,12]
--
-- >>> filtering (const $ True :. True :.  Nil) (1 :. 2 :. 3 :. Nil)
-- [[1,2,3],[1,2,3],[1,2,3],[1,2,3],[1,2,3],[1,2,3],[1,2,3],[1,2,3]]
filtering :: Applicative f => (a -> f Bool) -> List a -> f (List a)
——|使用产生效果的谓词筛选列表。
--
-->>>过滤(精确到一个偶数)(4.5.6.Nil)
--精确的里昂[4,6]
--
-->>>筛选(\a->如果a>13,则清空else Full)(a>>筛选(\a->如果a>13,则清空else Full)(a>>筛选(\a->如果a>13,则清空else Full)(a>>筛选(>)(4.5.6.7.8.9.10.11.12.Nil)8
-- [9,10,11,12]
--
-->>>筛选(常量$True:.True:.Nil)(1:.2:.3:.Nil)
-- [[1,2,3],[1,2,3],[1,2,3],[1,2,3],[1,2,3],[1,2,3],[1,2,3],[1,2,3]]
过滤::应用程序f=>(a->f布尔)->列表a->f(列表a)
我提出了以下实现,它满足了所有的要求

filtering f as =
  let x = sequence (f `map` as)
      y = zip as <$> x
      z = filter snd <$> y
   in map fst <$> z
将f过滤为=
设x=序列(f`map`as)
y=压缩为x
z=滤波器snd y
在地图fst z中
但我觉得这有点“迂回”,我想不出更直接的方法来做

<>注释:我已经扩展到<代码> x,y,z ,因为它使我更容易跟随正在发生的事情,并且当我意识到我可以把它全部表达在一行上时,我不认为这是更直接的,因此不能回答我的问题。
注2:本课程似乎是从基本部分构建通用类型类。我们从
List
的自定义实现开始,接着是
Functor
,现在是
Applicative
,因此我只能使用这些类中的概念。我还不能使用
Monad
中的任何内容。

我的第一个想法是要以普通的
过滤器开始,请执行以下操作:

filter :: (a -> Bool) -> List a -> List a
filter _ Nil = Nil
filter f (x :. xs) =
    let b = f x
        ys = filter f xs
    in
    if b then x :. ys else ys
…并尝试将其扩展到
Applicative

filtering :: (Applicative f) => (a -> f Bool) -> List a -> f (List a)
filtering _ Nil = pure Nil
filtering f (x :. xs) =
    let b = f x
        ys = filtering f xs
    in
    if b then x :. ys else ys
这种尝试有两个问题:
fx
fbool
,而不是
Bool
,因此
如果b那么…
是类型错误,
过滤fxs
f(列表a)
,而不是
列表a
,因此
x:.ys
是类型错误

我们可以使用
lift2::(Applicative f)=>(a->b->c)->fa->fb->fc来解决这些问题:

filtering f (x :. xs) =
    lift2 (\b ys -> if b then x :. ys else ys) (f x) (filtering f xs)
lift2
让我们分别从
fx
过滤fxs
局部提取
Bool
列表a
;或者更准确地说,我们将
if…then…else
计算包装在一个函数中,该函数
lift2
然后推入
f

或者,我们可以直接使用

filtering f (x :. xs) =
    (\b ys -> if b then x :. ys else ys) <$> f x <*> filtering f xs
过滤f(x:.xs)= (\b ys->if b then x:.ys else ys)f x筛选f xs
或者以稍微不同的方式编写助手函数:

filtering f (x :. xs) =
    (\b -> if b then (x :.) else id) <$> f x <*> filtering f xs
过滤f(x:.xs)= (\b->if b then(x:.)else id)f x筛选f xs
这里是一个关于
foldr
的实现(并且是使用基本类型和函数编写的)。我相当肯定它相当于


以下是一个不同的例子,灵感来自您的原始解决方案(注意
序列(map f xs)
遍历f xs
相同):

filterA::Applicative f=>(a->f Bool)->[a]->f[a]
filterA f=fmap concat.transverse(\x->bool[][x]f x)
bool Nothing(Just x)
catMaybes
来自
数据。可能
而不是
bool[][x]
concat
也会起作用。)


请注意,此解决方案需要对列表进行额外的遍历,因为
遍历
不足以实现筛选。这就是为什么
筛选
catMaybes
filterA
和朋友需要进行泛化的原因。

旁注:witherable库确实调用(一个概括的版本)它。回答得很好!对于所有不熟悉本课程的阅读者来说,自定义列表类型上的运算符(:)相当于股票列表类型上的(:)运算符。@ChechyLevas和
lift2
liftA2
from
Control.Applicative
import Control.Applicative (liftA2)
import Data.Bool (bool)

filterA :: Applicative f => (a -> f Bool) -> [a] -> f [a]
filterA f = foldr (\x xs -> liftA2 (++) (bool [] [x] <$> f x) xs) (pure [])
GHCi> filterA (\x -> print x *> pure (x > 5)) [1..10]
1
2
3
4
5
6
7
8
9
10
[6,7,8,9,10]
filterA :: Applicative f => (a -> f Bool) -> [a] -> f [a]
filterA f = fmap concat . traverse (\x -> bool [] [x] <$> f x)