更好的方法来实现需要[Maybe a]并返回Maybe [a]的函数

时间:2018-09-20 20:38:54

标签: haskell

我需要一个将[Maybe a]列表作为输入,获取每个值,对其进行处理并返回Maybe [a]的函数。如果输入列表中没有内容,我想返回Nothing。

firstRequest.doOnSuccess(resp1 -> {
  secondRequest.doOnSuccess(resp2 -> {

  });
});

我写了这个

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

它可以工作,但是我想知道是否可以做得更好。我不喜欢先做无mlist再重新映射mlist的部分。

1 个答案:

答案 0 :(得分:7)

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

表示从元素(abc之一开始为Nothing的那一刻起,结果就是Nothing,如果所有值都是Just,我们将使用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将产生一个叉积,但是如果提供我们要应用叉积的集合之一的元素的列表之一为空,则结果为也为空。