Eff verbose/ambiguous/type safety

Hello Group, Recently I discovered for my self an alternative for monad transformers - extensible effects. http://okmij.org/ftp/Haskell/extensible/ Overall it is really cool and Eff1.hs started working right away, but I noticed a problem with mixing several effects in 1 function. Type checker requires pretty verbose type signature, which looks unreasonable plus the error reported to a beginner developer is not intuitive. So my questions are: - why it happens? - what could I do to get more friendly error message? - is there a workaround enforcing GHC make an extra mile and work without these "extra hints"? - any more maintainable Eff implementations? Here it an example I wish should working. $ stack gchi Eff1.hs *Eff1 > doLift = lift (putStrLn "EFF!") *Eff1 > doWrite = tell "HELLO" *Eff1 > doLiftAndWrite = doLift >> doWrite *Eff1 > runLift (runWriter doLiftAndWrite) <interactive>:82:20: error: * Couldn't match type `Writer [Char]' with `Lift IO' arising from a use of `doLiftAndWrite' * In the first argument of `runWriter', namely `doLiftAndWrite' In the first argument of `runLift', namely `(runWriter doLiftAndWrite)' In the expression: runLift (runWriter doLiftAndWrite) The error message looks unclear, because documentation makes me think that Writer and Lift are members of same Eff monad and they are composable and doLiftAndWrite has been evaluated successfully. And my workaround: *Eff1 > runLift $ do { x :: ((), [String]) <- runWriter doLiftAndWrite; return x; } EFF! ((),["HELLO"]) Plus GHCi swallows a type error: *Eff1 > badCast = do { x :: ((), [Int]) <- runWriter doLiftAndWrite; return x; } *Eff1 > :t badCast badCast :: (MemberU2 Lift (Lift IO) r, OpenUnion52.FindElem (Writer [Char]) r) => Eff r ((), [Int]) Definitely Extensible Effects are more flexible that MTL, but compile type safety looks jeopardized. Type verbosity overhead is kind of acceptable, but having possibility of run-time errors is too big price for flexibility. -- Daneel S. Yaitskov

Hi! I'm not too familiar with the particular implementation in Eff1.hs but when working with highly polymorphic Haskell code in general (like here, where you want your actions to be polymorphic over the effect stack), it's a good idea to write out everything in a file with type signatures present, so that you're 100% about what is happening, and there isn't some weird type defaulting/type families getting stuck business going on. For other implementations you can take a look at freer-simple, polysemy, fused-effects, eff. ======= Georgi
participants (2)
-
Daneel Yaitskov
-
Georgi Lyubenov