Haskell 新手,我不知道如何将函数 (a -> b) 应用到列表 [Maybe a] 并获得 [Maybe b]
maybeX:: (a -> b) -> [Maybe a] -> [Maybe b]
该函数应该与 map 执行完全相同的操作,将函数 f 应用于 Maybe 语句列表,如果它 Just 它返回我一个 f Just 并且如果它是一个 Nothing 则只是一个 Nothing。
像以下示例一样,我想在以下 List 的每个元素上添加 +5 :
[Just 1,Just 2,Nothing,Just 3]
并得到
[Just 6,Just 7,Nothing,Just 8]
真的想弄清楚这一点,我尝试了很多,但它似乎总是我不知道这种 Maybe 数据类型的工作方式..
谢谢你的帮助!
最佳答案
让我们从定义如何作用于单个 Maybe
开始。 ,然后我们将其扩展到整个列表。
mapMaybe :: (a -> b) -> Maybe a -> Maybe b
mapMaybe f Nothing = Nothing
mapMaybe f (Just x) = Just (f x)
如果
Maybe
包含一个值,mapMaybe
申请 f
给它,如果它不包含一个值,那么我们只返回一个空的 Maybe
.但是我们有一个列表
Maybe
s,所以我们需要申请mapMaybe
给他们每个人。mapMaybes :: (a -> b) -> [Maybe a] -> [Maybe b]
mapMaybes f ms = [mapMaybe f m | m <- ms]
这里我使用列表推导来评估
mapMaybe f m
对于每个 m
在 ms
.现在换一种更先进的技术。
Functor
捕获了将函数应用于容器中的每个值的模式。类型类。class Functor f where
fmap :: (a -> b) -> f a -> f b
A型
f
是 Functor
如果您可以编写一个函数,该函数从 a
获取函数至b
, 并将该函数应用于 f
满满的a
s 获取 f
满满的b
s。例如,[]
和 Maybe
都是Functor
年代:instance Functor Maybe where
fmap f Nothing = Nothing
fmap f (Just x) = Just (f x)
instance Functor [] where
fmap f xs = [f x | x <- xs]
Maybe
fmap
的版本与 mapMaybe
相同我在上面写了,[]
的实现使用列表推导来应用 f
到列表中的每个元素。现在,写
mapMaybes :: (a -> b) -> [Maybe a] -> [Maybe b]
,您需要使用 []
对列表中的每个项目进行操作fmap
的版本, 然后对个体 Maybe
进行操作使用 Maybe
fmap
的版本.mapMaybes :: (a -> b) -> [Maybe a] -> [Maybe b]
mapMaybes f ms = fmap (fmap f) ms
-- or:
mapMaybes = fmap . fmap
请注意,我们实际上调用了两个不同的
fmap
这里的实现。外层是fmap :: (Maybe a -> Maybe b) -> [Maybe a] -> [Maybe b]
, 发送到 []
的Functor
实例。内页是(a -> b) -> Maybe a -> Maybe b
.还有一个附录 - 虽然这很深奥,所以如果你不明白这里的所有内容,请不要担心。我只是想让你尝尝我认为很酷的东西。
这种“
fmap
s 链”样式 (fmap . fmap . fmap ...
) 是深入钻取结构的多层的常用技巧。每个fmap
类型为 (a -> b) -> (f a -> f b)
, 所以当你用 (.)
组合它们时你正在构建一个高阶函数。fmap :: Functor g => (f a -> f b) -> (g (f a) -> g (f b))
fmap :: Functor f => (a -> b) -> (f a -> f b)
-- so...
fmap . fmap :: (Functor f, Functor g) => (a -> b) -> g (f a) -> g (f b)
因此,如果您有一个仿函数(仿函数...)的仿函数,那么 n
fmap
s 将允许您在结构的第 n 级映射元素。 Conal Elliot 称这种风格为 "semantic editor combinators" .该技巧也适用于
traverse :: (Traversable t, Applicative f) => (a -> f b) -> (t a -> f (t b))
,是一种“有效的fmap
”。traverse :: (...) => (t a -> f (t b)) -> (s (t a) -> f (s (t b)))
traverse :: (...) => (a -> f b) -> (t a -> f (t b))
-- so...
traverse . traverse :: (...) => (a -> f b) -> s (t a) -> f (s (t b))
(我省略了
=>
之前的位,因为我用完了水平空间。)因此,如果您有一个可遍历的(可遍历的...),您只需编写即可对第 n 级的元素执行有效的计算traverse
n次。像这样组成遍历是 lens
背后的基本思想。图书馆。
关于function - 在 Maybe 类型上应用函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47498896/