{-# LANGUAGE DataKinds , MultiParamTypeClasses , FlexibleContexts , FlexibleInstances , PolyKinds , ScopedTypeVariables , TypeFamilies , TypeOperators , UndecidableInstances #-} {-# OPTIONS_HADDOCK show-extensions #-} {-| Module : Data.Vinyl.Upcast Description : Upward cast and slicing. Copyright : (c) Marcin Mrotek, 2014 License : BSD3 Maintainer : marcin.jan.mrotek@gmail.com -} module Data.Vinyl.Upcast ( Overwrite(..) , slice , (:>)(..) , AltRec(..) ) where import Control.Applicative import Data.Monoid import Data.Vinyl import Data.Vinyl.TyFun -- |Overwrite a wider record with a narrower record. class Overwrite (xs :: [k]) (ys :: [k]) where overwrite :: Rec el f xs -> Rec el f ys -> Rec el f xs instance Overwrite xs '[] where overwrite xs _ = xs instance (IElem y xs, Overwrite xs ys) => Overwrite xs (y ': ys) where overwrite xs (y :& ys) = overwrite (ith (implicitly :: Elem y xs) y xs) ys where ith :: Elem x rs -> f (el $ x) -> Rec el f rs -> Rec el f rs ith Here y (_ :& xs) = y :& xs ith (There p) y (x :& xs) = x :& ith p y xs slice :: (Functor f, Overwrite xs ys, xs <: ys) => (Rec el g ys -> f (Rec el g ys)) -> Rec el g xs -> f (Rec el g xs) -- ^A lens from a record to a portion of it. slice k x = overwrite x <$> k (cast x) -- |Wrapper for Rec with a different Monoid instance. Instead of lifting mappend, it acts on (f (el $ r)) directly, to support temporarily turning records into monoids by changing functors. newtype AltRec el f rs = AltRec {getRec :: Rec el f rs} instance Monoid (AltRec el f '[]) where mempty = AltRec RNil _ `mappend` _ = AltRec RNil instance (Monoid (f (el $ r)), Monoid (AltRec el f rs)) => Monoid (AltRec el f (r ': rs)) where mempty = AltRec $ mempty :& getRec mempty (AltRec (x :& xs)) `mappend` (AltRec (y :& ys)) = AltRec $ (x <> y) :& getRec (AltRec xs `mappend` AltRec ys) -- |Upward record casting. class (Overwrite ys xs, ys <: xs) => (xs :: [k]) :> (ys :: [k]) where upcast :: (Monoid (AltRec el f ys)) => Rec el f xs -> Rec el f ys instance (Overwrite ys xs, ys <: xs) => xs :> ys where upcast xs = overwrite (getRec mempty) xs