Safe Haskell | None |
---|---|

Language | Haskell2010 |

Sometimes one needs a type like
`Barbie `

and it may feel like
a second-class record type, where one needs to
unpack values in each field. For those cases, we can leverage on
closed type-families:`Identity`

data`Bare`

data`Covered`

type family`Wear`

t f a where`Wear`

`Bare`

f a = a`Wear`

`Covered`

f a = f a data SignUpForm t f = SignUpForm { username ::`Wear`

t f`String`

, , password ::`Wear`

t f`String`

, mailingOk ::`Wear`

t f`Bool`

} instance`FunctorB`

(SignUpForm`Covered`

) instance`TraversableB`

(SignUpForm`Covered`

) ..., instance`BareB`

SignUpForm type SignUpRaw = SignUpForm`Covered`

`Maybe`

type SignUpData = SignUpForm`Bare`

`Identity`

formData = SignUpForm "jbond" "shaken007" False :: SignUpData

# Bare values

type family Wear t f a where ... Source #

The `Wear`

type-function allows one to define a Barbie-type as

data B t f = B { f1 ::`Wear`

t f`Int`

, f2 ::`Wear`

t f`Bool`

}

This gives rise to two rather different types:

`B`

is a normal Barbie-type, in the sense that`Covered`

f`f1 :: B`

, etc.`Covered`

f -> f`Int`

`B`

, on the other hand, is a normal record with no functor around the type:`Bare`

f

B { f1 :: 5, f2 =`True`

} :: B`Bare`

f

# Covering and stripping

class FunctorB (b Covered) => BareB b where Source #

Class of Barbie-types defined using `Wear`

and can therefore
have `Bare`

versions. Must satisfy:

`bcover`

.`bstrip`

=`id`

`bstrip`

.`bcover`

=`id`

Nothing

bstripFrom :: BareB b => (forall a. f a -> a) -> b Covered f -> b Bare Identity Source #

Generalization of `bstrip`

to arbitrary functors

bcoverWith :: BareB b => (forall a. a -> f a) -> b Bare Identity -> b Covered f Source #

Generalization of `bcover`

to arbitrary functors

type family WearTwo t f g a where ... Source #

Like the `Wear`

family, but with two wrappers `f`

and `g`

instead of one.
This is useful if you have a data-type where `f`

is parametric but `g`

is
not, consider this:

data T t f = T { f1 ::`Wear`

t f [Bool] , f2 ::`Wear`

t f (Sum Int) , f3 ::`WearTwo`

t f Sum Int , f4 ::`WearTwo`

t f Max Int }

with `x :: T Covered Option`

we would have

f1 x :: IO (Option [Bool]) f2 x :: IO (Option (Sum Int)) f3 x :: IO (Option (Sum Int)) f4 x :: IO (Option (Max Int))

and with `y :: T Bare Identity`

we would have

f1 y :: Int f2 y :: Sum Int f3 y :: Int f4 y :: Int

Note how `(Option (Sum Int))`

(or `Max`

) has a nice Semigroup instance that
we can use to merge two (covered) barbies,
while `WearTwo`

removes the wrapper for the bare barbie.

WearTwo Bare f g a = a | |

WearTwo Covered f g a = f (g a) | |

WearTwo (Param _ t) f g a = WearTwo t f g a | |

WearTwo t _ _ _ = TypeError ((Text "`WearTwo` should only be used with " :<>: Text "`Bare` or `Covered`.") :$$: (((Text "`" :<>: ShowType t) :<>: Text "`") :<>: Text " is not allowed in this context.")) |