haskell - Monads in monad transformer context -
i have trouble gripping monads , monad transformers. have following contrived example (not compilable):
import control.monad import control.monad.error import control.monad.reader data state = state int int int type foo = readert state io readeither :: string -> either string int readeither s = let p = reads s in case p of [] -> throwerror "could not parse" [(a, _)] -> return readeithert :: io (either string int) readeithert = let p s = reads s in runerrort $ l <- liftio (getline) readeither l foo :: foo int foo = d <- liftio $ readeithert case d of right dd -> return dd left em -> liftio $ putstrln em return (-1) bar :: foo string bar = liftio $ getline defaults = state 0 0 0
if copy functionality of readeither readeithert, works, have nagging feeling can leverage power of existing readeither function, can't figure out how. if try lift readeither in readeithert function, lifts errort string io (either string int)
should. should somehow errort string io int
.
if i'm going wrong direction this, correct way handle errors require io (or other monads) , called monadic context (see foo
function in example)
edit: apparently not clear trying do. maybe following function describes , why wondering
maybepulsequit :: handle -> io (either string ()) maybepulsequit h = runerrort $ f <- liftio $ (communicate h "finished" :: io (either string bool)) (errort . pure) f >>= \b → liftio $ when b $ liftio pulsequit
this works, still ugly because of binds. lot clearer previous version had case checking. recommended way this?
it not clear why need errort
. can implement readeithert
like
readeithert :: io (either string int) readeithert = fmap readeither getline
if need errort
reason, can create utility function eithertoerrort
:
eithertoerrort = errort . pure readeithert = runerrort $ l <- liftio $ getline eithertoerrort $ readeither l
[add] maybe want add errort
monad stack...
data state = state int int int type foo = errort string (readert state io) runfoo :: foo -> state -> io (either string a) runfoo foo s = runreadert (runerrort foo) s doit :: int -> foo int doit = if < 0 throwerror "i < 0" else return (i * 2)
example:
*main> runfoo (doit 1 >>= doit) (state 0 0 0) right 4 *main> runfoo (doit (-1) >>= doit) (state 0 0 0) left "i < 0"
Comments
Post a Comment