我试图运行这个更自由的代码:
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE TypeOperators #-}
module Lib where
import Control.Monad.Freer
import Control.Monad.Freer.Internal
import Control.Monad.Freer.State
import Data.IORef
runStateIO :: (Member (State s) r, Member IO r) => IORef s -> Eff (State s ': r) a -> Eff r (a,s)
runStateIO ref = loop
where
loop (Val v) = (v,) <$> send (readIORef ref)
loop (E u q) =
case decomp u of
Right Get -> send (readIORef ref) >>= loop . qApp q
Right (Put s) -> send (writeIORef ref s) >> loop (qApp q ())
Left u' -> E u' (tsingleton (loop . qApp q))
statefulFac :: Member (State Int) r => Int -> Eff r ()
statefulFac 1 = return ()
statefulFac n = do
a <- get
put (n * a)
statefulFac (n - 1)
runStatefulFac_IO :: Int -> IO Int
runStatefulFac_IO n = do
ref <- newIORef 1 :: IO (IORef Int)
let
-- none of these work:
-- stateful_fac :: (Member (State Int) r, Member IO r) => Eff r ()
-- stateful_fac :: Eff '[IO, State Int] ()
-- stateful_fac :: Eff '[State Int, IO] ()
stateful_fac = statefulFac 5
r = runStateIO ref stateful_fac
-- runM r
undefined
runStatefulFac_pure :: Int -> Int
runStatefulFac_pure n = snd (run (runState (statefulFac n) 1))
这是使用股票freer
,除了我导出State
效果的构造函数以便能够运行runStateIO
解释器。问题是它失败了
example.hs:42:11: error:
• Ambiguous type variable ‘r0’ arising from a use of ‘runStateIO’
prevents the constraint ‘(Data.Open.Union.Internal.Member'
(State Int)
r0
(Data.Open.Union.Internal.FindElem
(State Int) r0))’ from being solved.
Relevant bindings include
r :: Eff r0 ((), Int) (bound at example.hs:42:7)
stateful_fac :: Eff (State Int : r0) () (bound at example.hs:40:7)
Probable fix: use a type annotation to specify what ‘r0’ should be.
These potential instances exist:
two instances involving out-of-scope types
instance [safe] (r ~ (t' : r' : rs'),
Data.Open.Union.Internal.Member' t (r' : rs') n) =>
Data.Open.Union.Internal.Member'
t r ('Data.Open.Union.Internal.S n)
-- Defined in ‘Data.Open.Union.Internal’
instance [safe] r ~ (t : r') =>
Data.Open.Union.Internal.Member' t r 'Data.Open.Union.Internal.Z
-- Defined in ‘Data.Open.Union.Internal’
• In the expression: runStateIO ref stateful_fac
In an equation for ‘r’: r = runStateIO ref stateful_fac
In the expression:
do { ref <- newIORef 1 :: IO (IORef Int);
let stateful_fac = statefulFac 5
r = runStateIO ref stateful_fac;
undefined }
我想知道(1)此消息试图说明(2)此代码有什么问题以及如何解决?感谢。
答案 0 :(得分:3)
我认为这是签名
runStateIO :: (Member (State s) r, Member IO r) => IORef s -> Eff (State s ': r) a -> Eff r (a,s)
您不应该在约束中Member (State s) r
,因为您直接谈论State s ': r
。所以,如果你写
runStateIO :: ( Member IO r) => IORef s -> Eff (State s ': r) a -> Eff r (a,s)
然后main
中您想要的签名应该可以正常工作
let stateful_fac = statefulFac 5 :: Eff '[State Int, IO] ()
在State Int
被解释后,编译器仍在寻找State Int
成为r成员的方法。因此,如果我使用上面的签名stateful_fac
编译器抱怨:
• Couldn't match type ‘'[]’ with ‘r'0 : rs'0’
arising from a use of ‘runStateIO’
正确地说,因为它知道那里必须有另一个元素。