So, I have an AST data type with a large number of cases, which is parameterized by an "annotation" type
data Expr a = Plus a Int Int
| ...
| Times a Int Int
I have annotation types S
and T
, and some function f :: S -> T
. I want to take an Expr S
and convert it to an Expr T
using my conversion f
on each S
which occurs within an Expr value.
Is there a way to do this using SYB or generics and avoid having to pattern match on every case? It seems like the type of thing that this is suited for. I just am not familiar enough with SYB to know the specific way to do it.
It sounds like you want a
Functor
instance. This can be automatically derived by GHC using theDeriveFunctor
extension.Based on your follow-up question, it seems that a generics library is more appropriate to your situation than Functor. I'd recommend just using the function given on SYB's wiki page:
The reason for the extra
C
type is to avoid a problematic corner case where there are occurrences of fields at the same type asa
(more details on the wiki). The caller offmapData
doesn't need to ever see it.This function does have a few extra requirements compared to the real
fmap
: there must be instances ofTypeable
fora
, andData
fort a
. In your caset a
isExpr a
, which means that you'll need to add aderiving Data
to the definition ofExpr
, as well as have aData
instance in scope for whatevera
you're using.