haskell - 单个方法上的多个 MonadReader 约束
问题描述
看起来没有什么能阻止你定义这样的函数:
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 找到一个体面的实现,因为它需要具有 type local :: (r -> r) -> (t m a) -> (t m a)
,但似乎没有办法将 alocal :: (r -> r) -> m a -> m a
提升到此。
对于这种情况,本地的合理实现是什么?
最小完整示例:
{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, UndecidableInstances, LambdaCase, FlexibleContexts #-}
module Tmpfundep where
import Control.Monad.Reader
( MonadReader(ask, local, 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
解决方案
推荐阅读
- sql - 在 case 表达式中设置变量
- java - 如何使用 Java 代码向 Flink 集群提交作业?
- javascript - 创建符合 508 的 3 列 SELECT/OPTION 解决方案
- node.js - TypeORM 上传和服务(下载)文件
- regex - 谷歌表格中是否有一个函数只返回字符串中的唯一字符?
- javascript - 像 $(document).ready( 和 Vue.js 一样的功能
- javascript - 在javascript中获取url返回空数组
- c++ - Biguint < 运算符
- flutter - 如何仅针对 Flutter 中的某些类防止设备旋转?
- javascript - jQuery中的自动保存文本区域字段