如何使用可扩展效果和IO?

时间:2015-07-20 12:42:12

标签: haskell

我试图将示例从article改写为新版本的程序包extensible-effects 1.11.0.0,但我得到了"无法推断...& #34;当我尝试使用电梯进行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'

1 个答案:

答案 0 :(得分:4)

这有效:

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)

以及:

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 can't infer多态类型,相反,它首先推断出一种类型,假设递归约束变量是单态的,然后推广结果类型。这意味着如果我们使用递归绑定的不同实例化,则类型推断仅会失败。例如,这无法检查:

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

但这很好:

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

我很确定这样的问题就是这里的问题,尽管我还没有努力找出确切的停止在哪里。