Изменить ST-зависимую среду в ReaderT - проблема с функцией `local`
Этот вопрос является продолжением этой темы: /questions/16491943/neyavnoe-vyipolnenie-stref-v-srede-vo-vremya-vyichislenij/16491953#16491953
Я спрашивал там о проведении STRef
в ReaderT
среда и выполнение ST-действий под ней. Моя установка теперь выглядит так:
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
без изменений в качестве ссылки, сохраняя все изменения под ним.
Как это сделать? Я могу принять изменение моей первоначальной настройки, если это необходимо.
1 ответ
Параметр области 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
...