Skip to content

Instantly share code, notes, and snippets.



Last active Jan 30, 2020
What would you like to do?
implementation of transform using generics
data Expr
= Lit Int
| Add Expr Expr
| Mul Expr Expr
| Div Expr Expr
| Sub Expr Expr
| Neg Expr
deriving (Show, Eq, Generic)
-- Transform --
class GTransform a struct where
gtransform :: (a -> a) -> struct x -> struct x
instance GTransform a U1 where
gtransform _ U1 = U1
instance GTransform a V1 where
gtransform _ x = x
instance {-# OVERLAPPING #-} Transform a => GTransform a (K1 _1 a) where
gtransform f (K1 a) = K1 (f $ transform f a)
instance Transform b => GTransform a (K1 _1 b) where
gtransform f (K1 b) = K1 (transform f b)
instance (GTransform a x, GTransform a y) => GTransform a (x :+: y) where
gtransform f = \case
L1 x -> L1 $ gtransform f x
R1 y -> R1 $ gtransform f y
instance (GTransform a x, GTransform a y) => GTransform a (x :*: y) where
gtransform f (x :*: y) = gtransform f x :*: gtransform f y
instance GTransform a struct => GTransform a (M1 _x _y struct) where
gtransform f (M1 a) = M1 $ gtransform f a
class Transform x where
transform :: (a -> a) -> x -> x
default transform :: forall a. (Generic x, GTransform a (Rep x)) => (a -> a) -> x -> x
transform f = to . gtransform f . from
instance Transform Int where
transform = flip const
instance Transform Expr
{- ^
generics.hs:101:10: error:
• Overlapping instances for GTransform a (K1 R Int)
arising from a use of ‘Main.$dmtransform’
Matching instances:
two instances involving out-of-scope types
(use -fprint-potential-instances to see them all)
(The choice depends on the instantiation of ‘a’
To pick the first instance above, use IncoherentInstances
when compiling the other instance declarations)
• In the expression: Main.$dmtransform @(Expr)
In an equation for ‘transform’:
transform = Main.$dmtransform @(Expr)
In the instance declaration for ‘Transform Expr’
101 | instance Transform Expr
| ^^^^^^^^^^^^^^
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment