generics-mrsop-gdiff 0.0.1 → 0.0.2
raw patch · 8 files changed
+983/−44 lines, 8 filesdep ~basedep ~generics-mrsopPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: base, generics-mrsop
API changes (from Hackage documentation)
+ Generics.MRSOP.GDiff: matchCof :: EqHO ki => Cof ki codes a t -> NA ki (Fix ki codes) a -> Maybe (PoA ki (Fix ki codes) t)
+ Generics.MRSOP.STDiff: apply :: forall ki codes ix iy. (IsNat ix, IsNat iy, EqHO ki) => Almu ki codes ix iy -> Fix ki codes ix -> Maybe (Fix ki codes iy)
+ Generics.MRSOP.STDiff: diff :: (EqHO ki, TestEquality ki, IsNat ix) => Fix ki codes ix -> Fix ki codes ix -> Almu ki codes ix ix
+ Generics.MRSOP.STDiff: merge :: forall ki codes ix. (EqHO ki, IsNat ix) => Almu ki codes ix ix -> Almu ki codes ix ix -> Maybe (Almu ki codes ix ix)
+ Generics.MRSOP.STDiff.Compute: Copy :: Ann
+ Generics.MRSOP.STDiff.Compute: Modify :: Ann
+ Generics.MRSOP.STDiff.Compute: [CtxDel] :: InsOrDel ki codes (AlmuMin ki codes)
+ Generics.MRSOP.STDiff.Compute: [CtxIns] :: InsOrDel ki codes (Almu ki codes)
+ Generics.MRSOP.STDiff.Compute: annDest :: (EqHO ki, IsNat ix) => Fix ki codes ix -> ES ki codes xs '[ 'I ix] -> AnnFix ki codes (Const Ann) ix
+ Generics.MRSOP.STDiff.Compute: annSrc :: (EqHO ki, IsNat ix) => Fix ki codes ix -> ES ki codes '[ 'I ix] ys -> AnnFix ki codes (Const Ann) ix
+ Generics.MRSOP.STDiff.Compute: copiesAlgebra :: Const Ann ix -> Rep ki (Const Int) xs -> Const Int ix
+ Generics.MRSOP.STDiff.Compute: countCopies :: IsNat ix => AnnFix ki codes (Const Ann) ix -> AnnFix ki codes (Const Int :*: Const Ann) ix
+ Generics.MRSOP.STDiff.Compute: data Ann
+ Generics.MRSOP.STDiff.Compute: data InsOrDel (ki :: kon -> *) (codes :: [[[Atom kon]]]) :: (Nat -> Nat -> *) -> *
+ Generics.MRSOP.STDiff.Compute: diff :: (EqHO ki, TestEquality ki, IsNat ix) => Fix ki codes ix -> Fix ki codes ix -> Almu ki codes ix ix
+ Generics.MRSOP.STDiff.Compute: diffAl :: forall ki codes xs ys. (EqHO ki, TestEquality ki) => PoA ki (AnnFix ki codes (Const Int :*: Const Ann)) xs -> PoA ki (AnnFix ki codes (Const Int :*: Const Ann)) ys -> Al ki codes xs ys
+ Generics.MRSOP.STDiff.Compute: diffAlmu :: forall ki codes ix iy. (EqHO ki, IsNat ix, IsNat iy, TestEquality ki) => AnnFix ki codes (Const Int :*: Const Ann) ix -> AnnFix ki codes (Const Int :*: Const Ann) iy -> Almu ki codes ix iy
+ Generics.MRSOP.STDiff.Compute: diffAt :: (EqHO ki, TestEquality ki) => NA ki (AnnFix ki codes (Const Int :*: Const Ann)) a -> NA ki (AnnFix ki codes (Const Int :*: Const Ann)) a -> At ki codes a
+ Generics.MRSOP.STDiff.Compute: diffCtx :: forall ki codes p ix xs. (EqHO ki, TestEquality ki, IsNat ix) => InsOrDel ki codes p -> AnnFix ki codes (Const Int :*: Const Ann) ix -> PoA ki (AnnFix ki codes (Const Int :*: Const Ann)) xs -> Ctx ki codes p ix xs
+ Generics.MRSOP.STDiff.Compute: diffSpine :: forall ki codes ix iy. (TestEquality ki, EqHO ki, IsNat ix, IsNat iy) => SNat ix -> SNat iy -> Rep ki (AnnFix ki codes (Const Int :*: Const Ann)) (Lkup ix codes) -> Rep ki (AnnFix ki codes (Const Int :*: Const Ann)) (Lkup iy codes) -> Spine ki codes (Lkup ix codes) (Lkup iy codes)
+ Generics.MRSOP.STDiff.Compute: hasCopies :: AnnFix ki codes (Const Int :*: chi) ix -> Bool
+ Generics.MRSOP.STDiff.Compute: injCofAnn :: Cof ki codes a t -> Const ann ix -> PoA ki (AnnFix ki codes (Const ann)) t -> NA ki (AnnFix ki codes (Const ann)) a
+ Generics.MRSOP.STDiff.Compute: insCofAnn :: Cof ki codes a t -> Const ann ix -> PoA ki (AnnFix ki codes (Const ann)) (t :++: as) -> PoA ki (AnnFix ki codes (Const ann)) (a : as)
+ Generics.MRSOP.STDiff.Compute: instance GHC.Show.Show Generics.MRSOP.STDiff.Compute.Ann
+ Generics.MRSOP.STDiff.Compute: myForgetAnn :: NA ki (AnnFix ki codes (Const Int :*: Const Ann)) at -> NA ki (Fix ki codes) at
+ Generics.MRSOP.STDiff.Compute: myGetAnn :: (Const Int :*: Const Ann) x -> Ann
+ Generics.MRSOP.STDiff.Compute: myGetAnnAt :: NA ki (AnnFix ki codes (Const Int :*: Const Ann)) ( 'I x) -> Ann
+ Generics.MRSOP.STDiff.Compute: myGetCopies :: (Const Int :*: Const Ann) x -> Int
+ Generics.MRSOP.STDiff.Compute: stiffAl :: (TestEquality ki, EqHO ki) => PoA ki (Fix ki codes) xs -> PoA ki (Fix ki codes) ys -> Al ki codes xs ys
+ Generics.MRSOP.STDiff.Compute: stiffAlmu :: (TestEquality ki, EqHO ki) => Fix ki codes ix -> Fix ki codes iy -> Almu ki codes ix iy
+ Generics.MRSOP.STDiff.Compute: stiffAt :: (TestEquality ki, EqHO ki) => NA ki (Fix ki codes) x -> NA ki (Fix ki codes) x -> At ki codes x
+ Generics.MRSOP.STDiff.Compute: stiffSpine :: (TestEquality ki, EqHO ki) => Rep ki (Fix ki codes) xs -> Rep ki (Fix ki codes) ys -> Spine ki codes xs ys
+ Generics.MRSOP.STDiff.Enum: enumAlmu :: forall m ki codes ix iy. (MonadPlus m, TestEquality ki, EqHO ki, IsNat ix, IsNat iy) => Fix ki codes ix -> Fix ki codes iy -> m (Almu ki codes ix iy)
+ Generics.MRSOP.STDiff.Merge: merge :: forall ki codes ix. (EqHO ki, IsNat ix) => Almu ki codes ix ix -> Almu ki codes ix ix -> Maybe (Almu ki codes ix ix)
+ Generics.MRSOP.STDiff.Types: AlmuMin :: Almu ki codes iy ix -> AlmuMin ki codes ix iy
+ Generics.MRSOP.STDiff.Types: [A0] :: Al ki codes '[] '[]
+ Generics.MRSOP.STDiff.Types: [ADel] :: NA ki (Fix ki codes) x -> Al ki codes xs ys -> Al ki codes (x : xs) ys
+ Generics.MRSOP.STDiff.Types: [AIns] :: NA ki (Fix ki codes) x -> Al ki codes xs ys -> Al ki codes xs (x : ys)
+ Generics.MRSOP.STDiff.Types: [AX] :: At ki codes x -> Al ki codes xs ys -> Al ki codes (x : xs) (x : ys)
+ Generics.MRSOP.STDiff.Types: [AtFix] :: IsNat ix => Almu ki codes ix ix -> At ki codes ( 'I ix)
+ Generics.MRSOP.STDiff.Types: [AtSet] :: TrivialK ki kon -> At ki codes ( 'K kon)
+ Generics.MRSOP.STDiff.Types: [Del] :: IsNat iy => Constr (Lkup ix codes) c -> DelCtx ki codes iy (Lkup c (Lkup ix codes)) -> Almu ki codes ix iy
+ Generics.MRSOP.STDiff.Types: [H] :: IsNat iy => p ix iy -> PoA ki (Fix ki codes) xs -> Ctx ki codes p ix ( 'I iy : xs)
+ Generics.MRSOP.STDiff.Types: [Ins] :: Constr (Lkup iy codes) c -> InsCtx ki codes ix (Lkup c (Lkup iy codes)) -> Almu ki codes ix iy
+ Generics.MRSOP.STDiff.Types: [SChg] :: Constr s1 c1 -> Constr s2 c2 -> Al ki codes (Lkup c1 s1) (Lkup c2 s2) -> Spine ki codes s1 s2
+ Generics.MRSOP.STDiff.Types: [SCns] :: Constr s1 c1 -> NP (At ki codes) (Lkup c1 s1) -> Spine ki codes s1 s1
+ Generics.MRSOP.STDiff.Types: [Scp] :: Spine ki codes s1 s1
+ Generics.MRSOP.STDiff.Types: [Spn] :: Spine ki codes (Lkup ix codes) (Lkup iy codes) -> Almu ki codes ix iy
+ Generics.MRSOP.STDiff.Types: [T] :: NA ki (Fix ki codes) a -> Ctx ki codes p ix xs -> Ctx ki codes p ix (a : xs)
+ Generics.MRSOP.STDiff.Types: [Trivial] :: ki kon -> ki kon -> TrivialK ki kon
+ Generics.MRSOP.STDiff.Types: [unAlmuMin] :: AlmuMin ki codes ix iy -> Almu ki codes iy ix
+ Generics.MRSOP.STDiff.Types: data Al (ki :: kon -> *) (codes :: [[[Atom kon]]]) :: [Atom kon] -> [Atom kon] -> *
+ Generics.MRSOP.STDiff.Types: data Almu (ki :: kon -> *) (codes :: [[[Atom kon]]]) :: Nat -> Nat -> *
+ Generics.MRSOP.STDiff.Types: data At (ki :: kon -> *) (codes :: [[[Atom kon]]]) :: Atom kon -> *
+ Generics.MRSOP.STDiff.Types: data Ctx (ki :: kon -> *) (codes :: [[[Atom kon]]]) (p :: Nat -> Nat -> *) (ix :: Nat) :: [Atom kon] -> *
+ Generics.MRSOP.STDiff.Types: data Spine (ki :: kon -> *) (codes :: [[[Atom kon]]]) :: [[Atom kon]] -> [[Atom kon]] -> *
+ Generics.MRSOP.STDiff.Types: data TrivialK (ki :: kon -> *) :: kon -> *
+ Generics.MRSOP.STDiff.Types: newtype AlmuMin ki codes ix iy
+ Generics.MRSOP.STDiff.Types: type DelCtx ki codes ix xs = Ctx ki codes (AlmuMin ki codes) ix xs
+ Generics.MRSOP.STDiff.Types: type InsCtx ki codes ix xs = Ctx ki codes (Almu ki codes) ix xs
Files
- generics-mrsop-gdiff.cabal +39/−34
- src/Generics/MRSOP/GDiff.hs +4/−5
- src/Generics/MRSOP/GDiff/Util.hs +5/−5
- src/Generics/MRSOP/STDiff.hs +104/−0
- src/Generics/MRSOP/STDiff/Compute.hs +365/−0
- src/Generics/MRSOP/STDiff/Enum.hs +94/−0
- src/Generics/MRSOP/STDiff/Merge.hs +187/−0
- src/Generics/MRSOP/STDiff/Types.hs +185/−0
generics-mrsop-gdiff.cabal view
@@ -1,37 +1,42 @@-name: generics-mrsop-gdiff+-- This file has been generated from package.yaml by hpack version 0.28.2.+--+-- see: https://github.com/sol/hpack+--+-- hash: 0efe06cb6c261c979c1bb69945d291c4d6d3d9eae84840801fabae96a8592ee2 --- The package version. See the Haskell package versioning policy (PVP) --- for standards guiding when and how versions should be incremented.--- https://wiki.haskell.org/Package_versioning_policy--- PVP summary: +------- breaking API changes--- | +----- non-breaking API additions--- | | +--- code changes with no API change-version: 0.0.1-license: BSD3-license-file: LICENSE-synopsis: Reimplementation of the `gdiff` algorithm for `generics-mrsop`-description: Here we port the gdiff algorithm and library to work over the generics-mrsop, enabling code that relies on the later library to access the gdiff algorithm. -author: Arian van Putten and Victor Miraldo-maintainer: arian.vanputten@gmail.com v.cacciarimiraldo@gmail.com-category: Generics-build-type: Simple-cabal-version: >=1.10+name: generics-mrsop-gdiff+version: 0.0.2+synopsis: Reimplementation of the gdiff algorithm for generics-mrsop+description: Here we port the gdiff algorithm and library to work over the generics-mrsop, enabling code that relies on the later library to access the gdiff algorithm. Moreover, we also bring in the utilities for converting a gdiff patch into a more structured version, facilitating merging. For some literature on the topic check Arian's MSc thesis at <https://dspace.library.uu.nl/handle/1874/380853> or our TyDe 2017 paper at <https://victorcmiraldo.github.io/data/tyde2017.pdf>.+category: Generics+homepage: https://github.com/VictorCMiraldo/generics-mrsop-gdiff#readme+bug-reports: https://github.com/VictorCMiraldo/generics-mrsop-gdiff/issues+author: Arian van Putten and Victor Miraldo+maintainer: Victor Miraldo <v.cacciarimiraldo@gmail.com>+license: BSD3+license-file: LICENSE+build-type: Simple+cabal-version: >= 1.10 -library- ghc-options:- -O2 -Wall+source-repository head+ type: git+ location: https://github.com/VictorCMiraldo/generics-mrsop-gdiff - exposed-modules: - Generics.MRSOP.GDiff- Generics.MRSOP.GDiff.Util- - -- Other library packages from which modules are imported.- build-depends: base < 5,- generics-mrsop >= 2.2.0- - -- Directories containing source files.- hs-source-dirs: src- - -- Base language which the package is written in.- default-language: Haskell2010- +library+ exposed-modules:+ Generics.MRSOP.GDiff+ Generics.MRSOP.GDiff.Util+ Generics.MRSOP.STDiff+ Generics.MRSOP.STDiff.Compute+ Generics.MRSOP.STDiff.Enum+ Generics.MRSOP.STDiff.Merge+ Generics.MRSOP.STDiff.Types+ other-modules:+ Paths_generics_mrsop_gdiff+ hs-source-dirs:+ src/+ ghc-options: -Wall+ build-depends:+ base >=4.9 && <5+ , generics-mrsop >=2.3.0+ default-language: Haskell2010
src/Generics/MRSOP/GDiff.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE QuantifiedConstraints #-} {-# LANGUAGE PolyKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE DataKinds #-}@@ -17,7 +16,7 @@ -- module Generics.MRSOP.GDiff ( Cof(..)- , cofIdx , cofWitnessI , cofHeq+ , cofIdx , cofWitnessI , cofHeq , matchCof , ES(..) , apply, apply' , applyES , diff , diff'@@ -71,7 +70,7 @@ cofHeq (ConstrK x) (ConstrK y) = case testEquality x y of Just Refl ->- if x == y+ if eqHO x y then Just (Refl, Refl) else Nothing Nothing -> Nothing@@ -255,7 +254,7 @@ -> NA ki (Fix ki codes) a -> Maybe (PoA ki (Fix ki codes) t) matchCof (ConstrI c1 _) (NA_I (Fix x)) = match c1 x-matchCof (ConstrK k) (NA_K k2) = guard (k == k2) >> Just Nil+matchCof (ConstrK k) (NA_K k2) = guard (eqHO k k2) >> Just Nil -- we need to give Haskell a bit of a hint that Tyof codes c reduces to an IsList -- insCof is also really the only place where we _need_ IsList I think@@ -328,7 +327,7 @@ -- hence, we can not get the datatype info showCof :: forall ki fam codes a c. (HasDatatypeInfo ki fam codes, ShowHO ki) => Cof ki codes a c -> String-showCof (ConstrK k) = show k+showCof (ConstrK k) = showHO k showCof x@(ConstrI c _) = constructorName . constrInfoLkup c $ datatypeInfo (Proxy @fam) (cofIdx x) instance (HasDatatypeInfo ki fam codes, ShowHO ki) =>
src/Generics/MRSOP/GDiff/Util.hs view
@@ -1,9 +1,9 @@-{-# LANGUAGE TypeOperators #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE GADTs #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE GADTs #-} {-# LANGUAGE ConstraintKinds #-}-{-# LANGUAGE PolyKinds #-}+{-# LANGUAGE PolyKinds #-} -- | For the lack of a better name, here we put random stuff module Generics.MRSOP.GDiff.Util where
+ src/Generics/MRSOP/STDiff.hs view
@@ -0,0 +1,104 @@+{-# LANGUAGE ViewPatterns #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE PolyKinds #-}+{-# LANGUAGE GADTs #-}+module Generics.MRSOP.STDiff+ ( module Generics.MRSOP.STDiff.Types+ , apply , merge , diff+ ) where++import Data.Proxy+import Data.Type.Equality hiding (apply)+import Control.Monad+import Generics.MRSOP.Base++import Generics.MRSOP.STDiff.Types+import Generics.MRSOP.STDiff.Merge+import Generics.MRSOP.STDiff.Compute+++applyAt :: EqHO ki+ => (At ki codes :*: NA ki (Fix ki codes)) a+ -> Either String (NA ki (Fix ki codes) a)+applyAt (AtSet (Trivial a' b) :*: NA_K a) + | eqHO a' b = pure (NA_K a)+ | eqHO a' a = pure (NA_K b)+ | otherwise = Left "atom"+applyAt (AtFix x :*: NA_I x') = NA_I <$> applyAlmu x x'++applyAl+ :: EqHO ki+ => Al ki codes xs ys+ -> PoA ki (Fix ki codes) xs+ -> Either String (PoA ki (Fix ki codes) ys)+applyAl A0 Nil = return Nil+applyAl (AX dx dxs) (x :* xs) =+ (:*) <$> applyAt (dx :*: x) <*> applyAl dxs xs+applyAl (AIns x dxs) xs =+ (x :*) <$> applyAl dxs xs +applyAl (ADel x dxs) (x' :* xs) =+ if eqHO x x' then applyAl dxs xs else Left "al del"+ -- applyAl dxs xs++testEquality' :: (TestEquality f)+ => f a -> f b -> Either String (a :~: b)+testEquality' x y = case testEquality x y of+ Just r -> Right r+ Nothing -> Left "err"++applySpine + :: EqHO ki+ => SNat ix+ -> SNat iy+ -> Spine ki codes (Lkup ix codes) (Lkup iy codes)+ -> Rep ki (Fix ki codes) (Lkup ix codes)+ -> Either String (Rep ki (Fix ki codes) (Lkup iy codes))+applySpine _ _ Scp x = return x+applySpine ix iy (SCns c1 dxs) (sop -> Tag c2 xs) = do+ Refl <- testEquality' ix iy+ Refl <- testEquality' c1 c2+ inj c2 <$> (mapNPM applyAt (zipNP dxs xs))+applySpine _ _ (SChg c1 c2 al) (sop -> Tag c3 xs) = do+ Refl <- testEquality' c1 c3+ inj c2 <$> applyAl al xs++insCtx+ :: (IsNat ix, EqHO ki)+ => InsCtx ki codes ix xs+ -> Fix ki codes ix+ -> Either String (PoA ki (Fix ki codes) xs)+insCtx (H x x2) x1 = (\xi -> NA_I xi :* x2) <$> applyAlmu x x1+insCtx (T x x2) x1 = (x :*) <$> insCtx x2 x1++delCtx+ :: (EqHO ki, IsNat ix)+ => DelCtx ki codes ix xs+ -> PoA ki (Fix ki codes) xs+ -> Either String (Fix ki codes ix)+delCtx (H spu _) (NA_I x :* _) = applyAlmu (unAlmuMin spu) x+delCtx (T _ al) (_ :* p) = delCtx al p++applyAlmu + :: forall ki codes ix iy. (IsNat ix, IsNat iy, EqHO ki)+ => Almu ki codes ix iy+ -> Fix ki codes ix+ -> Either String (Fix ki codes iy)+applyAlmu (Spn spine) (Fix rep) = Fix <$> applySpine (getSNat (Proxy @ix)) (getSNat (Proxy @iy)) spine rep+applyAlmu (Ins c ctx) f@(Fix _) = Fix . inj c <$> insCtx ctx f+applyAlmu (Del c ctx) (Fix rep) = delCtx ctx <=< m2e . match c $ rep+ where+ m2e Nothing = Left (show "del")+ m2e (Just r) = Right r++-- |Applies a patch to an element+apply :: forall ki codes ix iy+ . (IsNat ix, IsNat iy, EqHO ki)+ => Almu ki codes ix iy+ -> Fix ki codes ix+ -> Maybe (Fix ki codes iy)+apply almu x = case applyAlmu almu x of+ Left _ -> Nothing+ Right y -> Just y
+ src/Generics/MRSOP/STDiff/Compute.hs view
@@ -0,0 +1,365 @@+{-# LANGUAGE ViewPatterns #-}+{-# LANGUAGE PolyKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE GADTs #-}+module Generics.MRSOP.STDiff.Compute where++import Data.Function (on)+import Data.Ord (comparing)+import Data.List (maximumBy)+import Data.Coerce+import Data.Proxy+import Data.Type.Equality+import Data.Functor.Const++import Generics.MRSOP.Base+import Generics.MRSOP.AG++import qualified Generics.MRSOP.GDiff as GDiff+import Generics.MRSOP.GDiff.Util+import Generics.MRSOP.STDiff.Types++import Data.Maybe (fromJust)++-- * Annotating Trees+--+-- $annotating+--+-- First we use /gdiff/ to annotate the source and destination+-- forests before translating them to a 'Generics.MRSOP.STDiff.Almu'+-- The idea being that the information comming from /gdiff/ is sufficient+-- to know which constructors are copies and which have been modified.++-- |Annotations to be placed throughout the tree.+data Ann = Modify | Copy deriving Show++-- |Adds an annotated constructor to a product of atoms.+injCofAnn :: GDiff.Cof ki codes a t+ -> Const ann ix+ -> PoA ki (AnnFix ki codes (Const ann)) t+ -> NA ki (AnnFix ki codes (Const ann)) a+injCofAnn (GDiff.ConstrI c _) ann xs = NA_I (AnnFix (coerce ann) $ inj c xs)+injCofAnn (GDiff.ConstrK k) _ _ = NA_K k++-- |Inserts an annotated constructor at the head of a+-- product of atoms.+insCofAnn :: GDiff.Cof ki codes a t+ -> Const ann ix+ -> PoA ki (AnnFix ki codes (Const ann)) (t :++: as)+ -> PoA ki (AnnFix ki codes (Const ann)) (a ': as)+insCofAnn (GDiff.ConstrK k) _ xs = NA_K k :* xs+insCofAnn (GDiff.ConstrI c prf) ann xs =+ let (xs0, xs1) = split prf xs+ in injCofAnn (GDiff.ConstrI c prf) ann xs0 :* xs1++{-+ - In Agda, it would be the following. However, I'm not sure+ - it is possible to carry around the IsJust constraint in Haskell+ - hence, we will be partial instead+ - ann-source : ∀{txs tys}(xs : ⟦ txs ⟧A*)(p : ES txs tys)+ - → (hip : IsJust (applyES p xs))+ - → ⟦ txs ⟧Aₐ*+ -+ - However, it's morally total if you know beforehand that the+ - patch is gonna apply. Which we know by construction everywhere we use this+ - , so we can just `fromJust` it where appropriate+ -+ - WARNING: Morally dubious, but we know that this edit script was+ - generated hte same time as the datatype, so it should never+ - fail to apply+ -+ - TODO: Actually make it return Maybe and be honest+ -}++-- |Annotates the source of an edit script.+annSrc :: (EqHO ki , IsNat ix)+ => Fix ki codes ix -- ^ + -> GDiff.ES ki codes '[ 'I ix] ys+ -> AnnFix ki codes (Const Ann) ix+annSrc x0 es0 = case annSrc' (NA_I x0 :* Nil) es0 of+ (NA_I y :* Nil) -> y+ where+ annSrc' :: EqHO ki+ => PoA ki (Fix ki codes) xs+ -> GDiff.ES ki codes xs ys+ -> PoA ki (AnnFix ki codes (Const Ann)) xs+ annSrc' _ GDiff.ES0 = Nil+ annSrc' Nil _ = Nil+ annSrc' xs (GDiff.Ins _ _ es) = annSrc' xs es+ annSrc' (x :* xs) (GDiff.Del _ c es) =+ let poa = fromJust $ GDiff.matchCof c x+ in insCofAnn c (Const Modify) (annSrc' (appendNP poa xs) es)+ annSrc' (x :* xs) (GDiff.Cpy _ c es) =+ let poa = fromJust $ GDiff.matchCof c x+ in insCofAnn c (Const Copy) (annSrc' (appendNP poa xs) es)++-- |Annotates the destination of an edit script.+annDest :: (EqHO ki , IsNat ix)+ => Fix ki codes ix -- ^ + -> GDiff.ES ki codes xs '[ 'I ix]+ -> AnnFix ki codes (Const Ann) ix+annDest x0 es0 = case annDest' (NA_I x0 :* Nil) es0 of+ (NA_I y :* Nil) -> y+ where+ annDest' :: EqHO ki+ => PoA ki (Fix ki codes) ys+ -> GDiff.ES ki codes xs ys+ -> PoA ki (AnnFix ki codes (Const Ann)) ys+ annDest' _ GDiff.ES0 = Nil+ annDest' Nil _ = Nil+ annDest' (x :* xs) (GDiff.Del _ _ es) = annDest' (x :* xs) es+ annDest' (x :* xs) (GDiff.Ins _ c es)+ = let poa = fromJust $ GDiff.matchCof c x+ in insCofAnn c (Const Modify) (annDest' (appendNP poa xs) es)+ annDest' (x :* xs) (GDiff.Cpy _ c es) =+ let poa = fromJust $ GDiff.matchCof c x+ in insCofAnn c (Const Copy) (annDest' (appendNP poa xs) es)++-- * Differencing Annotated Trees+--+-- $diffann+--+-- Once we have annotated the trees on the source and destination of the+-- edit script, we can easily diff them in the /stdiff/ style.+--++-- ** Stiff Patches+--+-- $stiffpatches+--+-- We call a patch /stiff/ if it has no copies. It is trivial+-- to produce sauch a patch given two elements. We simply delete+-- the entire source and insert the entire destination.++stiffAlmu :: (TestEquality ki, EqHO ki)+ => Fix ki codes ix -- ^+ -> Fix ki codes iy+ -> Almu ki codes ix iy+stiffAlmu (Fix rep1) (Fix rep2) = Spn (stiffSpine rep1 rep2)++stiffSpine :: (TestEquality ki, EqHO ki)+ => Rep ki (Fix ki codes) xs -- ^ + -> Rep ki (Fix ki codes) ys+ -> Spine ki codes xs ys+stiffSpine (sop -> Tag c1 p1) (sop -> Tag c2 p2) = SChg c1 c2 (stiffAl p1 p2)++stiffAt :: (TestEquality ki, EqHO ki)+ => NA ki (Fix ki codes) x -- ^ + -> NA ki (Fix ki codes) x+ -> At ki codes x+stiffAt (NA_K x) (NA_K y) = AtSet (Trivial x y)+stiffAt (NA_I x) (NA_I y) = AtFix (stiffAlmu x y)++stiffAl :: (TestEquality ki, EqHO ki)+ => PoA ki (Fix ki codes) xs -- ^+ -> PoA ki (Fix ki codes) ys+ -> Al ki codes xs ys+stiffAl Nil Nil = A0+stiffAl (x :* xs) Nil = ADel x (stiffAl xs Nil)+stiffAl Nil (y :* ys) = AIns y (stiffAl Nil ys)+stiffAl (x :* xs) (y :* ys) = + case testEquality x y of+ Just Refl -> AX (stiffAt x y) (stiffAl xs ys)+ Nothing -> AIns y (ADel x (stiffAl xs ys))++-- ** Copy Counting+--+-- $copycounting+--+-- In order to decide which path to follow from the roof to the+-- leaves whenver we are faced with a choice, we will pre-compute+-- the amount of copies present in each subtree.++-- |Algebra for counting copies.+copiesAlgebra :: Const Ann ix -- ^+ -> Rep ki (Const Int) xs+ -> Const Int ix+copiesAlgebra (Const ann) r+ = let inAnn = elimRep (const 0) getConst sum r+ in Const $ case ann of+ Modify -> inAnn+ Copy -> 1 + inAnn+ ++-- |Annotates the tree with how many copies are underneath each node+-- (inclusive with self)+--+-- > copies Copy = 1 + copies children+-- > copies Modify = copies children+--+countCopies :: IsNat ix+ => AnnFix ki codes (Const Ann) ix -- ^+ -> AnnFix ki codes (Const Int :*: Const Ann) ix+countCopies = synthesizeAnn (\ca r -> copiesAlgebra ca (mapRep getFst r) :*: ca)+ where+ getFst :: (a :*: b) x -> a x+ getFst (x :*: _) = x++-- |Returns whether or not a subtree constains any copies.+hasCopies :: AnnFix ki codes (Const Int :*: chi) ix -> Bool+hasCopies (AnnFix (Const x :*: _) _) = x > 0++-- |Easily retrieves annotations+myGetAnn :: (Const Int :*: Const Ann) x -> Ann+myGetAnn (_ :*: Const ann) = ann++myGetAnnAt :: NA ki (AnnFix ki codes (Const Int :*: Const Ann)) ('I x) -> Ann+myGetAnnAt (NA_I (AnnFix ann _)) = myGetAnn ann++-- |Easily retrieves annotations+myGetCopies :: (Const Int :*: Const Ann) x -> Int+myGetCopies (Const copies :*: _) = copies++myForgetAnn :: NA ki (AnnFix ki codes (Const Int :*: Const Ann)) at+ -> NA ki (Fix ki codes) at+myForgetAnn = mapNA id forgetAnn++-- ** Computing the Patch+--+-- $computing+--+-- Given trees annotated with information about each of their constructors+-- and how many of those are supposed to be copied, we can finally+-- deterministically translate two tress into a patch.++data InsOrDel (ki :: kon -> *) (codes :: [[[Atom kon]]]) :: (Nat -> Nat -> *) -> * where+ CtxIns :: InsOrDel ki codes (Almu ki codes)+ CtxDel :: InsOrDel ki codes (AlmuMin ki codes)+++-- |Finds the element in the @PoA ... xs@ with the most copies+-- and diff the given @AnnFix@.+--+-- PRECONDITION: The @PoA .. xs@ must contain at least one tree with+-- a copy. Always guard this call with 'hasCopies'+--+--+diffCtx :: forall ki codes p ix xs+ . (EqHO ki, TestEquality ki, IsNat ix)+ => InsOrDel ki codes p+ -> AnnFix ki codes (Const Int :*: Const Ann) ix+ -> PoA ki (AnnFix ki codes (Const Int :*: Const Ann)) xs+ -> Ctx ki codes p ix xs+diffCtx cid x xs+ = let maxIdx = fst $ maximumBy (comparing snd) zipped+ zipped = zip [0 .. ] elimmed+ elimmed = elimNP (elimNA (const 0) (myGetCopies . getAnn)) xs+ in drop' maxIdx xs+ where+ drop' :: Int+ -> PoA ki (AnnFix ki codes (Const Int :*: Const Ann)) ys+ -> Ctx ki codes p ix ys+ drop' _ Nil = error "unreachable"+ drop' 0 (NA_I y :* ys) =+ case cid of+ CtxIns -> H (diffAlmu x y) (mapNP myForgetAnn ys)+ CtxDel -> H (AlmuMin (diffAlmu y x)) (mapNP myForgetAnn ys)+ drop' n (y :* ys) = T (myForgetAnn y) (drop' (n - 1) ys)++-- | Takes two annotated trees, and produces a patch+diffAlmu :: forall ki codes ix iy+ . (EqHO ki, IsNat ix, IsNat iy, TestEquality ki)+ => AnnFix ki codes (Const Int :*: Const Ann) ix -- ^ + -> AnnFix ki codes (Const Int :*: Const Ann) iy+ -> Almu ki codes ix iy+diffAlmu x@(AnnFix ann1 rep1) y@(AnnFix ann2 rep2) =+ case (myGetAnn ann1, myGetAnn ann2) of+ (Copy, Copy) -> Spn (diffSpine (getSNat $ Proxy @ix) (getSNat $ Proxy @iy) rep1 rep2)+ (Copy, Modify) -> + if hasCopies y then diffIns x rep2 else stiffAlmu (forgetAnn x) (forgetAnn y)+ (Modify, Copy) ->+ if hasCopies x then diffDel rep1 y else stiffAlmu (forgetAnn x) (forgetAnn y)+ (Modify, Modify) ->+ if hasCopies x then diffDel rep1 y else stiffAlmu (forgetAnn x) (forgetAnn y)+ where+ diffIns :: AnnFix ki codes (Const Int :*: Const Ann) ix+ -> Rep ki (AnnFix ki codes (Const Int :*: Const Ann)) (Lkup iy codes)+ -> Almu ki codes ix iy+ diffIns x1 rep = case sop rep of Tag c xs -> Ins c (diffCtx CtxIns x1 xs)++ diffDel :: Rep ki (AnnFix ki codes (Const Int :*: Const Ann)) (Lkup ix codes)+ -> AnnFix ki codes (Const Int :*: Const Ann) iy+ -> Almu ki codes ix iy+ diffDel rep x1 = case sop rep of Tag c xs -> Del c (diffCtx CtxDel x1 xs)++-- | Takes two annotated 'Rep's, and produces a patch+diffSpine :: forall ki codes ix iy+ . (TestEquality ki, EqHO ki, IsNat ix, IsNat iy)+ => SNat ix -- ^ We need these to identify the mutrec family + -> SNat iy + -> Rep ki (AnnFix ki codes (Const Int :*: Const Ann)) (Lkup ix codes)+ -> Rep ki (AnnFix ki codes (Const Int :*: Const Ann)) (Lkup iy codes)+ -> Spine ki codes (Lkup ix codes) (Lkup iy codes)+diffSpine six siy s1@(sop -> Tag c1 p1) s2@(sop -> Tag c2 p2) =+ case testEquality six siy of+ Just Refl ->+ if (eqHO `on` mapRep forgetAnn) s1 s2+ then Scp+ else case testEquality c1 c2 of+ Just Refl ->+ SCns c1 (mapNP (\(a :*: b) -> diffAt a b) (zipNP p1 p2))+ Nothing -> SChg c1 c2 (diffAl p1 p2)+ Nothing -> SChg c1 c2 (diffAl p1 p2)+++diffAl :: forall ki codes xs ys+ . (EqHO ki, TestEquality ki)+ => PoA ki (AnnFix ki codes (Const Int :*: Const Ann)) xs -- ^+ -> PoA ki (AnnFix ki codes (Const Int :*: Const Ann)) ys+ -> Al ki codes xs ys+diffAl Nil Nil = A0+diffAl Nil (y :* ys) = AIns (mapNA id forgetAnn y) (diffAl Nil ys)+diffAl (x :* xs) Nil = ADel (mapNA id forgetAnn x) (diffAl xs Nil)+diffAl (x@(NA_K k1) :* xs) (y@(NA_K k2) :* ys) = + case testEquality k1 k2 of+ Just Refl -> AX (diffAt x y) (diffAl xs ys)+ Nothing -> AIns (mapNA id forgetAnn y) (ADel (mapNA id forgetAnn x) (diffAl xs ys))+diffAl (x@(NA_K _) :* xs) (y@(NA_I _) :* ys) = + case myGetAnnAt y of+ Modify -> AIns (mapNA id forgetAnn y) (diffAl (x :* xs) ys)+ Copy -> ADel (mapNA id forgetAnn x) (diffAl xs (y :* ys))+diffAl (x@(NA_I _) :* xs) (y@(NA_K _) :* ys) =+ case myGetAnnAt x of+ Modify -> ADel (mapNA id forgetAnn x) (diffAl xs (y :* ys))+ Copy -> AIns (mapNA id forgetAnn y) (diffAl (x :* xs) ys)+diffAl (x@(NA_I _) :* xs) (y@(NA_I _) :* ys) = + case (myGetAnnAt x, myGetAnnAt y) of+ (Modify, _) -> ADel (mapNA id forgetAnn x) (diffAl xs (y :* ys))+ (Copy, Modify) -> AIns (mapNA id forgetAnn y) (diffAl (x :* xs) ys)+ (Copy, Copy) -> + case testEquality x y of+ Just Refl -> AX (diffAt x y) (diffAl xs ys)+ -- NOTE we added this case+ Nothing -> AIns (mapNA id forgetAnn y) (ADel (mapNA id forgetAnn x) (diffAl xs ys))++diffAt :: (EqHO ki, TestEquality ki)+ => NA ki (AnnFix ki codes (Const Int :*: Const Ann)) a -- ^+ -> NA ki (AnnFix ki codes (Const Int :*: Const Ann)) a+ -> At ki codes a+diffAt (NA_K x) (NA_K y) = AtSet (Trivial x y)+diffAt (NA_I x) (NA_I y) = AtFix $ diffAlmu x y++-- |The interface function which witnesses thecomplete pipeline.+-- its implementation is straightforward:+--+-- > diff x y = let es = GDiff.diff' x y+-- > ax = countCopies $ annSrc x es+-- > ay = countCopies $ annDest y es+-- > in diffAlmu ax ay+--+diff :: (EqHO ki , TestEquality ki , IsNat ix)+ => Fix ki codes ix -- ^+ -> Fix ki codes ix+ -> Almu ki codes ix ix+diff x y = let es = GDiff.diff' x y+ ax = countCopies $ annSrc x es+ ay = countCopies $ annDest y es+ in diffAlmu ax ay+
+ src/Generics/MRSOP/STDiff/Enum.hs view
@@ -0,0 +1,94 @@+{-# LANGUAGE ViewPatterns #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE PolyKinds #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE GADTs #-}+module Generics.MRSOP.STDiff.Enum (enumAlmu) where++import Control.Monad+import Control.Applicative+import Data.Type.Equality++import Generics.MRSOP.Base+import Generics.MRSOP.STDiff.Types++enumAt :: (MonadPlus m , TestEquality ki , EqHO ki)+ => NA ki (Fix ki codes) at+ -> NA ki (Fix ki codes) at+ -> m (At ki codes at)+enumAt (NA_I x) (NA_I y) = AtFix <$> enumAlmu x y+enumAt (NA_K x) (NA_K y) = return $ AtSet (Trivial x y)++enumAl :: (MonadPlus m , TestEquality ki , EqHO ki)+ => PoA ki (Fix ki codes) p1+ -> PoA ki (Fix ki codes) p2+ -> m (Al ki codes p1 p2)+enumAl Nil Nil = return A0+enumAl (x :* xs) Nil = ADel x <$> enumAl xs Nil+enumAl Nil (y :* ys) = AIns y <$> enumAl Nil ys+enumAl (x :* xs) (y :* ys)+ = (ADel x <$> enumAl xs (y :* ys))+ <|> (AIns y <$> enumAl (x :* xs) ys)+ <|> case testEquality x y of+ Just Refl -> AX <$> (enumAt x y) <*> enumAl xs ys+ Nothing -> mzero++enumSpn :: (MonadPlus m , TestEquality ki , EqHO ki)+ => SNat ix -> SNat iy+ -> Rep ki (Fix ki codes) (Lkup ix codes)+ -> Rep ki (Fix ki codes) (Lkup iy codes)+ -> m (Spine ki codes (Lkup ix codes) (Lkup iy codes))+enumSpn six siy (sop -> Tag cx px) (sop -> Tag cy py)+ = case testEquality six siy of+ Nothing -> SChg cx cy <$> enumAl px py+ Just Refl -> + case testEquality cx cy of+ Nothing -> SChg cx cy <$> enumAl px py+ Just Refl -> if eqHO px py+ then return Scp+ else SCns cx <$> mapNPM (uncurry' enumAt) (zipNP px py)++enumDelCtx :: forall m ki codes iy prod+ . (MonadPlus m , TestEquality ki , EqHO ki , IsNat iy)+ => PoA ki (Fix ki codes) prod+ -> Fix ki codes iy+ -> m (DelCtx ki codes iy prod)+enumDelCtx Nil _ = mzero+enumDelCtx (NA_K x :* xs) f = T (NA_K x) <$> enumDelCtx xs f+enumDelCtx (NA_I x :* xs) f+ = (flip H xs . AlmuMin) <$> enumAlmu x f+ <|> T (NA_I x) <$> enumDelCtx xs f++enumInsCtx :: forall m ki codes iy prod+ . (MonadPlus m , TestEquality ki , EqHO ki , IsNat iy)+ => Fix ki codes iy+ -> PoA ki (Fix ki codes) prod+ -> m (InsCtx ki codes iy prod)+enumInsCtx _ Nil = mzero+enumInsCtx f (NA_K x :* xs) = T (NA_K x) <$> enumInsCtx f xs+enumInsCtx f (NA_I x :* xs) + = (flip H xs) <$> enumAlmu f x+ <|> T (NA_I x) <$> enumInsCtx f xs + +-- |Enumerates all possible patches that transform a value into another+-- on a @MonadPlus@ instance; /WARNING: this function has impractical runtime performance and should not be used!!/+enumAlmu :: forall m ki codes ix iy+ . (MonadPlus m , TestEquality ki , EqHO ki , IsNat ix , IsNat iy)+ => Fix ki codes ix+ -> Fix ki codes iy+ -> m (Almu ki codes ix iy)+enumAlmu x y+ = enumDel (sop $ unFix x) y+ <|> enumIns x (sop $ unFix y)+ <|> Spn <$> enumSpn (snatFixIdx x) (snatFixIdx y) (unFix x) (unFix y)+ where+ enumDel :: View ki (Fix ki codes) (Lkup ix codes)+ -> Fix ki codes iy+ -> m (Almu ki codes ix iy)+ enumDel (Tag c p) y0 = Del c <$> enumDelCtx p y0++ enumIns :: Fix ki codes ix+ -> View ki (Fix ki codes) (Lkup iy codes)+ -> m (Almu ki codes ix iy)+ enumIns x0 (Tag c p) = Ins c <$> enumInsCtx x0 p
+ src/Generics/MRSOP/STDiff/Merge.hs view
@@ -0,0 +1,187 @@+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE PolyKinds #-}+module Generics.MRSOP.STDiff.Merge (merge) where++import Data.Proxy+import Data.Type.Equality+import Control.Monad (guard)++import Generics.MRSOP.Base++import Generics.MRSOP.STDiff.Types++mergeAt :: EqHO ki+ => At ki codes a+ -> At ki codes a+ -> Maybe (At ki codes a)+mergeAt (AtSet (Trivial k1 k2)) (AtSet (Trivial k3 k4)) = + if eqHO k1 k2+ then pure $ AtSet $ Trivial k3 k4+ else if eqHO k3 k4+ then pure $ AtSet $ Trivial k3 k4+ else Nothing+mergeAt (AtFix x) (AtFix y) = AtFix <$> mergeAlmu x y++mergeAtAl :: EqHO ki+ => NP (At ki codes) xs+ -> Al ki codes xs ys+ -> Maybe (Al ki codes xs ys)+mergeAtAl Nil A0 = pure A0+mergeAtAl xs (AIns at al) = AIns at <$> mergeAtAl xs al+mergeAtAl (x :* xs) (ADel at al)+ | identityAt x = ADel at <$> mergeAtAl xs al+ | otherwise = Nothing+mergeAtAl (x :* xs) (AX at al) = AX <$> (mergeAt x at) <*> mergeAtAl xs al++identityAt :: (EqHO ki) => At ki codes a -> Bool+identityAt (AtFix (Spn Scp)) = True+identityAt (AtSet (Trivial k1 k2)) = eqHO k1 k2+identityAt _ = False++makeIdAt :: NA ki (Fix ki codes) a -> At ki codes a+makeIdAt (NA_I _) = AtFix (Spn Scp)+makeIdAt (NA_K k) = AtSet (Trivial k k)++mergeAlAt :: EqHO ki+ => Al ki codes xs ys+ -> NP (At ki codes) xs+ -> Maybe (NP (At ki codes) ys)+mergeAlAt A0 Nil = pure Nil+mergeAlAt (AIns at al) xs = (makeIdAt at :*) <$> mergeAlAt al xs+mergeAlAt (ADel _ al) (x :* xs)+ | identityAt x = mergeAlAt al xs+ | otherwise = Nothing+mergeAlAt (AX a al) (x :* xs) = (:*) <$> mergeAt a x <*> mergeAlAt al xs+++mergeAts :: EqHO ki+ => NP (At ki codes) xs+ -> NP (At ki codes) xs+ -> Maybe (NP (At ki codes) xs)+mergeAts Nil Nil = pure Nil+mergeAts (x :* xs) (y :* ys) = (:*) <$> mergeAt x y <*> mergeAts xs ys++mergeSpine :: EqHO ki+ => SNat ix+ -> SNat iy+ -> Spine ki codes (Lkup ix codes) (Lkup iy codes)+ -> Spine ki codes (Lkup ix codes) (Lkup iy codes)+ -> Maybe (Spine ki codes (Lkup ix codes) (Lkup iy codes))+mergeSpine _ _ Scp s = pure s+mergeSpine _ _ _ Scp = pure Scp+mergeSpine _ _ (SCns cx xs) (SCns cy ys) = do+ Refl <- testEquality cx cy+ SCns cx <$> mergeAts xs ys+mergeSpine _ _ (SCns cx xs) (SChg cy cz al) = do+ Refl <- testEquality cx cy+ SChg cy cz <$> mergeAtAl xs al+mergeSpine ix iy (SChg cx cy al) (SCns cz zs) = do+ Refl <- testEquality ix iy+ Refl <- testEquality cx cz+ SCns cy <$> mergeAlAt al zs+mergeSpine _ _ SChg{} SChg{} = Nothing++mergeCtxAt :: forall ki codes ix iy xs+ . (EqHO ki, IsNat ix, IsNat iy) + => DelCtx ki codes iy xs+ -> NP (At ki codes) xs+ -> Maybe (Almu ki codes ix iy)+mergeCtxAt (H (AlmuMin almu') _) (AtFix almu :* xs) = do+ Refl <- testEquality (almuDest almu) (almuDest almu')+ x <- mergeAlmu almu' almu+ Refl <- testEquality (almuSrc x) (getSNat (Proxy @ix))+ guard (and $ elimNP identityAt xs)+ pure x+mergeCtxAt (T _ ctx) (x :* xs) = do+ guard (identityAt x)+ mergeCtxAt ctx xs++mergeAtCtx :: (EqHO ki, IsNat iy)+ => NP (At ki codes) xs+ -> DelCtx ki codes iy xs+ -> Maybe (DelCtx ki codes iy xs)+mergeAtCtx (AtFix almu :* xs) (H (AlmuMin almu') rest) = do+ Refl <- testEquality (almuDest almu) (almuDest almu')+ almu'' <- mergeAlmu almu almu'+ guard (and $ elimNP identityAt xs)+ pure $ H (AlmuMin almu'') rest+mergeAtCtx (x :* xs) (T a ctx) = do+ guard (identityAt x)+ T a <$> mergeAtCtx xs ctx+mergeAtCtx Nil _ = error "unreachable" -- check x's type to be sure!++almuDest :: forall ix iy ki codes. IsNat iy => Almu ki codes ix iy -> SNat iy+almuDest _ = getSNat (Proxy @iy)++almuSrc :: forall ix iy ki codes. IsNat ix => Almu ki codes ix iy -> SNat ix+almuSrc _ = getSNat (Proxy @ix)++mergeCtxAlmu :: (EqHO ki, IsNat ix )+ => InsCtx ki codes ix xs+ -> Almu ki codes ix ix+ -> Maybe (NP (At ki codes) xs)+mergeCtxAlmu (H almu' rest) almu = do + Refl <- testEquality (almuDest almu) (almuDest almu')+ x <- AtFix <$> mergeAlmu almu' almu+ pure $ x :* mapNP makeIdAt rest+mergeCtxAlmu (T a ctx) almu = + (makeIdAt a :*) <$> mergeCtxAlmu ctx almu++mergeAlmuCtx :: (EqHO ki, IsNat ix)+ => Almu ki codes ix ix+ -> InsCtx ki codes ix xs+ -> Maybe (InsCtx ki codes ix xs)+mergeAlmuCtx almu (H almu' rest) = do+ Refl <- testEquality (almuDest almu) (almuDest almu')+ almu'' <- mergeAlmu almu almu'+ pure (H almu'' rest)+mergeAlmuCtx almu (T a ctx) = T a <$> mergeAlmuCtx almu ctx++mergeAlmu :: forall ki codes ix iy+ . (EqHO ki, IsNat ix, IsNat iy)+ => Almu ki codes ix iy+ -> Almu ki codes ix iy+ -> Maybe (Almu ki codes ix iy)+mergeAlmu (Ins _ _) (Ins _ _) = Nothing+mergeAlmu (Ins c1 s1) (Spn s2) = do+ Refl <- testEquality (getSNat (Proxy @ix)) (getSNat (Proxy @iy))+ Spn . SCns c1 <$> mergeCtxAlmu s1 (Spn s2)+mergeAlmu (Ins c1 s1) (Del c2 s2) = do+ Refl <- testEquality (getSNat (Proxy @ix)) (getSNat (Proxy @iy))+ Spn . SCns c1 <$> mergeCtxAlmu s1 (Del c2 s2)+mergeAlmu (Spn s1) (Ins c2 s2) = do+ Refl <- testEquality (getSNat (Proxy @ix)) (getSNat (Proxy @iy))+ Ins c2 <$> (mergeAlmuCtx (Spn s1) s2)+mergeAlmu (Del c1 s1) (Ins c2 s2) = do+ Refl <- testEquality (getSNat (Proxy @ix)) (getSNat (Proxy @iy))+ Ins c2 <$> (mergeAlmuCtx (Del c1 s1) s2)++mergeAlmu (Spn s1) (Spn s2) = Spn <$> mergeSpine (getSNat (Proxy @ix)) (getSNat (Proxy @iy)) s1 s2+mergeAlmu (Spn Scp) (Del c2 s2) = pure $ Del c2 s2+mergeAlmu (Spn (SCns c1 at1)) (Del c2 s2) = do+ + Refl <- testEquality c1 c2+ Del c1 <$> mergeAtCtx at1 s2+mergeAlmu (Spn (SChg _ _ _)) (Del _ _) = Nothing+mergeAlmu (Del _ _) (Spn Scp) = pure $ Spn Scp+mergeAlmu (Del c1 s1) (Spn (SCns c2 at2)) = do+ Refl <- testEquality c1 c2+ mergeCtxAt s1 at2+mergeAlmu (Del _ _) (Spn (SChg _ _ _)) = Nothing+mergeAlmu (Del _ _) (Del _ _) = Nothing++-- |Merges two patches in the /stdiff/ style. Satisfies the following+-- postcondition:+--+-- > if merge p q == Just pq && merge q p == Just qp+-- > then apply pq . q == apply qp . p+--+merge :: forall ki codes ix+ . (EqHO ki, IsNat ix)+ => Almu ki codes ix ix+ -> Almu ki codes ix ix+ -> Maybe (Almu ki codes ix ix)+merge = mergeAlmu
+ src/Generics/MRSOP/STDiff/Types.hs view
@@ -0,0 +1,185 @@+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE PolyKinds #-}+{-# LANGUAGE GADTs #-}+module Generics.MRSOP.STDiff.Types where++import Generics.MRSOP.Base++-- * Functorial Changes+--+-- $functorialchanges+--+-- Represents changes on the /first layer/ of two values of+-- mutually recursive families. For a more in-depth explanation+-- of the datatypes and their meaning we refer the interested reader+-- to the relevant literature:+--+-- - Miraldo, Dagand and Swierstra, TyDe 2017 <https://victorcmiraldo.github.io/data/tyde2017.pdf pdf>+-- - van Putten, MSc thesis <https://dspace.library.uu.nl/handle/1874/380853>+--++-- |Represents a change between two opaque values. When they+-- are equal represents a copy.+data TrivialK (ki :: kon -> *) :: kon -> * where+ Trivial :: ki kon -> ki kon -> TrivialK ki kon ++-- |Represents a change between two atoms, where an atom is+-- either a recursive or an opaque value.+data At (ki :: kon -> *) (codes :: [[[Atom kon]]]) :: Atom kon -> * where+ AtSet :: TrivialK ki kon -> At ki codes ('K kon)+ AtFix :: (IsNat ix) => Almu ki codes ix ix -> At ki codes ('I ix)++-- |Represents an alignment between two product of atoms.+data Al (ki :: kon -> *) (codes :: [[[Atom kon]]]) :: [Atom kon] -> [Atom kon] -> * where+ A0 :: Al ki codes '[] '[]+ AX :: At ki codes x -> Al ki codes xs ys -> Al ki codes (x ': xs) (x ': ys)+ ADel :: NA ki (Fix ki codes) x -> Al ki codes xs ys -> Al ki codes (x ': xs) ys+ AIns :: NA ki (Fix ki codes) x -> Al ki codes xs ys -> Al ki codes xs (x ': ys)++-- |Represents a change at the coproduct structure.+data Spine (ki :: kon -> *) (codes :: [[[Atom kon]]]) :: [[Atom kon]] -> [[Atom kon]] -> * where+ Scp :: Spine ki codes s1 s1+ SCns :: Constr s1 c1 + -> NP (At ki codes) (Lkup c1 s1)+ -> Spine ki codes s1 s1+ SChg :: Constr s1 c1+ -> Constr s2 c2+ -> Al ki codes (Lkup c1 s1) (Lkup c2 s2)+ -> Spine ki codes s1 s2++-- * Fixpoint Changes+--+-- $fixpointchanges+--+-- The next datatypes represent a sequence of 'Spine', 'Al' and 'At' assembled+-- coupled with operators to describe changes in the recursive structure such+-- as inserting and deleting constructors.+++-- |Represents a /one-hole context/ over a @NP (NA ki (fix ki codes)) xs@ where+-- the hole is in a distinguished element indexed by @'I ix@ and is filled+-- with applying @p@ to the relevant indexes.+data Ctx (ki :: kon -> *) (codes :: [[[Atom kon]]]) (p :: Nat -> Nat -> *)+ (ix :: Nat) :: [Atom kon] -> * where+ H :: IsNat iy+ => p ix iy+ -> PoA ki (Fix ki codes) xs+ -> Ctx ki codes p ix ('I iy ': xs)+ T :: NA ki (Fix ki codes) a+ -> Ctx ki codes p ix xs+ -> Ctx ki codes p ix (a ': xs)++-- |Simple synonym for contexts.+type InsCtx ki codes ix xs = Ctx ki codes (Almu ki codes) ix xs++-- |A deletion context needs to swap the indexes in the hole, hence+-- we use a newtype for that.+type DelCtx ki codes ix xs = Ctx ki codes (AlmuMin ki codes) ix xs++-- |The newtype used to swap the indexes to |Almu|.+newtype AlmuMin ki codes ix iy = AlmuMin { unAlmuMin :: Almu ki codes iy ix }++-- |Represent recursive spines.+data Almu (ki :: kon -> *) (codes :: [[[Atom kon]]]) :: Nat -> Nat -> * where+ Spn :: Spine ki codes (Lkup ix codes) (Lkup iy codes) -> Almu ki codes ix iy+ Ins :: Constr (Lkup iy codes) c+ -> InsCtx ki codes ix (Lkup c (Lkup iy codes)) -- its an ix with an iy typed-hoed+ -> Almu ki codes ix iy+ Del :: IsNat iy+ => Constr (Lkup ix codes) c+ -> DelCtx ki codes iy (Lkup c (Lkup ix codes))+ -> Almu ki codes ix iy++{-++{-+instance (ShowHO ki) => Show (At ki codes at) where+ show (AtSet t) = show t+ show (AtFix a) = a++instance ShowHO ki => Show (TrivialK ki x) where+ show (Trivial x y) = show x ++ "|" ++ show y+++-} ++++{-+instance (HasDatatypeInfo ki fam codes, Show1 ki) => Show (Al ki codes xs ys) where+ show A0 = "A0"+ show (AX x xs) = "(AX " ++ show1 x ++ " " ++ show xs ++ ")"+ show (ADel x xs) = "(ADel " ++ show x ++ " " ++ show xs ++ ")"+ show (AIns x xs) = "(AIns " ++ show x ++ " " ++ show xs ++ ")"+-}++{-+instance (IsNat ix,IsNat iy, HasDatatypeInfo ki fam codes, Show1 ki) => Show (AlmuMin ki codes ix iy) where+ show (AlmuMin x) = show x+-}++-- | An NP p xs, but there exists an x in xs such that h x+--+-- Note that: NP p xs <=> Ctx' p p xs+--+-- and that the list is never empty, because it contains at+-- least the pointed element+--+++instance (IsNat ix, HasDatatypeInfo ki fam codes, Show1 ki) => Show (InsCtx ki codes ix xs) where+ show (H p poa) = "(H " ++ show p ++ " " ++ show poa ++ ")"+ show (T n c) = "(T " ++ show n ++ " " ++ show c ++ ")"+instance (IsNat ix, HasDatatypeInfo ki fam codes, Show1 ki) => Show (DelCtx ki codes ix xs) where+ show (H p poa) = "(H " ++ show p ++ " " ++ show poa ++ ")"+ show (T n c) = "(T " ++ show n ++ " " ++ show c ++ ")"+++ -- TODO ins del+++instance forall ki fam codes ix iy. (IsNat ix, IsNat iy, Show1 ki, HasDatatypeInfo ki fam codes) => Show (Almu ki codes ix iy) where+ show (Spn s) = "(Spn " ++ showSpine (getSNat @ix Proxy) (getSNat @iy Proxy) s ++ ")"+ show (Ins c ic) = "(Ins " ++ showC c ++ " " ++ show ic ++ ")"+ where showC c = constructorName . constrInfoLkup c $ (datatypeInfo (Proxy @fam) (getSNat @iy Proxy))+ show (Del c ic) = "(Del " ++ showC c ++ " " ++ show ic ++ ")"+ where showC c = constructorName . constrInfoLkup c $ (datatypeInfo (Proxy @fam) (getSNat @ix Proxy))++instance (Show1 p) => Show1 (NP p) where+ show1 np = parens . concat . intersperse " " $ elimNP show1 np+ where+ parens x = "(" ++ x ++ ")"+++showSpine :: forall ki fam codes ix iy. (Show1 ki, HasDatatypeInfo ki fam codes, IsNat ix, IsNat iy) => SNat ix -> SNat iy -> Spine ki codes (Lkup ix codes) (Lkup iy codes) -> String+showSpine six siy Scp = "Scp"+showSpine six siy (SCns c x) = "(Scns " ++ showC c six ++ " " ++ show1 x ++ ")" + where showC c six = constructorName . constrInfoLkup c $ (datatypeInfo (Proxy @fam) six)+showSpine six siy (SChg c1 c2 a) = "(SChg " ++ showCX ++ " " ++ showCY ++ " " ++ show a ++ ")"+ where showCX = constructorName . constrInfoLkup c1 $ (datatypeInfo (Proxy @fam) six)+ showCY = constructorName . constrInfoLkup c2 $ (datatypeInfo (Proxy @fam) siy)+{-+instance (HasDatatypeInfo ki fam codes, Show1 ki) => Show (Spine ki codes x y) where+ show Scp = "COPY"+ show (SCns c x) = "(Scns " ++ showC c ++ " " ++ show1 x ++ ")" + where + showC + showC c = constructorName . consterInfoLookup c (datatypeInfo (Proxy @fam) (getSNat @ix Proxy))+ show (SChg c1 c2 a) = "(SChg " ++ showC c1 ++ " " ++ showC c2 ++ " " ++ show a ++ ")"+ where showC c = constructorName . consterInfoLookup c (datatypeInfo (Proxy @fam) (getSNat @ix Proxy))+-}++-- OR what about: ix iy+guard' :: String -> Bool -> Either String ()+guard' s False = Left s+guard' _ True = Right ()++instance Show1 SNat where+ show1 = show . go+ where+ go :: SNat n -> Int+ go SZ = 0+ go (SS s) = 1 + go s++-}