在 monad 中打印
Printing inside monad
我正在 haskell 中编写解释器。我想用 monad 做到这一点。
我已经创建了解析器,所以我有很多函数 :: State -> MyMonad State
,我可以 运行 我的程序使用绑定。 m >>= inst1 >>= inst2
。
一切正常,但我不知道如何用我的语言用那个 monad 创建指令 print
(或 read
)。
我不想要简单但丑陋的解决方案,例如让字符串在 State 内打印并最后在 main 中打印。 (如果打印时我有无穷大怎么办?)
我无法理解来自网络的关于 monad 功能的那部分的文本。有一些解释,如 "pack inside IO Monad, it's quite straightforward",但没有任何工作示例。几乎所有的打印教程都是关于在 main 中打印的。
为了更好地解释问题,我准备了最小的 "interpreter" 示例(如下)。 State
只是 Int
,我的 monad 是 AutomatM
指令类型为 :: Int -> AutomatM Int
。所以可能的指令是:
inc :: Int -> AutomatM Int
inc x = return (x+1)
我设计得尽可能简单:
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
我的主要目标是在magicPrint
中添加print x
。但是,如果它不难,那么有 getLine 就好了。
我在 magicPrint 中更改了状态,因为用我的语言打印有副作用。
我知道我需要一些关于 monad 转换器和 MonadIO 的东西,但是很难找到任何对初学者有简单解释的教程。
因此,我非常感谢扩展我的最小代码示例以处理打印(可能 getLine/other 读取 Int)和一些解释(可能带有链接)。
Functor 和 Aplicative 代码基于
为了创建一个带有 Monad
实例的新类型并在其中访问 IO
表单,您需要创建另一个名为 AutomatMT
的 monad 转换器类型并声明一个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 ()
我正在 haskell 中编写解释器。我想用 monad 做到这一点。
我已经创建了解析器,所以我有很多函数 :: State -> MyMonad State
,我可以 运行 我的程序使用绑定。 m >>= inst1 >>= inst2
。
一切正常,但我不知道如何用我的语言用那个 monad 创建指令 print
(或 read
)。
我不想要简单但丑陋的解决方案,例如让字符串在 State 内打印并最后在 main 中打印。 (如果打印时我有无穷大怎么办?) 我无法理解来自网络的关于 monad 功能的那部分的文本。有一些解释,如 "pack inside IO Monad, it's quite straightforward",但没有任何工作示例。几乎所有的打印教程都是关于在 main 中打印的。
为了更好地解释问题,我准备了最小的 "interpreter" 示例(如下)。 State
只是 Int
,我的 monad 是 AutomatM
指令类型为 :: Int -> AutomatM Int
。所以可能的指令是:
inc :: Int -> AutomatM Int
inc x = return (x+1)
我设计得尽可能简单:
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
我的主要目标是在magicPrint
中添加print x
。但是,如果它不难,那么有 getLine 就好了。
我在 magicPrint 中更改了状态,因为用我的语言打印有副作用。
我知道我需要一些关于 monad 转换器和 MonadIO 的东西,但是很难找到任何对初学者有简单解释的教程。 因此,我非常感谢扩展我的最小代码示例以处理打印(可能 getLine/other 读取 Int)和一些解释(可能带有链接)。
Functor 和 Aplicative 代码基于
为了创建一个带有 Monad
实例的新类型并在其中访问 IO
表单,您需要创建另一个名为 AutomatMT
的 monad 转换器类型并声明一个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 ()