haskell - 修改 ReaderT 中的 ST 依赖环境 – `local` 函数的问题
问题描述
这个问题是这个线程的续集:https ://stackoverflow.com/a/54317095/4400060
我在那里询问有关携带STRef
的ReaderT
环境并在其下执行 ST-actions 的问题。我的设置现在看起来像:
import Data.HashTable.ST.Cuckoo as HT
-- |Environment for Comp
newtype Env s = Env { dataspace :: HashTable s Int Data
, namespace :: Map Name Int }
-- |Main computation monad
newtype Comp a = Comp (forall s. ReaderT (Env s) (ST s) a)
-- |Evaluate computation
runComp (Comp c) = runST $ do
ds <- HT.new
runReaderT c (Env ds empty)
-- |Perform an action on `dataspace` hashmap
onDataspace :: (forall s. HashTable s Int Data -> ST s a) -> Comp a
onDataspace f = Comp $ asks dataspace >>= lift . f
总的来说它很酷——我可以dataspace
自由地访问或修改。但是,当我添加不可变时,namespace
我开始挣扎。我需要的功能是以不会影响进一步计算的命名空间的方式运行Comp
更新的操作namespace
——正是这样local
做的。
首先,我想为 编写MonadReader
实例Comp
,但是我遇到了ST
的幻像类型并得到了illegal instance
错误:
instance MonadReader (Env s) Comp where {}
instance MonadReader (forall s. Env s) Comp where {}
instance forall s. MonadReader (Env s) Comp where {}
完整的错误信息:
Illegal instance declaration for
‘MonadReader (EvalEnv s) Evaluator’
The coverage condition fails in class ‘MonadReader’
for functional dependency: ‘m -> r’
Reason: lhs type ‘Evaluator’
does not determine rhs type ‘EvalEnv s’
Un-determined variable: s
我理解这个错误,但我认为没有办法绕过它。老实说,我并不需要完整local
的功能。我只需要能够以Comp
不同namespace
但相同的方式运行dataspace
。
最好的解决方案是提供完整的MonadReader
实例。我知道这可能是不可能的,所以作为一种解决方法,我想要一个函数
withNs :: Map Name Int -> Comp a -> Comp a
总结:我希望能够在Comp
修改后运行,namespace
同时保持dataspace
不变作为参考,保留所有更改。
怎么做?如果需要,我可以接受修改我的初始设置。
解决方案
的范围参数s
应ST
保持在外部:
newtype Comp s a = Comp (ReaderT (Env s) (ST s) a)
唯一需要更高级别类型的地方是调用runST
.
runComp :: (forall s. Comp s a) -> a
runComp = runST $ do
ds <- HT.new
runReaderT c (Env ds empty)
在其他任何地方,您都可以简单地在s
.
doStuff :: Comp s Bool
doMoreStuff :: Comp s Int
那么MonadReader
实例可以写成:
instance MonadReader (Env s) (Comp s) where
...
推荐阅读
- c++ - 无法理解函数返回的类型
- discord - Nuke 命令 discord.py
- python - 我正在尝试使用两个端点 (x1,y1)(x2,y2) 为一条线设置动画,但 line.set_data() 函数似乎没有更新 x 和 y 坐标
- javascript - 连接集合查看器 Firebase
- firebase - 如何使用 Firebase 身份验证获取 onAuthStateChanged 流?
- java - “主要”java.lang.ClassCastException:[Ljava.lang.Comparable; 不能转换为 [LNode;
- python - ZeroDivisionError:在 chess.py 中除以零
- python - Swift 中的简单线性插值
- node.js - 如何使用 node.js 仅更新 JSON 文件中的一个键
- android - zipalign:符号查找错误:/usr/lib/x86_64-linux-gnu/android/libbacktrace.so.0:未定义符号:_ZN11unwindstack12ElfInterfaceD2Ev