Haskell中的单子

pdsfdshx  于 2022-12-13  发布在  其他
关注(0)|答案(2)|浏览(158)

我是Monads的新手,我想写一个add函数,但我不知道为什么这个函数不起作用。当使用Monads时,有没有一个特定的方法来返回一个值?

monadd :: (Monad m, Num b) => m b -> m b -> m b
monadd mx my = mx >>= (\x -> my >>= (\y -> (x + y)))
zz2j4svz

zz2j4svz1#

您要使用purereturn的更一般形式)

monadd :: Monad m => Num a => m a -> m a -> m a
monadd mx my = mx >>= (\x -> my >>= (\y -> pure (x + y)))

>>=的右边(继续)必须总是返回一元动作,但是当你加上x + y :: a时,你得到一个数字,你需要pure (x + y) :: m a将它转换成一元动作:

monadd :: Monad m => Num a => m a -> m a -> m a
monadd mx my = mx >>= (\x -> my >>= (\y -> pure (x + y)))
              ^^^       ^   ^^^       ^    ^^^^^^^^^^^^
              m a       a   m a       a    m a

可以等效地用do表示法来写它。

monadd :: Monad m => Num a => m a -> m a -> m a
monadd mx my = do
  x <- mx
  y <- my
  pure (x + y)

实际上,这并不需要MonadApplicative(n元提升)就足够了:

monadd :: Applicative m => Num a => m a -> m a -> m a
monadd = liftA2 (+)

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

liftA0 :: Applicative f => (a)                -> (f a)
liftF1 :: Functor     f => (a -> b)           -> (f a -> f b)
liftA2 :: Applicative f => (a -> b -> c)      -> (f a -> f b -> f c)
liftA3 :: Applicative f => (a -> b -> c -> d) -> (f a -> f b -> f c -> f d)

只有当计算之间存在 * 依赖性 * 时,才需要Monad。注意,在您的示例中,my计算不依赖于mx计算的结果。
如果m b依赖于m a的输出,它将变成a -> m b。那么Monad是必需的:

dependency :: Monad m => (a -> b -> c) -> m a -> (a -> m b) -> m c
dependency (·) as bs = do
  a <- as
  b <- bs a
  pure (a · b)
5sxhfpxr

5sxhfpxr2#

当使用单子时,是否需要特定的方法来返回一个值?
是的,您需要将xy Package 回一元上下文中,使用**return :: 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)))

由于单子mxmy的两个操作彼此独立,因此Applicative就足够了,您可以将其实现为:

monadd :: (Applicative f, Num b) => f b -> f b -> f b
monadd mx my = (+) <$> mx <*> my

或通过**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 (+)

相关问题