Haskell避免在返回mays的函数中使用双重包装的mays

问题描述 投票:1回答:3

[我可以看到这里有很多关于Maybe类型和成分的问题,但是我很困惑,如果说实话,阅读这些内容会让我头疼。

这是我的处境:

为例,我有一个功能:

addm a b = Just (a + b)

如何在不使用模式匹配来展开add :: Maybe Int -> Maybe Int -> Maybe Int的情况下使用addm函数创建函数Maybe

我尝试过类似的东西

add x y = (addm <$> x) <*> y

但是它的类型为Maybe Int -> Maybe Int -> Maybe (Maybe Int)

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

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

add x y = x >>= addm y

做到了。不过,我对最初问题的答案感到好奇。

haskell monads functor maybe
3个回答
6
投票

有多种写法。所有这些都涉及到Maybe是Monad的事实。

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

add ma mb = join $ addm <$> ma <*> mb

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

add ma mb = do
    a <- ma
    b <- mb
    addm a b

或者您可以显式使用“ bind”(>>=)运算符,这是除终止符上方的do块所要执行的操作(但我发现它比其他两个选项不太明确和易于理解:]

add ma mb = ma >>= \a -> mb >>= \b -> addm a b

5
投票

在顶部贴上join

Control.Monad.join :: Monad m => m (m a) -> m -- 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

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


3
投票

使用force类型,卢克!

您的addm具有类型Int -> Int -> Maybe Int。您的目标是以一种可以给您Maybe Int -> Maybe Int -> Maybe Int的方式包装它。为此,我们需要一个类型为(Int -> Int -> Maybe Int) -> Maybe Int -> Maybe Int -> Maybe Int的函数。如果我们是search for that type on Hoogle,尽管base中没有结果,但是第三方库中有一些结果。 liftJoin2liftJoin2是等效的,两者都可以完全满足您的要求。如果您不希望为此引入新的依赖项,请检查其来源以查看其工作方式:

bind2
bind2

(我在这里对bind2 :: Monad m => (a -> b -> m c) -> m a -> m b -> m c bind2 f x y = liftA2 (,) x y >>= uncurry f 进行了一些修改,仅直接使用liftJoin2 :: (Monad m) => (a -> b -> m c) -> m a -> m b -> m c liftJoin2 f ma mb = join (liftM2 f ma mb) 方法,而不是liftJoin2的重命名包装器。)

© www.soinside.com 2019 - 2024. All rights reserved.