# How to cancel my template

I am using the syntactic library to create AST. To evaluate an AST for a value (Haskell), all my nodes must be an instance of a syntax class `EvalEnv`

:

```
class EvalEnv sym env where
compileSym :: proxy env -> sym sig -> DenotationM (Reader env) sig
```

Syntactic also provides a default implementation:

```
compileSymDefault :: (Eval sym, Signature sig)
=> proxy env -> sym sig -> DenotationM (Reader env) sig
```

but the constraint on is `sig`

not valid in cases `EvalEnv`

, making the following (say, overlapping) instance impossible:

```
instance EvalEnv sym env where
compileSym = compileSymDefault
```

All my custom AST nodes are GADTs, usually with multiple constructors, where the parameter `a`

always satisfies the constraint for `compileSymDefault`

:

```
data ADDITIVE a where
Add :: (Num a) => ADDITIVE (a :-> a :-> Full a)
Sub :: (Num a) => ADDITIVE (a :-> a :-> Full a)
```

As a result, I found that **all** my instances for `EvalEnv`

look like this:

```
instance EvalEnv ADDITIVE env where
compileSym p Add = compileSymDefault p Add
compileSym p Sub = compileSymDefault p Sub
```

This template instance is identical for all AST nodes, and each of the GADT constructors must be specified separately, since the signature of the GADT constructor implies restrictions `compileSymDefault`

.

Is there any way to avoid having to list every constructor for every node type I do?

source to share

If I understand the problem correctly, templating comes from having to use template matching with each constructor to bring the required context into scope. Apart from the constructor name, all case branches are identical.

The following code uses the `removeBoilerplate`

rank-2 function that can be used to bring the context into scope. Two example functions are first defined using template code and then converted to use a helper function `removeBoilerplate`

.

If you have a lot of GADTs, you will need one `removeBoilerplate`

for each one. Thus, this approach is beneficial if you need to remove the templated template more than once for each type.

I'm not familiar with the syntax to be 100% sure this will work, but it looks like it has a good chance. You will probably need to change the function type a little `removeBoilerplate`

.

```
{-# LANGUAGE GADTs , ExplicitForAll , ScopedTypeVariables ,
FlexibleContexts , RankNTypes #-}
class Class a where
-- Random function requiring the class
requiresClass1 :: Class a => a -> String
requiresClass1 _ = "One!"
-- Another one
requiresClass2 :: Class a => a -> String
requiresClass2 _ = "Two!"
-- Our GADT, in which each constructor puts Class in scope
data GADT a where
Cons1 :: Class (GADT a) => GADT a
Cons2 :: Class (GADT a) => GADT a
Cons3 :: Class (GADT a) => GADT a
-- Boring boilerplate
boilerplateExample1 :: GADT a -> String
boilerplateExample1 x@Cons1 = requiresClass1 x
boilerplateExample1 x@Cons2 = requiresClass1 x
boilerplateExample1 x@Cons3 = requiresClass1 x
-- More boilerplate
boilerplateExample2 :: GADT a -> String
boilerplateExample2 x@Cons1 = requiresClass2 x
boilerplateExample2 x@Cons2 = requiresClass2 x
boilerplateExample2 x@Cons3 = requiresClass2 x
-- Scrapping Boilerplate: let list the constructors only here, once for all
removeBoilerplate :: GADT a -> (forall b. Class b => b -> c) -> c
removeBoilerplate x@Cons1 f = f x
removeBoilerplate x@Cons2 f = f x
removeBoilerplate x@Cons3 f = f x
-- No more boilerplate!
niceBoilerplateExample1 :: GADT a -> String
niceBoilerplateExample1 x = removeBoilerplate x requiresClass1
niceBoilerplateExample2 :: GADT a -> String
niceBoilerplateExample2 x = removeBoilerplate x requiresClass2
```

source to share

You cannot abandon your template, but you can reduce it a little. Neither does it remove your template , nor can new GHC Generics code infer instances for GADT, like yours. It is possible to instantiate `EvalEnv`

with template haskell , but I will not discuss that.

We can reduce the number of templates we write very little. The idea we ran into with the problem is that `forall a`

there is an instance `Signature a`

for anyone `ADDITIVE a`

. Let's make a class of things for which this is true.

```
class Signature1 f where
signatureDict :: f a -> Dict (Signature a)
```

`Dict`

is the GADT that captures the constraint. To determine it is required `{-# LANGUAGE ConstraintKinds #-}`

. Alternatively, you can import it from `Data.Constraint`

within the constraints package .

```
data Dict c where
Dict :: c => Dict c
```

To use a constructor constraint, `Dict`

we must match a template to it. Then we can write `compileSym`

through `signatureDict`

and `compileSymDefault`

.

```
compileSymSignature1 :: (Eval sym, Signature1 sym) =>
proxy env -> sym sig -> DenotationM (Reader env) sig
compileSymSignature1 p s =
case signatureDict s of
Dict -> compileSymDefault p s
```

Now we can write down `ADDITIVE`

instances of it, capturing the idea that there is always an instance `Signature a`

for anyone `ADDITIVE a`

.

```
data ADDITIVE a where
Add :: (Num a) => ADDITIVE (a :-> a :-> Full a)
Sub :: (Num a) => ADDITIVE (a :-> a :-> Full a)
instance Eval ADDITIVE where
evalSym Add = (+)
evalSym Sub = (-)
instance Signature1 ADDITIVE where
signatureDict Add = Dict
signatureDict Sub = Dict
instance EvalEnv ADDITIVE env where
compileSym = compileSymSignature1
```

Writing an instance `Signature1`

doesn't have much of the benefit of writing an instance `EvalEnv`

. The only advantages we got is that we took an idea that might be useful elsewhere, and the instance is a `Signature1`

little easier to write down.

source to share