module Darcs.Patch.Merge
(
CleanMerge(..)
, Merge(..)
, selfMerger
, swapMerger
, mergerIdFL
, mergerFLId
, mergerFLFL
, cleanMergeFL
, mergeFL
, swapMerge
, swapCleanMerge
, mergeList
, prop_mergeSymmetric
, prop_mergeCommute
) where
import Control.Monad ( foldM )
import Darcs.Prelude
import Darcs.Patch.Commute ( Commute(..) )
import Darcs.Patch.CommuteFn ( MergeFn, PartialMergeFn )
import Darcs.Patch.Invert ( Invert(..) )
import Darcs.Patch.Witnesses.Eq ( Eq2(..), isIsEq )
import Darcs.Patch.Witnesses.Ordered
( (:\/:)(..)
, (:/\:)(..)
, FL(..)
, (:>)(..)
, (+>+)
)
import Darcs.Patch.Witnesses.Sealed ( Sealed(..) )
class CleanMerge p where
cleanMerge :: (p :\/: p) wX wY -> Maybe ((p :/\: p) wX wY)
instance CleanMerge p => CleanMerge (FL p) where
cleanMerge (NilFL :\/: x) = return $ x :/\: NilFL
cleanMerge (x :\/: NilFL) = return $ NilFL :/\: x
cleanMerge ((x :>: xs) :\/: ys) = do
ys' :/\: x' <- cleanMergeFL (x :\/: ys)
xs' :/\: ys'' <- cleanMerge (ys' :\/: xs)
return $ ys'' :/\: (x' :>: xs')
cleanMergeFL :: CleanMerge p => PartialMergeFn p (FL p)
cleanMergeFL (p :\/: NilFL) = return $ NilFL :/\: p
cleanMergeFL (p :\/: (x :>: xs)) = do
x' :/\: p' <- cleanMerge (p :\/: x)
xs' :/\: p'' <- cleanMergeFL (p' :\/: xs)
return $ (x' :>: xs') :/\: p''
class CleanMerge p => Merge p where
merge :: (p :\/: p) wX wY -> (p :/\: p) wX wY
selfMerger :: Merge p => MergeFn p p
selfMerger = merge
instance Merge p => Merge (FL p) where
merge = mergerFLFL merge
mergeFL :: Merge p
=> (p :\/: FL p) wX wY
-> (FL p :/\: p) wX wY
mergeFL = mergerIdFL merge
mergerIdFL :: MergeFn p q -> MergeFn p (FL q)
mergerIdFL _mergeFn (p :\/: NilFL) = NilFL :/\: p
mergerIdFL mergeFn (p :\/: (x :>: xs)) =
case mergeFn (p :\/: x) of
x' :/\: p' -> case mergerIdFL mergeFn (p' :\/: xs) of
xs' :/\: p'' -> (x' :>: xs') :/\: p''
mergerFLId :: MergeFn p q -> MergeFn (FL p) q
mergerFLId mergeFn = swapMerger (mergerIdFL (swapMerger mergeFn))
mergerFLFL :: MergeFn p q -> MergeFn (FL p) (FL q)
mergerFLFL mergeFn = mergerIdFL (mergerFLId mergeFn)
swapMerge :: Merge p => (p :\/: p) wX wY -> (p :/\: p) wX wY
swapMerge = swapMerger merge
swapMerger :: MergeFn p q -> MergeFn q p
swapMerger mergeFn (x :\/: y) = case mergeFn (y :\/: x) of x' :/\: y' -> y' :/\: x'
swapCleanMerge :: CleanMerge p => (p :\/: p) wX wY -> Maybe ((p :/\: p) wX wY)
swapCleanMerge (x :\/: y) = do
x' :/\: y' <- cleanMerge (y :\/: x)
return $ y' :/\: x'
mergeList :: CleanMerge p
=> [Sealed (FL p wX)]
-> Either (Sealed (FL p wX), Sealed (FL p wX)) (Sealed (FL p wX))
mergeList = foldM mergeTwo (Sealed NilFL)
where
mergeTwo (Sealed ps) (Sealed qs) =
case cleanMerge (ps :\/: qs) of
Just (qs' :/\: _) -> Right $ Sealed $ ps +>+ qs'
Nothing -> Left (Sealed ps, Sealed qs)
_forceCommute :: (Commute p, Merge p, Invert p) => (p :> p) wX wY -> (p :> p) wX wY
_forceCommute (p :> q) =
case commute (p :> q) of
Just (q' :> p') -> q' :> p'
Nothing ->
case merge (invert p :\/: q) of
q' :/\: ip' -> q' :> invert ip'
prop_mergeSymmetric :: (Eq2 p, Merge p) => (p :\/: p) wX wY -> Bool
prop_mergeSymmetric (p :\/: q) =
case merge (p :\/: q) of
q' :/\: p' ->
case merge (q :\/: p) of
p'' :/\: q'' ->
isIsEq (q' =\/= q'') && isIsEq (p' =\/= p'')
prop_mergeCommute :: (Commute p, Eq2 p, Merge p) => (p :\/: p) wX wY -> Bool
prop_mergeCommute (p :\/: q) =
case merge (p :\/: q) of
q' :/\: p' ->
case commute (p :> q') of
Nothing -> False
Just (q'' :> p'') ->
isIsEq (q'' =\/= q) && isIsEq (p'' =/\= p')
&&
case commute (q :> p') of
Nothing -> False
Just (p'' :> q'') ->
isIsEq (p'' =\/= p) && isIsEq (q'' =/\= q')