# 7. Constructor removal/transformation¶

Removing constructors from an EADT is equivalent to transforming every instance of these constructors into other constructors of another EADT.

We consider 3 cases:

- Fixed input EADT type; fixed list of constructors to act on
- Generic input EADT type; fixed list of constructors to act on
- Generic input EADT type; extensible list of constructors to act on

Note in the 3 cases we need to specify the resulting EADT type as it could be anything fulfilling the constraints.

## 7.1. Fixed input, fixed matches¶

If the type of the input EADT is fixed, we can use safe pattern-matching as follows:

```
-- replace Even and Odd constructors with a Cons constructor
removeOddEven l = toCont l >::>
(\(EvenF a r) -> Cons a r
,\(OddF a r) -> Cons a r
,\NilF -> Nil
)
eo :: EADT '[EvenF Int, OddF Int, NilF]
eo = Even (10 :: Int) $ Odd (5 :: Int) $ Odd (7 :: Int) Nil
> eadtShow (cata removeOddEven eo :: List Int)
"10 : 5 : 7 : Nil"
```

Note that `removeOddEven`

only works on a specific EADT. If we want it to work on
any EADT that contains `Even`

and `Odd`

constructors, read the following
sections.

## 7.2. Generic input, fixed matches¶

If we want `removeEvenOdd`

to work on input EADTs of any type, we can extract
the constructors that we are interested in with `splitVariantF`

and lift the
left-over constructors with `liftVariantF`

as follows:

```
removeOddEven x = case splitVariantF @'[EvenF Int, OddF Int] x of
-- replace Even and Odd constructors with a Cons constructor
Right v -> toCont v >::>
( \(EvenF a l) -> Cons a l
, \(OddF a l) -> Cons a l
)
-- do nothing to the other constructors
Left leftovers -> Fix (liftVariantF leftovers)
eo1 :: EADT '[EvenF Int, OddF Int, NilF]
eo1 = Even (10 :: Int) $ Odd (5 :: Int) $ Odd (7 :: Int) Nil
> eadtShow (cata removeOddEven eo1 :: List Int)
"10 : 5 : 7 : Nil"
-- additional `ConsF Int` constructor
eo2 :: EADT '[ConsF Int, EvenF Int, OddF Int, NilF]
eo2 = Even (10 :: Int) $ Cons (5 :: Int) $ Odd (7 :: Int) Nil
> eadtShow (cata removeOddEven eo2 :: List Int)
"10 : 5 : 7 : Nil"
```

## 7.3. Generic input, extensible matches¶

If we want the `removeOddEven`

pattern match to be extensible, we can use
type-classes with an overlappable instance handling the generic case (i.e. that
only transfers constructors from one EADT to another without modifying them).

```
class RemoveOddEven ys (f :: * -> *) where
removeOddEven :: f (EADT ys) -> EADT ys
-- replace Odd and Even with Cons
instance ConsF a :<: ys => RemoveOddEven ys (OddF a) where
removeOddEven (OddF a l) = Cons a l
instance ConsF a :<: ys => RemoveOddEven ys (EvenF a) where
removeOddEven (EvenF a l) = Cons a l
-- handle the combinator
instance
( AlgVariantF (RemoveOddEven ys) (EADT ys) xs
) => RemoveOddEven ys (VariantF xs)
where
removeOddEven = algVariantF @(RemoveOddEven ys) removeOddEven
-- handle remaining constructors
instance {-# OVERLAPPABLE #-} f :<: ys => RemoveOddEven ys f where
removeOddEven = VF -- keep the other constructors as is
```

Test:

```
eo :: EADT '[EvenF Int, OddF Int, NilF]
eo = Even (10 :: Int) $ Odd (5 :: Int) $ Odd (7 :: Int) Nil
> eadtShow (cata removeOddEven eo :: List Int)
"10 : 5 : 7 : Nil"
-- EADT with an additional `ConsF Int` constructor
eo2 :: EADT '[ConsF Int, EvenF Int, OddF Int, NilF]
eo2 = Even (10 :: Int) $ Odd (5 :: Int) $ Cons (7 :: Int) $ Odd (7 :: Int) Nil
> eadtShow (cata removeOddEven eo2 :: List Int)
"10 : 5 : 7 : 7 : Nil"
-- EADT with an additional `ConsF String` constructor
eo3 :: EADT '[ConsF Int, EvenF Int, OddF Int, ConsF String, NilF]
eo3 = Even (10 :: Int) $ Cons "Test" $ Odd (5 :: Int) $ Cons (7 :: Int) $ Odd (7 :: Int) Nil
> eadtShow (cata removeOddEven eo3 :: EADT '[ConsF Int, ConsF String, NilF])
"10 : \"Test\" : 5 : 7 : 7 : Nil"
```

We can extend `removeOddEven`

to support other constructors by adding new
instances of `RemoveOddEven`

for them.