Как пользоваться Государственной Монадой - PullRequest
0 голосов
/ 23 мая 2019

Я уже задавал вопрос о понимании государственной монады, но теперь я чувствовал, что этот должен быть другим.

Учитывая, что я реализовал монаду состояния, я хочу, чтобы мой state был структурой данных, которая напоминает Environment:

Окружающая среда

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}

Я не знаю, как интегрировать эту структуру данных в качестве State в монаде состояния, чтобы можно было изменить name среды, распечатать или использовать ее. Это может показаться слишком широким, но я не могу понять это без полного примера:

Реализация государственной монады

newtype State s a = State {run::s->(a,s)} 

instance Functor (State s) where
    fmap=Control.Monad.liftM
instance Applicative (State s) where
    pure=return
    (<*>)=Control.Monad.ap
instance Monad (State s) where
    return a= State $ \k->(a,k) 
    (>>=) m f=State $ \s -> let (a,s')=run m s in
        run (f a) s'

Что я хочу реализовать

readEnv::State a Env->Env
readEnv m =

changeEnvName::State a Env->State a Env
changeEnvName m =  --given the environment packed in a state , 
                   -- i want to change the name 

getEnvFileLengths::State a Env->[Int]
getEnvFileLengths s a= s>>= getLengths

getLengths::[String]->[Int]
getLengths xs=map length xs

P.S Я понимаю, что должен использовать Reader или Writer монаду, но я хотел, чтобы подход all in one позволил понять, как все вещи сочетаются друг с другом.

Есть идеи?

1 Ответ

1 голос
/ 23 мая 2019

Возможно, будет легче добиться прогресса, если вы правильно выберете типовые сигнатуры:

readEnv::State Env Env
changeEnvName::String -> State Env ()
getEnvFileLengths::State Env [Int]

Если эти варианты выглядят для вас странным выбором типов, возможно, стоит попытаться расширить newtype и посмотреть, будут ли они более разумными после этого:

-- give me an initial environment from your store, I'll give you the new environment
-- to store and another copy of the environment as the result of the computation
readEnv :: Env -> (Env, Env)

-- give me a new name and the old environment, I'll give you a new environment and
-- a trivial acknowledgement that I'm done
changeEnvName :: String -> Env -> ((), Env)

-- give me an initial environment that you're storing, I'll give you the new
-- environment to store (actually same as the old one) and the result of the
-- length computations
getEnvFileLengths :: Env -> ([Int], Env)
...