-- Copyright (C) 2007 David Roundy, 2009 Ganesh Sittampalam -- -- This program is free software; you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation; either version 2, or (at your option) -- any later version. -- -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with this program; see the file COPYING. If not, write to -- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -- Boston, MA 02110-1301, USA. {-# LANGUAGE CPP, FlexibleInstances #-} #include "gadts.h" module Darcs.Witnesses.Sealed ( Sealed(..), seal, unseal, mapSeal, unsafeUnseal, unsafeUnsealFlipped, unsafeUnseal2, Sealed2(..), seal2, unseal2, mapSeal2, FlippedSeal(..), flipSeal, unsealFlipped, mapFlipped, unsealM, liftSM, Gap(..), FreeLeft, unFreeLeft, FreeRight, unFreeRight ) where import Darcs.Witnesses.Eq ( MyEq, EqCheck(..) ) import Darcs.Witnesses.Show import Darcs.Witnesses.Eq ( (=\/=) ) import Darcs.Witnesses.Unsafe ( unsafeCoerceP1, unsafeCoerceP ) data Sealed a where Sealed :: a C(x ) -> Sealed a seal :: a C(x ) -> Sealed a seal = Sealed instance MyEq a => Eq (Sealed (a C(x ))) where Sealed x == Sealed y | IsEq <- x =\/= y = True | otherwise = False data Sealed2 a where Sealed2 :: !(a C(x y )) -> Sealed2 a seal2 :: a C(x y ) -> Sealed2 a seal2 = Sealed2 data FlippedSeal a C(y) where FlippedSeal :: !(a C(x y)) -> FlippedSeal a C(y) flipSeal :: a C(x y) -> FlippedSeal a C(y) flipSeal = FlippedSeal unsafeUnseal :: Sealed a -> a C(x) unsafeUnseal (Sealed a) = unsafeCoerceP1 a unsafeUnsealFlipped :: FlippedSeal a C(y) -> a C(x y) unsafeUnsealFlipped (FlippedSeal a) = unsafeCoerceP a unsafeUnseal2 :: Sealed2 a -> a C(x y) unsafeUnseal2 (Sealed2 a) = unsafeCoerceP a unseal :: (FORALL(x) a C(x ) -> b) -> Sealed a -> b unseal f x = f (unsafeUnseal x) -- laziness property: -- unseal (const True) undefined == True unsealM :: Monad m => m (Sealed a) -> (FORALL(x) a C(x) -> m b) -> m b unsealM m1 m2 = do sx <- m1 unseal m2 sx liftSM :: Monad m => (FORALL(x) a C(x) -> b) -> m (Sealed a) -> m b liftSM f m = do sx <- m return (unseal f sx) mapSeal :: (FORALL(x) a C(x ) -> b C(x )) -> Sealed a -> Sealed b mapSeal f = unseal (seal . f) mapFlipped :: (FORALL(x) a C(x y) -> b C(x z)) -> FlippedSeal a C(y) -> FlippedSeal b C(z) mapFlipped f (FlippedSeal x) = FlippedSeal (f x) unseal2 :: (FORALL(x y) a C(x y ) -> b) -> Sealed2 a -> b unseal2 f a = f (unsafeUnseal2 a) mapSeal2 :: (FORALL(x y) a C(x y ) -> b C(x y )) -> Sealed2 a -> Sealed2 b mapSeal2 f = unseal2 (seal2 . f) unsealFlipped :: (FORALL(x y) a C(x y) -> b) -> FlippedSeal a C(z) -> b unsealFlipped f (FlippedSeal a) = f a instance Show1 a => Show (Sealed a) where showsPrec d (Sealed x) = showParen (d > appPrec) $ showString "Sealed " . showsPrec1 (appPrec + 1) x instance Show2 a => Show (Sealed2 a) where showsPrec d (Sealed2 x) = showParen (d > appPrec) $ showString "Sealed2 " . showsPrec2 (appPrec + 1) x -- |'Poly' is similar to 'Sealed', but the type argument is -- universally quantified instead of being existentially quantified. newtype Poly a = Poly { unPoly :: FORALL(x) a C(x) } -- |'Stepped' is a type level composition operator. -- For example, 'Stepped Sealed p' is equivalent to 'lambda x . Sealed (p x)' newtype Stepped (f :: SEALEDPATCHKIND -> *) a C(x) = Stepped { unStepped :: f (a C(x)) } -- |'FreeLeft p' is '\forall x . \exists y . p x y' -- In other words the caller is free to specify the left witness, -- and then the right witness is an existential. -- Note that the order of the type constructors is important for ensuring -- that 'y' is dependent on the 'x' that is supplied. -- This is why 'Stepped' is needed, rather than writing the more obvious -- 'Sealed (Poly p)' which would notionally have the same quantification -- of the type witnesses. newtype FreeLeft p = FLInternal (Poly (Stepped Sealed p)) -- |'FreeLeft p' is '\forall y . \exists x . p x y' -- In other words the caller is free to specify the right witness, -- and then the left witness is an existential. -- Note that the order of the type constructors is important for ensuring -- that 'x' is dependent on the 'y' that is supplied. newtype FreeRight p = FRInternal (Poly (FlippedSeal p)) -- |Unwrap a 'FreeLeft' value unFreeLeft :: FreeLeft p -> Sealed (p C(x)) unFreeLeft (FLInternal x) = unStepped (unPoly x) -- |Unwrap a 'FreeRight' value unFreeRight :: FreeRight p -> FlippedSeal p C(x) unFreeRight (FRInternal x) = unPoly x -- |'Gap' abstracts over 'FreeLeft' and 'FreeRight' for code constructing these values class Gap w where -- |An empty 'Gap', e.g. 'NilFL' or 'NilRL' emptyGap :: (FORALL(x) p C(x x)) -> w p -- |A 'Gap' constructed from a completely polymorphic value, for example the constructors -- for primitive patches freeGap :: (FORALL(x y) p C(x y)) -> w p -- |Compose two 'Gap' values together in series, e.g. 'joinGap (+>+)' or 'joinGap (:>:)' joinGap :: (FORALL(x y z) p C(x y) -> q C(y z) -> r C(x z)) -> w p -> w q -> w r instance Gap FreeLeft where emptyGap e = FLInternal (Poly (Stepped (Sealed e))) freeGap e = FLInternal (Poly (Stepped (Sealed e))) joinGap op (FLInternal p) (FLInternal q) = FLInternal (Poly (case unPoly p of Stepped (Sealed p') -> case unPoly q of Stepped (Sealed q') -> Stepped (Sealed (p' `op` q')))) instance Gap FreeRight where emptyGap e = FRInternal (Poly (FlippedSeal e)) freeGap e = FRInternal (Poly (FlippedSeal e)) joinGap op (FRInternal p) (FRInternal q) = FRInternal (Poly (case unPoly q of FlippedSeal q' -> case unPoly p of FlippedSeal p' -> FlippedSeal (p' `op` q')))