Closed rkanati closed 6 years ago
I have pushed a fix for this problem, and I plan on releasing a new version with the fix shortly. However, I will note that it does not make your program work as-written, since removing the LastMember IO (Fx1 ': effs)
now results in a different type error:
src/Main.hs:20:5: error:
• Could not deduce (Monad m0) arising from a use of ‘interpretM’
from the context: LastMember IO effs
bound by the type signature for:
runFx :: LastMember IO effs =>
Eff (Fx2 : Fx1 : effs) a -> Eff effs a
at src/Main.hs:(12,1)-(17,19)
The type variable ‘m0’ is ambiguous
These potential instances exist:
instance Monad (Either e) -- Defined in ‘Data.Either’
instance Monad (Eff effs)
-- Defined in ‘Control.Monad.Freer.Internal’
instance Monad IO -- Defined in ‘GHC.Base’
...plus four others
...plus 14 instances involving out-of-scope types
(use -fprint-potential-instances to see them all)
• In the second argument of ‘(.)’, namely
‘interpretM (\ Fx2 -> putStrLn "Fx2")’
In the expression:
interpretM (\ Fx1 -> putStrLn "Fx1")
. interpretM (\ Fx2 -> putStrLn "Fx2")
In an equation for ‘runFx’:
runFx
= interpretM (\ Fx1 -> putStrLn "Fx1")
. interpretM (\ Fx2 -> putStrLn "Fx2")
src/Main.hs:20:25: error:
• Couldn't match type ‘m0’ with ‘IO’
‘m0’ is untouchable
inside the constraints: x ~ ()
bound by a pattern with constructor: Fx2 :: Fx2 (),
in a lambda abstraction
at src/Main.hs:20:18-20
Expected type: m0 x
Actual type: IO ()
• In the expression: putStrLn "Fx2"
In the first argument of ‘interpretM’, namely
‘(\ Fx2 -> putStrLn "Fx2")’
In the second argument of ‘(.)’, namely
‘interpretM (\ Fx2 -> putStrLn "Fx2")’
I’m not entirely sure why this happens, since it’s unclear to me why the local constraint x ~ ()
makes m0
untouchable. It’s especially odd to me that it only occurs in the second use of interpretM
, not the first.
It can be solved by adding a type annotation:
runFx :: forall effs a
. ( LastMember IO effs )
=> Eff (Fx2 ': Fx1 ': effs) a
-> Eff effs a
runFx
= interpretM (\Fx1 -> putStrLn "Fx1")
. interpretM ((\Fx2 -> putStrLn "Fx2") :: Fx2 ~> IO)
…or with explicit type application:
runFx :: forall effs a
. ( LastMember IO effs )
=> Eff (Fx2 ': Fx1 ': effs) a
-> Eff effs a
runFx
= interpretM (\Fx1 -> putStrLn "Fx1")
. interpretM @_ @IO (\Fx2 -> putStrLn "Fx2")
I may look into the actual reason for this secondary problem, but it seems separate, and it might have more to due with GHC’s inference mechanism than this library.
Thanks!
Super strange - It definitely typechecks for me with the change I mentioned. Holler at me if you want any extra details for any reason.
I can’t reproduce your behavior, even on GHC 8.2.1 with your set of extensions. Perhaps you can set up a self-contained stack
project that pins everything that produces the behavior you describe?
I'll have a go in a few hours.
Many thanks!
So compositions of
interpretM
seem to have trouble carrying throughLastMember
constraints, somehow. This is the smallest example I could construct that reproduces.Removing the marked line works around the problem.