Невозможно использовать монаду состояния в контексте ввода-вывода - PullRequest
2 голосов
/ 08 июня 2019

Я пытаюсь использовать Государственную монаду, чтобы сделать некоторые вычисления, также изменяя ее. Я реализовал экземпляры Applicative, Monad и Functor, а также get и put, modify и т. Д. Я не понимаю desugaring блока do. Как вы поставляете и штат, и трансформатор состояния?

Utils

    get::State s s
    get=State $ \s ->(s,s) 

    put::s->State s ()
    put x=State $ \_ -> ((),x)

    modify::(s->s)->State s ()
    modify f=get>>= \x -> put (f x)

    evalState::State s a->s->a
    evalState act =fst . run act

    execState::State s a->s->s
    execState act=snd.run act

Код

module Env where
    import State 
    import System.Directory
    import Control.Monad
    data Env=Env{
        envName::String,
        fileNames::[String]
    }
    instance Show Env where 
        show Env{envName=x,fileNames=xs} = "{ envName:"++x++" , files: ["++foldr (\t y-> t++","++y) "" xs ++"] }"

    initEnv::IO Env
    initEnv=do
        name<- getLine
        names<- getCurrentDirectory>>=listDirectory
        return Env{envName=name,fileNames=names}

    changeName::String->State Env ()
    changeName (y:ys)=State $ \ (Env (x:xs) ls) -> ((),Env (y:xs) ls)

    toStats::State Env String
    toStats= State $ \env -> (show env,env)

    useEnv::IO (State Env String)
    useEnv=do
        liftM put initEnv   --passes state transformer
        liftM changeName getLine  --passes strate transformer
        print . evalState . toStats         --how do i supply both ?
        return toStats

Как вы можете видеть, в моей последней строке я инициализирую преобразователь состояния и передаю его для дальнейшего изменения ... пока не достигну evalState и не захочу его использовать. В этом случае я не знаю, как поставить состояние и трансформатор.

P.S Под трансформатором я подразумеваю оболочку над s->(a,s)

1 Ответ

5 голосов
/ 08 июня 2019

Ваш код не использует монадные преобразователи.Я думаю, что вы просто ищете

useEnv :: IO ()
useEnv = do
    env <- initEnv
    name <- getLine
    let actions = do
            changeName name
            toStats
    let str = evalState actions env
    putStrLn str

, т.е. выполните действия State изнутри блока IO do.

...