Я пишу переводчик в Haskell. Я хочу сделать это с помощью монад.
Я уже создал парсер, поэтому у меня много функций :: State -> MyMonad State
, и я могу запустить свою программу, используя bind. m >>= inst1 >>= inst2
.
Все отлично работает, но я не знаю, как создать инструкцию print
(или read
) на моем языке с этой монадой.
Я не хочу простых, но безобразных решений, таких как сохранение строк для печати внутри State и печать в основном в конце. (Что, если у меня есть бесконечность, пока с печатью?)
Я не мог понять тексты из Интернета об этой части функциональности монады. Были некоторые объяснения типа «упаковать в IO Monad, это довольно просто», но без каких-либо рабочих примеров. И почти все учебники по печати были посвящены печати в основном.
Чтобы лучше объяснить проблему, я подготовил минимальный пример "интерпретатора" (ниже). Там State
это просто Int
, моя монада 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
Моя главная цель - добавить print x
внутрь magicPrint
. Однако, если не сложнее, было бы неплохо иметь getLine.
Я изменил состояние в magicPrint, потому что у печати на моем языке есть побочные эффекты.
Я знаю, что мне нужно что-то с монадными преобразователями и, возможно, с MonadIO, но трудно найти какое-либо руководство с простым объяснением для начинающих.
Поэтому я был бы очень признателен за расширение моего минимального примера кода для работы с принтами (и, возможно, getLine / other read Int) и некоторые пояснения к этому (возможно, со ссылками).
Функтор и Аппликативный код основаны на Определение новой монады в haskell не вызывает инстанции для Applicative