vinyl-0.2: Data/Vinyl/Relation.hs
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
module Data.Vinyl.Relation
( (<:)(..)
, (:~:)
, (~=)
-- , rIso
) where
import Data.Vinyl.Field
import Data.Vinyl.Lens
import Data.Vinyl.Rec
import Data.Vinyl.Witnesses
import GHC.Prim (Constraint)
-- | A subtyping relation.
class (IsSubtype r1 r2) => r1 <: r2 where
cast :: r1 -> r2
-- | One record is a subtype of another if the fields of the latter are a
-- subset of the fields of the former.
type family IsSubtype r1 r2 :: Constraint
type instance IsSubtype (Rec ss f) (Rec ts f) = ISubset ts ss
-- | If two records types are subtypes of each other, that means that they
-- differ only in order of fields.
type r1 :~: r2 = (r1 <: r2, r2 <: r1)
-- | Term-level record congruence.
(~=) :: (Eq a, a :~: b) => a -> b -> Bool
x ~= y = x == (cast y)
instance Rec xs f <: Rec '[] f where
cast _ = RNil
instance (y ~ (sy ::: t), IElem y xs, Rec xs f <: Rec ys f) => Rec xs f <: Rec (y ': ys) f where
cast r = rGet' field r :& cast r
where field = lookupField (implicitly :: Elem y xs) r
lookupField :: Elem x xs -> Rec xs f -> x
lookupField Here (_ :& _) = Field
lookupField (There p) (_ :& xs) = lookupField p xs
-- rIso :: (r1 :~: r2) => Iso' r1 r2
-- rIso = iso cast cast