1
1
mirror of https://github.com/github/semantic.git synced 2025-01-06 06:46:07 +03:00

Diffs are Church-encoded.

This commit is contained in:
Rob Rix 2015-12-24 21:11:09 -05:00
parent 8bb1d7f0bf
commit 7695992f70
5 changed files with 21 additions and 18 deletions

View File

@ -2,7 +2,7 @@ module Diff where
import Syntax import Syntax
import Data.Set import Data.Set
import Control.Monad.Free import Control.Monad.Free.Church
import Patch import Patch
import Term import Term
import Range import Range
@ -18,7 +18,7 @@ data Info = Info { characterRange :: !Range, categories :: !(Set Category) }
instance Categorizable Info where instance Categorizable Info where
categories = Diff.categories categories = Diff.categories
type Diff a annotation = Free (Annotated a (annotation, annotation)) (Patch (Term a annotation)) type Diff a annotation = F (Annotated a (annotation, annotation)) (Patch (Term a annotation))
diffSum :: (Patch (Term a annotation) -> Integer) -> Diff a annotation -> Integer diffSum :: (Patch (Term a annotation) -> Integer) -> Diff a annotation -> Integer
diffSum patchCost diff = sum $ fmap patchCost diff diffSum patchCost diff = sum $ fmap patchCost diff

View File

@ -21,7 +21,7 @@ import Data.Maybe
type Comparable a annotation = Term a annotation -> Term a annotation -> Bool type Comparable a annotation = Term a annotation -> Term a annotation -> Bool
interpret :: (Eq a, Eq annotation) => Comparable a annotation -> Term a annotation -> Term a annotation -> Diff a annotation interpret :: (Eq a, Eq annotation) => Comparable a annotation -> Term a annotation -> Term a annotation -> Diff a annotation
interpret comparable a b = fromMaybe (Pure $ Replace a b) $ constructAndRun comparable a b interpret comparable a b = fromMaybe (pure $ Replace a b) $ constructAndRun comparable a b
hylo :: Functor f => (t -> f b -> b) -> (a -> (t, f a)) -> a -> b hylo :: Functor f => (t -> f b -> b) -> (a -> (t, f a)) -> a -> b
hylo down up a = down annotation $ hylo down up <$> syntax where hylo down up a = down annotation $ hylo down up <$> syntax where
@ -33,15 +33,15 @@ constructAndRun _ a b | a == b = hylo introduce eliminate <$> zipTerms a b where
eliminate :: Cofree f a -> (a, f (Cofree f a)) eliminate :: Cofree f a -> (a, f (Cofree f a))
eliminate (extract :< unwrap) = (extract, unwrap) eliminate (extract :< unwrap) = (extract, unwrap)
introduce :: (annotation, annotation) -> Syntax a (Diff a annotation) -> Diff a annotation introduce :: (annotation, annotation) -> Syntax a (Diff a annotation) -> Diff a annotation
introduce ann syntax = Free $ Annotated ann syntax introduce ann syntax = wrap $ Annotated ann syntax
constructAndRun comparable a b | not $ comparable a b = Nothing constructAndRun comparable a b | not $ comparable a b = Nothing
constructAndRun comparable (annotation1 :< a) (annotation2 :< b) = constructAndRun comparable (annotation1 :< a) (annotation2 :< b) =
run comparable $ algorithm a b where run comparable $ algorithm a b where
algorithm (Indexed a') (Indexed b') = Free $ ByIndex a' b' (annotate . Indexed) algorithm (Indexed a') (Indexed b') = Free $ ByIndex a' b' (annotate . Indexed)
algorithm (Keyed a') (Keyed b') = Free $ ByKey a' b' (annotate . Keyed) algorithm (Keyed a') (Keyed b') = Free $ ByKey a' b' (annotate . Keyed)
algorithm (Leaf a') (Leaf b') | a' == b' = annotate $ Leaf b' algorithm (Leaf a') (Leaf b') | a' == b' = annotate $ Leaf b'
algorithm a' b' = Free $ Recursive (annotation1 :< a') (annotation2 :< b') Pure algorithm a' b' = wrap $ Recursive (annotation1 :< a') (annotation2 :< b') pure
annotate = Pure . Free . Annotated (annotation1, annotation2) annotate = pure . wrap . Annotated (annotation1, annotation2)
-- | Runs the diff algorithm -- | Runs the diff algorithm
run :: (Eq a, Eq annotation) => Comparable a annotation -> Algorithm a annotation (Diff a annotation) -> Maybe (Diff a annotation) run :: (Eq a, Eq annotation) => Comparable a annotation -> Algorithm a annotation (Diff a annotation) -> Maybe (Diff a annotation)
@ -55,14 +55,14 @@ run comparable (Free (Recursive (annotation1 :< a) (annotation2 :< b) f)) = run
bKeys = Map.keys b' bKeys = Map.keys b'
repack key = (key, interpretInBoth key a' b') repack key = (key, interpretInBoth key a' b')
interpretInBoth key x y = interpret comparable (x ! key) (y ! key) interpretInBoth key x y = interpret comparable (x ! key) (y ! key)
recur _ _ = Pure $ Replace (annotation1 :< a) (annotation2 :< b) recur _ _ = pure $ Replace (annotation1 :< a) (annotation2 :< b)
annotate = Free . Annotated (annotation1, annotation2) annotate = wrap . Annotated (annotation1, annotation2)
run comparable (Free (ByKey a b f)) = run comparable $ f byKey where run comparable (Free (ByKey a b f)) = run comparable $ f byKey where
byKey = Map.fromList $ toKeyValue <$> List.union aKeys bKeys byKey = Map.fromList $ toKeyValue <$> List.union aKeys bKeys
toKeyValue key | List.elem key deleted = (key, Pure . Delete $ a ! key) toKeyValue key | List.elem key deleted = (key, pure . Delete $ a ! key)
toKeyValue key | List.elem key inserted = (key, Pure . Insert $ b ! key) toKeyValue key | List.elem key inserted = (key, pure . Insert $ b ! key)
toKeyValue key = (key, interpret comparable (a ! key) (b ! key)) toKeyValue key = (key, interpret comparable (a ! key) (b ! key))
aKeys = Map.keys a aKeys = Map.keys a
bKeys = Map.keys b bKeys = Map.keys b

View File

@ -3,7 +3,6 @@ module SES where
import Patch import Patch
import Diff import Diff
import Term import Term
import Control.Monad.Free
import Control.Monad.State import Control.Monad.State
import Data.Foldable (minimumBy) import Data.Foldable (minimumBy)
import Data.List (uncons) import Data.List (uncons)
@ -20,9 +19,9 @@ ses diffTerms cost as bs = fst <$> evalState diffState Map.empty where
diffAt :: Compare a annotation -> Cost a annotation -> (Integer, Integer) -> [Term a annotation] -> [Term a annotation] -> State (Map.Map (Integer, Integer) [(Diff a annotation, Integer)]) [(Diff a annotation, Integer)] diffAt :: Compare a annotation -> Cost a annotation -> (Integer, Integer) -> [Term a annotation] -> [Term a annotation] -> State (Map.Map (Integer, Integer) [(Diff a annotation, Integer)]) [(Diff a annotation, Integer)]
diffAt _ _ _ [] [] = return [] diffAt _ _ _ [] [] = return []
diffAt _ cost _ [] bs = return $ foldr toInsertions [] bs where diffAt _ cost _ [] bs = return $ foldr toInsertions [] bs where
toInsertions each = consWithCost cost (Pure . Insert $ each) toInsertions each = consWithCost cost (pure . Insert $ each)
diffAt _ cost _ as [] = return $ foldr toDeletions [] as where diffAt _ cost _ as [] = return $ foldr toDeletions [] as where
toDeletions each = consWithCost cost (Pure . Delete $ each) toDeletions each = consWithCost cost (pure . Delete $ each)
diffAt diffTerms cost (i, j) (a : as) (b : bs) = do diffAt diffTerms cost (i, j) (a : as) (b : bs) = do
cachedDiffs <- get cachedDiffs <- get
case Map.lookup (i, j) cachedDiffs of case Map.lookup (i, j) cachedDiffs of
@ -39,8 +38,8 @@ diffAt diffTerms cost (i, j) (a : as) (b : bs) = do
put $ Map.insert (i, j) nomination cachedDiffs' put $ Map.insert (i, j) nomination cachedDiffs'
return nomination return nomination
where where
delete = consWithCost cost (Pure . Delete $ a) delete = consWithCost cost (pure . Delete $ a)
insert = consWithCost cost (Pure . Insert $ b) insert = consWithCost cost (pure . Insert $ b)
costOf [] = 0 costOf [] = 0
costOf ((_, c) : _) = c costOf ((_, c) : _) = c
best = minimumBy (comparing costOf) best = minimumBy (comparing costOf)

View File

@ -10,6 +10,7 @@ import Syntax
import Control.Comonad.Cofree import Control.Comonad.Cofree
import Range import Range
import Control.Monad.Free import Control.Monad.Free
import Control.Monad.Free.Church
import Data.ByteString.Lazy.Internal import Data.ByteString.Lazy.Internal
import Text.Blaze.Html import Text.Blaze.Html
import Text.Blaze.Html5 hiding (map) import Text.Blaze.Html5 hiding (map)
@ -88,8 +89,8 @@ instance ToMarkup (Renderable (SplitDiff a Info)) where
toMarkupAndRange term@(Info range _ :< _) = ((div ! A.class_ (stringValue "patch")) . toMarkup $ Renderable (source, term), range) toMarkupAndRange term@(Info range _ :< _) = ((div ! A.class_ (stringValue "patch")) . toMarkup $ Renderable (source, term), range)
splitDiffByLines :: Diff a Info -> (Int, Int) -> (Source Char, Source Char) -> ([Row (SplitDiff a Info)], (Range, Range)) splitDiffByLines :: Diff a Info -> (Int, Int) -> (Source Char, Source Char) -> ([Row (SplitDiff a Info)], (Range, Range))
splitDiffByLines diff (prevLeft, prevRight) sources = case diff of splitDiffByLines diff (prevLeft, prevRight) sources = case fromF diff of
Free (Annotated annotation syntax) -> (splitAnnotatedByLines sources (ranges annotation) (categories annotation) syntax, ranges annotation) Free (Annotated annotation syntax) -> (splitAnnotatedByLines sources (ranges annotation) (categories annotation) (toF <$> syntax), ranges annotation)
Pure (Insert term) -> let (lines, range) = splitTermByLines term (snd sources) in Pure (Insert term) -> let (lines, range) = splitTermByLines term (snd sources) in
(Row EmptyLine . fmap Pure <$> lines, (Range prevLeft prevLeft, range)) (Row EmptyLine . fmap Pure <$> lines, (Range prevLeft prevLeft, range))
Pure (Delete term) -> let (lines, range) = splitTermByLines term (fst sources) in Pure (Delete term) -> let (lines, range) = splitTermByLines term (fst sources) in

View File

@ -7,7 +7,7 @@ import Term
import Range import Range
import Source hiding ((++)) import Source hiding ((++))
import Control.Arrow import Control.Arrow
import Control.Monad.Free import Control.Monad.Free.Church
import Control.Comonad.Cofree import Control.Comonad.Cofree
import Data.List hiding (foldl) import Data.List hiding (foldl)
import qualified OrderedMap as Map import qualified OrderedMap as Map
@ -24,6 +24,9 @@ unified diff before after = do
annotationAndSyntaxToChunks source (Info range _) (Fixed f) = (unifiedRange range f source, Just range) annotationAndSyntaxToChunks source (Info range _) (Fixed f) = (unifiedRange range f source, Just range)
annotationAndSyntaxToChunks source (Info range _) (Keyed k) = (unifiedRange range (sort $ snd <$> Map.toList k) source, Just range) annotationAndSyntaxToChunks source (Info range _) (Keyed k) = (unifiedRange range (sort $ snd <$> Map.toList k) source, Just range)
iter :: Functor f => (f a -> a) -> F f a -> a
iter phi xs = runF xs id phi
unifiedPatch :: Patch (Term a Info) -> [Chunk String] unifiedPatch :: Patch (Term a Info) -> [Chunk String]
unifiedPatch patch = (fore red . bold <$> beforeChunk) <> (fore green . bold <$> afterChunk) where unifiedPatch patch = (fore red . bold <$> beforeChunk) <> (fore green . bold <$> afterChunk) where
beforeChunk = maybe [] (change "-" . unifiedTerm before) $ Patch.before patch beforeChunk = maybe [] (change "-" . unifiedTerm before) $ Patch.before patch