pattern
Safe HaskellSafe-Inferred
LanguageHaskell2010

Pattern.Reconcile

Description

Pattern reconciliation for normalizing duplicate identities.

This module provides operations to reconcile patterns by resolving duplicate identities and completing partial references. When patterns are parsed, streamed, or merged from multiple sources, the same identity may appear multiple times with different or evolving content. Reconciliation transforms such patterns into coherent ones where each identity appears exactly once.

Problem Statement

Currently nothing prevents the same identity from appearing multiple times with different content in a Pattern v. This can arise from:

  • Parsing gram notation with duplicate node definitions
  • Streaming pattern updates where identities evolve over time
  • Merging patterns from different sources
  • References: atomic patterns pointing to fuller definitions elsewhere

Solution Overview

The reconcile operation normalizes patterns using configurable policies:

  1. **Collect**: Group all occurrences by identity
  2. **Reconcile**: Resolve duplicates according to policy
  3. **Rebuild**: Construct normalized pattern with each identity appearing once

Quick Start

>>> import Pattern.Core (Pattern(..), pattern, point)
>>> import Pattern.Reconcile
>>> import Subject.Core (Subject(..), Symbol(..))
>>> 
>>> -- Reconcile with LastWriteWins policy
>>> reconcile LastWriteWins patternWithDuplicates
>>> 
>>> -- Get detailed report
>>> let (result, report) = reconcileWithReport LastWriteWins pattern
>>> reportDuplicatesFound report  -- Number of duplicate identities

Reconciliation Policies

  • LastWriteWins - Keep the last occurrence of each identity. Useful for streaming updates where the most recent value is authoritative.
  • FirstWriteWins - Keep the first occurrence of each identity. Useful when initial definitions are authoritative.
  • Merge elementStrategy valueStrategy - Combine all occurrences using configurable strategies for structure (elements) and content (value).
  • Strict - Fail with detailed error if any duplicates have different content. Useful for validation and debugging.
Synopsis

Core Abstractions

class Ord i => HasIdentity v i | v -> i where Source #

Allows extracting a unique identifier from a value.

Methods

identity :: v -> i Source #

Instances

Instances details
HasIdentity Subject Symbol Source # 
Instance details

Defined in Pattern.Reconcile

class Mergeable v where Source #

Allows merging two values according to a strategy.

Associated Types

type MergeStrategy v Source #

Configuration for how to merge this specific type

Methods

merge :: MergeStrategy v -> v -> v -> v Source #

Merge two values. The first value is the "accumulated" or "existing" one, the second is the "incoming" one.

Instances

Instances details
Mergeable Subject Source # 
Instance details

Defined in Pattern.Reconcile

Associated Types

type MergeStrategy Subject 
Instance details

Defined in Pattern.Reconcile

class Refinable v where Source #

Allows checking if one value is a "partial" version of another.

Methods

isRefinementOf :: v -> v -> Bool Source #

Returns True if sub contains a subset of the information in sup. Used to detect if an atomic pattern is a reference to a full definition.

Instances

Instances details
Refinable Subject Source # 
Instance details

Defined in Pattern.Reconcile

Reconciliation Policies

data ReconciliationPolicy s Source #

Policy for resolving duplicate identities during reconciliation.

When a pattern contains the same identity multiple times (determined by comparing identity values), a reconciliation policy determines how to combine or choose between the duplicate occurrences.

The type parameter s is the value-specific merge strategy (e.g., SubjectMergeStrategy).

Constructors

LastWriteWins

Keep the last occurrence of each identity. Useful for streaming updates where the most recent value is authoritative.

FirstWriteWins

Keep the first occurrence of each identity. Useful when initial definitions are authoritative and later ones are ignored.

Merge ElementMergeStrategy s

Combine all occurrences using specified strategies for elements and values.

Strict

Fail if any duplicate identities have different content.

Instances

Instances details
Generic (ReconciliationPolicy s) Source # 
Instance details

Defined in Pattern.Reconcile

Associated Types

type Rep (ReconciliationPolicy s) 
Instance details

Defined in Pattern.Reconcile

type Rep (ReconciliationPolicy s) = D1 ('MetaData "ReconciliationPolicy" "Pattern.Reconcile" "pattern-0.4.0.0-inplace" 'False) ((C1 ('MetaCons "LastWriteWins" 'PrefixI 'False) (U1 :: Type -> Type) :+: C1 ('MetaCons "FirstWriteWins" 'PrefixI 'False) (U1 :: Type -> Type)) :+: (C1 ('MetaCons "Merge" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 ElementMergeStrategy) :*: S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 s)) :+: C1 ('MetaCons "Strict" 'PrefixI 'False) (U1 :: Type -> Type)))
Show s => Show (ReconciliationPolicy s) Source # 
Instance details

Defined in Pattern.Reconcile

Eq s => Eq (ReconciliationPolicy s) Source # 
Instance details

Defined in Pattern.Reconcile

type Rep (ReconciliationPolicy s) Source # 
Instance details

Defined in Pattern.Reconcile

type Rep (ReconciliationPolicy s) = D1 ('MetaData "ReconciliationPolicy" "Pattern.Reconcile" "pattern-0.4.0.0-inplace" 'False) ((C1 ('MetaCons "LastWriteWins" 'PrefixI 'False) (U1 :: Type -> Type) :+: C1 ('MetaCons "FirstWriteWins" 'PrefixI 'False) (U1 :: Type -> Type)) :+: (C1 ('MetaCons "Merge" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 ElementMergeStrategy) :*: S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 s)) :+: C1 ('MetaCons "Strict" 'PrefixI 'False) (U1 :: Type -> Type)))

data ElementMergeStrategy Source #

Strategy for merging the children (elements) of a pattern.

Constructors

ReplaceElements

Later element list completely replaces earlier ones.

AppendElements

Concatenate all element lists in traversal order.

UnionElements

Deduplicate elements by identity.

Instances

Instances details
Generic ElementMergeStrategy Source # 
Instance details

Defined in Pattern.Reconcile

Associated Types

type Rep ElementMergeStrategy 
Instance details

Defined in Pattern.Reconcile

type Rep ElementMergeStrategy = D1 ('MetaData "ElementMergeStrategy" "Pattern.Reconcile" "pattern-0.4.0.0-inplace" 'False) (C1 ('MetaCons "ReplaceElements" 'PrefixI 'False) (U1 :: Type -> Type) :+: (C1 ('MetaCons "AppendElements" 'PrefixI 'False) (U1 :: Type -> Type) :+: C1 ('MetaCons "UnionElements" 'PrefixI 'False) (U1 :: Type -> Type)))
Show ElementMergeStrategy Source # 
Instance details

Defined in Pattern.Reconcile

Eq ElementMergeStrategy Source # 
Instance details

Defined in Pattern.Reconcile

type Rep ElementMergeStrategy Source # 
Instance details

Defined in Pattern.Reconcile

type Rep ElementMergeStrategy = D1 ('MetaData "ElementMergeStrategy" "Pattern.Reconcile" "pattern-0.4.0.0-inplace" 'False) (C1 ('MetaCons "ReplaceElements" 'PrefixI 'False) (U1 :: Type -> Type) :+: (C1 ('MetaCons "AppendElements" 'PrefixI 'False) (U1 :: Type -> Type) :+: C1 ('MetaCons "UnionElements" 'PrefixI 'False) (U1 :: Type -> Type)))

data SubjectMergeStrategy Source #

Strategy for merging Subject content.

Instances

Instances details
Generic SubjectMergeStrategy Source # 
Instance details

Defined in Pattern.Reconcile

Associated Types

type Rep SubjectMergeStrategy 
Instance details

Defined in Pattern.Reconcile

type Rep SubjectMergeStrategy = D1 ('MetaData "SubjectMergeStrategy" "Pattern.Reconcile" "pattern-0.4.0.0-inplace" 'False) (C1 ('MetaCons "SubjectMergeStrategy" 'PrefixI 'True) (S1 ('MetaSel ('Just "labelMerge") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 LabelMerge) :*: S1 ('MetaSel ('Just "propertyMerge") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 PropertyMerge)))
Show SubjectMergeStrategy Source # 
Instance details

Defined in Pattern.Reconcile

Eq SubjectMergeStrategy Source # 
Instance details

Defined in Pattern.Reconcile

type Rep SubjectMergeStrategy Source # 
Instance details

Defined in Pattern.Reconcile

type Rep SubjectMergeStrategy = D1 ('MetaData "SubjectMergeStrategy" "Pattern.Reconcile" "pattern-0.4.0.0-inplace" 'False) (C1 ('MetaCons "SubjectMergeStrategy" 'PrefixI 'True) (S1 ('MetaSel ('Just "labelMerge") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 LabelMerge) :*: S1 ('MetaSel ('Just "propertyMerge") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 PropertyMerge)))

data LabelMerge Source #

Instances

Instances details
Generic LabelMerge Source # 
Instance details

Defined in Pattern.Reconcile

Associated Types

type Rep LabelMerge 
Instance details

Defined in Pattern.Reconcile

type Rep LabelMerge = D1 ('MetaData "LabelMerge" "Pattern.Reconcile" "pattern-0.4.0.0-inplace" 'False) (C1 ('MetaCons "UnionLabels" 'PrefixI 'False) (U1 :: Type -> Type) :+: (C1 ('MetaCons "IntersectLabels" 'PrefixI 'False) (U1 :: Type -> Type) :+: C1 ('MetaCons "ReplaceLabels" 'PrefixI 'False) (U1 :: Type -> Type)))
Show LabelMerge Source # 
Instance details

Defined in Pattern.Reconcile

Eq LabelMerge Source # 
Instance details

Defined in Pattern.Reconcile

type Rep LabelMerge Source # 
Instance details

Defined in Pattern.Reconcile

type Rep LabelMerge = D1 ('MetaData "LabelMerge" "Pattern.Reconcile" "pattern-0.4.0.0-inplace" 'False) (C1 ('MetaCons "UnionLabels" 'PrefixI 'False) (U1 :: Type -> Type) :+: (C1 ('MetaCons "IntersectLabels" 'PrefixI 'False) (U1 :: Type -> Type) :+: C1 ('MetaCons "ReplaceLabels" 'PrefixI 'False) (U1 :: Type -> Type)))

data PropertyMerge Source #

Instances

Instances details
Generic PropertyMerge Source # 
Instance details

Defined in Pattern.Reconcile

Associated Types

type Rep PropertyMerge 
Instance details

Defined in Pattern.Reconcile

type Rep PropertyMerge = D1 ('MetaData "PropertyMerge" "Pattern.Reconcile" "pattern-0.4.0.0-inplace" 'False) (C1 ('MetaCons "ReplaceProperties" 'PrefixI 'False) (U1 :: Type -> Type) :+: (C1 ('MetaCons "ShallowMerge" 'PrefixI 'False) (U1 :: Type -> Type) :+: C1 ('MetaCons "DeepMerge" 'PrefixI 'False) (U1 :: Type -> Type)))
Show PropertyMerge Source # 
Instance details

Defined in Pattern.Reconcile

Eq PropertyMerge Source # 
Instance details

Defined in Pattern.Reconcile

type Rep PropertyMerge Source # 
Instance details

Defined in Pattern.Reconcile

type Rep PropertyMerge = D1 ('MetaData "PropertyMerge" "Pattern.Reconcile" "pattern-0.4.0.0-inplace" 'False) (C1 ('MetaCons "ReplaceProperties" 'PrefixI 'False) (U1 :: Type -> Type) :+: (C1 ('MetaCons "ShallowMerge" 'PrefixI 'False) (U1 :: Type -> Type) :+: C1 ('MetaCons "DeepMerge" 'PrefixI 'False) (U1 :: Type -> Type)))

defaultSubjectMergeStrategy :: SubjectMergeStrategy Source #

Default merge strategy for Subjects.

Error and Report Types

data Conflict i v Source #

Constructors

Conflict 

Instances

Instances details
Generic (Conflict i v) Source # 
Instance details

Defined in Pattern.Reconcile

Associated Types

type Rep (Conflict i v) 
Instance details

Defined in Pattern.Reconcile

type Rep (Conflict i v) = D1 ('MetaData "Conflict" "Pattern.Reconcile" "pattern-0.4.0.0-inplace" 'False) (C1 ('MetaCons "Conflict" 'PrefixI 'True) ((S1 ('MetaSel ('Just "conflictId") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 i) :*: S1 ('MetaSel ('Just "conflictExisting") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 v)) :*: (S1 ('MetaSel ('Just "conflictIncoming") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 v) :*: S1 ('MetaSel ('Just "conflictLocations") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 [Path]))))

Methods

from :: Conflict i v -> Rep (Conflict i v) x #

to :: Rep (Conflict i v) x -> Conflict i v #

(Show i, Show v) => Show (Conflict i v) Source # 
Instance details

Defined in Pattern.Reconcile

Methods

showsPrec :: Int -> Conflict i v -> ShowS #

show :: Conflict i v -> String #

showList :: [Conflict i v] -> ShowS #

(Eq i, Eq v) => Eq (Conflict i v) Source # 
Instance details

Defined in Pattern.Reconcile

Methods

(==) :: Conflict i v -> Conflict i v -> Bool #

(/=) :: Conflict i v -> Conflict i v -> Bool #

type Rep (Conflict i v) Source # 
Instance details

Defined in Pattern.Reconcile

type Rep (Conflict i v) = D1 ('MetaData "Conflict" "Pattern.Reconcile" "pattern-0.4.0.0-inplace" 'False) (C1 ('MetaCons "Conflict" 'PrefixI 'True) ((S1 ('MetaSel ('Just "conflictId") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 i) :*: S1 ('MetaSel ('Just "conflictExisting") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 v)) :*: (S1 ('MetaSel ('Just "conflictIncoming") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 v) :*: S1 ('MetaSel ('Just "conflictLocations") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 [Path]))))

data ReconcileError i v Source #

Constructors

ReconcileError 

Instances

Instances details
Generic (ReconcileError i v) Source # 
Instance details

Defined in Pattern.Reconcile

Associated Types

type Rep (ReconcileError i v) 
Instance details

Defined in Pattern.Reconcile

type Rep (ReconcileError i v) = D1 ('MetaData "ReconcileError" "Pattern.Reconcile" "pattern-0.4.0.0-inplace" 'False) (C1 ('MetaCons "ReconcileError" 'PrefixI 'True) (S1 ('MetaSel ('Just "errorMessage") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 String) :*: S1 ('MetaSel ('Just "errorConflicts") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 [Conflict i v])))

Methods

from :: ReconcileError i v -> Rep (ReconcileError i v) x #

to :: Rep (ReconcileError i v) x -> ReconcileError i v #

(Show i, Show v) => Show (ReconcileError i v) Source # 
Instance details

Defined in Pattern.Reconcile

(Eq i, Eq v) => Eq (ReconcileError i v) Source # 
Instance details

Defined in Pattern.Reconcile

type Rep (ReconcileError i v) Source # 
Instance details

Defined in Pattern.Reconcile

type Rep (ReconcileError i v) = D1 ('MetaData "ReconcileError" "Pattern.Reconcile" "pattern-0.4.0.0-inplace" 'False) (C1 ('MetaCons "ReconcileError" 'PrefixI 'True) (S1 ('MetaSel ('Just "errorMessage") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 String) :*: S1 ('MetaSel ('Just "errorConflicts") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 [Conflict i v])))

data ReconcileReport i Source #

Instances

Instances details
Generic (ReconcileReport i) Source # 
Instance details

Defined in Pattern.Reconcile

Associated Types

type Rep (ReconcileReport i) 
Instance details

Defined in Pattern.Reconcile

type Rep (ReconcileReport i) = D1 ('MetaData "ReconcileReport" "Pattern.Reconcile" "pattern-0.4.0.0-inplace" 'False) (C1 ('MetaCons "ReconcileReport" 'PrefixI 'True) ((S1 ('MetaSel ('Just "reportDuplicatesFound") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 Int) :*: S1 ('MetaSel ('Just "reportReferencesResolved") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 Int)) :*: (S1 ('MetaSel ('Just "reportMergesPerformed") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 Int) :*: S1 ('MetaSel ('Just "reportSubjectCounts") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (Map i Int)))))
Show i => Show (ReconcileReport i) Source # 
Instance details

Defined in Pattern.Reconcile

Eq i => Eq (ReconcileReport i) Source # 
Instance details

Defined in Pattern.Reconcile

type Rep (ReconcileReport i) Source # 
Instance details

Defined in Pattern.Reconcile

type Rep (ReconcileReport i) = D1 ('MetaData "ReconcileReport" "Pattern.Reconcile" "pattern-0.4.0.0-inplace" 'False) (C1 ('MetaCons "ReconcileReport" 'PrefixI 'True) ((S1 ('MetaSel ('Just "reportDuplicatesFound") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 Int) :*: S1 ('MetaSel ('Just "reportReferencesResolved") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 Int)) :*: (S1 ('MetaSel ('Just "reportMergesPerformed") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 Int) :*: S1 ('MetaSel ('Just "reportSubjectCounts") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (Map i Int)))))

type Path = [Int] Source #

Reconciliation Operations

Inspection

findConflicts :: (HasIdentity v i, Eq v) => Pattern v -> [Conflict i v] Source #

Utilities