Può esserci un meccanismo simile a mtl per i trasformatori monad creati da FreeT/ProgramT?Classi di penetrazione dello stack di Monad con trasformatori Monad liberi/operativi?
La mia comprensione della storia è la seguente. C'era una volta inventato il trasformatore di monad. Poi la gente ha iniziato a impilare i trasformatori monad uno sull'altro, poi ha trovato fastidioso inserire lift
ovunque. Poi un paio di persone hanno inventato le classi monad, così che possiamo ad es. ask :: m r
in qualsiasi monade m
tale che MonadReader r m
. Questo è stato possibile realizzando ogni classe monade penetrare ogni trasformatore monade, come
(Monoid w, MonadState s m) => MonadState s (WriterT w m)
MonadWriter w m => MonadWriter w (StateT s m)
Occorrono tale coppia di dichiarazioni istanza per ogni coppia di trasformatori monade, quindi quando c'è n monad trasformatori c'è n^2 costi. Questo non era un grosso problema, tuttavia, poiché le persone utilizzano principalmente le monade predefinite e raramente creano le proprie. La storia fino ad ora è comprensibile, ed è anche dettagliata ad es. nel seguente Q & A:
Avoiding lift with Monad Transformers
Allora il mio problema è con le nuove monadi gratuiti http://hackage.haskell.org/package/free e monadi operativi http://hackage.haskell.org/package/operational. Ci permettono di scrivere la nostra DSL e usarla come monade, semplicemente definendo il linguaggio come un tipo algebrico data
(Operational non ha nemmeno bisogno delle istanze Functor
). La buona notizia è che possiamo avere monadi e trasformatori monad gratis; allora che ne dici delle lezioni di monad? La cattiva notizia è che l'ipotesi "raramente definiamo i nostri trasformatori monadi" non regge più.
Come tentativo di comprendere questo problema, ho creato due ProgramT
s e li ho fatti penetrare l'un l'altro;
https://github.com/nushio3/practice/blob/master/operational/exe-src/test-05.hs
Il pacchetto operational
non supporta le classi monade così ho preso un'altra implementazione minioperational
e modificato a lavorare come ho bisogno; https://github.com/nushio3/minioperational
Eppure, mi serviva la dichiarazione di istanza specializzata
instance (Monad m, Operational ILang m) => Operational ILang (ProgramT SLang m) where
perché la dichiarazione generale del seguente modulo conduce alle istanze indecidibili.
instance (Monad m, Operational f m) => Operational f (ProgramT g m) where
La mia domanda è che come possiamo rendere più facile da affittare I nostri monadi operativi penetrano reciprocamente. Oppure, è il mio desiderio di avere una penetrazione per qualsiasi monade operativa mal posta.
mi piacerebbe anche sapere il corretto termine tecnico per penetrazione :)
Grazie, Petr. Con il tuo aiuto ho capito come combinare due costruttori di tipi usando Either su '(* -> *)'. https://github.com/nushio3/practice/blob/master/operational/exe-src/test-06.hs La scrittura di interpreti componibili è altrettanto semplice: https://github.com/nushio3/practice/ blob/master/operational/exe-src/test-07.hs Possiamo anche comporre più di due lingue al costo di 'OverlappingInstances'. https://github.com/nushio3/practice/blob/master/operational/exe-src/test-08.hs – nushio