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

发布于 2024-12-21 19:33:09 字数 258 浏览 3 评论 0原文

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

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

提前致谢,克里斯

i am looking for a function which takes a function (a -> a -> a) and a list of [Maybe a] and returns Maybe a. Hoogle gave me nothing useful. This looks like a pretty common pattern, so i am asking if there is a best practice for this case?

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

Thanks in advance, Chris

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

廻憶裏菂餘溫 2024-12-28 19:33:09

您应该首先将 [Maybe a] 转换为包含所有 Just 元素的 Maybe [a](产生 Nothing 如果其中任何一个是Nothing)。
这可以使用 sequence,使用 Maybe 的 Monad 实例:

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

序列的定义 等价于以下内容:

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)

使用 monad 法则的 do-notation 表达式,我们可以将其重写如下:

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

如果你知道 Maybe monad 是如何工作的,你现在应该明白 sequence 是如何实现的这期望的行为。 :)

然后,您可以使用 (<$>) (来自 Control.Applicative;相当于 fmap或 liftM)将二进制函数折叠到列表上:

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

当然,您可以使用任何您想要的折叠,例如 foldrfoldl1 等 另外,

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

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

和类似的foldrfoldl 等。您需要导入 Control.Monad 为此。

然而,它的使用方式必须略有不同:

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

or

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

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

You should first turn the [Maybe a] into a Maybe [a] with all the Just elements (yielding Nothing if any of them are Nothing).
This can be done using sequence, using Maybe's Monad instance:

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

The definition of sequence is equivalent to the following:

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

So we can expand the latter example as:

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

Using the do-notation expression of the monad laws, we can rewrite this as follows:

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

If you know how the Maybe monad works, you should now understand how sequence works to achieve the desired behaviour. :)

You can then compose this with foldr using (<$>) (from Control.Applicative; equivalently, fmap or liftM) to fold your binary function over the list:

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

Of course, you can use any fold you want, such as foldr, foldl1 etc.

As an extra, if you want the result to be Nothing when the list is empty, and thus be able to omit the zero value of the fold without worrying about errors on empty lists, then you can use this fold function:

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

and similarly for foldr, foldl, etc. You'll need to import Control.Monad for this.

However, this has to be used slightly differently:

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

or

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

This is because, unlike the other folds, the result type looks like m a instead of a; it's a bind rather than a map.

时光病人 2024-12-28 19:33:09

据我了解,您想要获得一堆可能的总和,或者如果其中任何一个是Nothing,则Nothing。这实际上非常简单:

maybeSum = foldl1 (liftM2 (+))

您可以将其概括为:

f :: Monad m => (a -> a -> a) -> [m a] -> m a
f = foldl1 . liftM2

当与 Maybe monad 一起使用时,f 完全按照您想要的方式工作。

如果您关心空列表,可以使用此版本:

f :: MonadPlus m => (a -> a -> a) -> [m a] -> m a
f _ []      = mzero
f fn (x:xs) = foldl (liftM2 fn) x xs

As I understand it, you want to get the sum of a bunch of maybes or Nothing if any of them are Nothing. This is actually pretty simple:

maybeSum = foldl1 (liftM2 (+))

You can generalize this to something like:

f :: Monad m => (a -> a -> a) -> [m a] -> m a
f = foldl1 . liftM2

When used with the Maybe monad, f works exactly the way you want.

If you care about empty lists, you can use this version:

f :: MonadPlus m => (a -> a -> a) -> [m a] -> m a
f _ []      = mzero
f fn (x:xs) = foldl (liftM2 fn) x xs
苦笑流年记忆 2024-12-28 19:33:09

或者

λ Prelude > fmap sum . sequence $ [Just 1, Just 2]
Just 3
λ Prelude > fmap sum . sequence $ [Just 1, Just 2, Nothing]
Nothing

,通过使用 (+)

λ Prelude > fmap (foldr (+) 0) . sequence $ [Just 1, Just 2]
Just 3
λ Prelude > fmap (foldr (+) 0) . sequence $ [Just 1, Just 2, Nothing]
Nothing

那么, maybeSum = fmap sum 。序列

What about something as simple as:

λ Prelude > fmap sum . sequence $ [Just 1, Just 2]
Just 3
λ Prelude > fmap sum . sequence $ [Just 1, Just 2, Nothing]
Nothing

Or, by using (+):

λ Prelude > fmap (foldr (+) 0) . sequence $ [Just 1, Just 2]
Just 3
λ Prelude > fmap (foldr (+) 0) . sequence $ [Just 1, Just 2, Nothing]
Nothing

So, maybeSum = fmap sum . sequence.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文