haskell - 也许单子和一个列表
问题描述
好的,所以我正在尝试学习如何使用单子,从可能开始。我想出了一个例子,我无法弄清楚如何以一种很好的方式应用它,所以我希望其他人可以:
我有一个包含一堆值的列表。根据这些值,我的函数应该返回列表本身,或者返回 Nothing。换句话说,我想做一种过滤器,但命中的结果是函数失败。
我能想到的唯一方法是使用过滤器,然后比较我得到的列表的大小为零。有没有更好的办法?
解决方案
这看起来很适合traverse
:
traverse :: (Traversable t, Applicative f) => (a -> f b) -> t a -> f (t b)
这有点拗口,所以让我们专门针对您的用例,使用列表和Maybe
:
GHCi> :set -XTypeApplications
GHCi> :t traverse @[] @Maybe
traverse @[] @Maybe :: (a -> Maybe b) -> [a] -> Maybe [b]
它的工作原理是这样的:你给它一个a -> Maybe b
函数,它被应用于列表的所有元素,就像这样fmap
做一样。扭曲的是,这些值随后以一种仅在没有任何sMaybe b
时才为您提供修改后的列表的方式组合;Nothing
否则,总体结果为Nothing
。这就像手套一样符合您的要求:
noneOrNothing :: (a -> Bool) -> [a] -> Maybe [a]
noneOrNothing p = traverse (\x -> if p x then Nothing else Just x)
(allOrNothing
本来是一个更悦耳的名字,但我不得不根据你的描述翻转测试。)
关于Traversable
和Applicative
类,我们可能会讨论很多事情。现在,我会多谈一点Applicative
,以防你还没有遇到它。Applicative
是 的超类,Monad
具有两个基本方法:pure
,与 相同return
,并且(<*>)
与 (>>=)
例如Maybe
...
GHCi> :t (>>=) @Maybe
(>>=) @Maybe :: Maybe a -> (a -> Maybe b) -> Maybe b
GHCi> :t (<*>) @Maybe
(<*>) @Maybe :: Maybe (a -> b) -> Maybe a -> Maybe b
...我们可以这样描述差异: in mx >>= f
, ifmx
是一个Just
-value,(>>=)
到达它的内部以应用f
并产生一个结果,根据里面的内容mx
,结果将是一个Just
-value 或 a Nothing
。mf <*> mx
但是,在 if和mf
are mx
-valuesJust
中,您可以保证获得一个Just
值,该值将保存将函数 frommf
应用于值 from的结果mx
。(顺便说一句:如果mf
或是mx
会发生什么Nothing
?)
traverse
涉及Applicative
因为我在开头提到的值的组合(在您的示例中,将多个Maybe a
值转换为 a Maybe [a]
)是使用(<*>)
. 由于您的问题最初是关于 monads,值得注意的是可以定义traverse
usingMonad
而不是Applicative
. 这种变体的名称为mapM
:
mapM :: (Traversable t, Monad m) => (a -> m b) -> t a -> m (t b)
我们更喜欢它traverse
,mapM
因为它更通用——如上所述,Applicative
它是Monad
.
最后,您对这是“一种过滤器”的直觉很有意义。特别是,一种思考方式Maybe a
是,当您选择布尔值并将类型的值附加a
到True
. 从这个有利的角度来看,它(<*>)
可以作为&&
这些奇怪的布尔值的一个,如果你碰巧提供了它们中的两个,它会结合附加的值(参见DarthFennec 的使用 实现的建议any
)。一旦你习惯了Traversable
,你可能会喜欢看一下and类,它们利用了Filterable
Witherable
Maybe
and之间的这种关系Bool
。
推荐阅读
- javascript - 使用 zeit 部署 MERN 应用程序时出错(现在)
- python - 使用 pip 安装 turicreate 时出错 ...同时为 llvmlite 构建轮子
- android - Android打开新活动并从数据库中传递值
- php - 比较 JSON 数据和 MySQL 表,更新行和插入新行
- php - laravel 中的唯一字段验证问题
- rust - 返回类型是一个结构,但它需要一个引用
- javascript - javascript在foreach循环完成后执行过滤
- react-native - 传递对象时出现 React Native Share 问题
- angular - 为什么我在部署 Angular 9 + Firebase 应用程序后出现路由错误
- swift - 如何在 Xcode swift 5 中制作视频循环?