How do I use expandable effects and IO?

I'm trying to rewrite the examples from the article to the new version of the extensible-effects package 1.11.0.0, but I get "Failed to output ..." when I try to use the lift for the IO monad :(

ghc 7.10.1

{-# LANGUAGE FlexibleContexts, ScopedTypeVariables, TypeOperators #-}
{-# LANGUAGE DeriveFunctor, DeriveDataTypeable #-}
module Main where

import Data.Typeable
import Control.Eff
import Control.Eff.Lift

data Log v = Log String v deriving (Functor, Typeable)

log' :: Member Log r => String -> Eff r ()
log' txt = send . inj $ Log txt ()

verboseAddition :: Member Log r => Eff r Int
verboseAddition = do
   log' "I'm starting with 1..."
   x <- return 1

   log' "and I'm adding 2..."
   y <- return 2

   let r = x + y

   log' $ "Looks like the result is " ++ show r
   return r

runLogger :: Eff (Log :> r) a -> Eff r ([String],a)
runLogger = loop
   where 
     prefixLogWith txt (l,v) = (txt:l, v)
     loop = freeMap
       (\x -> return ([], x))
       (\u -> handleRelay u loop
              $ \(Log txt next) -> fmap (prefixLogWith txt) (loop next))

runIOLogger :: SetMember Lift (Lift IO) r => Eff (Log :> r) a -> Eff r a
runIOLogger = loop
   where
     loop = freeMap
       return
       (\u -> handleRelay u loop 
              $ \(Log txt next) -> 
                  lift (putStrLn txt)  >>  --  Could not deduce ...    :(
                  loop next)

main:: IO ()
main = --    print $ run $ runLogger verboseAddition -- ok
       runLift (runIOLogger verboseAddition) >>= print 

      

Could not deduce (extensible-effects-1.11.0.0:Data.OpenUnion.Internal.Base.M emberUImpl
                    extensible-effects-1.11.0.0:Data.OpenUnion.Internal.Open Union2.OU2
                    Lift
                    (Lift IO)
                    r)
  arising from a use of `lift'
from the context (SetMember Lift (Lift IO) r)
  bound by the type signature for
             runIOLogger :: SetMember Lift (Lift IO) r =>
                            Eff (Log :> r) a -> Eff r a
  at src\Main.hs:37:16-72
In the first argument of `(>>)', namely `lift (putStrLn txt)'
In the expression: lift (putStrLn txt) >> loop next
In the second argument of `($)', namely
  `\ (Log txt next) -> lift (putStrLn txt) >> loop next'

      

+3


source to share


1 answer


It works:

runIOLogger :: SetMember Lift (Lift IO) r => Eff (Log :> r) a -> Eff r a
runIOLogger = freeMap
  return
  (\u -> handleRelay u runIOLogger $ \(Log txt next) -> do
           lift $ putStrLn txt
           runIOLogger next)

      

Besides:

runIOLogger :: SetMember Lift (Lift IO) r => Eff (Log :> r) a -> Eff r a
runIOLogger = loop
   where
     loop :: SetMember Lift (Lift IO) r => Eff (Log :> r) a -> Eff r a
     loop = freeMap
       return
       (\u -> handleRelay u loop 
              $ \(Log txt next) -> 
                  lift (putStrLn txt)  >>  --  Could not deduce ...    :(
                  loop next)

      

GHC cannot infer polymorphic types for recursive bindings, instead it first injects a type with the assumption that the recursively bound variable is monomorphic, then generalizes the resulting type. This means that type inference fails if we use different instances of recursive binding. For example, this does not allow you to check:



id' a = fst (a, id' (a, a))

      

But this is fine:

id' :: a -> a
id' a = fst (a, id' (a, a))

      

I'm pretty sure there is something like this here, but I haven't tried to figure out exactly where the output is going.

+4


source







All Articles