Этот вопрос является продолжением этой темы: https://stackoverflow.com/a/54317095/4400060
Я спрашивал там о переносе 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
без изменений в качестве ссылки, сохраняя все изменения под ним.
Как это сделать? Я могу принять изменение моей первоначальной настройки, если это необходимо.