From 7dbc27396115e2acb41b7b9c2fd419e2f2b32d57 Mon Sep 17 00:00:00 2001 From: Frederick Pringle Date: Sat, 31 Jan 2026 22:23:40 +0100 Subject: [PATCH 1/6] Move the main library into its own subdirectory --- cabal.project | 2 +- CHANGELOG.md => generic-diff/CHANGELOG.md | 0 LICENSE => generic-diff/LICENSE | 0 README.md => generic-diff/README.md | 0 generic-diff.cabal => generic-diff/generic-diff.cabal | 0 {src => generic-diff/src}/Generics/Diff.hs | 0 {src => generic-diff/src}/Generics/Diff/Class.hs | 0 {src => generic-diff/src}/Generics/Diff/Instances.hs | 0 {src => generic-diff/src}/Generics/Diff/Render.hs | 0 {src => generic-diff/src}/Generics/Diff/Special.hs | 0 {src => generic-diff/src}/Generics/Diff/Special/List.hs | 0 {src => generic-diff/src}/Generics/Diff/Type.hs | 0 {test => generic-diff/test}/Generics/Diff/PropertyTestsSpec.hs | 0 {test => generic-diff/test}/Generics/Diff/UnitTestsSpec.hs | 0 {test => generic-diff/test}/Spec.hs | 0 {test => generic-diff/test}/Util.hs | 0 16 files changed, 1 insertion(+), 1 deletion(-) rename CHANGELOG.md => generic-diff/CHANGELOG.md (100%) rename LICENSE => generic-diff/LICENSE (100%) rename README.md => generic-diff/README.md (100%) rename generic-diff.cabal => generic-diff/generic-diff.cabal (100%) rename {src => generic-diff/src}/Generics/Diff.hs (100%) rename {src => generic-diff/src}/Generics/Diff/Class.hs (100%) rename {src => generic-diff/src}/Generics/Diff/Instances.hs (100%) rename {src => generic-diff/src}/Generics/Diff/Render.hs (100%) rename {src => generic-diff/src}/Generics/Diff/Special.hs (100%) rename {src => generic-diff/src}/Generics/Diff/Special/List.hs (100%) rename {src => generic-diff/src}/Generics/Diff/Type.hs (100%) rename {test => generic-diff/test}/Generics/Diff/PropertyTestsSpec.hs (100%) rename {test => generic-diff/test}/Generics/Diff/UnitTestsSpec.hs (100%) rename {test => generic-diff/test}/Spec.hs (100%) rename {test => generic-diff/test}/Util.hs (100%) diff --git a/cabal.project b/cabal.project index 1698ce8..0c0cb21 100644 --- a/cabal.project +++ b/cabal.project @@ -1,3 +1,3 @@ packages: - ./generic-diff.cabal + ./generic-diff/generic-diff.cabal examples/containers-instances/generic-diff-containers.cabal diff --git a/CHANGELOG.md b/generic-diff/CHANGELOG.md similarity index 100% rename from CHANGELOG.md rename to generic-diff/CHANGELOG.md diff --git a/LICENSE b/generic-diff/LICENSE similarity index 100% rename from LICENSE rename to generic-diff/LICENSE diff --git a/README.md b/generic-diff/README.md similarity index 100% rename from README.md rename to generic-diff/README.md diff --git a/generic-diff.cabal b/generic-diff/generic-diff.cabal similarity index 100% rename from generic-diff.cabal rename to generic-diff/generic-diff.cabal diff --git a/src/Generics/Diff.hs b/generic-diff/src/Generics/Diff.hs similarity index 100% rename from src/Generics/Diff.hs rename to generic-diff/src/Generics/Diff.hs diff --git a/src/Generics/Diff/Class.hs b/generic-diff/src/Generics/Diff/Class.hs similarity index 100% rename from src/Generics/Diff/Class.hs rename to generic-diff/src/Generics/Diff/Class.hs diff --git a/src/Generics/Diff/Instances.hs b/generic-diff/src/Generics/Diff/Instances.hs similarity index 100% rename from src/Generics/Diff/Instances.hs rename to generic-diff/src/Generics/Diff/Instances.hs diff --git a/src/Generics/Diff/Render.hs b/generic-diff/src/Generics/Diff/Render.hs similarity index 100% rename from src/Generics/Diff/Render.hs rename to generic-diff/src/Generics/Diff/Render.hs diff --git a/src/Generics/Diff/Special.hs b/generic-diff/src/Generics/Diff/Special.hs similarity index 100% rename from src/Generics/Diff/Special.hs rename to generic-diff/src/Generics/Diff/Special.hs diff --git a/src/Generics/Diff/Special/List.hs b/generic-diff/src/Generics/Diff/Special/List.hs similarity index 100% rename from src/Generics/Diff/Special/List.hs rename to generic-diff/src/Generics/Diff/Special/List.hs diff --git a/src/Generics/Diff/Type.hs b/generic-diff/src/Generics/Diff/Type.hs similarity index 100% rename from src/Generics/Diff/Type.hs rename to generic-diff/src/Generics/Diff/Type.hs diff --git a/test/Generics/Diff/PropertyTestsSpec.hs b/generic-diff/test/Generics/Diff/PropertyTestsSpec.hs similarity index 100% rename from test/Generics/Diff/PropertyTestsSpec.hs rename to generic-diff/test/Generics/Diff/PropertyTestsSpec.hs diff --git a/test/Generics/Diff/UnitTestsSpec.hs b/generic-diff/test/Generics/Diff/UnitTestsSpec.hs similarity index 100% rename from test/Generics/Diff/UnitTestsSpec.hs rename to generic-diff/test/Generics/Diff/UnitTestsSpec.hs diff --git a/test/Spec.hs b/generic-diff/test/Spec.hs similarity index 100% rename from test/Spec.hs rename to generic-diff/test/Spec.hs diff --git a/test/Util.hs b/generic-diff/test/Util.hs similarity index 100% rename from test/Util.hs rename to generic-diff/test/Util.hs From e88f6c4d0cf5cfd10c0d3bf807a497ed54ef5592 Mon Sep 17 00:00:00 2001 From: Frederick Pringle Date: Sat, 31 Jan 2026 22:43:21 +0100 Subject: [PATCH 2/6] Move example `containers` instances to a real package `generic-diff-instances` --- cabal.project | 2 +- generic-diff-instances/CHANGELOG.md | 14 +++++++++ generic-diff-instances/LICENSE | 30 +++++++++++++++++++ generic-diff-instances/README.md | 12 ++++++++ .../generic-diff-instances.cabal | 21 +++++++++---- .../src/Generics/Diff/Special/Map.hs | 0 .../src/Generics/Diff/Special/Seq.hs | 0 .../src/Generics/Diff/Special/Set.hs | 0 .../src/Generics/Diff/Special/Tree.hs | 0 .../test/Generics/Diff/PropertyTestsSpec.hs | 0 .../test/Generics/Diff/UnitTestsSpec.hs | 0 .../test/Spec.hs | 0 .../test/Util.hs | 0 13 files changed, 73 insertions(+), 6 deletions(-) create mode 100644 generic-diff-instances/CHANGELOG.md create mode 100644 generic-diff-instances/LICENSE create mode 100644 generic-diff-instances/README.md rename examples/containers-instances/generic-diff-containers.cabal => generic-diff-instances/generic-diff-instances.cabal (73%) rename {examples/containers-instances => generic-diff-instances}/src/Generics/Diff/Special/Map.hs (100%) rename {examples/containers-instances => generic-diff-instances}/src/Generics/Diff/Special/Seq.hs (100%) rename {examples/containers-instances => generic-diff-instances}/src/Generics/Diff/Special/Set.hs (100%) rename {examples/containers-instances => generic-diff-instances}/src/Generics/Diff/Special/Tree.hs (100%) rename {examples/containers-instances => generic-diff-instances}/test/Generics/Diff/PropertyTestsSpec.hs (100%) rename {examples/containers-instances => generic-diff-instances}/test/Generics/Diff/UnitTestsSpec.hs (100%) rename {examples/containers-instances => generic-diff-instances}/test/Spec.hs (100%) rename {examples/containers-instances => generic-diff-instances}/test/Util.hs (100%) diff --git a/cabal.project b/cabal.project index 0c0cb21..46245a5 100644 --- a/cabal.project +++ b/cabal.project @@ -1,3 +1,3 @@ packages: ./generic-diff/generic-diff.cabal - examples/containers-instances/generic-diff-containers.cabal + ./generic-diff-instances/generic-diff-instances.cabal diff --git a/generic-diff-instances/CHANGELOG.md b/generic-diff-instances/CHANGELOG.md new file mode 100644 index 0000000..dd4040f --- /dev/null +++ b/generic-diff-instances/CHANGELOG.md @@ -0,0 +1,14 @@ +# Changelog + +All notable changes to `generic-diff-instances` will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), +and this project adheres to [Haskell Package Versioning Policy](https://pvp.haskell.org). + +## [Unreleased] + +### Added + +- `Diff` instances for `Map`, `Seq`, `Set` and `Tree` from `containers`. + +[unreleased]: https://github.com/fpringle/generic-diff/compare/7dbc273...HEAD diff --git a/generic-diff-instances/LICENSE b/generic-diff-instances/LICENSE new file mode 100644 index 0000000..fc423c4 --- /dev/null +++ b/generic-diff-instances/LICENSE @@ -0,0 +1,30 @@ +Copyright (c) 2025, Frederick Pringle + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + * Neither the name of Frederick Pringle nor the names of other + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/generic-diff-instances/README.md b/generic-diff-instances/README.md new file mode 100644 index 0000000..00277e6 --- /dev/null +++ b/generic-diff-instances/README.md @@ -0,0 +1,12 @@ +[![Haskell CI](https://github.com/fpringle/generic-diff/actions/workflows/haskell.yml/badge.svg)](https://github.com/fpringle/generic-diff/actions/workflows/haskell.yml) + +# `generic-diff` instances + +The [generic-diff](https://hackage.haskell.org/package/generic-diff) package +aims to be lightweight and not force any instances which might have more than +one interpretation. + +This package provides a more comprehensive set of instances for types from a +range of common packages. + +Currently we provide instances for [Map](https://hackage-content.haskell.org/package/containers-0.8/docs/Data-Map-Lazy.html#t:Map), [Seq](https://hackage-content.haskell.org/package/containers-0.8/docs/Data-Sequence.html#t:Seq), [Set](https://hackage-content.haskell.org/package/containers-0.8/docs/Data-Set.html#t:Set) and [Tree](https://hackage-content.haskell.org/package/containers-0.8/docs/Data-Tree.html#t:Tree) from the containers package. diff --git a/examples/containers-instances/generic-diff-containers.cabal b/generic-diff-instances/generic-diff-instances.cabal similarity index 73% rename from examples/containers-instances/generic-diff-containers.cabal rename to generic-diff-instances/generic-diff-instances.cabal index 0082578..bd4a161 100644 --- a/examples/containers-instances/generic-diff-containers.cabal +++ b/generic-diff-instances/generic-diff-instances.cabal @@ -1,12 +1,23 @@ cabal-version: 3.0 -name: generic-diff-containers +name: generic-diff-instances version: 0.1.0.0 +synopsis: Diff instances for common types +description: + The [generic-diff](https://hackage.haskell.org/package/generic-diff) package + aims to be lightweight and not force any instances which might have more than + one interpretation. + + This package provides a more comprehensive set of instances for types from a + range of common packages. license: BSD-3-Clause author: Frederick Pringle maintainer: freddyjepringle@gmail.com copyright: Copyright(c) Frederick Pringle 2025 homepage: https://github.com/fpringle/generic-diff +category: Generics, Test build-type: Simple +extra-doc-files: CHANGELOG.md + README.md tested-with: GHC == 9.12.2 GHC == 9.10.1 @@ -24,11 +35,11 @@ common warnings common deps build-depends: , base >= 4.12 && < 5 - , generic-diff + , generic-diff >= 0.1 && < 0.2 , sop-core >= 0.4.0.1 && < 0.6 , generics-sop >= 0.4 && < 0.6 , text >= 1.1 && < 2.2 - , containers + , containers >= 0.5.9.2 && < 0.9 common extensions default-extensions: @@ -67,7 +78,7 @@ library hs-source-dirs: src default-language: Haskell2010 -test-suite generic-diff-containers-test +test-suite generic-diff-instances-test import: warnings , deps @@ -85,6 +96,6 @@ test-suite generic-diff-containers-test ghc-options: -Wno-orphans build-depends: , generic-diff - , generic-diff-containers + , generic-diff-instances , QuickCheck , hspec diff --git a/examples/containers-instances/src/Generics/Diff/Special/Map.hs b/generic-diff-instances/src/Generics/Diff/Special/Map.hs similarity index 100% rename from examples/containers-instances/src/Generics/Diff/Special/Map.hs rename to generic-diff-instances/src/Generics/Diff/Special/Map.hs diff --git a/examples/containers-instances/src/Generics/Diff/Special/Seq.hs b/generic-diff-instances/src/Generics/Diff/Special/Seq.hs similarity index 100% rename from examples/containers-instances/src/Generics/Diff/Special/Seq.hs rename to generic-diff-instances/src/Generics/Diff/Special/Seq.hs diff --git a/examples/containers-instances/src/Generics/Diff/Special/Set.hs b/generic-diff-instances/src/Generics/Diff/Special/Set.hs similarity index 100% rename from examples/containers-instances/src/Generics/Diff/Special/Set.hs rename to generic-diff-instances/src/Generics/Diff/Special/Set.hs diff --git a/examples/containers-instances/src/Generics/Diff/Special/Tree.hs b/generic-diff-instances/src/Generics/Diff/Special/Tree.hs similarity index 100% rename from examples/containers-instances/src/Generics/Diff/Special/Tree.hs rename to generic-diff-instances/src/Generics/Diff/Special/Tree.hs diff --git a/examples/containers-instances/test/Generics/Diff/PropertyTestsSpec.hs b/generic-diff-instances/test/Generics/Diff/PropertyTestsSpec.hs similarity index 100% rename from examples/containers-instances/test/Generics/Diff/PropertyTestsSpec.hs rename to generic-diff-instances/test/Generics/Diff/PropertyTestsSpec.hs diff --git a/examples/containers-instances/test/Generics/Diff/UnitTestsSpec.hs b/generic-diff-instances/test/Generics/Diff/UnitTestsSpec.hs similarity index 100% rename from examples/containers-instances/test/Generics/Diff/UnitTestsSpec.hs rename to generic-diff-instances/test/Generics/Diff/UnitTestsSpec.hs diff --git a/examples/containers-instances/test/Spec.hs b/generic-diff-instances/test/Spec.hs similarity index 100% rename from examples/containers-instances/test/Spec.hs rename to generic-diff-instances/test/Spec.hs diff --git a/examples/containers-instances/test/Util.hs b/generic-diff-instances/test/Util.hs similarity index 100% rename from examples/containers-instances/test/Util.hs rename to generic-diff-instances/test/Util.hs From 5e591e13af5ee0ce740fa484d36c971837338d76 Mon Sep 17 00:00:00 2001 From: Frederick Pringle Date: Sat, 31 Jan 2026 22:43:39 +0100 Subject: [PATCH 3/6] [minor] link to instances package from `generic-diff` --- generic-diff/generic-diff.cabal | 3 +++ 1 file changed, 3 insertions(+) diff --git a/generic-diff/generic-diff.cabal b/generic-diff/generic-diff.cabal index 1b05339..746b9d0 100644 --- a/generic-diff/generic-diff.cabal +++ b/generic-diff/generic-diff.cabal @@ -7,6 +7,9 @@ description: using [generics-sop](https://hackage.haskell.org/package/generics-sop). See the module documentation in "Generics.Diff". + + For a wider range of instances for common types, see + [generic-diff-instances](https://hackage.haskell.org/package/generic-diff-instances). license: BSD-3-Clause license-file: LICENSE author: Frederick Pringle From c9c966b37c651ab32c4dbdd711e539e8febcaef3 Mon Sep 17 00:00:00 2001 From: Frederick Pringle Date: Sat, 31 Jan 2026 22:55:17 +0100 Subject: [PATCH 4/6] Main readme --- README.md | 5 +++++ generic-diff/README.md | 2 -- 2 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..726bfdb --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +[![Haskell CI](https://github.com/fpringle/generic-diff/actions/workflows/haskell.yml/badge.svg)](https://github.com/fpringle/generic-diff/actions/workflows/haskell.yml) + +`generic-diff` provides a typeclass-based way to structurally compare values of the same type. + +See [generic-diff](./generic-diff#readme) for the core package, or [generic-diff-instances](./generic-diff-instances#readme) for a more "batteries-included" set of instances. diff --git a/generic-diff/README.md b/generic-diff/README.md index a25177b..61d5ad4 100644 --- a/generic-diff/README.md +++ b/generic-diff/README.md @@ -1,5 +1,3 @@ -[![Haskell CI](https://github.com/fpringle/generic-diff/actions/workflows/haskell.yml/badge.svg)](https://github.com/fpringle/generic-diff/actions/workflows/haskell.yml) - # Generic structural diffs `generic-diff` lets us pinpoint exactly where two values differ, which can be very useful, for example for debugging failing tests. From 76db8772e27c152001132d7ef2400bd67a1083f4 Mon Sep 17 00:00:00 2001 From: Frederick Pringle Date: Sat, 31 Jan 2026 23:04:37 +0100 Subject: [PATCH 5/6] Fix a haddock comment refering to the old `examples/` directory --- generic-diff/src/Generics/Diff/Type.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/generic-diff/src/Generics/Diff/Type.hs b/generic-diff/src/Generics/Diff/Type.hs index 170d611..519493f 100644 --- a/generic-diff/src/Generics/Diff/Type.hs +++ b/generic-diff/src/Generics/Diff/Type.hs @@ -81,8 +81,8 @@ such as lists (see 'ListDiffError'), or even user-defined types that internally or have unusual 'Eq' instances. In this case we can implement an instance of 'SpecialDiff' for the type. -For concrete examples implementing 'SpecialDiff' on types from "containers", see the -[examples/containers-instances](https://github.com/fpringle/generic-diff/tree/main/examples/containers-instances) +For concrete implementations of 'SpecialDiff' on types from "containers", see +[generic-diff-instances](https://hackage.haskell.org/package/generic-diff-instances). directory. -} class (Show (SpecialDiffError a), Eq (SpecialDiffError a)) => SpecialDiff a where From 5757cbaa28aad474227c5fc88b89b8ef69a1c33f Mon Sep 17 00:00:00 2001 From: Frederick Pringle Date: Sun, 1 Feb 2026 13:35:31 +0100 Subject: [PATCH 6/6] Minor documentation changes --- generic-diff-instances/src/Generics/Diff/Special/Map.hs | 6 +----- generic-diff-instances/src/Generics/Diff/Special/Set.hs | 9 ++++----- generic-diff-instances/src/Generics/Diff/Special/Tree.hs | 9 ++++++++- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/generic-diff-instances/src/Generics/Diff/Special/Map.hs b/generic-diff-instances/src/Generics/Diff/Special/Map.hs index 09065fd..020c35b 100644 --- a/generic-diff-instances/src/Generics/Diff/Special/Map.hs +++ b/generic-diff-instances/src/Generics/Diff/Special/Map.hs @@ -30,7 +30,7 @@ data MapDiffError k v deriving (Show, Eq) {- | Render a 'MapDiffError'. This is a top-level function because we'll use it in the implementations -of 'renderSpecialDiffError' for both 'Map' and 'IntMap'. +of 'renderSpecialDiffError' for both 'Map' and 'Data.IntMap.IntMap'. -} mapDiffErrorDoc :: (Show k) => MapDiffError k v -> Doc mapDiffErrorDoc = \case @@ -43,9 +43,6 @@ mapDiffErrorDoc = \case RightMissingKey k -> linesDoc $ pure $ "The left map contains key " <> showB k <> " but the right doesn't" ------------------------------------------------------------- --- Map - instance (Show k, Ord k, Diff v) => SpecialDiff (Map k v) where type SpecialDiffError (Map k v) = MapDiffError k v @@ -67,6 +64,5 @@ instance (Show k, Ord k, Diff v) => SpecialDiff (Map k v) where renderSpecialDiffError = mapDiffErrorDoc --- | Now we can implement 'Diff' using 'diffWithSpecial'. instance (Show k, Ord k, Diff v) => Diff (Map k v) where diff = diffWithSpecial diff --git a/generic-diff-instances/src/Generics/Diff/Special/Set.hs b/generic-diff-instances/src/Generics/Diff/Special/Set.hs index e04a3d4..c660d53 100644 --- a/generic-diff-instances/src/Generics/Diff/Special/Set.hs +++ b/generic-diff-instances/src/Generics/Diff/Special/Set.hs @@ -31,7 +31,7 @@ data SetDiffError k deriving (Show, Eq) {- | Render a 'SetDiffError'. This is a top-level function because we'll use it in the implementations -of 'renderSpecialDiffError' for both 'Set' and 'IntSet'. +of 'renderSpecialDiffError' for both 'Set' and 'Data.IntSet.IntSet'. There are no nested 'DiffError's here, so we use 'linesDoc'. -} @@ -42,9 +42,8 @@ setDiffErrorDoc = \case RightMissingKey k -> linesDoc $ pure $ "The left set contains key " <> showB k <> " but the right doesn't" -{- | First we define an instance of 'SpecialDiff'. We need 'Show' and 'Eq' so that 'SetDiffError' -also has these instances; we need 'Ord' to compare elements of the set. --} +-- First we define an instance of 'SpecialDiff'. We need 'Show' and 'Eq' so that 'SetDiffError' +-- also has these instances; we need 'Ord' to compare elements of the set. instance (Show k, Eq k, Ord k) => SpecialDiff (Set k) where type SpecialDiffError (Set k) = SetDiffError k @@ -62,6 +61,6 @@ instance (Show k, Eq k, Ord k) => SpecialDiff (Set k) where renderSpecialDiffError = setDiffErrorDoc --- | Now we can implement 'Diff' using 'diffWithSpecial'. +-- Now we can implement 'Diff' using 'diffWithSpecial'. instance (Show k, Ord k) => Diff (Set k) where diff = diffWithSpecial diff --git a/generic-diff-instances/src/Generics/Diff/Special/Tree.hs b/generic-diff-instances/src/Generics/Diff/Special/Tree.hs index 436a202..b628e89 100644 --- a/generic-diff-instances/src/Generics/Diff/Special/Tree.hs +++ b/generic-diff-instances/src/Generics/Diff/Special/Tree.hs @@ -1,7 +1,7 @@ {-# LANGUAGE DerivingVia #-} {-# OPTIONS_GHC -Wno-orphans #-} -{- | A worked example of implementing 'SpecialDiff' (and thereby 'Diff') for 'Tree's. +{- | A worked example of implementing 'SpecialDiff' (and thereby 'Diff') for 'Tree.Tree's. As with other 3rd-party types, there are different approaches we can take here. We'll show 2 of them: @@ -22,6 +22,7 @@ import Generics.SOP.GGP ------------------------------------------------------------ -- Using gspecialDiffNested +-- | Generically-derived instance. instance (Diff a) => SpecialDiff (Tree.Tree a) where type SpecialDiffError (Tree.Tree a) = DiffErrorNested (GCode (Tree.Tree a)) specialDiff = gspecialDiffNested @@ -33,17 +34,23 @@ instance (Diff a) => Diff (Tree.Tree a) where ------------------------------------------------------------ -- Using SpecialDiff +{- | A newtype wrapper around 'Tree.Tree' to demonstrate one alternate way we could hand-write +a 'SpecialDiff' instance. +-} newtype CustomTree a = CustomTree (Tree.Tree a) deriving (Show) via (Tree.Tree a) +-- | Where are we in the tree? Each element of the list says which child node we step to next. newtype TreePath = TreePath [Int] deriving (Show, Eq) via [Int] +-- | A custom error type for 'CustomTree'. data CustomTreeDiffError a = DiffAtNode TreePath (DiffError a) | WrongLengthsOfChildren TreePath Int Int deriving (Show, Eq) +-- | Render a tree path as a 'TB.Builder' renderTreePath :: TreePath -> TB.Builder renderTreePath (TreePath []) = "" renderTreePath (TreePath (x : xs)) = mconcat $ showB x : ["->" <> showB y | y <- xs]