实现采用 [Maybe a] 和 returns Maybe [a] 的函数的更好方法
better way to implement function that takes [Maybe a] and returns Maybe [a]
我需要一个函数,它将 [Maybe a] 列表作为输入,获取每个值,对其进行处理,然后 return Maybe [a]。如果输入列表没有任何内容,我想 return Nothing。
func [Just 1,Just 2,Just 3,Just 4,Just 5] => this returns Just [1,2,3,4,5]
func [Just 1,Nothing,Just 3,Just 4,Just 5] => this returns Nothing
这是我写的
func mlist = if elem Nothing mlist
then Nothing
else Just $ map (\(Just e) -> e) mlist
它有效,但我想知道我是否可以做得更好。我不喜欢我首先执行 elem Nothing mlist 然后再次映射 mlist 的部分。
此功能已与 sequence :: Monad m => [m a] -> m [a]
函数一起存在:
Prelude> import Control.Monad
Prelude Control.Monad> sequence [Just 3]
Just [3]
Prelude Control.Monad> sequence [Just 3, Nothing]
Nothing
Prelude Control.Monad> sequence [Just 3, Just 2]
Just [3,2]
Prelude Control.Monad> sequence [Just 1,Just 2,Just 3,Just 4,Just 5]
Just [1,2,3,4,5]
Prelude Control.Monad> sequence [Just 1,Nothing,Just 3,Just 4,Just 5]
Nothing
本质上这只是一个 mapM id :: (Monad m, Traversable t) => t (m a) -> m (t a)
,因为例如对于 3 列表,它等于:
-- special case for 3 elements to demonstrate how it works
func3 [a, b, c] = do
ya <- a
yb <- b
yc <- c
return [ya, yb, yc]
或者像这样:
func3 [a, b, c] = a >>= \ya -> b >>= \yb -> c >>= yc -> return [ya, yb, yc]
(我在这里使用了一个特例,因为 mapM
引入了一些额外的函数使其更难理解)
因为 Maybe
,Monad Maybe
的实现方式如下:
instance Monad Maybe where
return = Just
Nothing >>= _ = Nothing
(Just x) >>= f = f x
所以这意味着从元素之一(a
、b
或 c
)是 Nothing
的那一刻起,结果将是 Nothing
,如果所有值都是 Just
s,我们将 "collect" 这些与 lambda 表达式,并最终产生一个包含元素的列表。
您可以将列表 []
视为 Maybe
的概括(其中 Nothing
是空列表,而 Just
是单例列表),并且可以观察到相同的行为:
Prelude Control.Monad> sequence [[1,2], [4,3]]
[[1,4],[1,3],[2,4],[2,3]]
Prelude Control.Monad> sequence [[1,2], [4,3], []]
[]
此处 sequence
将生成一个 叉积 ,但是如果提供我们应用叉积的集合之一的元素的列表之一是空,结果也为空
我需要一个函数,它将 [Maybe a] 列表作为输入,获取每个值,对其进行处理,然后 return Maybe [a]。如果输入列表没有任何内容,我想 return Nothing。
func [Just 1,Just 2,Just 3,Just 4,Just 5] => this returns Just [1,2,3,4,5]
func [Just 1,Nothing,Just 3,Just 4,Just 5] => this returns Nothing
这是我写的
func mlist = if elem Nothing mlist
then Nothing
else Just $ map (\(Just e) -> e) mlist
它有效,但我想知道我是否可以做得更好。我不喜欢我首先执行 elem Nothing mlist 然后再次映射 mlist 的部分。
此功能已与 sequence :: Monad m => [m a] -> m [a]
函数一起存在:
Prelude> import Control.Monad
Prelude Control.Monad> sequence [Just 3]
Just [3]
Prelude Control.Monad> sequence [Just 3, Nothing]
Nothing
Prelude Control.Monad> sequence [Just 3, Just 2]
Just [3,2]
Prelude Control.Monad> sequence [Just 1,Just 2,Just 3,Just 4,Just 5]
Just [1,2,3,4,5]
Prelude Control.Monad> sequence [Just 1,Nothing,Just 3,Just 4,Just 5]
Nothing
本质上这只是一个 mapM id :: (Monad m, Traversable t) => t (m a) -> m (t a)
,因为例如对于 3 列表,它等于:
-- special case for 3 elements to demonstrate how it works
func3 [a, b, c] = do
ya <- a
yb <- b
yc <- c
return [ya, yb, yc]
或者像这样:
func3 [a, b, c] = a >>= \ya -> b >>= \yb -> c >>= yc -> return [ya, yb, yc]
(我在这里使用了一个特例,因为 mapM
引入了一些额外的函数使其更难理解)
因为 Maybe
,Monad Maybe
的实现方式如下:
instance Monad Maybe where
return = Just
Nothing >>= _ = Nothing
(Just x) >>= f = f x
所以这意味着从元素之一(a
、b
或 c
)是 Nothing
的那一刻起,结果将是 Nothing
,如果所有值都是 Just
s,我们将 "collect" 这些与 lambda 表达式,并最终产生一个包含元素的列表。
您可以将列表 []
视为 Maybe
的概括(其中 Nothing
是空列表,而 Just
是单例列表),并且可以观察到相同的行为:
Prelude Control.Monad> sequence [[1,2], [4,3]]
[[1,4],[1,3],[2,4],[2,3]]
Prelude Control.Monad> sequence [[1,2], [4,3], []]
[]
此处 sequence
将生成一个 叉积 ,但是如果提供我们应用叉积的集合之一的元素的列表之一是空,结果也为空