patch

Data structures for describing changes to other data structures.

https://obsidian.systems

Stackage Nightly 2025-04-24:0.0.8.4
Latest on Hackage:0.0.8.4

See all snapshots patch appears in

BSD-3-Clause licensed by Ryan Trinkle
Maintained by [email protected]
This version can be pinned in stack with:patch-0.0.8.4@sha256:00904a2f2e6b9bef71b12a5200bc047d6e108af3ad74954eed1795e419949bed,3368

patch

Haskell Hackage BSD3 License

Data structures for describing changes to other data structures.

A Patch type represents a kind of change made to a data structure.

class Patch p where
  type PatchTarget p :: *
  -- | Apply the patch p a to the value a.  If no change is needed, return
  -- 'Nothing'.
  apply :: p -> PatchTarget p -> Maybe (PatchTarget p)

Patching Maps

For example, Data.Patch.Map defines the PatchMap type which can be used to patch Maps. A PatchMap represents updates to a Map that can insert, remove, or replace items in the Map. In this example, the Map is the PatchTarget and the PatchMap is the Patch. Keep in mind that there are many other possible Patches that can be applied to a Map (i.e., Map can be the PatchTarget for many different Patch instances).

PatchMap is defined as:

newtype PatchMap k v = PatchMap { unPatchMap :: Map k (Maybe v) }

The Maybe around the value is used to represent insertion/updates or deletion of the element at a given key.

Its Patch instance begins with:

instance Ord k => Patch (PatchMap k v) where
  type PatchTarget (PatchMap k v) = Map k v
  ...

When a PatchMap is applied to its PatchTarget, the following changes can occur:

  • If the key is present in the Patch and the PatchTarget

    • And the Patch value at that key is Nothing: delete that key from the PatchTarget.

    • And the Patch value at that key is Just x: update the value at that key in the PatchTarget to x.

  • If the key is present in the Patch and not present in the PatchTarget

    • And the Patch value at that key is Nothing: do nothing because we’re trying to delete a key that doesn’t exist in the target in the first place.

    • And the Patch value at that key is Just x: insert the key and the value x into the PatchTarget

  • If the key is not present in the Patch but present in the PatchTarget: do nothing.

There are, of course, more complicated ways of patching maps involving, for example, moving values from one key to another. You can find the code for that in Data.Patch.PatchMapWithMove. Note that the PatchTarget type associated with the PatchMapWithMove patch instance is still Map k v!

Changes

Revision history for patch

0.0.8.4

  • Support for GHC 9.12

0.0.8.3

  • Add support for GHC 9.8 and 9.10

  • Replace partial Map.lookup with proper custom error for internal error. (This would make debugging a bug in the implementation easier.)

0.0.8.2

  • Add support for GHC 9.6

0.0.8.1

  • Add support for GHC 9.2 and 9.4

0.0.8.0 - 2022-12-09

  • Drop support for GHC 8.0 and 8.2. It may still be possible to use this library with those versions of GHC, but we do not guarantee or test it anymore.
  • Fix an issue where (<>) crashed for some PatchMapWithPatchingMoves.
  • Change DecidablyEmpty for Sum and Product to use Num and Eq rather than delegating to the argument type’s DecidablyEmpty class. Since Sum and Product have Monoid actions and units that are inherently based on Num, it makes sense to have a DecidablyEmpty instances that inherently agree with that. Also, since Int and other numeric types don’t have (and can’t reasonably have) DecidablyEmpty instances, this is necessary to make them actually usable in this context.

0.0.7.0 - 2022-06-23

  • Use commutative-semigroups for Commutative, making Additive a deprecated alias.

0.0.6.0 - 2022-06-10

  • Add PatchOrReplacement, patch which either is some other patch type or a new replacement value.

  • Support GHC 9.2

0.0.5.2 - 2022-01-09

  • Correct field order of PatchMapWithMove.NodeInfo.

    When we this was reimplemented as a pattern synonym wrapper in 0.0.5.0, we accidentally flipped the argument order. Reversing it now to match 0.0.4.0 and restore compatibility. The previous releases in the 0.0.5.* series will correspondingly be deprecated.

0.0.5.1 - 2021-12-28

  • New dep of base-orphans for old GHC to get instances honestly instead of via monoidal-containers.

0.0.5.0 - 2021-12-17

  • Additive now lives in Data.Semigroup.Additive, but is still reexported from Data.Patch for compatability.

  • Rewrite PatchMapWithMove in terms of PatchMapWithPatchingMove. Care is taken to make this not a breaking change. In particular, PatchMapWithMove is a newtype of PatchMapWithPatchingMove, as is the NodeInfo and From of PatchMapWithPatchingMove’s versions of those. There are complete constructor and field patterns too, and everything is exported under the newtype as real constructors and fields would be.

0.0.4.0 - 2021-04-20

  • Enable PolyKinds

0.0.3.2 - 2020-11-06

  • Update version bounds

0.0.3.1 - 2020-02-05

  • Replace fromJust with something easier to debug.

0.0.3.0 - 2020-02-05

  • Create PatchMapWithPatchingMove variant which supports moves with a patch.

  • Create DecidablyEmpty subclass of Monoid.

0.0.2.0 - 2020-01-17

  • Consistently provide:

    • Wrapped instances

    • *WithIndex instances

    • un* newtype unwrappers

    for PatchMap, PatchIntMap, and PatchMapWithMove.

0.0.1.0 - 2020-01-09

  • Support older GHCs with split-these flag.

  • Additional instances for the Group class for basic types.

0.0.0.1 - 2020-01-08

  • Remove unneeded dependencies

0.0.0.0 - 2020-01-08

  • Extract patching functionality from Reflex.