2020-07-03 19:52:06 +04:00
|
|
|
{-|
|
|
|
|
The heterogeneous list.
|
|
|
|
-}
|
2020-06-09 15:56:11 +04:00
|
|
|
|
|
|
|
module Product where
|
|
|
|
|
2020-07-10 15:11:49 +04:00
|
|
|
import GHC.Types
|
|
|
|
|
2020-07-03 19:52:06 +04:00
|
|
|
-- | `Product xs` contains elements of each of the types from the `xs` list.
|
2020-06-09 15:56:11 +04:00
|
|
|
data Product xs where
|
2020-07-03 19:52:06 +04:00
|
|
|
Cons :: x -> Product xs -> Product (x : xs)
|
2020-06-09 15:56:11 +04:00
|
|
|
Nil :: Product '[]
|
|
|
|
|
2020-07-03 19:52:06 +04:00
|
|
|
-- | Find/modify the element with a given type.
|
|
|
|
--
|
|
|
|
-- If you want to have same-types, use newtype wrappers.
|
|
|
|
--
|
2020-06-09 15:56:11 +04:00
|
|
|
class Contains x xs where
|
|
|
|
getElem :: Product xs -> x
|
2020-07-03 19:52:06 +04:00
|
|
|
modElem :: (x -> x) -> Product xs -> Product xs
|
2020-06-09 15:56:11 +04:00
|
|
|
|
|
|
|
instance {-# OVERLAPS #-} Contains x (x : xs) where
|
2020-07-03 19:52:06 +04:00
|
|
|
getElem (Cons x _) = x
|
|
|
|
modElem f (Cons x xs) = Cons (f x) xs
|
2020-06-09 15:56:11 +04:00
|
|
|
|
|
|
|
instance Contains x xs => Contains x (y : xs) where
|
|
|
|
getElem (Cons _ xs) = getElem xs
|
2020-07-03 19:52:06 +04:00
|
|
|
modElem f (Cons x xs) = Cons x (modElem f xs)
|
|
|
|
|
|
|
|
-- | Add a name to the type.
|
|
|
|
--
|
2020-07-10 15:11:49 +04:00
|
|
|
newtype (s :: Symbol) := t = Tag { unTag :: t }
|
2020-07-03 19:52:06 +04:00
|
|
|
|
|
|
|
-- | Retrieve a type associated with the given name.
|
|
|
|
--
|
|
|
|
getTag :: forall s t xs. Contains (s := t) xs => Product xs -> t
|
|
|
|
getTag = unTag . getElem @(s := t)
|
|
|
|
|
|
|
|
-- | Modify a type associated with the given name.
|
|
|
|
--
|
|
|
|
modTag
|
|
|
|
:: forall s t xs
|
|
|
|
. Contains (s := t) xs
|
|
|
|
=> (t -> t)
|
|
|
|
-> Product xs -> Product xs
|
|
|
|
modTag f = modElem @(s := t) (Tag . f . unTag)
|