2017-05-08 18:52:36 +03:00
|
|
|
|
{-# LANGUAGE TypeSynonymInstances, UndecidableInstances #-}
|
2017-03-14 02:23:33 +03:00
|
|
|
|
{-# OPTIONS_GHC -fno-warn-orphans #-}
|
2015-11-18 00:25:36 +03:00
|
|
|
|
module Diff where
|
|
|
|
|
|
2017-07-28 21:37:02 +03:00
|
|
|
|
import qualified Control.Comonad.Trans.Cofree as CofreeF
|
|
|
|
|
import Control.DeepSeq
|
|
|
|
|
import qualified Control.Monad.Free as Free
|
|
|
|
|
import qualified Control.Monad.Trans.Free as FreeF
|
|
|
|
|
import Data.Bifunctor
|
2016-06-27 19:02:25 +03:00
|
|
|
|
import Data.Functor.Both as Both
|
2017-08-28 19:48:36 +03:00
|
|
|
|
import Data.Functor.Classes.Pretty.Generic
|
2016-07-23 00:38:10 +03:00
|
|
|
|
import Data.Mergeable
|
2016-09-12 20:40:22 +03:00
|
|
|
|
import Data.Record
|
2015-11-18 05:23:53 +03:00
|
|
|
|
import Patch
|
2016-09-12 20:40:22 +03:00
|
|
|
|
import Syntax
|
2016-02-29 18:04:59 +03:00
|
|
|
|
import Term
|
2015-11-18 00:25:36 +03:00
|
|
|
|
|
2016-01-14 20:30:21 +03:00
|
|
|
|
-- | An annotated series of patches of terms.
|
2017-07-28 21:37:02 +03:00
|
|
|
|
type DiffF f annotation = FreeF.FreeF (TermF f (Both annotation)) (Patch (Term f annotation))
|
|
|
|
|
type Diff f annotation = Free.Free (TermF f (Both annotation)) (Patch (Term f annotation))
|
2016-05-03 22:50:38 +03:00
|
|
|
|
|
2017-07-23 18:01:34 +03:00
|
|
|
|
type SyntaxDiff fields = Diff Syntax (Record fields)
|
2016-09-12 20:40:22 +03:00
|
|
|
|
|
2016-09-14 23:12:47 +03:00
|
|
|
|
diffSum :: (Foldable f, Functor f) => (Patch (Term f annotation) -> Int) -> Diff f annotation -> Int
|
2015-12-01 18:13:05 +03:00
|
|
|
|
diffSum patchCost diff = sum $ fmap patchCost diff
|
2015-12-01 03:06:48 +03:00
|
|
|
|
|
2016-04-11 22:06:59 +03:00
|
|
|
|
-- | The sum of the node count of the diff’s patches.
|
2016-09-14 23:12:47 +03:00
|
|
|
|
diffCost :: (Foldable f, Functor f) => Diff f annotation -> Int
|
2015-12-01 03:16:22 +03:00
|
|
|
|
diffCost = diffSum $ patchSum termSize
|
2016-06-27 19:02:25 +03:00
|
|
|
|
|
2016-07-05 16:45:28 +03:00
|
|
|
|
-- | Merge a diff using a function to provide the Term (in Maybe, to simplify recovery of the before/after state) for every Patch.
|
2017-05-08 18:52:36 +03:00
|
|
|
|
mergeMaybe :: Mergeable f => (Patch (Term f annotation) -> Maybe (Term f annotation)) -> (Both annotation -> annotation) -> Diff f annotation -> Maybe (Term f annotation)
|
2017-07-28 21:37:02 +03:00
|
|
|
|
mergeMaybe transform extractAnnotation = Free.iter algebra . fmap transform
|
|
|
|
|
where algebra (annotations CofreeF.:< syntax) = cofree . (extractAnnotation annotations CofreeF.:<) <$> sequenceAlt syntax
|
2016-10-21 00:22:45 +03:00
|
|
|
|
|
2016-07-05 16:45:28 +03:00
|
|
|
|
-- | Recover the before state of a diff.
|
2016-09-15 00:13:10 +03:00
|
|
|
|
beforeTerm :: Mergeable f => Diff f annotation -> Maybe (Term f annotation)
|
2016-10-21 01:19:42 +03:00
|
|
|
|
beforeTerm = mergeMaybe before Both.fst
|
2016-06-27 19:50:25 +03:00
|
|
|
|
|
2016-07-05 16:45:28 +03:00
|
|
|
|
-- | Recover the after state of a diff.
|
2016-10-21 00:33:47 +03:00
|
|
|
|
afterTerm :: Mergeable f => Diff f annotation -> Maybe (Term f annotation)
|
2016-10-21 01:19:42 +03:00
|
|
|
|
afterTerm = mergeMaybe after Both.snd
|
2017-02-07 22:57:42 +03:00
|
|
|
|
|
2017-02-07 22:58:11 +03:00
|
|
|
|
-- | Map a function over the annotations in a diff, whether in diff or term nodes.
|
2017-02-07 23:03:59 +03:00
|
|
|
|
--
|
2017-02-08 20:03:50 +03:00
|
|
|
|
-- Typed using Free so as to accommodate Free structures derived from diffs that don’t fit into the Diff type synonym.
|
2017-02-07 23:02:40 +03:00
|
|
|
|
mapAnnotations :: (Functor f, Functor g)
|
|
|
|
|
=> (annotation -> annotation')
|
2017-07-28 21:37:02 +03:00
|
|
|
|
-> Free.Free (TermF f (g annotation)) (Patch (Term f annotation))
|
|
|
|
|
-> Free.Free (TermF f (g annotation')) (Patch (Term f annotation'))
|
|
|
|
|
mapAnnotations f = Free.hoistFree (first (fmap f)) . fmap (fmap (fmap f))
|
2017-02-08 20:03:10 +03:00
|
|
|
|
|
2017-05-08 18:46:12 +03:00
|
|
|
|
|
2017-07-28 21:42:07 +03:00
|
|
|
|
instance (NFData (f (Diff f a)), NFData (f (Term f a)), NFData a, Functor f) => NFData (Diff f a) where
|
2017-03-14 02:23:33 +03:00
|
|
|
|
rnf fa = case runFree fa of
|
2017-07-28 21:37:02 +03:00
|
|
|
|
FreeF.Free f -> rnf f `seq` ()
|
|
|
|
|
FreeF.Pure a -> rnf a `seq` ()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
free :: FreeF.FreeF f a (Free.Free f a) -> Free.Free f a
|
|
|
|
|
free (FreeF.Free f) = Free.Free f
|
|
|
|
|
free (FreeF.Pure a) = Free.Pure a
|
|
|
|
|
|
|
|
|
|
runFree :: Free.Free f a -> FreeF.FreeF f a (Free.Free f a)
|
|
|
|
|
runFree (Free.Free f) = FreeF.Free f
|
|
|
|
|
runFree (Free.Pure a) = FreeF.Pure a
|
2017-08-28 19:48:36 +03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
instance Pretty1 f => Pretty1 (Free.Free f) where
|
|
|
|
|
liftPretty p pl = go where go (Free.Pure a) = p a
|
|
|
|
|
go (Free.Free f) = liftPretty go (list . map (liftPretty p pl)) f
|
|
|
|
|
|
|
|
|
|
instance (Pretty1 f, Pretty a) => Pretty (Free.Free f a) where
|
|
|
|
|
pretty = liftPretty pretty prettyList
|