Îõ³h&0õ-6­      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨© ª « ¬  Safe-InferredÜ› tree-diffList edit operationsThe Ü constructor is redundant, but it let us spot a recursion point when performing tree diffs. tree-diffinsert tree-diffdelete tree-diffcopy unchanged tree-diffswap, i.e. delete + insert tree-diffList difference.diffBy (==) "hello" "world"9[Swp 'h' 'w',Swp 'e' 'o',Swp 'l' 'r',Cpy 'l',Swp 'o' 'd']diffBy (==) "kitten" "sitting"Á[Swp 'k' 's',Cpy 'i',Cpy 't',Cpy 't',Swp 'e' 'i',Cpy 'n',Ins 'g']Ï\xs ys -> length (diffBy (==) xs ys) >= max (length xs) (length (ys :: String))É\xs ys -> length (diffBy (==) xs ys) <= length xs + length (ys :: String) Safe-Inferred8 &  tree-diffempty :: OMap String Integer fromList []  tree-diff Elements in key ascending order.  tree-diffÄtoAscList $ fromList [('a', "alpha"), ('b', "beta"), ('g', "gamma")]*[('a',"alpha"),('b',"beta"),('g',"gamma")]ÄtoAscList $ fromList [('g', "gamma"), ('b', "beta"), ('a', "alpha")]*[('a',"alpha"),('b',"beta"),('g',"gamma")] tree-diff O(n log n)+. List in creation order. Doesn't respect ­ instance.ÁtoList $ fromList [('a', "alpha"), ('b', "beta"), ('g', "gamma")]*[('a',"alpha"),('b',"beta"),('g',"gamma")]ÁtoList $ fromList [('g', "gamma"), ('b', "beta"), ('a', "alpha")]*[('g',"gamma"),('b',"beta"),('a',"alpha")] tree-diff8fromList [('g', "gamma"), ('b', "beta"), ('a', "alpha")]3fromList [('g',"gamma"),('b',"beta"),('a',"alpha")] tree-diff1let xs = fromList [('a', "alpha"), ('b', "beta")]-let ys = fromList [('c', 3 :: Int), ('b', 2)]alignWith id xs ys?fromList [('a',This "alpha"),('c',That 3),('b',These "beta" 2)] tree-diffÉxs = toAscList $ fromList [('a', "alpha"), ('b', "beta"), ('g', "gamma")]Éys = toAscList $ fromList [('g', "gamma"), ('b', "beta"), ('a', "alpha")]xs == ysTrueÉzs = toAscList $ fromList [('d', "delta"), ('b', "beta"), ('a', "alpha")]xs == zsFalse tree-diffNote: The instance uses , so ­ual  s can be shown differently.    Safe-Inferred J  tree-diffType used in the result of ediff. tree-diffunchanged tree tree-diff"A untyped Haskell-like expression."Having richer structure than just Tree allows to have richer diffs.  tree-diff application! tree-diffrecord constructor" tree-difflist constructor# tree-diff"Record field name is a string too.$ tree-diffConstructor name is a string% tree-diff Diff two .For examples see ediff in Data.TreeDiff.Class. !"#$% !"$#% Safe-Inferred )*/<Â×ÙÚÜêM. tree-diff/ converts a Haskell value into untyped Haskell-like syntax tree, .(toExpr ((1, Just 2) :: (Int, Maybe Int))1App "_\215_" [App "1" [],App "Just" [App "2" []]]1 tree-diffDifference between two . values.'let x = (1, Just 2) :: (Int, Maybe Int)let y = (1, Nothing)prettyEditExpr (ediff x y)_×_ 1 -(Just 2) +Nothingñdata Foo = Foo { fooInt :: Either Char Int, fooBool :: [Maybe Bool], fooString :: String } deriving (Eq, Generic)instance ToExpr FooØprettyEditExpr $ ediff (Foo (Right 2) [Just True] "fo") (Foo (Right 3) [Just True] "fo")ÃFoo {fooInt = Right -2 +3, fooBool = [Just True], fooString = "fo"}ýprettyEditExpr $ ediff (Foo (Right 42) [Just True, Just False] "old") (Foo (Right 42) [Nothing, Just False, Just True] "new")Foo { fooInt = Right 42,; fooBool = [-Just True, +Nothing, Just False, +Just True], fooString = -"old" +"new"}2 tree-diffCompare different types.Note:? Use with care as you can end up comparing apples with oranges. xs == concat (unconcat uncons xs)5 tree-diff6 tree-diffG tree-diffprettyExpr $ toExpr UUID.nil+UUID "00000000-0000-0000-0000-000000000000"H tree-diff+prettyExpr $ toExpr (123.456 :: Scientific)scientific 123456 `-3`I tree-diffõtraverse_ (print . prettyExpr . toExpr . SBS.toShort . BS8.pack) ["", "\n", "foo", "foo\n", "foo\nbar", "foo\nbar\n"]"""\n""foo""foo\n"mconcat ["foo\n", "bar"]mconcat ["foo\n", "bar\n"]J tree-diffçtraverse_ (print . prettyExpr . toExpr . BS8.pack) ["", "\n", "foo", "foo\n", "foo\nbar", "foo\nbar\n"]"""\n""foo""foo\n"BS.concat ["foo\n", "bar"]BS.concat ["foo\n", "bar\n"]K tree-diffètraverse_ (print . prettyExpr . toExpr . LBS8.pack) ["", "\n", "foo", "foo\n", "foo\nbar", "foo\nbar\n"]"""\n""foo""foo\n"LBS.concat ["foo\n", "bar"]LBS.concat ["foo\n", "bar\n"]M tree-diff-prettyExpr $ toExpr $ ModifiedJulianDay 58014Day "2017-09-18"N tree-diffåtraverse_ (print . prettyExpr . toExpr . T.pack) ["", "\n", "foo", "foo\n", "foo\nbar", "foo\nbar\n"]"""\n""foo""foo\n"T.concat ["foo\n", "bar"]T.concat ["foo\n", "bar\n"]O tree-diffætraverse_ (print . prettyExpr . toExpr . LT.pack) ["", "\n", "foo", "foo\n", "foo\nbar", "foo\nbar\n"]"""\n""foo""foo\n"LT.concat ["foo\n", "bar"]LT.concat ["foo\n", "bar\n"]c tree-diff"prettyExpr $ toExpr $ Identity 'a' Identity 'a'e tree-diff(prettyExpr $ toExpr (3 % 12 :: Rational)_%_ 1 4m tree-diffprettyExpr $ toExpr 'a''a'!prettyExpr $ toExpr "Hello world" "Hello world""prettyExpr $ toExpr "Hello\nworld"concat ["Hello\n", "world"]Ütraverse_ (print . prettyExpr . toExpr) ["", "\n", "foo", "foo\n", "foo\nbar", "foo\nbar\n"]"""\n""foo""foo\n"concat ["foo\n", "bar"]concat ["foo\n", "bar\n"]° tree-diffname of concat-./0123412./034- Safe-InferredÜGŠ tree-diff Parsers for  using parsers type-classes.ÁYou can use this with your parser-combinator library of choice: parsec,  attoparsec, trifecta...ŠŠ Safe-Inferred#‹ tree-diffßBecause we don't want to commit to single pretty printing library, we use explicit dictionary. tree-diffDisplay $Ž tree-diffDisplay   tree-diffDisplay ! tree-diffDisplay "‘ tree-diffDisplay unchanged parts’ tree-diffDisplay added parts“ tree-diffDisplay removed parts” tree-diffCombined edits (usually some sep combinator)• tree-diffEllipsis– tree-diffParens an expression— tree-diff Escape field or constructor nameputStrLn $ escapeName "Foo"FooputStrLn $ escapeName "_×_"_×_putStrLn $ escapeName "-3"`-3`"putStrLn $ escapeName "kebab-case" kebab-case#putStrLn $ escapeName "inner space" `inner space`2putStrLn $ escapeName $ show "looks like a string""looks like a string".putStrLn $ escapeName $ show "tricky" ++ " " `"tricky" `putStrLn $ escapeName "[]"`[]`putStrLn $ escapeName "_,_"`_,_`˜ tree-diffPretty print an + using explicit pretty-printing dictionary.™ tree-diffPretty print an  + using explicit pretty-printing dictionary.š tree-diffLike ™) but print unchanged parts only shallowly› tree-diff‹ via pretty library.œ tree-diff Pretty print  using pretty.https://github.com/phadej/tree-diff/blob/master/tests/Tests.hs for a proper example.§ tree-diff goldenTest tree-diff test name tree-diffpath to "golden file" tree-diff result value§§ Safe-Inferred'‘¨ tree-diff A variant of ===/, which outputs a diff when values are inequal.¨¨  Safe-Inferred-© tree-diffType used in the result of «.It's essentially a ±', but the forest list is changed from [tree a] to [ (tree a)]. This highlights that «) performs a list diff on each tree level.« tree-diffA breadth-traversal diff.It's different from gdiffü, as it doesn't produce a flat edit script, but edit script iself is a tree. This makes visualising the diff much simpler.ExamplesÄLet's start from simple tree. We pretty print them as s-expressions.Îlet x = Node 'a' [Node 'b' [], Node 'c' [return 'd', return 'e'], Node 'f' []]ppTree PP.char x(a b (c d e) f)>If we modify an argument in a tree, we'll notice it's changed:Îlet y = Node 'a' [Node 'b' [], Node 'c' [return 'x', return 'e'], Node 'f' []]ppTree PP.char y(a b (c x e) f)!ppEditTree PP.char (treeDiff x y)(a b (c -d +x e) f)äIf we modify a constructor, the whole sub-trees is replaced, though there might be common subtrees.8let z = Node 'a' [Node 'b' [], Node 'd' [], Node 'f' []]ppTree PP.char z (a b d f)!ppEditTree PP.char (treeDiff x z)(a b -(c d e) +d f)*If we add arguments, they are spotted too:Úlet w = Node 'a' [Node 'b' [], Node 'c' [return 'd', return 'x', return 'e'], Node 'f' []]ppTree PP.char w(a b (c d x e) f)!ppEditTree PP.char (treeDiff x w)(a b (c d +x e) f)©ª««©ª²    !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•––—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±² ³ ´ µ ¶·¸¹º»¼½¾¿ÀÁÂ#tree-diff-0.3-EQ0S4ZVJdRIfDd4gbtWK8Data.TreeDiff.ListData.TreeDiff.OMapData.TreeDiff.ExprData.TreeDiff.ClassData.TreeDiff.ParserData.TreeDiff.PrettyData.TreeDiff.GoldenData.TreeDiff.QuickCheckData.TreeDiff.Tree Data.TreeDiffEditInsDelCpySwpdiffBy $fNFDataEdit $fShowCell$fEqEdit $fShowEditOMapemptyelems toAscListtoListfromList $fNFDataVal$fSemialignOMap$fArbitrary1OMap$fArbitraryOMap $fNFDataOMap $fOrdOMap$fEqOMap $fShowOMap $fFunctorOMap $fFunctorValEditExprEditAppEditRecEditLstEditExpExprAppRecLst FieldNameConstructorNameexprDiff$fArbitraryExpr $fNFDataExpr$fNFDataEditExpr$fShowEditExpr$fEqExpr $fOrdExpr $fShowExprGToExprToExprtoExpr listToExprediffediff'defaultExprViaShow genericToExpr$fToExprByteArray$fToExprByteArray0 $fToExprThese $fToExprPair$fToExprThese0$fToExprEither $fToExprMaybe$fToExprKeyMap $fToExprKey $fToExprValue$fToExprHashSet$fToExprHashMap$fToExprHashed$fToExprTagged$fToExprVector$fToExprVector0$fToExprVector1$fToExprVector2 $fToExprUUID$fToExprScientific$fToExprShortByteString$fToExprByteString$fToExprByteString0$fToExprUTCTime $fToExprDay $fToExprText $fToExprText0 $fToExprSeq$fToExprIntSet$fToExprIntMap $fToExprSet $fToExprMap $fToExprTree $fToExprLast $fToExprFirst $fToExprMax $fToExprMin $fToExprLast0$fToExprFirst0$fToExprProduct $fToExprSum $fToExprDual $fToExprVoid$fToExprNonEmpty$fToExprZipList $fToExprConst$fToExprIdentity $fToExprFixed $fToExprRatio$fToExpr(,,,,) $fToExpr(,,,) $fToExpr(,,) $fToExpr(,) $fToExpr[]$fToExprEither0$fToExprMaybe0 $fToExprChar $fToExprProxy$fToExprWord64$fToExprWord32$fToExprWord16 $fToExprWord8 $fToExprWord $fToExprInt64 $fToExprInt32 $fToExprInt16 $fToExprInt8 $fToExprInt$fToExprDouble $fToExprFloat$fToExprNatural$fToExprInteger$fToExprOrdering $fToExprBool $fToExpr() $fToExprExpr$fGSumToExprV1$fGSumToExpr:+: $fGToExprM1$fGLeafToExprK1$fGProductToExprM1$fGProductToExprU1$fGProductToExpr:*:$fGSumToExprM1$fShowAppOrRec exprParserPrettyppConppAppppRecppLstppCpyppInsppDelppEditsppEllipppParens escapeNameppExpr ppEditExprppEditExprCompact prettyPretty prettyExprprettyEditExprprettyEditExprCompact ansiWlPretty ansiWlExpransiWlEditExpransiWlEditExprCompactansiWlBgPretty ansiWlBgExpransiWlBgEditExpransiWlBgEditExprCompact ediffGoldenediffEqEditTreeEditNodetreeDiff$fShowEditTreeghc-prim GHC.ClassesEqbaseGHC.Showshowunconcat stringToExprcontainers-0.6.5.1 Data.TreeTree