Sto scrivendo il codice che si occupa di valori da Language.Exts.Annotated.Syntax, in cui sono definite una varietà di tipi che rispecchiano la struttura di un modulo di Haskell:Evitare boilerplate quando si tratta di molti tipi non correlati
data Module l = ...
data Decl l = ...
data Exp t = ...
-- etc
mi piacerebbe essere in grado di scrivere funzioni che camminano su queste strutture dati ed eseguono varie trasformazioni su di esse. Poiché non esiste un tipo di dati comune, non posso scrivere una funzione che faccia tutto.
Finora ho scritto un tipo Tree
che avvolge ciascuno di questi tipi in modo che la mia funzione di trasformazione può fare Tree l -> Tree l
:
data Tree l = ModuleT (Module l)
| DeclT (Decl l)
| ExpT (Exp l)
-- etc copy & paste
Comunque ora sto trovando a scrivere un sacco di codice che prende una Module
, lo avvolge ModuleT
, chiama una funzione, quindi scarta nuovamente il risultato su Module
. Ho:
class AnnotatedTree ast where
tree :: ast l -> Tree l
untree :: Tree l -> ast l
instance AnnotatedTree Module where
tree = ModuleT
untree (ModuleT x) = x
untree _ = error "expected ModuleT"
-- etc ad nauseam
Due domande:
- dato che non posso cambiare i tipi di Language.Exts.Annotated.Syntax, sto andare su questo nel modo sbagliato?
- In caso contrario, posso ridurre in qualche modo questa caldaia?
uniplate sembra proprio quello di cui avevo bisogno, grazie. Ora ho scartato la mia caldaia. –
Con questo approccio non hai più bisogno del tuo tipo di albero, vero? – Martijn
Proprio così, io no; Posso configurare le mie funzioni di riscrittura degli alberi come una serie di applicazioni di riscritturaBi, una per ogni tipo a cui tengo. –