Время для моего вопроса об объективе в неделю;Содержит контекст сохранения штатов монады
У меня есть стек монады:
newtype Action a = Action
{ runAct :: StateT ActionState (ReaderT Hooks IO) a
} deriving (Functor, Applicative, Monad, MonadState ActionState, MonadReader Hooks, MonadIO)
data ActionState = ActionState
{ _ed :: Editor
, _asyncs :: [AsyncAction]
}
я использовал makeClassy
на Editor
типа для создания HasEditor
класса типов, которые мой редактор линзы зависит от.
Editor
имеет множество Buffer
s; Я определил другой тип стека монады для действия, которое действует над определенным буфером (BufAction
); единственное различие заключается в том, что StateT находится над Buffer
:
newtype BufAction a = BufAction
{ runBufAct::StateT Buffer (ReaderT Hooks IO) a
} deriving (Functor, Applicative, Monad, MonadState Buffer, MonadReader Hooks, MonadIO)
запустить BufAction
я использую zoom (editor.buffers.ix selected)
, чтобы увеличить StateT к определенному буфера; но проблема в том, что теперь внутри BufAction
я больше не могу использовать какие-либо объективы, которые работают за editor
, или требуют HasEditor
.
В идеале все Action
ы работать внутри BufAction
без подъема, в то время как BufAction
s не может работать внутри Action
. В этом случае BufAction
потребует полного ActionState
, но также ссылки на конкретный буфер для запуска; тогда как Action
просто требует ActionState
; так что BufAction
является более ограничительным Monad и Action
s должен быть внедрен в него.
Так примерно я хочу какой-то тип, как это:
newtype Action a = forall s. HasEditor s => Action
{ runAct :: StateT s (ReaderT Hooks IO) a
} deriving (Functor, Applicative, Monad, MonadState s, MonadReader Hooks, MonadIO)
Однако GHC дросселей на этом; он не может обрабатывать экзистенции и ограничения в newtype;
Я переключил его на тип data
; но затем я теряю GeneralizedNewtypeDeriving и должен реализовать все из тех, которые выводят статьи вручную; который я бы действительно не сделал.
Я также пробовал использовать псевдоним типа; что означало бы, что мне не нужно выводить классы, но поскольку я также вставляю Actions в другие типы данных, я сталкиваюсь с ошибками; например, так как я использую Action
здесь:
data ActionState = ActionState
{ _ed :: Editor
, _asyncs :: [Async (Action())]
, _hooks :: Hooks
, _nextHook :: Int
}
Я бегу в:
• Illegal polymorphic type: Action()
GHC doesn't yet support impredicative polymorphism
• In the definition of data constructor ‘ActionState’
In the data type declaration for ‘ActionState’
Принимая другую тактичность; Я также попытался реализацией гибкого экземпляра MonadState:
instance (HasEditor s, HasBuffer s) => (MonadState s) BufAction where
но получить:
• Illegal instance declaration for ‘MonadState s BufAction’
The coverage condition fails in class ‘MonadState’
for functional dependency: ‘m -> s’
Reason: lhs type ‘BufAction’ does not determine rhs type ‘s’
Un-determined variable: s
• In the instance declaration for ‘(MonadState s) BufAction’
Поскольку MonadState использует функциональную зависимость ...
Действительно застрял на этом, и я мог бы использовать рука!
Спасибо, что посмотрели! Я очень ценю помощь!
Ваш вопрос неясен. Вы говорите «все» действия '' BufAction' без подъема, в то время как 'BufAction' не может работать внутри 'Action' '- как это будет работать, когда состояние' BufAction' меньше, чем 'Action'' состояние? Неужели это должно быть наоборот? –
Извините, что это неясно; Я попытаюсь объяснить немного лучше. Правильно, BufAction использует меньшее состояние, чем «Действие», но это не столько «меньшее состояние», сколько состояние с «большей информацией». Мы можем думать о состоянии, доступном для 'BufAction', как' (ActionState, BufId) '; по сути, доступно все «ActionState» (точно так же, как «Действие»), но у нас есть информация, которая позволяет нам также сфокусировать определенный буфер. Поэтому любые 'Action', которые работают над' ActionState', все равно должны быть доступны в 'BufAction'; но 'BufAction' требует контекста 'BufId' и не может работать в' Action'. Чем яснее? –
Это означает, конечно, что нам нужно будет изменить состояние, которое BufAction действует на то, что на самом деле содержит большее состояние; но это то, к чему относятся ограничения HasEditor и 'HasBuffer'; «Действие» должно выполняться над состоянием только с «HasEditor»; в то время как 'BufAction' должен работать над состоянием с' HasEditor' AND 'HasBuffer', поэтому он более ограничительный. –