问题描述
看起来没有什么可以阻止您定义这样的函数:
tmp :: (MonadReader Int m,MonadReader Bool m) => m Int
tmp = ifM ask ((+1) <$> ask) ((+2) <$> ask)
所以就像一个可类型化的上下文,只要你给它一个类型,ask 就会为你提供具有该类型的环境部分,我认为这是名称阴影的合理替代。
然而,使用 MonadReader
定义的 Control.Monad.Reader
的默认实例,看起来没有办法实际调用此方法。所以我定义了一个新模块来尝试这样做:
{-# LANGUAGE FlexibleInstances,MultiParamTypeClasses,UndecidableInstances #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
module Control.Monad.Reader.Extra
( MonadReader(ask)
) where
import Control.Monad.Reader (MonadReader(ask,local,reader))
import Control.Monad.Trans.Class (MonadTrans(lift))
instance {-# OVERLAPPABLE #-} ( Monad m,MonadTrans t,Monad (t m),MonadReader r m
) =>
MonadReader r (t m) where
ask = lift ask
local _ _ = undefined
reader f = lift (reader f)
只要第二个实例在范围内,您就可以运行 tmp
,例如 runReaderT (runReaderT tmp 1) True
。
不幸的是,我无法为本地找到合适的实现,因为它需要具有 local :: (r -> r) -> (t m a) -> (t m a)
类型,但似乎没有办法将 local :: (r -> r) -> m a -> m a
提升到此.
对于此实例,本地的合理实现是什么?
最小完整示例:
{-# LANGUAGE FlexibleInstances,UndecidableInstances,LambdaCase,FlexibleContexts #-}
module Tmpfundep where
import Control.Monad.Reader
( MonadReader(ask,reader),ReaderT(ReaderT),runReaderT
)
instance {-# INCOHERENT #-} (Monad m,MonadReader r m) =>
MonadReader r (ReaderT r' m) where
ask = ReaderT (const ask)
local f (ReaderT m) = ReaderT (local f . m)
reader f = ReaderT (const (reader f))
withEnv :: r -> ReaderT r m a -> m a
withEnv r m = runReaderT m r
tmp :: (MonadReader Int m,MonadReader Bool m) => m Int
tmp = ask >>= \case
True -> (+1) <$> ask
False -> (+2) <$> ask
main :: IO ()
main = withEnv True (withEnv (1 :: Int) tmp) >>= print
能够使用 echo main | stack exec -- runghc Tmpfundep.hs
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)