Haskell 中的 Monad

has*_*023 7 monads haskell

我是 Monads 的新手,正在尝试编写一个添加函数,但我不确定为什么这不起作用。使用 monad 时,是否需要以特定方式返回值?

monadd :: (Monad m, Num b) => m b -> m b -> m b
monadd mx my = mx >>= (\x -> my >>= (\y -> (x + y)))
Run Code Online (Sandbox Code Playgroud)

Ice*_*ack 9

你想使用pure(更一般的形式return

\n
monadd :: Monad m => Num a => m a -> m a -> m a\nmonadd mx my = mx >>= (\\x -> my >>= (\\y -> pure (x + y)))\n
Run Code Online (Sandbox Code Playgroud)\n

的右侧(延续)>>=必须始终返回一元操作。但当你添加时,x + y :: a你就有了一个数字。你需要pure (x + y) :: m a把它变成一个单一的动作:

\n
monadd :: Monad m => Num a => m a -> m a -> m a\nmonadd mx my = mx >>= (\\x -> my >>= (\\y -> pure (x + y)))\n              ^^^       ^   ^^^       ^    ^^^^^^^^^^^^\n              m a       a   m a       a    m a\n
Run Code Online (Sandbox Code Playgroud)\n

你可以等效地写成do- 表示法

\n
monadd :: Monad m => Num a => m a -> m a -> m a\nmonadd mx my = do\n  x <- mx\n  y <- my\n  pure (x + y)\n
Run Code Online (Sandbox Code Playgroud)\n

实际上。这不需要Monad.Applicative(n 元提升)就足够了:

\n
monadd :: Applicative m => Num a => m a -> m a -> m a\nmonadd = liftA2 (+)\n
Run Code Online (Sandbox Code Playgroud)\n

Functor提升一元函数以及Applicative提升常量和 n 元函数的提醒(其中liftA0 = pureliftF1 = fmap):

\n
liftA0 :: Applicative f => (a)                -> (f a)\nliftF1 :: Functor     f => (a -> b)           -> (f a -> f b)\nliftA2 :: Applicative f => (a -> b -> c)      -> (f a -> f b -> f c)\nliftA3 :: Applicative f => (a -> b -> c -> d) -> (f a -> f b -> f c -> f d)\n
Run Code Online (Sandbox Code Playgroud)\n

仅当计算之间Monad存在依赖性时才需要。请注意,在您的情况下,my计算并不依赖于结果mx

\n

如果m b取决于它的输出,m a它会变成a -> m b。然后Monad需要:

\n
dependency :: Monad m => (a -> b -> c) -> m a -> (a -> m b) -> m c\ndependency (\xc2\xb7) as bs = do\n  a <- as\n  b <- bs a\n  pure (a \xc2\xb7 b)\n
Run Code Online (Sandbox Code Playgroud)\n


Wil*_*sem 7

使用 monad 时,是否需要以特定方式返回值?

是的,您需要在单子上下文中换行x并返回,使用 ,因此:yreturn :: Monad m => a -> m a

monadd :: (Monad m, Num b) => m b -> m b -> m b
monadd mx my = mx >>= (\x -> my >>= return (x+y)))
Run Code Online (Sandbox Code Playgroud)

然而,由于 monadmx和的两个操作my彼此独立Applicative就足够了,您可以将其实现为:

monadd :: (Applicative f, Num b) => f b -> f b -> f b
monadd mx my = (+) <$> mx <*> my
Run Code Online (Sandbox Code Playgroud)

或通过liftA2 :: Applicative f => (a -> b -> c) -> f a -> f b -> f c

monadd :: (Applicative f, Num b) => f b -> f b -> f b
monadd = liftA2 (+)
Run Code Online (Sandbox Code Playgroud)

  • 请不要说“两个单子”。这里只涉及一个单子。 (2认同)