haskell - 如何评估 Maybe 列表的最佳实践

标签 haskell monads

我正在寻找一个函数,它接受一个函数 (a -> a -> a) 和一个 [Maybe a] 列表并返回 Maybe a。胡格尔没有给我任何有用的东西。这看起来是一个很常见的模式,所以我想问这种情况是否有最佳实践?

>>> f (+) [Just 3, Just 3]
Just 6
>>> f (+) [Just 3, Just 3, Nothing]
Nothing

提前致谢,克里斯

最佳答案

您应该首先打开 [Maybe a]进入Maybe [a]与所有Just元素(如果其中任何一个是 Nothing ,则产生 Nothing )。 这可以使用 sequence 来完成,使用 Maybe 的 Monad 实例:

GHCi> sequence [Just 1, Just 2]
Just [1,2]
GHCi> sequence [Just 1, Just 2, Nothing]
Nothing

definition of sequence相当于以下内容:

sequence [] = return []
sequence (m:ms) = do
  x <- m
  xs <- sequence ms
  return (x:xs)

因此我们可以将后一个示例扩展为:

do x <- Just 1
   xs <- do
       y <- Just 2
       ys <- do
           z <- Nothing
           zs <- return []
           return (z:zs)
       return (y:ys)
   return (x:xs)

使用do-notation expression of the monad laws ,我们可以将其重写如下:

do x <- Just 1
   y <- Just 2
   z <- Nothing
   return [x, y, z]

如果您知道 Maybe monad 是如何工作的,那么您现在应该了解 sequence 是如何工作的。努力实现所需的行为。 :)

然后您可以使用 foldr 来编写此内容使用(<$>) (来自 Control.Applicative ;等效于 fmapliftM )将二进制函数折叠到列表上:

GHCi> foldl' (+) 0 <$> sequence [Just 1, Just 2]
Just 3

当然,您可以使用任何您想要的折叠,例如 foldr , foldl1等等

作为额外的,如果您希望结果为 Nothing当列表为空时,从而能够省略折叠的零值而不用担心空列表上的错误,那么你可以使用这个折叠函数:

mfoldl1' :: (MonadPlus m) => (a -> a -> a) -> [a] -> m a
mfoldl1' _ [] = mzero
mfoldl1' f (x:xs) = return $ foldl' f x xs

foldr 也类似, foldl等。您需要导入 Control.Monad为此。

但是,使用方式必须略有不同:

GHCi> mfoldl1' (+) =<< sequence [Just 1, Just 2]
Just 3

GHCi> sequence [Just 1, Just 2] >>= mfoldl1' (+)
Just 3

这是因为,与其他折叠不同,结果类型看起来像 m a而不是a ;它是一个绑定(bind)而不是映射

关于haskell - 如何评估 Maybe 列表的最佳实践,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8544278/

相关文章:

Haskell 种类系统与类型族和多参数类型类

scala - 如何评估对链中最后成功步骤的理解?

haskell - 如何使用带有镜头的一元函数进行修改?

Haskell `ncurses` 库

haskell - (共)递归定义如何在 Haskell 中工作?

haskell - 我可以使用 Stack 在 Release模式下编译 Haskell 项目吗?

list - 在 Haskell 中获取自定义列表类型的头部和尾部

haskell - 具有 Bound 的相互递归语法

haskell - 在 Haskell 中折叠 Maybes

scala - 是否有 Scala 模式用于从一系列独立计算中收集错误消息?