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提供任何实例
为了创建一个新的类型与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)