Haskell 在返回可能的函数中避免双重包装的可能

Wil*_*sco 1 monads haskell functor maybe

我可以看到这里有很多关于 Maybe 类型和构图的问题,但我很困惑,如果我很诚实的话,阅读这些会让我头疼。

这是我的情况:

举例来说,我有一个函数:

addm a b = Just (a + b)
Run Code Online (Sandbox Code Playgroud)

如何add :: Maybe Int -> Maybe Int -> Maybe Int使用addm函数创建函数而不使用模式匹配来解包Maybes?

我试过类似的东西

add x y = (addm <$> x) <*> y
Run Code Online (Sandbox Code Playgroud)

但这有一种 Maybe Int -> Maybe Int -> Maybe (Maybe Int)

如果可能的话,我还想避免使用标准库之外的任何东西。

编辑:在我的具体情况下,我实际上只需要一个函数,Maybe Int -> Int -> Maybe Int 所以我能够使用

add x y = x >>= addm y
Run Code Online (Sandbox Code Playgroud)

成功了。不过,我仍然对原始问题的答案感到好奇。

Rob*_*ond 6

有很多方法可以写这个。所有都涉及到Maybe一个 Monad的事实。

也许最容易理解的方法是使用join函数,对于任何 Monad,它都会删除最外层的嵌套。这里有 type Maybe (Maybe a) -> Maybe a,这正是您要寻找的,与标准 Applicative 运算符相结合:

add ma mb = join $ addm <$> ma <*> mb
Run Code Online (Sandbox Code Playgroud)

或者您可以使用do符号以更命令式的方式编写计算,看起来像变量赋值,其中 Monad 负责传播任何Nothing值:

add ma mb = do
    a <- ma
    b <- mb
    addm a b
Run Code Online (Sandbox Code Playgroud)

或者,您可以显式使用“绑定”( >>=) 运算符,这就是do上面的代码块的作用(但我发现这比其他两个选项更不明确和易于理解):

add ma mb = ma >>= \a -> mb >>= \b -> addm a b
Run Code Online (Sandbox Code Playgroud)


HTN*_*TNW 5

join在上面贴一个。

Control.Monad.join :: Monad m => m (m a) -> m a -- combine two ms into one, this is why, as the meme goes, monads are monoids in the category of endofunctors

add x y = join $ addm <$> x <*> y
Run Code Online (Sandbox Code Playgroud)

我想指出,addm这样的写法(实际上,任何总是返回的函数Just)都是不自然的。您实际上只需编写add x y = (+) <$> x <*> y或 只是,但是当您处理真正有趣的单子代码时,以应用风格add = liftA2 (+)抛出在表达式之上的一般模式非常有用。join

  • 我几乎在评论中指出,“addm”的定义根本不需要或不想使用“Maybe”,但后来我反映OP说“为了举例”,所以我假设真正的功能更复杂并且涉及一些产生“Nothing”的机会。 (3认同)