印在monad里面

Tac*_*cet 1 monads haskell functional-programming monad-transformers

我在haskell写作翻译.我想用monads做到这一点.我已经创建了解析器,所以我有很多函数:: State -> MyMonad State,我可以使用bind运行我的程序.m >>= inst1 >>= inst2.一切都很好,但我不知道如何使用那个monad用我的语言创建指令print(或read).

我不想要简单但丑陋的解决方案,比如保持字符串在State内打印,最后在main中打印.(如果我在打印时有无穷大怎么办?)我无法理解来自网络的关于monad功能部分的文本.有一些解释,如"在IO Monad中包装,它非常简单",但没有任何工作示例.几乎所有的印刷教程都是关于主要的印刷.

为了更好地解释问题,我准备了最小的"解释器"示例(如下).还有State就是Int,我的单子是AutomatM说明有型:: Int -> AutomatM Int.所以可能的指令是:

inc :: Int -> AutomatM Int
inc x = return (x+1)
Run Code Online (Sandbox Code Playgroud)

我设计它就像我想象的那样简单:

import Control.Applicative
import Control.Monad (liftM, ap)
import Control.Monad.IO.Class (MonadIO(..))
import System.IO

data AutomatM a = AutomatError | Running a

instance Show a => Show (AutomatM a) where
    show (AutomatError) = "AutomatError"
    show (Running a) = "Running " ++ show a

instance Functor AutomatM where
  fmap = liftM

instance Applicative AutomatM where
  pure  = return
  (<*>) = ap


instance Monad AutomatM where
  return x = Running x
  m >>= g = case m of
              AutomatError -> AutomatError
              Running x -> g x
magicPrint x = do
    -- print x         -- How can I make print work?
    -- c <- getLine    -- And if that is as simple as print
    b <- return "1000" -- how can I change constant to c?
    return (x + (read b :: Int))

main = do
    a <- getLine
    print $ (Running (read a :: Int)) >>= (\x -> return (x*2)) >>= magicPrint
Run Code Online (Sandbox Code Playgroud)

我的主要目标是添加print x内部magicPrint.但是,如果不是更难,那么拥有getLine会更好.

我在magicPrint中改变了状态,因为用我的语言打印有副作用.

我知道我需要monad变换器和MonadIO的东西,但是很难找到任何有初学者简单解释的教程.因此,我非常感谢扩展我的最小代码示例以使用print(也许是getLine /其他读取Int)以及对它的一些解释(可能带有链接).

Functor和Aplicative代码基于在haskell中定义一个新的monad,不会为Applicative提供任何实例

MCH*_*MCH 7

为了创建一个新的类型与Monad实例和访问IO它内部的形式,您将需要创建另一个叫做单子转换类型AutomatMT和声明的一个实例Monad,MonadTrans等它.它涉及很多样板代码.我会尝试澄清任何没有意义的事情.

import Control.Applicative
import Control.Monad (liftM, ap)
import Control.Monad.IO.Class (MonadIO(..))
import System.IO
import Control.Monad.Trans.Class (MonadTrans(..), lift)

data AutomatM a = AutomatError | Running a

instance Show a => Show (AutomatM a) where
    show (AutomatError) = "AutomatError"
    show (Running a) = "Running " ++ show a

instance Functor AutomatM where
  fmap = liftM

instance Applicative AutomatM where
  pure  = return
  (<*>) = ap

instance Monad AutomatM where
  return x = Running x
  m >>= g = case m of
              AutomatError -> AutomatError
              Running x -> g x

newtype AutomatMT m a = AutomatMT { runAutomatMT :: m (AutomatM a) }

mapAutomatMT :: (m (AutomatM a) -> n (AutomatM b)) -> AutomatMT m a -> AutomatMT n b
mapAutomatMT f = AutomatMT . f . runAutomatMT

instance (Functor m) => Functor (AutomatMT m) where
    fmap f = mapAutomatMT (fmap (fmap f))

instance MonadTrans AutomatMT where
    lift = AutomatMT . liftM Running

instance (Functor m, Monad m) => Applicative (AutomatMT m) where
    pure = AutomatMT . return . Running

    mf <*> mx = AutomatMT $ do
        mb_f <- runAutomatMT mf
        case mb_f of
            AutomatError -> return AutomatError
            Running f  -> do
                mb_x <- runAutomatMT mx
                case mb_x of
                    AutomatError -> return AutomatError
                    Running x  -> return (Running (f x))

instance (MonadIO m) => MonadIO (AutomatMT m) where
    liftIO = lift . liftIO

instance (Monad m) => Monad (AutomatMT m) where
    x >>= f = AutomatMT $ do
        v <- runAutomatMT x
        case v of
            AutomatError -> return AutomatError
            Running y  -> runAutomatMT (f y)

    fail _ = AutomatMT (return AutomatError)


magicPrint :: String -> (AutomatMT IO String)
magicPrint x = do
  liftIO $ print $ "You gave magic print " ++ x
  let x = "12"
  y <- pure 1
  liftIO $ print y
  pure $ "1"

main = do
  print "Enter some text"
  a <- getLine
  b <- runAutomatMT $ magicPrint a
  pure ()
Run Code Online (Sandbox Code Playgroud)