"MonadReader (Foo m) m" 函数依赖导致无限类型
"MonadReader (Foo m) m" results in infinite type from functional dependency
我试图在 Reader 中传递一个函数,该函数将与调用函数从同一个 monad 调用,但我收到无限类型错误。
简化代码为:
{-# LANGUAGE FlexibleContexts #-}
module G2 where
import Control.Monad
import Control.Monad.Reader
data Foo m = Foo { bar :: m () }
runFoo :: MonadReader (Foo m) m => m ()
runFoo = do
b <- asks bar
b
main :: Monad m => m ()
main = do
let bar = return () :: m ()
foo = Foo bar
runReaderT runFoo foo
错误是:
• Occurs check: cannot construct the infinite type:
m0 ~ ReaderT (Foo m0) m
arising from a functional dependency between:
constraint ‘MonadReader
(Foo (ReaderT (Foo m0) m)) (ReaderT (Foo m0) m)’
arising from a use of ‘runFoo’
instance ‘MonadReader r (ReaderT r m1)’ at <no location info>
• In the first argument of ‘runReaderT’, namely ‘runFoo’
In a stmt of a 'do' block: runReaderT runFoo foo
In the expression:
do let bar = ...
foo = Foo bar
runReaderT runFoo foo
• Relevant bindings include main :: m () (bound at G2.hs:16:1)
|
19 | runReaderT runFoo foo
| ^^
非常感谢任何帮助,谢谢!
runFoo :: MonadReader (Foo m) m => m ()
让我们忘记 class,假设 MonadReader env mon
表示 mon ~ ((->) env)
。这对应于简单地使用 (->)
作为我们的 monad 而不是更高级的 ReaderT
。然后你得到 m ~ ((->) m) => m ()
。您看到 m
需要包含自身(具体来说,m
的参数是 m
)。这对于值来说是可以的,但是如果类型检查器必须处理无限大的类型,那就太糟糕了。 ReaderT
也是如此(而且你需要使用ReaderT
因为你调用了runReaderT runFoo
)。您需要定义另一个新类型来编码此递归:
data RecReader c a = RecReader { runRecReader :: c (RecReader c) -> a }
instance Functor (RecReader c) where
fmap f (RecReader r) = RecReader $ f . r
instance Applicative (RecReader c) where
pure = RecReader . const
RecReader f <*> RecReader g = RecReader $ \e -> f e (g e)
instance Monad (RecReader c) where
return = pure
RecReader x >>= f = RecReader $ \e -> runRecReader (f (x e)) e
instance MonadReader (c (RecReader c)) (RecReader c) where
ask = RecReader id
local f (RecReader x) = RecReader $ x . f
有效:
runRecReader runFoo (Foo $ return ())
-- ==>
()
我试图在 Reader 中传递一个函数,该函数将与调用函数从同一个 monad 调用,但我收到无限类型错误。
简化代码为:
{-# LANGUAGE FlexibleContexts #-}
module G2 where
import Control.Monad
import Control.Monad.Reader
data Foo m = Foo { bar :: m () }
runFoo :: MonadReader (Foo m) m => m ()
runFoo = do
b <- asks bar
b
main :: Monad m => m ()
main = do
let bar = return () :: m ()
foo = Foo bar
runReaderT runFoo foo
错误是:
• Occurs check: cannot construct the infinite type:
m0 ~ ReaderT (Foo m0) m
arising from a functional dependency between:
constraint ‘MonadReader
(Foo (ReaderT (Foo m0) m)) (ReaderT (Foo m0) m)’
arising from a use of ‘runFoo’
instance ‘MonadReader r (ReaderT r m1)’ at <no location info>
• In the first argument of ‘runReaderT’, namely ‘runFoo’
In a stmt of a 'do' block: runReaderT runFoo foo
In the expression:
do let bar = ...
foo = Foo bar
runReaderT runFoo foo
• Relevant bindings include main :: m () (bound at G2.hs:16:1)
|
19 | runReaderT runFoo foo
| ^^
非常感谢任何帮助,谢谢!
runFoo :: MonadReader (Foo m) m => m ()
让我们忘记 class,假设 MonadReader env mon
表示 mon ~ ((->) env)
。这对应于简单地使用 (->)
作为我们的 monad 而不是更高级的 ReaderT
。然后你得到 m ~ ((->) m) => m ()
。您看到 m
需要包含自身(具体来说,m
的参数是 m
)。这对于值来说是可以的,但是如果类型检查器必须处理无限大的类型,那就太糟糕了。 ReaderT
也是如此(而且你需要使用ReaderT
因为你调用了runReaderT runFoo
)。您需要定义另一个新类型来编码此递归:
data RecReader c a = RecReader { runRecReader :: c (RecReader c) -> a }
instance Functor (RecReader c) where
fmap f (RecReader r) = RecReader $ f . r
instance Applicative (RecReader c) where
pure = RecReader . const
RecReader f <*> RecReader g = RecReader $ \e -> f e (g e)
instance Monad (RecReader c) where
return = pure
RecReader x >>= f = RecReader $ \e -> runRecReader (f (x e)) e
instance MonadReader (c (RecReader c)) (RecReader c) where
ask = RecReader id
local f (RecReader x) = RecReader $ x . f
有效:
runRecReader runFoo (Foo $ return ())
-- ==>
()