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
dataBare
dataCovered
type familyWear
t f a whereWear
Bare
f a = aWear
Covered
f a = f a data SignUpForm t f = SignUpForm { username ::Wear
t fString
, , password ::Wear
t fString
, mailingOk ::Wear
t fBool
} instanceFunctorB
(SignUpFormCovered
) instanceTraversableB
(SignUpFormCovered
) ..., instanceBareB
SignUpForm type SignUpRaw = SignUpFormCovered
Maybe
type SignUpData = SignUpFormBare
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 fInt
, f2 ::Wear
t fBool
}
This gives rise to two rather different types:
B
is a normal Barbie-type, in the sense thatCovered
ff1 :: B
, etc.Covered
f -> fInt
B
, on the other hand, is a normal record with no functor around the type:Bare
f
B { f1 :: 5, f2 =True
} :: BBare
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.")) |