这个问题是这个线程的续集: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
不变作为参考,保留所有更改。
怎么做?如果需要,我可以接受修改我的初始设置。