!_      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ NoneX 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"A[Swp 'k' 's',Cpy 'i',Cpy 't',Cpy 't',Swp 'e' 'i',Cpy 'n',Ins 'g']O\xs ys -> length (diffBy (==) xs ys) >= max (length xs) (length (ys :: String))I\xs ys -> length (diffBy (==) xs ys) <= length xs + length (ys :: String)Note:g currently this has O(n*m) memory requirements, for the sake of more obviously correct implementation.None  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.     None &',8>SXHf tree-diffB 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" []]] tree-diffDifference between two  values.'let x = (1, Just 2) :: (Int, Maybe Int)let y = (1, Nothing)prettyEditExpr (ediff x y)__ 1 -(Just 2) +Nothingqdata Foo = Foo { fooInt :: Either Char Int, fooBool :: [Maybe Bool], fooString :: String } deriving (Eq, Generic)instance ToExpr FooXprettyEditExpr $ ediff (Foo (Right 2) [Just True] "fo") (Foo (Right 3) [Just True] "fo")CFoo {fooBool = [Just True], fooInt = Right -2 +3, fooString = "fo"}}prettyEditExpr $ ediff (Foo (Right 42) [Just True, Just False] "old") (Foo (Right 42) [Nothing, Just False, Just True] "new")Foo< {fooBool = [-Just True, +Nothing, Just False, +Just True], fooInt = Right 42, fooString = -"old" +"new"} tree-diffCompare different types.Note:? Use with care as you can end up comparing apples with oranges.<prettyEditExpr $ ediff' ["foo", "bar"] [Just "foo", Nothing]'[-"foo", +Just "foo", -"bar", +Nothing] tree-diff8An alternative implementation for literal types. We use  representation of them. tree-diffLprettyExpr $ sopToExpr (gdatatypeInfo (Proxy :: Proxy String)) (gfrom "foo") _:_ 'f' "oo" tree-diff Split on '\n'.(\xs -> xs == concat (unconcat uncons xs)' tree-diffprettyExpr $ toExpr UUID.nil+UUID "00000000-0000-0000-0000-000000000000"( tree-diff+prettyExpr $ toExpr (123.456 :: Scientific)scientific 123456 `-3`) tree-diffutraverse_ (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"]* tree-diffgtraverse_ (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"]+ tree-diffhtraverse_ (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"]- tree-diff-prettyExpr $ toExpr $ ModifiedJulianDay 58014Day "2017-09-18". tree-diffetraverse_ (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"]/ tree-diffftraverse_ (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"]D tree-diff"prettyExpr $ toExpr $ Identity 'a' Identity 'a'F tree-diff(prettyExpr $ toExpr (3 % 12 :: Rational)_%_ 1 4N 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 concatNoneXK[b tree-diff Parsers for   using parsers type-classes.AYou can use this with your parser-combinator library of choice: parsec,  attoparsec, trifecta...bbNone`Ac tree-diff_Because we don't want to commit to single pretty printing library, we use explicit dictionary.n 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 "_,_"`_,_`o tree-diffPretty print an  + using explicit pretty-printing dictionary.p tree-diffPretty print an  + using explicit pretty-printing dictionary.q tree-diffLike p) but print unchanged parts only shallowlyr tree-diffc via pretty library.s tree-diff Pretty print   using pretty.;prettyExpr $ Rec "ex" (Map.fromList [("[]", App "bar" [])])ex {`[]` = bar}t tree-diff Pretty print   using pretty.u tree-diffCompact t.v tree-diffc via ansi-wl-pprint library (with colors).w tree-diff Pretty print   using ansi-wl-pprint.x tree-diff Pretty print   using ansi-wl-pprint.y tree-diffCompact xz tree-diffLike v but color the background.{ tree-diff Pretty print   using ansi-wl-pprint.| tree-diff Pretty print   using ansi-wl-pprint.} tree-diffCompact |.cdefghijklmnopqrstuvwxyz{|}cdefghijklmopqrstuvwxyz{|}n NoneaO4  bcdefghijklmnopqrstuvwxyz{|}Nonel~ tree-diffMake a golden tests.~B is testing framework agnostic, thus the type looks intimidating.An example using  tasty-golden,  goldenTest is imported from Test.Tasty.Golden.Advanced exTest :: TestTree exTest = ~S goldenTest "golden test" "fixtures/ex.expr" $ action constructing actual value The ~ will read an  ; from provided path to golden file, and compare it with a K of a result. If values differ, the (compact) diff of two will be printed.See  >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~~Nonen tree-diff A variant of ===/, which outputs a diff when values are inequal.None 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.ExamplesDLet's start from simple tree. We pretty print them as s-expressions.Nlet 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:Nlet 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)dIf 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:Zlet 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[\]^_`abcdefghijklmmnopqrstuvwxyz{|}~&tree-diff-0.0.2-9tQ1SScxUq75HLTOJKwNFiData.TreeDiff.ListData.TreeDiff.ExprData.TreeDiff.ClassData.TreeDiff.ParserData.TreeDiff.PrettyData.TreeDiff.GoldenData.TreeDiff.QuickCheckData.TreeDiff.Tree Data.TreeDiffEditInsDelCpySwpdiffBy $fShowEditEditExprEditAppEditRecEditLstEditExpExprAppRecLst FieldNameConstructorNameexprDiff$fArbitraryExpr$fEqExpr $fShowExpr$fShowEditExprToExprtoExpr listToExprediffediff'defaultExprViaShow sopToExpr $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$fToExprOption $fToExprLast0$fToExprFirst0$fToExprProduct $fToExprSum $fToExprDual $fToExprVoid$fToExprNonEmpty$fToExprZipList $fToExprConst$fToExprIdentity $fToExprFixed $fToExprRatio$fToExpr(,,,,) $fToExpr(,,,) $fToExpr(,,) $fToExpr(,) $fToExpr[]$fToExprEither $fToExprMaybe $fToExprChar $fToExprProxy$fToExprWord64$fToExprWord32$fToExprWord16 $fToExprWord8 $fToExprWord $fToExprInt64 $fToExprInt32 $fToExprInt16 $fToExprInt8 $fToExprInt$fToExprDouble $fToExprFloat$fToExprNatural$fToExprInteger$fToExprOrdering $fToExprBool $fToExpr() $fToExprExpr exprParserPrettyppConppRecppLstppCpyppInsppDelppSepppParensppHang escapeNameppExpr ppEditExprppEditExprCompact prettyPretty prettyExprprettyEditExprprettyEditExprCompact ansiWlPretty ansiWlExpransiWlEditExpransiWlEditExprCompactansiWlBgPretty ansiWlBgExpransiWlBgEditExpransiWlBgEditExprCompact ediffGoldenediffEqEditTreeEditNodetreeDiff$fShowEditTreebaseGHC.Showshowunconcat stringToExprcontainers-0.6.0.1 Data.TreeTree