Haskell从IO a转换为ma

BAR*_*ARJ 1 monads haskell

我想将monadic值转换为另一个Monad类的monadic值.

让我们说我有一个实例声明:

    instance ClassM TypeT where
        funcX = abc >>= \x -> return (x)
Run Code Online (Sandbox Code Playgroud)

ClassM:是一个自己的monad定义类
TypeT:是一个自己定义的类型/数据,带有monad实现实现
abc:类型为IO a

我如何将abc :: IO a
的monadic值转换为classM的monadic值m => ma
又名m1 a - > m2 a(其中m1不是m2)(例如:IO 5 - >只是5)

我对funcX的实现显然不正确.如果有可能,那么正确的实施应该是什么?

感谢您的时间和帮助.

J. *_*son 6

Monad这个类代表所有monad的东西---它不是一个名词而是一个形容词.如果你想将一个特定的monad转换为一个在所有monad中都是通用的值,那么这个类型看起来就像其中之一

Monad m => IO a       -> m a
Monad m => Maybe a    -> m a
Monad m => [a]        -> m a
Monad m => Either e a -> m a
Run Code Online (Sandbox Code Playgroud)

虽然有一种非常特殊的monad具有这种特性,但它通常是不可能的.

您可能要做的另一件事是在底部使用Monad变压器IO.这意味着您将另一个monad"叠加在"之上IO.这使您可以进行常规操作

lift :: MonadTrans t => m a -> t m a     -- notice that t takes two parameters
lift :: IO a -> MyTransformer IO a       -- specializing the generic function
Run Code Online (Sandbox Code Playgroud)

并且,MyTransformer具体操作取决于具体操作

runMyTransformer :: MyTransformer m a -> m a
runMyTransformer :: MyTransformer IO a -> IO a   -- specialized
Run Code Online (Sandbox Code Playgroud)

例如,最简单的MonadTransIdT.

newtype IdT m a = IdT { runIdT :: m a } deriving Functor

instance Monad m => Monad (IdT m) where
  return a = IdT (return a)
  IdT ma >>= f = IdT (ma >>= runIdT . f) 

instance MonadTrans IdT where
  lift ma = IdT ma
Run Code Online (Sandbox Code Playgroud)

给我们操作

lift   :: IO a -> IdT IO a
runIdT :: IdT IO a -> IO a
Run Code Online (Sandbox Code Playgroud)

在这种情况下,它们只是彼此相反.通常,行为可能要复杂得多.