module Darcs.Patch.Ident
    ( Ident(..)
    , SignedIdent
    , PatchId
    , SignedId(..)
    , StorableId(..)
    , IdEq2(..)
    , merge2FL
    , fastRemoveFL
    , fastRemoveRL
    , fastRemoveSubsequenceRL
    , findCommonFL
    , commuteToPrefix
    , commuteToPostfix
    , commuteWhatWeCanToPostfix
    -- * Properties
    , prop_identInvariantUnderCommute
    , prop_sameIdentityImpliesCommutable
    , prop_equalImpliesSameIdentity
    ) where

import qualified Data.Set as S

import Darcs.Prelude

import Darcs.Patch.Commute ( Commute, commute, commuteFL, commuteRL )
import Darcs.Patch.Merge ( Merge, mergeFL )
import Darcs.Patch.Permutations ( partitionFL', commuteWhatWeCanFL )
import Darcs.Patch.Show ( ShowPatchFor )
import Darcs.Patch.Witnesses.Eq ( Eq2(..), EqCheck(..), isIsEq )
import Darcs.Patch.Witnesses.Ordered
    ( (:/\:)(..)
    , (:>)(..)
    , (:\/:)(..)
    , FL(..)
    , RL(..)
    , Fork(..)
    , (+<<+)
    , (+>>+)
    , mapFL
    , mapRL
    , reverseRL
    )
import Darcs.Patch.Witnesses.Unsafe ( unsafeCoercePEnd, unsafeCoercePStart )

import Darcs.Util.Parser ( Parser )
import Darcs.Util.Printer ( Doc )

type family PatchId (p :: * -> * -> *)

{- | Class of patches that have an identity.

It generalizes named prim patches a la camp (see Darcs.Patch.Prim.Named) and
Named patches i.e. those with a PatchInfo.

Patch identity should be invariant under commutation: if there is also an
@instance 'Commute' p@, then

prop> commute (p :> q) == Just (q' :> p') => ident p == ident p' && ident q == ident q'

The converse should also be true: patches with the same identity can be
commuted (back) to the same context and then compare equal. Assuming

@
  p :: p wX wY, (ps :> q) :: (RL p :> p) wX wZ
@

then

prop> ident p == ident q => commuteRL (ps :> q) == Just (p :> _)

As a special case we get that parallel patches with the same identity are
equal: if @p :: p wX wY, q :: p wX wZ@, then

prop> ident p == ident q => p =\/= q == IsEq

In general, comparing patches via their identity is coarser than
(structural) equality, so we only have

prop> unsafeCompare p q => (ident p == ident q)
-}
class Ord (PatchId p) => Ident p where
  ident :: p wX wY -> PatchId p

{- | Signed identities.

Like for class 'Invert', we require that 'invertId' is self-inverse:

prop> invertId . invertId = id

We also require that inverting changes the sign:

prop> positiveId . invertId = not . positiveId

Side remark: in mathematical terms, these properties can be expressed by
stating that 'invertId' is an involution and that 'positiveId' is a
"homomorphism of sets with an involution" (there is no official term for
this) from @a@ to the simplest non-trivial set with involution, namely
'Bool' with the involution 'not'.
-}
class Ord a => SignedId a where
  positiveId :: a -> Bool
  invertId :: a -> a

{- | Constraint for patches that have an identity that is signed,
     i.e. can be positive (uninverted) or negative (inverted).

Provided that an instance 'Invert' exists, inverting a patch
inverts its identity:

prop> ident (invert p) = invertId (ident p)

-}
type SignedIdent p = (Ident p, SignedId (PatchId p))


{- | Storable identities.

The methods here can be used to help implement ReadPatch and ShowPatch
for a patch type containing the identity.

As with all Read/Show pairs, We expect that the output of
@showId ForStorage a@ can be parsed by 'readId' to produce @a@.
-}
class StorableId a where
  readId :: Parser a
  showId :: ShowPatchFor -> a -> Doc

-- | Faster equality tests for patches with an identity.
class IdEq2 p where
  (=\^/=) :: p wA wB -> p wA wC -> EqCheck wB wC
  (=/^\=) :: p wA wC -> p wB wC -> EqCheck wA wB
  default (=\^/=) :: Ident p => p wA wB -> p wA wC -> EqCheck wB wC
  p wA wB
p =\^/= p wA wC
q = if p wA wB -> PatchId p
forall (p :: * -> * -> *) wX wY. Ident p => p wX wY -> PatchId p
ident p wA wB
p PatchId p -> PatchId p -> Bool
forall a. Eq a => a -> a -> Bool
== p wA wC -> PatchId p
forall (p :: * -> * -> *) wX wY. Ident p => p wX wY -> PatchId p
ident p wA wC
q then EqCheck wB wB -> EqCheck wB wC
forall (a :: * -> * -> *) wX wY1 wY2. a wX wY1 -> a wX wY2
unsafeCoercePEnd EqCheck wB wB
forall wA. EqCheck wA wA
IsEq else EqCheck wB wC
forall wA wB. EqCheck wA wB
NotEq
  default (=/^\=) :: Ident p => p wA wC -> p wB wC -> EqCheck wA wB
  p wA wC
p =/^\= p wB wC
q = if p wA wC -> PatchId p
forall (p :: * -> * -> *) wX wY. Ident p => p wX wY -> PatchId p
ident p wA wC
p PatchId p -> PatchId p -> Bool
forall a. Eq a => a -> a -> Bool
== p wB wC -> PatchId p
forall (p :: * -> * -> *) wX wY. Ident p => p wX wY -> PatchId p
ident p wB wC
q then EqCheck wB wB -> EqCheck wA wB
forall (a :: * -> * -> *) wX1 wY wX2. a wX1 wY -> a wX2 wY
unsafeCoercePStart EqCheck wB wB
forall wA. EqCheck wA wA
IsEq else EqCheck wA wB
forall wA wB. EqCheck wA wB
NotEq

-- | The 'Commute' requirement here is not technically needed but makes
-- sense logically.
instance (Commute p, Ident p) => IdEq2 (FL p) where
  FL p wA wB
ps =\^/= :: FL p wA wB -> FL p wA wC -> EqCheck wB wC
=\^/= FL p wA wC
qs
    | [PatchId p] -> Set (PatchId p)
forall a. Ord a => [a] -> Set a
S.fromList ((forall wW wZ. p wW wZ -> PatchId p) -> FL p wA wB -> [PatchId p]
forall (a :: * -> * -> *) b wX wY.
(forall wW wZ. a wW wZ -> b) -> FL a wX wY -> [b]
mapFL forall wW wZ. p wW wZ -> PatchId p
forall (p :: * -> * -> *) wX wY. Ident p => p wX wY -> PatchId p
ident FL p wA wB
ps) Set (PatchId p) -> Set (PatchId p) -> Bool
forall a. Eq a => a -> a -> Bool
== [PatchId p] -> Set (PatchId p)
forall a. Ord a => [a] -> Set a
S.fromList ((forall wW wZ. p wW wZ -> PatchId p) -> FL p wA wC -> [PatchId p]
forall (a :: * -> * -> *) b wX wY.
(forall wW wZ. a wW wZ -> b) -> FL a wX wY -> [b]
mapFL forall wW wZ. p wW wZ -> PatchId p
forall (p :: * -> * -> *) wX wY. Ident p => p wX wY -> PatchId p
ident FL p wA wC
qs) = EqCheck wB wB -> EqCheck wB wC
forall (a :: * -> * -> *) wX wY1 wY2. a wX wY1 -> a wX wY2
unsafeCoercePEnd EqCheck wB wB
forall wA. EqCheck wA wA
IsEq
    | Bool
otherwise = EqCheck wB wC
forall wA wB. EqCheck wA wB
NotEq
  FL p wA wC
ps =/^\= :: FL p wA wC -> FL p wB wC -> EqCheck wA wB
=/^\= FL p wB wC
qs
    | [PatchId p] -> Set (PatchId p)
forall a. Ord a => [a] -> Set a
S.fromList ((forall wW wZ. p wW wZ -> PatchId p) -> FL p wA wC -> [PatchId p]
forall (a :: * -> * -> *) b wX wY.
(forall wW wZ. a wW wZ -> b) -> FL a wX wY -> [b]
mapFL forall wW wZ. p wW wZ -> PatchId p
forall (p :: * -> * -> *) wX wY. Ident p => p wX wY -> PatchId p
ident FL p wA wC
ps) Set (PatchId p) -> Set (PatchId p) -> Bool
forall a. Eq a => a -> a -> Bool
== [PatchId p] -> Set (PatchId p)
forall a. Ord a => [a] -> Set a
S.fromList ((forall wW wZ. p wW wZ -> PatchId p) -> FL p wB wC -> [PatchId p]
forall (a :: * -> * -> *) b wX wY.
(forall wW wZ. a wW wZ -> b) -> FL a wX wY -> [b]
mapFL forall wW wZ. p wW wZ -> PatchId p
forall (p :: * -> * -> *) wX wY. Ident p => p wX wY -> PatchId p
ident FL p wB wC
qs) = EqCheck wB wB -> EqCheck wA wB
forall (a :: * -> * -> *) wX1 wY wX2. a wX1 wY -> a wX2 wY
unsafeCoercePStart EqCheck wB wB
forall wA. EqCheck wA wA
IsEq
    | Bool
otherwise = EqCheck wA wB
forall wA wB. EqCheck wA wB
NotEq

-- | This function is similar to 'merge', but with one important
-- difference: 'merge' works on patches for which there is not necessarily a
-- concept of identity (e.g. primitive patches, conflictors, etc). Thus it does
-- not even try to recognize patches that are common to both sequences. Instead
-- these are passed on to the Merge instance for single patches. This instance
-- may handle duplicate patches by creating special patches (Duplicate,
-- Conflictor).
-- 
-- We do not want this to happen for named patches, or in general for patches
-- with an identity. Instead, we want to
-- /discard/ one of the two duplicates, retaining only one copy. This is done
-- by the fastRemoveFL calls below. We call mergeFL only after we have ensured
-- that the head of the left hand side does not occur in the right hand side.
merge2FL :: (Commute p, Merge p, Ident p)
         => FL p wX wY
         -> FL p wX wZ
         -> (FL p :/\: FL p) wY wZ
merge2FL :: FL p wX wY -> FL p wX wZ -> (:/\:) (FL p) (FL p) wY wZ
merge2FL FL p wX wY
xs FL p wX wZ
NilFL = FL p wY wY
forall (a :: * -> * -> *) wX. FL a wX wX
NilFL FL p wY wY -> FL p wX wY -> (:/\:) (FL p) (FL p) wY wX
forall (a3 :: * -> * -> *) (a4 :: * -> * -> *) wX wY wZ.
a3 wX wZ -> a4 wY wZ -> (:/\:) a3 a4 wX wY
:/\: FL p wX wY
xs
merge2FL FL p wX wY
NilFL FL p wX wZ
ys = FL p wX wZ
ys FL p wX wZ -> FL p wZ wZ -> (:/\:) (FL p) (FL p) wX wZ
forall (a3 :: * -> * -> *) (a4 :: * -> * -> *) wX wY wZ.
a3 wX wZ -> a4 wY wZ -> (:/\:) a3 a4 wX wY
:/\: FL p wZ wZ
forall (a :: * -> * -> *) wX. FL a wX wX
NilFL
merge2FL FL p wX wY
xs (p wX wY
y :>: FL p wY wZ
ys)
  | Just FL p wY wY
xs' <- p wX wY -> FL p wX wY -> Maybe (FL p wY wY)
forall (p :: * -> * -> *) wX wY wZ.
(Commute p, Ident p) =>
p wX wY -> FL p wX wZ -> Maybe (FL p wY wZ)
fastRemoveFL p wX wY
y FL p wX wY
xs = FL p wY wY -> FL p wY wZ -> (:/\:) (FL p) (FL p) wY wZ
forall (p :: * -> * -> *) wX wY wZ.
(Commute p, Merge p, Ident p) =>
FL p wX wY -> FL p wX wZ -> (:/\:) (FL p) (FL p) wY wZ
merge2FL FL p wY wY
xs' FL p wY wZ
ys
merge2FL (p wX wY
x :>: FL p wY wY
xs) FL p wX wZ
ys
  | Just FL p wY wZ
ys' <- p wX wY -> FL p wX wZ -> Maybe (FL p wY wZ)
forall (p :: * -> * -> *) wX wY wZ.
(Commute p, Ident p) =>
p wX wY -> FL p wX wZ -> Maybe (FL p wY wZ)
fastRemoveFL p wX wY
x FL p wX wZ
ys = FL p wY wY -> FL p wY wZ -> (:/\:) (FL p) (FL p) wY wZ
forall (p :: * -> * -> *) wX wY wZ.
(Commute p, Merge p, Ident p) =>
FL p wX wY -> FL p wX wZ -> (:/\:) (FL p) (FL p) wY wZ
merge2FL FL p wY wY
xs FL p wY wZ
ys'
  | Bool
otherwise =
    case (:\/:) p (FL p) wY wZ -> (:/\:) (FL p) p wY wZ
forall (p :: * -> * -> *) wX wY.
Merge p =>
(:\/:) p (FL p) wX wY -> (:/\:) (FL p) p wX wY
mergeFL (p wX wY
x p wX wY -> FL p wX wZ -> (:\/:) p (FL p) wY wZ
forall (a1 :: * -> * -> *) (a2 :: * -> * -> *) wX wY wZ.
a1 wZ wX -> a2 wZ wY -> (:\/:) a1 a2 wX wY
:\/: FL p wX wZ
ys) of
      FL p wY wZ
ys' :/\: p wZ wZ
x' ->
        case FL p wY wY -> FL p wY wZ -> (:/\:) (FL p) (FL p) wY wZ
forall (p :: * -> * -> *) wX wY wZ.
(Commute p, Merge p, Ident p) =>
FL p wX wY -> FL p wX wZ -> (:/\:) (FL p) (FL p) wY wZ
merge2FL FL p wY wY
xs FL p wY wZ
ys' of
          FL p wY wZ
ys'' :/\: FL p wZ wZ
xs' -> FL p wY wZ
ys'' FL p wY wZ -> FL p wZ wZ -> (:/\:) (FL p) (FL p) wY wZ
forall (a3 :: * -> * -> *) (a4 :: * -> * -> *) wX wY wZ.
a3 wX wZ -> a4 wY wZ -> (:/\:) a3 a4 wX wY
:/\: (p wZ wZ
x' p wZ wZ -> FL p wZ wZ -> FL p wZ wZ
forall (a :: * -> * -> *) wX wY wZ.
a wX wY -> FL a wY wZ -> FL a wX wZ
:>: FL p wZ wZ
xs')

{-# INLINABLE fastRemoveFL #-}
-- | Remove a patch from an FL of patches with an identity. The result is
-- 'Just' whenever the patch has been found and removed and 'Nothing'
-- otherwise. If the patch is not found at the head of the sequence we must
-- first commute it to the head before we can remove it.
-- 
-- We assume that this commute always succeeds. This is justified because
-- patches are created with a (universally) unique identity, implying that if
-- two patches have the same identity, then they have originally been the same
-- patch; thus being at a different position must be due to commutation,
-- meaning we can commute it back.
fastRemoveFL :: forall p wX wY wZ. (Commute p, Ident p)
             => p wX wY
             -> FL p wX wZ
             -> Maybe (FL p wY wZ)
fastRemoveFL :: p wX wY -> FL p wX wZ -> Maybe (FL p wY wZ)
fastRemoveFL p wX wY
a FL p wX wZ
bs
  | PatchId p
i PatchId p -> [PatchId p] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` (forall wW wZ. p wW wZ -> PatchId p) -> FL p wX wZ -> [PatchId p]
forall (a :: * -> * -> *) b wX wY.
(forall wW wZ. a wW wZ -> b) -> FL a wX wY -> [b]
mapFL forall wW wZ. p wW wZ -> PatchId p
forall (p :: * -> * -> *) wX wY. Ident p => p wX wY -> PatchId p
ident FL p wX wZ
bs = Maybe (FL p wY wZ)
forall a. Maybe a
Nothing
  | Bool
otherwise = do
      p wX wZ
_ :> FL p wZ wZ
bs' <- RL p wX wX -> FL p wX wZ -> Maybe ((:>) p (FL p) wX wZ)
forall wA wB wC.
RL p wA wB -> FL p wB wC -> Maybe ((:>) p (FL p) wA wC)
pullout RL p wX wX
forall (a :: * -> * -> *) wX. RL a wX wX
NilRL FL p wX wZ
bs
      FL p wY wZ -> Maybe (FL p wY wZ)
forall a. a -> Maybe a
Just (FL p wZ wZ -> FL p wY wZ
forall (a :: * -> * -> *) wX1 wY wX2. a wX1 wY -> a wX2 wY
unsafeCoercePStart FL p wZ wZ
bs')
  where
    i :: PatchId p
i = p wX wY -> PatchId p
forall (p :: * -> * -> *) wX wY. Ident p => p wX wY -> PatchId p
ident p wX wY
a
    pullout :: RL p wA wB -> FL p wB wC -> Maybe ((p :> FL p) wA wC)
    pullout :: RL p wA wB -> FL p wB wC -> Maybe ((:>) p (FL p) wA wC)
pullout RL p wA wB
_ FL p wB wC
NilFL = Maybe ((:>) p (FL p) wA wC)
forall a. Maybe a
Nothing
    pullout RL p wA wB
acc (p wB wY
x :>: FL p wY wC
xs)
      | p wB wY -> PatchId p
forall (p :: * -> * -> *) wX wY. Ident p => p wX wY -> PatchId p
ident p wB wY
x PatchId p -> PatchId p -> Bool
forall a. Eq a => a -> a -> Bool
== PatchId p
i = do
          p wA wZ
x' :> RL p wZ wY
acc' <- (:>) (RL p) p wA wY -> Maybe ((:>) p (RL p) wA wY)
forall (p :: * -> * -> *) wX wY.
Commute p =>
(:>) (RL p) p wX wY -> Maybe ((:>) p (RL p) wX wY)
commuteRL (RL p wA wB
acc RL p wA wB -> p wB wY -> (:>) (RL p) p wA wY
forall (a1 :: * -> * -> *) (a2 :: * -> * -> *) wX wY wZ.
a1 wX wZ -> a2 wZ wY -> (:>) a1 a2 wX wY
:> p wB wY
x)
          (:>) p (FL p) wA wC -> Maybe ((:>) p (FL p) wA wC)
forall a. a -> Maybe a
Just (p wA wZ
x' p wA wZ -> FL p wZ wC -> (:>) p (FL p) wA wC
forall (a1 :: * -> * -> *) (a2 :: * -> * -> *) wX wY wZ.
a1 wX wZ -> a2 wZ wY -> (:>) a1 a2 wX wY
:> RL p wZ wY
acc' RL p wZ wY -> FL p wY wC -> FL p wZ wC
forall (p :: * -> * -> *) wX wY wZ.
RL p wX wY -> FL p wY wZ -> FL p wX wZ
+>>+ FL p wY wC
xs)
      | Bool
otherwise = RL p wA wY -> FL p wY wC -> Maybe ((:>) p (FL p) wA wC)
forall wA wB wC.
RL p wA wB -> FL p wB wC -> Maybe ((:>) p (FL p) wA wC)
pullout (RL p wA wB
acc RL p wA wB -> p wB wY -> RL p wA wY
forall (a :: * -> * -> *) wX wY wZ.
RL a wX wY -> a wY wZ -> RL a wX wZ
:<: p wB wY
x) FL p wY wC
xs

-- | Same as 'fastRemoveFL' only for 'RL'.
fastRemoveRL :: forall p wX wY wZ. (Commute p, Ident p)
             => p wY wZ
             -> RL p wX wZ
             -> Maybe (RL p wX wY)
fastRemoveRL :: p wY wZ -> RL p wX wZ -> Maybe (RL p wX wY)
fastRemoveRL p wY wZ
a RL p wX wZ
bs
  | PatchId p
i PatchId p -> [PatchId p] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` (forall wW wZ. p wW wZ -> PatchId p) -> RL p wX wZ -> [PatchId p]
forall (a :: * -> * -> *) b wX wY.
(forall wW wZ. a wW wZ -> b) -> RL a wX wY -> [b]
mapRL forall wW wZ. p wW wZ -> PatchId p
forall (p :: * -> * -> *) wX wY. Ident p => p wX wY -> PatchId p
ident RL p wX wZ
bs = Maybe (RL p wX wY)
forall a. Maybe a
Nothing
  | Bool
otherwise = do
      RL p wX wZ
bs' :> p wZ wZ
_ <- RL p wX wZ -> FL p wZ wZ -> Maybe ((:>) (RL p) p wX wZ)
forall wA wB wC.
RL p wA wB -> FL p wB wC -> Maybe ((:>) (RL p) p wA wC)
pullout RL p wX wZ
bs FL p wZ wZ
forall (a :: * -> * -> *) wX. FL a wX wX
NilFL
      RL p wX wY -> Maybe (RL p wX wY)
forall a. a -> Maybe a
Just (RL p wX wZ -> RL p wX wY
forall (a :: * -> * -> *) wX wY1 wY2. a wX wY1 -> a wX wY2
unsafeCoercePEnd RL p wX wZ
bs')
  where
    i :: PatchId p
i = p wY wZ -> PatchId p
forall (p :: * -> * -> *) wX wY. Ident p => p wX wY -> PatchId p
ident p wY wZ
a
    pullout :: RL p wA wB -> FL p wB wC -> Maybe ((RL p :> p) wA wC)
    pullout :: RL p wA wB -> FL p wB wC -> Maybe ((:>) (RL p) p wA wC)
pullout RL p wA wB
NilRL FL p wB wC
_ = Maybe ((:>) (RL p) p wA wC)
forall a. Maybe a
Nothing
    pullout (RL p wA wY
xs :<: p wY wB
x) FL p wB wC
acc
      | p wY wB -> PatchId p
forall (p :: * -> * -> *) wX wY. Ident p => p wX wY -> PatchId p
ident p wY wB
x PatchId p -> PatchId p -> Bool
forall a. Eq a => a -> a -> Bool
== PatchId p
i = do
          FL p wY wZ
acc' :> p wZ wC
x' <- (:>) p (FL p) wY wC -> Maybe ((:>) (FL p) p wY wC)
forall (p :: * -> * -> *) wX wY.
Commute p =>
(:>) p (FL p) wX wY -> Maybe ((:>) (FL p) p wX wY)
commuteFL (p wY wB
x p wY wB -> FL p wB wC -> (:>) p (FL p) wY wC
forall (a1 :: * -> * -> *) (a2 :: * -> * -> *) wX wY wZ.
a1 wX wZ -> a2 wZ wY -> (:>) a1 a2 wX wY
:> FL p wB wC
acc)
          (:>) (RL p) p wA wC -> Maybe ((:>) (RL p) p wA wC)
forall a. a -> Maybe a
Just (RL p wA wY
xs RL p wA wY -> FL p wY wZ -> RL p wA wZ
forall (p :: * -> * -> *) wX wY wZ.
RL p wX wY -> FL p wY wZ -> RL p wX wZ
+<<+ FL p wY wZ
acc' RL p wA wZ -> p wZ wC -> (:>) (RL p) p wA wC
forall (a1 :: * -> * -> *) (a2 :: * -> * -> *) wX wY wZ.
a1 wX wZ -> a2 wZ wY -> (:>) a1 a2 wX wY
:> p wZ wC
x')
      | Bool
otherwise = RL p wA wY -> FL p wY wC -> Maybe ((:>) (RL p) p wA wC)
forall wA wB wC.
RL p wA wB -> FL p wB wC -> Maybe ((:>) (RL p) p wA wC)
pullout RL p wA wY
xs (p wY wB
x p wY wB -> FL p wB wC -> FL p wY wC
forall (a :: * -> * -> *) wX wY wZ.
a wX wY -> FL a wY wZ -> FL a wX wZ
:>: FL p wB wC
acc)

fastRemoveSubsequenceRL :: (Commute p, Ident p)
                        => RL p wY wZ
                        -> RL p wX wZ
                        -> Maybe (RL p wX wY)
fastRemoveSubsequenceRL :: RL p wY wZ -> RL p wX wZ -> Maybe (RL p wX wY)
fastRemoveSubsequenceRL RL p wY wZ
NilRL RL p wX wZ
ys = RL p wX wZ -> Maybe (RL p wX wZ)
forall a. a -> Maybe a
Just RL p wX wZ
ys
fastRemoveSubsequenceRL (RL p wY wY
xs :<: p wY wZ
x) RL p wX wZ
ys =
  p wY wZ -> RL p wX wZ -> Maybe (RL p wX wY)
forall (p :: * -> * -> *) wX wY wZ.
(Commute p, Ident p) =>
p wY wZ -> RL p wX wZ -> Maybe (RL p wX wY)
fastRemoveRL p wY wZ
x RL p wX wZ
ys Maybe (RL p wX wY)
-> (RL p wX wY -> Maybe (RL p wX wY)) -> Maybe (RL p wX wY)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= RL p wY wY -> RL p wX wY -> Maybe (RL p wX wY)
forall (p :: * -> * -> *) wY wZ wX.
(Commute p, Ident p) =>
RL p wY wZ -> RL p wX wZ -> Maybe (RL p wX wY)
fastRemoveSubsequenceRL RL p wY wY
xs

-- | Find the common and uncommon parts of two lists that start in a common
-- context, using patch identity for comparison. Of the common patches, only
-- one is retained, the other is discarded, similar to 'merge2FL'.
findCommonFL :: (Commute p, Ident p)
             => FL p wX wY
             -> FL p wX wZ
             -> Fork (FL p) (FL p) (FL p) wX wY wZ
findCommonFL :: FL p wX wY -> FL p wX wZ -> Fork (FL p) (FL p) (FL p) wX wY wZ
findCommonFL FL p wX wY
xs FL p wX wZ
ys =
  case Set (PatchId p) -> FL p wX wY -> Maybe ((:>) (FL p) (RL p) wX wY)
forall (p :: * -> * -> *) wX wY.
(Commute p, Ident p) =>
Set (PatchId p) -> FL p wX wY -> Maybe ((:>) (FL p) (RL p) wX wY)
commuteToPrefix Set (PatchId p)
commonIds FL p wX wY
xs of
    Maybe ((:>) (FL p) (RL p) wX wY)
Nothing -> [Char] -> Fork (FL p) (FL p) (FL p) wX wY wZ
forall a. HasCallStack => [Char] -> a
error [Char]
"failed to commute common patches (lhs)"
    Just (FL p wX wZ
cxs :> RL p wZ wY
xs') ->
      case Set (PatchId p) -> FL p wX wZ -> Maybe ((:>) (FL p) (RL p) wX wZ)
forall (p :: * -> * -> *) wX wY.
(Commute p, Ident p) =>
Set (PatchId p) -> FL p wX wY -> Maybe ((:>) (FL p) (RL p) wX wY)
commuteToPrefix Set (PatchId p)
commonIds FL p wX wZ
ys of
        Maybe ((:>) (FL p) (RL p) wX wZ)
Nothing -> [Char] -> Fork (FL p) (FL p) (FL p) wX wY wZ
forall a. HasCallStack => [Char] -> a
error [Char]
"failed to commute common patches (rhs)"
        Just (FL p wX wZ
cys :> RL p wZ wZ
ys') ->
          case FL p wX wZ
cxs FL p wX wZ -> FL p wX wZ -> EqCheck wZ wZ
forall (p :: * -> * -> *) wA wB wC.
IdEq2 p =>
p wA wB -> p wA wC -> EqCheck wB wC
=\^/= FL p wX wZ
cys of
            EqCheck wZ wZ
NotEq -> [Char] -> Fork (FL p) (FL p) (FL p) wX wY wZ
forall a. HasCallStack => [Char] -> a
error [Char]
"common patches aren't equal"
            EqCheck wZ wZ
IsEq -> FL p wX wZ
-> FL p wZ wY -> FL p wZ wZ -> Fork (FL p) (FL p) (FL p) wX wY wZ
forall (common :: * -> * -> *) (left :: * -> * -> *)
       (right :: * -> * -> *) wA wX wY wU.
common wA wU
-> left wU wX -> right wU wY -> Fork common left right wA wX wY
Fork FL p wX wZ
cxs (RL p wZ wY -> FL p wZ wY
forall (a :: * -> * -> *) wX wZ. RL a wX wZ -> FL a wX wZ
reverseRL RL p wZ wY
xs') (RL p wZ wZ -> FL p wZ wZ
forall (a :: * -> * -> *) wX wZ. RL a wX wZ -> FL a wX wZ
reverseRL RL p wZ wZ
ys')
  where
    commonIds :: Set (PatchId p)
commonIds =
      [PatchId p] -> Set (PatchId p)
forall a. Ord a => [a] -> Set a
S.fromList ((forall wW wZ. p wW wZ -> PatchId p) -> FL p wX wY -> [PatchId p]
forall (a :: * -> * -> *) b wX wY.
(forall wW wZ. a wW wZ -> b) -> FL a wX wY -> [b]
mapFL forall wW wZ. p wW wZ -> PatchId p
forall (p :: * -> * -> *) wX wY. Ident p => p wX wY -> PatchId p
ident FL p wX wY
xs) Set (PatchId p) -> Set (PatchId p) -> Set (PatchId p)
forall a. Ord a => Set a -> Set a -> Set a
`S.intersection` [PatchId p] -> Set (PatchId p)
forall a. Ord a => [a] -> Set a
S.fromList ((forall wW wZ. p wW wZ -> PatchId p) -> FL p wX wZ -> [PatchId p]
forall (a :: * -> * -> *) b wX wY.
(forall wW wZ. a wW wZ -> b) -> FL a wX wY -> [b]
mapFL forall wW wZ. p wW wZ -> PatchId p
forall (p :: * -> * -> *) wX wY. Ident p => p wX wY -> PatchId p
ident FL p wX wZ
ys)

-- | Try to commute patches matching any of the 'PatchId's in the set to the
-- head of an 'FL', i.e. backwards in history. It is not required that all the
-- 'PatchId's are found in the sequence, but if they do then the traversal
-- terminates as soon as the set is exhausted.
commuteToPrefix :: (Commute p, Ident p)
                => S.Set (PatchId p) -> FL p wX wY -> Maybe ((FL p :> RL p) wX wY)
commuteToPrefix :: Set (PatchId p) -> FL p wX wY -> Maybe ((:>) (FL p) (RL p) wX wY)
commuteToPrefix Set (PatchId p)
is FL p wX wY
ps
  | FL p wX wZ
prefix :> RL p wZ wZ
NilRL :> RL p wZ wY
rest <-
      (forall wU wV. p wU wV -> Bool)
-> RL p wX wX
-> RL p wX wX
-> FL p wX wY
-> (:>) (FL p) (RL p :> RL p) wX wY
forall (p :: * -> * -> *) wA wB wC wD.
Commute p =>
(forall wU wV. p wU wV -> Bool)
-> RL p wA wB
-> RL p wB wC
-> FL p wC wD
-> (:>) (FL p) (RL p :> RL p) wA wD
partitionFL' ((PatchId p -> Set (PatchId p) -> Bool
forall a. Ord a => a -> Set a -> Bool
`S.member` Set (PatchId p)
is) (PatchId p -> Bool) -> (p wU wV -> PatchId p) -> p wU wV -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. p wU wV -> PatchId p
forall (p :: * -> * -> *) wX wY. Ident p => p wX wY -> PatchId p
ident) RL p wX wX
forall (a :: * -> * -> *) wX. RL a wX wX
NilRL RL p wX wX
forall (a :: * -> * -> *) wX. RL a wX wX
NilRL FL p wX wY
ps = (:>) (FL p) (RL p) wX wY -> Maybe ((:>) (FL p) (RL p) wX wY)
forall a. a -> Maybe a
Just (FL p wX wZ
prefix FL p wX wZ -> RL p wZ wY -> (:>) (FL p) (RL p) wX wY
forall (a1 :: * -> * -> *) (a2 :: * -> * -> *) wX wY wZ.
a1 wX wZ -> a2 wZ wY -> (:>) a1 a2 wX wY
:> RL p wZ wY
RL p wZ wY
rest)
  | Bool
otherwise = Maybe ((:>) (FL p) (RL p) wX wY)
forall a. Maybe a
Nothing

-- | Try to commute patches matching any of the 'PatchId's in the set to the
-- head of an 'RL', i.e. forwards in history. It is not required that all the
-- 'PatchId's are found in the sequence, but if they do then the traversal
-- terminates as soon as the set is exhausted.
commuteToPostfix :: forall p wX wY. (Commute p, Ident p)
                 => S.Set (PatchId p) -> RL p wX wY -> Maybe ((FL p :> RL p) wX wY)
commuteToPostfix :: Set (PatchId p) -> RL p wX wY -> Maybe ((:>) (FL p) (RL p) wX wY)
commuteToPostfix Set (PatchId p)
ids RL p wX wY
patches = Set (PatchId p)
-> (:>) (RL p) (FL p) wX wY -> Maybe ((:>) (FL p) (RL p) wX wY)
forall wA wB.
Set (PatchId p)
-> (:>) (RL p) (FL p) wA wB -> Maybe ((:>) (FL p) (RL p) wA wB)
push Set (PatchId p)
ids (RL p wX wY
patches RL p wX wY -> FL p wY wY -> (:>) (RL p) (FL p) wX wY
forall (a1 :: * -> * -> *) (a2 :: * -> * -> *) wX wY wZ.
a1 wX wZ -> a2 wZ wY -> (:>) a1 a2 wX wY
:> FL p wY wY
forall (a :: * -> * -> *) wX. FL a wX wX
NilFL)
  where
    push :: S.Set (PatchId p) -> (RL p :> FL p) wA wB -> Maybe ((FL p :> RL p) wA wB)
    push :: Set (PatchId p)
-> (:>) (RL p) (FL p) wA wB -> Maybe ((:>) (FL p) (RL p) wA wB)
push Set (PatchId p)
_ (RL p wA wZ
NilRL :> FL p wZ wB
left) = (:>) (FL p) (RL p) wZ wB -> Maybe ((:>) (FL p) (RL p) wZ wB)
forall (m :: * -> *) a. Monad m => a -> m a
return (FL p wZ wB
left FL p wZ wB -> RL p wB wB -> (:>) (FL p) (RL p) wZ wB
forall (a1 :: * -> * -> *) (a2 :: * -> * -> *) wX wY wZ.
a1 wX wZ -> a2 wZ wY -> (:>) a1 a2 wX wY
:> RL p wB wB
forall (a :: * -> * -> *) wX. RL a wX wX
NilRL) -- input RL is ehausted
    push Set (PatchId p)
is (RL p wA wZ
ps :> FL p wZ wB
left)
      | Set (PatchId p) -> Bool
forall a. Set a -> Bool
S.null Set (PatchId p)
is = (:>) (FL p) (RL p) wA wB -> Maybe ((:>) (FL p) (RL p) wA wB)
forall (m :: * -> *) a. Monad m => a -> m a
return (RL p wA wZ
ps RL p wA wZ -> FL p wZ wB -> FL p wA wB
forall (p :: * -> * -> *) wX wY wZ.
RL p wX wY -> FL p wY wZ -> FL p wX wZ
+>>+ FL p wZ wB
left FL p wA wB -> RL p wB wB -> (:>) (FL p) (RL p) wA wB
forall (a1 :: * -> * -> *) (a2 :: * -> * -> *) wX wY wZ.
a1 wX wZ -> a2 wZ wY -> (:>) a1 a2 wX wY
:> RL p wB wB
forall (a :: * -> * -> *) wX. RL a wX wX
NilRL) -- set of IDs is exhausted
    push Set (PatchId p)
is (RL p wA wY
ps :<: p wY wZ
p :> FL p wZ wB
left)
      | let i :: PatchId p
i = p wY wZ -> PatchId p
forall (p :: * -> * -> *) wX wY. Ident p => p wX wY -> PatchId p
ident p wY wZ
p
      , PatchId p
i PatchId p -> Set (PatchId p) -> Bool
forall a. Ord a => a -> Set a -> Bool
`S.member` Set (PatchId p)
is = do
          FL p wY wZ
left' :> p wZ wB
p' <- (:>) p (FL p) wY wB -> Maybe ((:>) (FL p) p wY wB)
forall (p :: * -> * -> *) wX wY.
Commute p =>
(:>) p (FL p) wX wY -> Maybe ((:>) (FL p) p wX wY)
commuteFL (p wY wZ
p p wY wZ -> FL p wZ wB -> (:>) p (FL p) wY wB
forall (a1 :: * -> * -> *) (a2 :: * -> * -> *) wX wY wZ.
a1 wX wZ -> a2 wZ wY -> (:>) a1 a2 wX wY
:> FL p wZ wB
left)
          FL p wA wZ
left'' :> RL p wZ wZ
right <- Set (PatchId p)
-> (:>) (RL p) (FL p) wA wZ -> Maybe ((:>) (FL p) (RL p) wA wZ)
forall wA wB.
Set (PatchId p)
-> (:>) (RL p) (FL p) wA wB -> Maybe ((:>) (FL p) (RL p) wA wB)
push (PatchId p -> Set (PatchId p) -> Set (PatchId p)
forall a. Ord a => a -> Set a -> Set a
S.delete PatchId p
i Set (PatchId p)
is) (RL p wA wY
ps RL p wA wY -> FL p wY wZ -> (:>) (RL p) (FL p) wA wZ
forall (a1 :: * -> * -> *) (a2 :: * -> * -> *) wX wY wZ.
a1 wX wZ -> a2 wZ wY -> (:>) a1 a2 wX wY
:> FL p wY wZ
left')
          (:>) (FL p) (RL p) wA wB -> Maybe ((:>) (FL p) (RL p) wA wB)
forall (m :: * -> *) a. Monad m => a -> m a
return (FL p wA wZ
left'' FL p wA wZ -> RL p wZ wB -> (:>) (FL p) (RL p) wA wB
forall (a1 :: * -> * -> *) (a2 :: * -> * -> *) wX wY wZ.
a1 wX wZ -> a2 wZ wY -> (:>) a1 a2 wX wY
:> RL p wZ wZ
right RL p wZ wZ -> p wZ wB -> RL p wZ wB
forall (a :: * -> * -> *) wX wY wZ.
RL a wX wY -> a wY wZ -> RL a wX wZ
:<: p wZ wB
p')
      | Bool
otherwise = Set (PatchId p)
-> (:>) (RL p) (FL p) wA wB -> Maybe ((:>) (FL p) (RL p) wA wB)
forall wA wB.
Set (PatchId p)
-> (:>) (RL p) (FL p) wA wB -> Maybe ((:>) (FL p) (RL p) wA wB)
push Set (PatchId p)
is (RL p wA wY
ps RL p wA wY -> FL p wY wB -> (:>) (RL p) (FL p) wA wB
forall (a1 :: * -> * -> *) (a2 :: * -> * -> *) wX wY wZ.
a1 wX wZ -> a2 wZ wY -> (:>) a1 a2 wX wY
:> p wY wZ
p p wY wZ -> FL p wZ wB -> FL p wY wB
forall (a :: * -> * -> *) wX wY wZ.
a wX wY -> FL a wY wZ -> FL a wX wZ
:>: FL p wZ wB
left)

-- | Like 'commuteToPostfix' but drag dependencies with us.
commuteWhatWeCanToPostfix :: forall p wX wY. (Commute p, Ident p)
                          => S.Set (PatchId p) -> RL p wX wY -> (FL p :> RL p) wX wY
commuteWhatWeCanToPostfix :: Set (PatchId p) -> RL p wX wY -> (:>) (FL p) (RL p) wX wY
commuteWhatWeCanToPostfix Set (PatchId p)
ids RL p wX wY
patches = Set (PatchId p)
-> (:>) (RL p) (FL p) wX wY -> (:>) (FL p) (RL p) wX wY
forall wA wB.
Set (PatchId p)
-> (:>) (RL p) (FL p) wA wB -> (:>) (FL p) (RL p) wA wB
push Set (PatchId p)
ids (RL p wX wY
patches RL p wX wY -> FL p wY wY -> (:>) (RL p) (FL p) wX wY
forall (a1 :: * -> * -> *) (a2 :: * -> * -> *) wX wY wZ.
a1 wX wZ -> a2 wZ wY -> (:>) a1 a2 wX wY
:> FL p wY wY
forall (a :: * -> * -> *) wX. FL a wX wX
NilFL)
  where
    push :: S.Set (PatchId p) -> (RL p :> FL p) wA wB -> (FL p :> RL p) wA wB
    push :: Set (PatchId p)
-> (:>) (RL p) (FL p) wA wB -> (:>) (FL p) (RL p) wA wB
push Set (PatchId p)
_ (RL p wA wZ
NilRL :> FL p wZ wB
left) = FL p wZ wB
left FL p wZ wB -> RL p wB wB -> (:>) (FL p) (RL p) wZ wB
forall (a1 :: * -> * -> *) (a2 :: * -> * -> *) wX wY wZ.
a1 wX wZ -> a2 wZ wY -> (:>) a1 a2 wX wY
:> RL p wB wB
forall (a :: * -> * -> *) wX. RL a wX wX
NilRL -- input RL is ehausted
    push Set (PatchId p)
is (RL p wA wZ
ps :> FL p wZ wB
left)
      | Set (PatchId p) -> Bool
forall a. Set a -> Bool
S.null Set (PatchId p)
is = RL p wA wZ
ps RL p wA wZ -> FL p wZ wB -> FL p wA wB
forall (p :: * -> * -> *) wX wY wZ.
RL p wX wY -> FL p wY wZ -> FL p wX wZ
+>>+ FL p wZ wB
left FL p wA wB -> RL p wB wB -> (:>) (FL p) (RL p) wA wB
forall (a1 :: * -> * -> *) (a2 :: * -> * -> *) wX wY wZ.
a1 wX wZ -> a2 wZ wY -> (:>) a1 a2 wX wY
:> RL p wB wB
forall (a :: * -> * -> *) wX. RL a wX wX
NilRL -- set of IDs is exhausted
    push Set (PatchId p)
is (RL p wA wY
ps :<: p wY wZ
p :> FL p wZ wB
left)
      | let i :: PatchId p
i = p wY wZ -> PatchId p
forall (p :: * -> * -> *) wX wY. Ident p => p wX wY -> PatchId p
ident p wY wZ
p
      , PatchId p
i PatchId p -> Set (PatchId p) -> Bool
forall a. Ord a => a -> Set a -> Bool
`S.member` Set (PatchId p)
is =
          case (:>) p (FL p) wY wB -> (:>) (FL p) (p :> FL p) wY wB
forall (p :: * -> * -> *) wX wY.
Commute p =>
(:>) p (FL p) wX wY -> (:>) (FL p) (p :> FL p) wX wY
commuteWhatWeCanFL (p wY wZ
p p wY wZ -> FL p wZ wB -> (:>) p (FL p) wY wB
forall (a1 :: * -> * -> *) (a2 :: * -> * -> *) wX wY wZ.
a1 wX wZ -> a2 wZ wY -> (:>) a1 a2 wX wY
:> FL p wZ wB
left) of
            FL p wY wZ
left' :> p wZ wZ
p' :> FL p wZ wB
deps ->
              case Set (PatchId p)
-> (:>) (RL p) (FL p) wA wZ -> (:>) (FL p) (RL p) wA wZ
forall wA wB.
Set (PatchId p)
-> (:>) (RL p) (FL p) wA wB -> (:>) (FL p) (RL p) wA wB
push (PatchId p -> Set (PatchId p) -> Set (PatchId p)
forall a. Ord a => a -> Set a -> Set a
S.delete PatchId p
i Set (PatchId p)
is) (RL p wA wY
ps RL p wA wY -> FL p wY wZ -> (:>) (RL p) (FL p) wA wZ
forall (a1 :: * -> * -> *) (a2 :: * -> * -> *) wX wY wZ.
a1 wX wZ -> a2 wZ wY -> (:>) a1 a2 wX wY
:> FL p wY wZ
left') of
                FL p wA wZ
left'' :> RL p wZ wZ
right -> FL p wA wZ
left'' FL p wA wZ -> RL p wZ wB -> (:>) (FL p) (RL p) wA wB
forall (a1 :: * -> * -> *) (a2 :: * -> * -> *) wX wY wZ.
a1 wX wZ -> a2 wZ wY -> (:>) a1 a2 wX wY
:> (RL p wZ wZ
right RL p wZ wZ -> p wZ wZ -> RL p wZ wZ
forall (a :: * -> * -> *) wX wY wZ.
RL a wX wY -> a wY wZ -> RL a wX wZ
:<: p wZ wZ
p' RL p wZ wZ -> FL p wZ wB -> RL p wZ wB
forall (p :: * -> * -> *) wX wY wZ.
RL p wX wY -> FL p wY wZ -> RL p wX wZ
+<<+ FL p wZ wB
deps)
      | Bool
otherwise = Set (PatchId p)
-> (:>) (RL p) (FL p) wA wB -> (:>) (FL p) (RL p) wA wB
forall wA wB.
Set (PatchId p)
-> (:>) (RL p) (FL p) wA wB -> (:>) (FL p) (RL p) wA wB
push Set (PatchId p)
is (RL p wA wY
ps RL p wA wY -> FL p wY wB -> (:>) (RL p) (FL p) wA wB
forall (a1 :: * -> * -> *) (a2 :: * -> * -> *) wX wY wZ.
a1 wX wZ -> a2 wZ wY -> (:>) a1 a2 wX wY
:> p wY wZ
p p wY wZ -> FL p wZ wB -> FL p wY wB
forall (a :: * -> * -> *) wX wY wZ.
a wX wY -> FL a wY wZ -> FL a wX wZ
:>: FL p wZ wB
left)

prop_identInvariantUnderCommute :: (Commute p, Ident p)
                                => (p :> p) wX wY -> Maybe Bool
prop_identInvariantUnderCommute :: (:>) p p wX wY -> Maybe Bool
prop_identInvariantUnderCommute (p wX wZ
p :> p wZ wY
q) =
  case (:>) p p wX wY -> Maybe ((:>) p p wX wY)
forall (p :: * -> * -> *) wX wY.
Commute p =>
(:>) p p wX wY -> Maybe ((:>) p p wX wY)
commute (p wX wZ
p p wX wZ -> p wZ wY -> (:>) p p wX wY
forall (a1 :: * -> * -> *) (a2 :: * -> * -> *) wX wY wZ.
a1 wX wZ -> a2 wZ wY -> (:>) a1 a2 wX wY
:> p wZ wY
q) of
    Just (p wX wZ
q' :> p wZ wY
p') -> Bool -> Maybe Bool
forall a. a -> Maybe a
Just (Bool -> Maybe Bool) -> Bool -> Maybe Bool
forall a b. (a -> b) -> a -> b
$ p wX wZ -> PatchId p
forall (p :: * -> * -> *) wX wY. Ident p => p wX wY -> PatchId p
ident p wX wZ
p PatchId p -> PatchId p -> Bool
forall a. Eq a => a -> a -> Bool
== p wZ wY -> PatchId p
forall (p :: * -> * -> *) wX wY. Ident p => p wX wY -> PatchId p
ident p wZ wY
p' Bool -> Bool -> Bool
&& p wZ wY -> PatchId p
forall (p :: * -> * -> *) wX wY. Ident p => p wX wY -> PatchId p
ident p wZ wY
q PatchId p -> PatchId p -> Bool
forall a. Eq a => a -> a -> Bool
== p wX wZ -> PatchId p
forall (p :: * -> * -> *) wX wY. Ident p => p wX wY -> PatchId p
ident p wX wZ
q'
    Maybe ((:>) p p wX wY)
Nothing -> Maybe Bool
forall a. Maybe a
Nothing

prop_sameIdentityImpliesCommutable :: (Commute p, Eq2 p, Ident p)
                                   => (p :\/: (RL p :> p)) wX wY -> Maybe Bool
prop_sameIdentityImpliesCommutable :: (:\/:) p (RL p :> p) wX wY -> Maybe Bool
prop_sameIdentityImpliesCommutable (p wZ wX
p :\/: (RL p wZ wZ
ps :> p wZ wY
q))
  | p wZ wX -> PatchId p
forall (p :: * -> * -> *) wX wY. Ident p => p wX wY -> PatchId p
ident p wZ wX
p PatchId p -> PatchId p -> Bool
forall a. Eq a => a -> a -> Bool
== p wZ wY -> PatchId p
forall (p :: * -> * -> *) wX wY. Ident p => p wX wY -> PatchId p
ident p wZ wY
q =
      case (:>) (RL p) p wZ wY -> Maybe ((:>) p (RL p) wZ wY)
forall (p :: * -> * -> *) wX wY.
Commute p =>
(:>) (RL p) p wX wY -> Maybe ((:>) p (RL p) wX wY)
commuteRL (RL p wZ wZ
ps RL p wZ wZ -> p wZ wY -> (:>) (RL p) p wZ wY
forall (a1 :: * -> * -> *) (a2 :: * -> * -> *) wX wY wZ.
a1 wX wZ -> a2 wZ wY -> (:>) a1 a2 wX wY
:> p wZ wY
q) of
        Just (p wZ wZ
p' :> RL p wZ wY
_) -> Bool -> Maybe Bool
forall a. a -> Maybe a
Just (Bool -> Maybe Bool) -> Bool -> Maybe Bool
forall a b. (a -> b) -> a -> b
$ EqCheck wX wZ -> Bool
forall wA wB. EqCheck wA wB -> Bool
isIsEq (p wZ wX
p p wZ wX -> p wZ wZ -> EqCheck wX wZ
forall (p :: * -> * -> *) wA wB wC.
Eq2 p =>
p wA wB -> p wA wC -> EqCheck wB wC
=\/= p wZ wZ
p')
        Maybe ((:>) p (RL p) wZ wY)
Nothing -> Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
False
  | Bool
otherwise = Maybe Bool
forall a. Maybe a
Nothing

prop_equalImpliesSameIdentity :: (Eq2 p, Ident p)
                              => (p :\/: p) wX wY -> Maybe Bool
prop_equalImpliesSameIdentity :: (:\/:) p p wX wY -> Maybe Bool
prop_equalImpliesSameIdentity (p wZ wX
p :\/: p wZ wY
q)
  | EqCheck wX wY
IsEq <- p wZ wX
p p wZ wX -> p wZ wY -> EqCheck wX wY
forall (p :: * -> * -> *) wA wB wC.
Eq2 p =>
p wA wB -> p wA wC -> EqCheck wB wC
=\/= p wZ wY
q = Bool -> Maybe Bool
forall a. a -> Maybe a
Just (Bool -> Maybe Bool) -> Bool -> Maybe Bool
forall a b. (a -> b) -> a -> b
$ p wZ wX -> PatchId p
forall (p :: * -> * -> *) wX wY. Ident p => p wX wY -> PatchId p
ident p wZ wX
p PatchId p -> PatchId p -> Bool
forall a. Eq a => a -> a -> Bool
== p wZ wY -> PatchId p
forall (p :: * -> * -> *) wX wY. Ident p => p wX wY -> PatchId p
ident p wZ wY
q
  | Bool
otherwise = Maybe Bool
forall a. Maybe a
Nothing