折叠在哈斯克尔的Maybes

jan*_*ers 20 monads haskell

为了学习Haskell,我遇到了一种情况,我希望在列表中进行折叠,但我的累加器是一个Maybe.然而,我正在折叠的函数接受了Maybe中的"提取"值,如果一个失败,它们都会失败.我有一个解决方案,我发现kludgy,但我知道像我一样小Haskell,我相信应该有一个更好的方法.假设我们有以下玩具问题:我们想要列出一个列表,但由于某种原因四肢是坏的,所以如果我们在任何时候尝试总计四个,我们想要返回Nothing.我目前的解决方案如下:

import Maybe

explodingFourSum :: [Int] -> Maybe Int
explodingFourSum numberList =
    foldl explodingFourMonAdd (Just 0) numberList
    where explodingFourMonAdd =
        (\x y -> if isNothing x
                    then Nothing
                    else explodingFourAdd (fromJust x) y)

explodingFourAdd :: Int -> Int -> Maybe Int
explodingFourAdd _ 4 = Nothing
explodingFourAdd x y = Just(x + y)
Run Code Online (Sandbox Code Playgroud)

所以基本上,有没有办法在explodingFourMonAdd使用某种Monad折叠时清理或消除lambda ?或者以某种方式在>> =运算符中进行曲线处理,以便折叠表现得像>> =的链接函数列表?

hug*_*omg 23

我想你可以使用foldM

explodingFourSum numberList = foldM explodingFourAdd 0 numberList
Run Code Online (Sandbox Code Playgroud)

这可以让你摆脱额外的lambda 和开始时的那个(Just 0).


顺便说一句,看看hoogle搜索你真的不记得名字的功能.

  • @missingno:在发布答案之前,我几乎总是在GHCi中测试.我确定在这种情况下,因为你在我测试我的时候写了你的答案.;]我已经学会了先检查的困难方法,尤其是涉及一些monadic提升功能的地方.`foldM`实际上不是我通常想要的monadic折叠(有时会忘记认为它). (2认同)

sep*_*p2k 6

所以基本上,有没有办法使用某种单子折叠清理,或消除,在explodingFourMonAdd拉姆达?

亚普.在Control.Monad中有这个foldM功能,这正是你想要的.所以,你可以更换您的来电foldlfoldM explodingFourAdd 0 numberList.


fuz*_*fuz 5

你可以利用这个事实,即Maybemonad.该函数sequence :: [m a] -> m [a]具有以下效果,如果mMaybe:如果列表中的所有元素都是Just x某些元素x,则结果是所有这些元素的列表.否则,结果是Nothing.

因此,您首先要确定所有元素,不管它是否失败.例如,举个例子:

foursToNothing :: [Int] -> [Maybe Int]
foursToNothing = map go where
  go 4 = Nothing
  go x = Just x
Run Code Online (Sandbox Code Playgroud)

然后你运行序列和fmap折叠:

explodingFourSum = fmap (foldl' (+) 0) . sequence . foursToNothing
Run Code Online (Sandbox Code Playgroud)

当然,您必须根据具体情况进行调整.