Изменить 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
  ...
Другие вопросы по тегам