Conversion from type `T a` to` T b` without template
So I have an AST datatype with a lot of cases, which is parameterized by the "annotation" type
data Expr a = Plus a Int Int
| ...
| Times a Int Int
I have annotation types S
and T
as well as some function f :: S -> T
. I want to take Expr S
and convert it to Expr T
using my conversion f
for each S
that occurs within the Expr value.
Is there a way to do this with SYB or generics and avoid having to match patterns in each case? It looks like the type of thing for which it fits. I'm just not familiar with SYB to know how to do this.
source to share
Based on your follow-up question, it seems that a generics library is more appropriate for your situation than Functor. I would recommend using the function listed on the SYB wiki page :
{-# LANGUAGE DeriveDataTypeable, ScopedTypeVariables, FlexibleContexts #-}
import Data.Generics
import Unsafe.Coerce
newtype C a = C a deriving (Data,Typeable)
fmapData :: forall t a b. (Typeable a, Data (t (C a)), Data (t a)) =>
(a -> b) -> t a -> t b
fmapData f input = uc . everywhere (mkT $ \(x::C a) -> uc (f (uc x)))
$ (uc input :: t (C a))
where uc = unsafeCoerce
The reason for the extra type C
is to avoid the problematic corner case where there are occurrences of fields of the same type as a
(more on wiki). The caller fmapData
does not need to see it.
This function has several additional requirements compared to the real one fmap
: there must be instances Typeable
for a
and Data
for t a
. In your case t a
there is Expr a
which means you need to add deriving Data
to the definition Expr
and also have an instance Data
in scope for any a
re using.
source to share