Temps pour ma question sur l'objectif hebdomadaire;Zoom monad stack maintien du contexte
J'ai une pile de monade:
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]
}
I utilisé makeClassy
du type Editor
pour générer un HasEditor
que mes lentilles classe de types éditeur dépendent. Un Editor
a de nombreux Buffer
s; J'ai défini un autre type de pile monad pour une action qui agit sur un tampon spécifique (un BufAction
); la seule différence est que le StateT est sur une Buffer
:
newtype BufAction a = BufAction
{ runBufAct::StateT Buffer (ReaderT Hooks IO) a
} deriving (Functor, Applicative, Monad, MonadState Buffer, MonadReader Hooks, MonadIO)
pour lancer un BufAction
J'utilise zoom (editor.buffers.ix selected)
pour agrandir l'StateT à un tampon spécifique; mais le problème est que maintenant à l'intérieur du BufAction
je ne peux plus utiliser les lentilles qui fonctionnent sur editor
ou nécessitent HasEditor
.
Idéalement tous Action
Courons dans un BufAction
sans soulever, alors que BufAction
s ne peuvent pas courir à l'intérieur d'un Action
. Dans ce cas BufAction
nécessiterait le ActionState
complet, mais aussi une référence à un tampon spécifique afin de fonctionner; tandis que Action
nécessite simplement le ActionState
; donc BufAction
est une Monade plus restrictive et Action
s devrait être embarquable dedans.
donc à peu près je veux une sorte de type comme ceci:
newtype Action a = forall s. HasEditor s => Action
{ runAct :: StateT s (ReaderT Hooks IO) a
} deriving (Functor, Applicative, Monad, MonadState s, MonadReader Hooks, MonadIO)
Cependant GHC selfs à ce sujet; il ne peut pas gérer les existentiels et les contraintes dans un newtype; Je l'ai changé pour un type data
; mais alors je perds GeneralizedNewtypeDeriving et ai besoin de mettre en application tous ceux qui dérivent des clauses manuellement; que je préférerais ne pas faire.
J'ai également essayé d'utiliser un alias de type; ce qui signifierait que je n'ai pas besoin de dériver des typeclasses, mais puisque j'intègre aussi des Actions dans d'autres types de données, je rencontre des erreurs; par exemple depuis que je l'utilise Action
ici:
data ActionState = ActionState
{ _ed :: Editor
, _asyncs :: [Async (Action())]
, _hooks :: Hooks
, _nextHook :: Int
}
je rencontre:
• 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’
Prendre un tact différent; J'ai aussi essayé la mise en œuvre d'une instance MonadState souple:
instance (HasEditor s, HasBuffer s) => (MonadState s) BufAction where
mais je reçois:
• 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’
Parce que MonadState utilise des dépendances fonctionnelles ...
vraiment coincé sur celui-ci et je pourrais utiliser un main!
Merci d'avoir regardé! J'apprécie vraiment l'aide!
Votre question n'est pas claire. Vous dites que "tout' l'Action fonctionne dans un 'BufAction' sans lever, alors que' BufAction's ne peut pas fonctionner dans une 'Action'" - comment cela fonctionnerait-il, quand l'état de 'BufAction' est plus petit que 'Action'' s état? Cela devrait sûrement être l'inverse? –
Désolé que ce ne soit pas clair; Je vais essayer d'expliquer un peu mieux. Correct, BufAction utilise un état plus petit que «Action», mais ce n'est pas un «état plus petit» mais un état avec «plus d'informations». Nous pouvons penser à l'état disponible pour 'BufAction' comme' (ActionState, BufId) '; La totalité de 'ActionState' est disponible (tout comme' Action'), mais nous avons aussi des informations qui nous permettent de cibler un tampon spécifique. Ainsi, les 'actions 'qui opèrent sur' ActionState' devraient toujours être disponibles dans 'BufAction'; mais 'BufAction's requièrent le contexte' BufId' et ne peuvent pas fonctionner dans une 'Action'. Un plus clair? –
Cela signifie bien sûr que nous devrons changer l'état dans lequel BufAction agit en quelque chose qui contient réellement l'état le plus grand; mais c'est ce à quoi renvoient les contraintes 'HasEditor' et' HasBuffer'; 'Action' devrait être exécuté sur un état avec seulement' HasEditor'; alors que 'BufAction' devrait être exécuté sur l'état avec' HasEditor' AND 'HasBuffer', c'est donc plus restrictif. –