{-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE PolyKinds #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} module Data.Vinyl.Constraint ( (<:)(..) , (:~:) , (~=) , RecAll ) where import Data.Vinyl.Core import Data.Vinyl.Witnesses import Data.Vinyl.TyFun import GHC.Prim (Constraint) -- | One record is a subtype of another if the fields of the latter are a -- subset of the fields of the former. class (xs :: [k]) <: (ys :: [k]) where cast :: Rec el f xs -> Rec el f ys instance xs <: '[] where cast _ = RNil instance (y ∈ xs, xs <: ys) => xs <: (y ': ys) where cast xs = ith (implicitly :: Elem y xs) xs :& cast xs where ith :: Elem r rs -> Rec el f rs -> f (el $ r) ith Here (a :& _) = a ith (There p) (_ :& as) = ith p as -- | 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 (Rec el f xs), xs :~: ys) => Rec el f xs -> Rec el f ys -> Bool x ~= y = x == (cast y) type family RecAll (el :: TyFun k l -> *) (f :: * -> *) (rs :: [k]) (c :: * -> Constraint) :: Constraint type instance RecAll el f '[] c = () type instance RecAll el f (r ': rs) c = (c (f (el $ r)), RecAll el f rs c)