| Safe Haskell | Safe-Inferred |
|---|---|
| Language | Haskell2010 |
Pattern.Core
Synopsis
- data Pattern v = Pattern {}
- pattern :: v -> [Pattern v] -> Pattern v
- point :: v -> Pattern v
- fromList :: v -> [v] -> Pattern v
- length :: Pattern v -> Int
- size :: Pattern v -> Int
- depth :: Pattern v -> Int
- values :: Pattern v -> [v]
- anyValue :: (v -> Bool) -> Pattern v -> Bool
- allValues :: (v -> Bool) -> Pattern v -> Bool
- filterPatterns :: (Pattern v -> Bool) -> Pattern v -> [Pattern v]
- findPattern :: (Pattern v -> Bool) -> Pattern v -> Maybe (Pattern v)
- findAllPatterns :: (Pattern v -> Bool) -> Pattern v -> [Pattern v]
- matches :: Eq v => Pattern v -> Pattern v -> Bool
- contains :: Eq v => Pattern v -> Pattern v -> Bool
- flatten :: Pattern v -> [v]
- toTuple :: Pattern v -> (v, [Pattern v])
- extract :: Comonad w => w a -> a
- duplicate :: Comonad w => w a -> w (w a)
- extend :: Comonad w => (w a -> b) -> w a -> w b
- depthAt :: Pattern v -> Pattern Int
- sizeAt :: Pattern v -> Pattern Int
- indicesAt :: Eq v => Pattern v -> Pattern [Int]
- para :: (Pattern v -> [r] -> r) -> Pattern v -> r
Pattern Type
Core Pattern data type and basic operations.
This module defines the fundamental Pattern type as a recursive structure that can represent graph elements and sequences.
Conceptual Model: Patterns as Decorated Sequences
Conceptually, a Pattern is a decorated sequence: the elements form the pattern itself, and the value provides decoration about that pattern. For example, the pattern "A B B A" with decoration "Enclosed rhyme" represents a specific sequence pattern (A B B A) that is classified as an "Enclosed rhyme". The Pattern type represents such decorated sequences where:
elements- The pattern itself, represented as a sequence of elementsvalue- Decoration about what kind of pattern it is
The elements ARE the pattern; they are not subordinate to the value. While implemented using a recursive tree structure, the primary semantic is that elements form the pattern sequence itself. Each element in the sequence is itself a Pattern, enabling arbitrarily nested and complex pattern structures.
Implementation: Recursive Tree Structure
The Pattern type is implemented as a recursive tree structure, but this is purely an implementation detail. The relationship between the sequence conceptual model and tree implementation is:
- *Primary Semantic (Conceptual)**: Patterns are decorated sequences where elements form the pattern itself. The sequence order is essential to the pattern.
- *Implementation Detail**: The tree structure is how sequences are represented in memory. Each tree node stores a decoration (value) and contains the pattern elements as a list, enabling recursive nesting.
- *Relationship**: The tree implementation supports sequence semantics:
- The
elementsfield IS the pattern - it contains the sequence that defines the pattern - The
valuefield provides decoration about what kind of pattern it is - Tree traversal provides access to sequence elements in order
- The recursive structure enables patterns to contain patterns containing patterns, etc.
Conceptually, developers should think of patterns as decorated sequences where elements form the pattern itself. The tree structure is an implementation detail that supports sequence operations (ordering, length, access by position).
This recursive implementation enables:
- Atomic patterns: Patterns with no elements (
elements == []), representing empty sequences. Atomic patterns are the fundamental building blocks from which all other patterns are constructed. - Patterns with elements: Patterns containing one or more pattern elements in sequence
- Arbitrary nesting: Patterns can contain patterns containing patterns, enabling deeply nested pattern structures
Values and Pattern Decoration
Each Pattern instance decorates a sequence of elements with a value:
- The
valuefield stores decoration about what kind of pattern it is. This can be any typev, such as a string identifier, an integer, a custom data type, etc. - The
valueis decoration about the pattern sequence itself, not part of the pattern. - All patterns in a structure must share the same value type
v(enforced by the type system).
For example, an atomic pattern might have value = Person
(decoration indicating the pattern type) and elements = [] (empty sequence pattern).
A pattern with two elements might have value = "knows" (the pattern type decoration)
and elements = [atomA, atomB] (the pattern itself - a sequence of two atomic patterns).
Elements and Pattern Structure
The elements field IS the pattern - it contains the sequence that defines the pattern:
- An empty sequence (
elements == []) represents a pattern with no elements (empty sequence) - A non-empty sequence represents a pattern containing one or more pattern elements
- The elements are ordered and maintain their sequence order - this order is essential to the pattern
- Each element in the sequence is itself a Pattern, enabling recursive nesting
The pattern structure enables compositional patterns:
- A pattern can include other patterns as its elements
- Those element patterns can themselves include patterns
- This enables arbitrary depth nesting while maintaining the pattern sequence semantic
For example, a pattern might have elements = [atom1, atom2, pair1]
where each element is a Pattern. A pair pattern itself might have
elements = [atomA, atomB], creating a nested pattern structure.
Type Safety and Type Parameter v
The Pattern type is parameterized over value type v:
Pattern vallows patterns to store values of any typev- All patterns in a structure must share the same value type
v - This type consistency is enforced by Haskell's type system
- The type parameter ensures type safety when working with patterns
For example:
Pattern String- patterns storing string valuesPattern Int- patterns storing integer valuesPattern Person- patterns storing custom Person values
Type consistency means that if you have a Pattern String, all patterns in
its elements list must also be Pattern String. This prevents mixing
different value types within a single pattern structure.
Mathematical Foundation
Patterns form the foundation for category-theoretic graph representations. The recursive structure enables functor instances and supports various graph interpretations through categorical views. The sequence semantic aligns with categorical composition and transformation operations.
The Pattern type has a Functor instance that enables value transformation while preserving pattern structure. This supports functional transformations and type conversions essential for pattern manipulation. See the Functor instance documentation below for details on structure preservation and functor laws.
The Pattern type has a Foldable instance that enables value aggregation over pattern
structures. This supports operations like summing values, concatenating strings, counting
elements, and computing statistics without manually traversing the pattern tree. The instance
provides foldr for right-associative folding, foldl for left-associative folding,
foldMap for monoid-based aggregation, and toList for extracting all values as a flat list.
The module also provides flatten as an explicit function for extracting all values as a flat
list, equivalent to toList. See the Foldable instance documentation below for details on
value aggregation and folding operations.
The Pattern type has a Traversable instance that enables effectful traversal over pattern
structures while preserving pattern structure. This supports operations like validation,
state threading, IO operations, and error handling over pattern values. The instance provides
traverse for applying effectful functions to all values and sequenceA for sequencing
applicative effects. See the Traversable instance documentation below for details on effectful
traversal and structure preservation.
The Pattern type has an Ord instance that provides lexicographic ordering for patterns based
on their structure. Patterns are ordered by comparing their value first, then their elements
recursively. This ordering is consistent with the Eq instance and enables patterns to be
used as keys in Data.Map and elements in Data.Set. The Ord instance requires that the value
type v has an Ord instance. See the Ord instance documentation below for details on
ordering rules and consistency with equality.
The Pattern type has a Semigroup instance that enables combining patterns by concatenating
their elements and combining their values using the value type's Semigroup instance. This
enables incremental pattern construction using standard Haskell combinators like <>,
sconcat, and stimes. The instance preserves the decorated sequence model where elements
form the pattern and values provide decoration. The Semigroup instance requires that the
value type v has a Semigroup instance. See the Semigroup instance documentation below
for details on combination semantics and associativity.
The Pattern type has a Monoid instance that extends the Semigroup instance by providing
an identity element (mempty). The identity pattern has mempty value (from value type's
Monoid) and empty elements list, enabling identity-based operations and standard Monoid
combinators (e.g., mconcat) while preserving the decorated sequence model. The Monoid
instance requires that the value type v has a Monoid instance. See the Monoid instance
documentation below for details on identity semantics and laws.
The Pattern type has a Hashable instance that enables using patterns as keys in HashMap
and elements in HashSet for efficient hash-based lookups and deduplication. The instance
uses structure-preserving hashing based on value and elements recursively, ensuring that
equal patterns (according to Eq) produce the same hash value while providing good
distribution. The Hashable instance requires that the value type v has a Hashable
instance. See the Hashable instance documentation below for details on hash semantics and
consistency with equality.
The Pattern type has a Comonad instance that enables context-aware computations where
functions have access to the full structural context (parent, siblings, depth, indices) around
each value, not just the value itself. This extends beyond Foldable (which only provides
values) to enable computations that consider structural context, depth, position, and
relationships between pattern elements. The instance provides extract (extract decoration
value), duplicate (create pattern of contexts), and extend (context-aware transformation),
satisfying all Comonad laws (extract-extend, extend-extract, extend composition). See the
Comonad instance documentation below for details on context-aware computation and relationship
to zippers.
The Pattern type provides query functions for introspecting pattern structure:
length- Returns the number of direct elements in a pattern's sequence (O(1))size- Returns the total number of nodes in a pattern structure, including all nested patterns (O(n))depth- Returns the maximum nesting depth of a pattern structure (O(n))values- Extracts all values from a pattern structure as a flat list (O(n))value- Field accessor for accessing a pattern's decoration value (O(1))anyValue- Checks if any value in a pattern satisfies a predicate (O(n))allValues- Checks if all values in a pattern satisfy a predicate (O(n))filterPatterns- Filters all subpatterns (including root) matching a pattern predicate (O(n))findPattern- Finds the first subpattern (including root) matching a pattern predicate (O(n))findAllPatterns- Finds all subpatterns (including root) matching a pattern predicate (O(n))matches- Checks if two patterns match structurally (O(n))contains- Checks if a pattern contains a subpattern (O(n))
These query functions enable pattern introspection, validation, and analysis operations. See individual function documentation for details on usage and performance characteristics.
Examples
Atomic pattern:
>>>atom = point "atom1">>>value atom"atom1">>>elements atom[]
Pattern with elements:
>>>elem1 = point "elem1">>>elem2 = point "elem2">>>p = pattern "pattern" [elem1, elem2]>>>value p"pattern">>>length (elements p)2>>>map value (elements p)["elem1","elem2"]
Nested pattern:
>>>level3 = point "level3">>>level2 = pattern "level2" [level3]>>>level1 = pattern "level1" [level2]>>>nested = pattern "root" [level1]>>>value nested"root">>>value (head (elements nested))"level1"
Constructors
| Pattern | |
Instances
| Comonad Pattern Source # | Enables context-aware computations where functions have access to the full structural context (parent, siblings, depth, indices) around each value. Semantics:
* Laws: * Left Identity: `extract . extend f == f` * Right Identity: `extend extract == id` * Associativity: `extend f . extend g == extend (f . extend g)` ExamplesExtract returns the root value:
Duplicate creates context structure:
Extend applies context-aware function:
|
| Applicative Pattern Source # |
Enables applying functions stored in patterns to values stored in patterns. Semantics:
* Laws (all satisfied): * Identity: `pure id * v == v` * Composition: `pure (.) * u * v * w == u * (v * w)` * Homomorphism: `pure f * pure x == pure (f x)` * Interchange: `u * pure y == pure ($ y) * u` * Functor Consistency: `fmap f x == pure f * x` ExamplesPure creates atomic pattern:
Applying function pattern to value pattern:
Functor consistency (pure f * x == fmap f x):
Identity law (pure id * v == v):
|
| Functor Pattern Source # | Maps a function over the values decorating the pattern structure. Preserves the pattern structure (number and order of elements). Laws: * Identity: `fmap id == id` * Composition: `fmap (f . g) == fmap f . fmap g` Examples
|
| Foldable Pattern Source # |
folds over the values decorating the pattern structure. The fold order is defined by the recursive structure: 1. The value at the current node 2. The elements in the elements list (recursively) Examples
|
Defined in Pattern.Core Methods fold :: Monoid m => Pattern m -> m # foldMap :: Monoid m => (a -> m) -> Pattern a -> m # foldMap' :: Monoid m => (a -> m) -> Pattern a -> m # foldr :: (a -> b -> b) -> b -> Pattern a -> b # foldr' :: (a -> b -> b) -> b -> Pattern a -> b # foldl :: (b -> a -> b) -> b -> Pattern a -> b # foldl' :: (b -> a -> b) -> b -> Pattern a -> b # foldr1 :: (a -> a -> a) -> Pattern a -> a # foldl1 :: (a -> a -> a) -> Pattern a -> a # elem :: Eq a => a -> Pattern a -> Bool # maximum :: Ord a => Pattern a -> a # minimum :: Ord a => Pattern a -> a # | |
| Traversable Pattern Source # |
Enables effectful traversal over pattern values while preserving structure. Semantics: * Applies an effectful function to each value. * Sequences the effects. * Reconstructs the pattern structure with the results. Laws: * Naturality: `t . traverse f = traverse (t . f)` * Identity: `traverse Identity = Identity` * Composition: `traverse (Compose . fmap g . f) = Compose . fmap (traverse g) . traverse f` ExamplesBasic traversal with Identity (equivalent to fmap):
Traversal with Maybe (validation):
Sequencing effects:
Atomic pattern:
Pattern with multiple elements:
Nested pattern structure:
Effect failure propagation:
|
| Monoid v => Monoid (Pattern v) Source # | Extends the Semantics:
* Identity Laws: * `mempty <> p = p` * `p <> mempty = p` Requires the value type ExamplesIdentity element:
Identity laws:
Combining list of patterns:
Empty list returns mempty:
|
| Semigroup v => Semigroup (Pattern v) Source # |
Enables combining two patterns into a new pattern. Semantics:
* Values are combined using the value type's This aligns with the decorated sequence model: * The pattern sequence becomes the concatenation of the two sequences. * The decoration becomes the combination of the two decorations. Requires the value type ExamplesCombining atomic patterns:
Combining patterns with elements:
Using Sum semigroup:
Using Product semigroup:
Using sconcat for list of non-empty patterns:
Using stimes for repetition:
Complex combination:
|
| Show v => Show (Pattern v) Source # | |
| Eq v => Eq (Pattern v) Source # | |
| Ord v => Ord (Pattern v) Source # | Provides lexicographic ordering for patterns based on their structure.
Patterns are compared by their value first, then by their elements recursively.
This ordering is consistent with the The ordering rules are: 1. Compare values: if values differ, their order determines the pattern order. 2. If values are equal, compare elements lists lexicographically. This instance enables patterns to be used as keys in Requires the value type ExamplesComparing atomic patterns:
Comparing patterns with elements (value takes precedence):
Comparing identical patterns:
Deep structural comparison:
Using standard operators:
Min and Max:
|
| Hashable v => Hashable (Pattern v) Source # |
Enables using patterns as keys in Semantics: * Hashing combines the hash of the value and the hash of the elements list. * Structural equality implies hash equality (if p1 == p2, then hash p1 == hash p2). * Different structures with same flattened values produce different hashes. Requires the value type ExamplesHashing atomic patterns:
Hashing patterns with elements:
Hash consistency with equality:
Structure distinguishes hash:
Using in HashMap:
Using in HashSet:
|
Construction Functions
pattern :: v -> [Pattern v] -> Pattern v Source #
Create a pattern with a value and elements.
This is the primary constructor for creating patterns. Takes a decoration value and a list of pattern elements. The elements form the pattern itself; the value provides decoration about that pattern.
Examples
>>>pattern "root" [point "child"]Pattern "root" [Pattern "child" []]
>>>pattern "pair" [point 1, point 2]Pattern "pair" [Pattern 1 [],Pattern 2 []]
point :: v -> Pattern v Source #
Create an atomic pattern (a pattern with no elements) from a value.
This uses category-theory terminology (pointed functor). Functionally equivalent to 'pattern v []' and 'pure v'.
Examples
>>>point "atom"Pattern "atom" []
>>>point 42Pattern 42 []
fromList :: v -> [v] -> Pattern v Source #
Create a pattern from a list of values.
Creates a pattern where the first argument is the decoration value, and the list of values are converted to atomic patterns and used as elements.
Examples
>>>fromList "root" ["a", "b", "c"]Pattern "root" [Pattern "a" [],Pattern "b" [],Pattern "c" []]
Query Functions
length :: Pattern v -> Int Source #
Returns the number of direct elements in a pattern's sequence.
This operation is O(1).
Examples
>>>length (point "atom")0
>>>length (pattern "pair" [point 1, point 2])2
size :: Pattern v -> Int Source #
Returns the total number of nodes in a pattern structure.
Counts the root node plus all nodes in all nested subpatterns. This operation is O(n) where n is the total number of nodes.
Examples
>>>size (point "atom")1
>>>size (pattern "root" [point "child"])2
>>>size (pattern "root" [point "a", point "b"])3
depth :: Pattern v -> Int Source #
Returns the maximum nesting depth of a pattern structure.
An atomic pattern has depth 0 (root only, no nesting). A pattern with elements has depth 1 + max depth of elements. This operation is O(n) where n is the total number of nodes.
Examples
>>>depth (point "atom")0
>>>depth (pattern "root" [point "child"])1
>>>depth (pattern "root" [pattern "middle" [point "inner"]])2
values :: Pattern v -> [v] Source #
Extracts all values from a pattern structure as a flat list.
The order of values corresponds to a pre-order traversal (root, then elements).
This is equivalent to toList from Foldable, but specific to Pattern.
This operation is O(n) where n is the total number of nodes.
Examples
>>>values (point "atom")["atom"]
>>>values (pattern "root" [point "a", point "b"])["root","a","b"]
Predicate Functions
anyValue :: (v -> Bool) -> Pattern v -> Bool Source #
Checks if any value in the pattern satisfies the predicate.
Traverses the pattern structure and applies the predicate to each value. Returns True if at least one value satisfies the predicate. This operation is O(n).
Examples
>>>anyValue (> 5) (pattern 3 [point 6, point 2])True
>>>anyValue (> 10) (pattern 3 [point 6, point 2])False
allValues :: (v -> Bool) -> Pattern v -> Bool Source #
Checks if all values in the pattern satisfy the predicate.
Traverses the pattern structure and applies the predicate to each value. Returns True if all values satisfy the predicate. This operation is O(n).
Examples
>>>allValues (> 0) (pattern 3 [point 6, point 2])True
>>>allValues (> 5) (pattern 3 [point 6, point 2])False
filterPatterns :: (Pattern v -> Bool) -> Pattern v -> [Pattern v] Source #
Filters subpatterns (including root) that satisfy a pattern predicate.
Traverses the pattern structure and applies the predicate to each subpattern. Returns a list of all matching patterns. This operation is O(n).
Examples
>>>p = pattern 3 [point 6, point 2]>>>map value $ filterPatterns (\x -> value x > 5) p[6]
>>>map value $ filterPatterns (\x -> length x > 0) p[3]
findPattern :: (Pattern v -> Bool) -> Pattern v -> Maybe (Pattern v) Source #
Finds the first subpattern (including root) that satisfies a pattern predicate.
Traverses the pattern structure in pre-order and returns the first match. Returns Nothing if no pattern matches. This operation is O(n).
Examples
>>>p = pattern 3 [point 6, point 2]>>>fmap value $ findPattern (\x -> value x > 5) pJust 6
>>>findPattern (\x -> value x > 10) pNothing
findAllPatterns :: (Pattern v -> Bool) -> Pattern v -> [Pattern v] Source #
Finds all subpatterns (including root) that satisfy a pattern predicate.
Equivalent to filterPatterns. Returns a list of all matching patterns.
This operation is O(n).
Examples
>>>p = pattern 3 [point 6, point 2]>>>map value $ findAllPatterns (\x -> value x > 1) p[3,6,2]
matches :: Eq v => Pattern v -> Pattern v -> Bool Source #
Checks if two patterns match structurally.
Uses the Eq instance to compare patterns for structural equality.
Both values and elements must match recursively.
This operation is O(n).
Examples
>>>matches (point "a") (point "a")True
>>>matches (point "a") (point "b")False
contains :: Eq v => Pattern v -> Pattern v -> Bool Source #
Checks if a pattern contains a specific subpattern.
Traverses the pattern structure to see if any subpattern matches the target.
Uses matches (structural equality) for comparison.
This operation is O(n).
Examples
>>>p = pattern "root" [point "child"]>>>contains p (point "child")True
>>>contains p (point "missing")False
Foldable/Traversable Extras
toTuple :: Pattern v -> (v, [Pattern v]) Source #
Extracts the pattern structure as a tuple (value, elements).
Preserves the structure while exposing the internal components. Useful for pattern matching or transformation without direct field access.
Examples
>>>toTuple (point "atom")("atom",[])
>>>toTuple (pattern "root" [point "child"])("root",[Pattern "child" []])
Context/Comonad Functions
depthAt :: Pattern v -> Pattern Int Source #
Computes the nesting depth at each position in the pattern.
Returns a new pattern with the same structure where each value is replaced by its depth (maximum nesting depth of the subtree at that position).
Examples
>>>p = pattern "root" [point "child"]>>>depthAt pPattern 1 [Pattern 0 []]
sizeAt :: Pattern v -> Pattern Int Source #
Computes the size of the subtree at each position in the pattern.
Returns a new pattern with the same structure where each value is replaced by the size (number of nodes) of the subtree rooted at that position.
Examples
>>>p = pattern "root" [point "a", point "b"]>>>sizeAt pPattern 3 [Pattern 1 [],Pattern 1 []]
indicesAt :: Eq v => Pattern v -> Pattern [Int] Source #
Computes the path indices from root to each position in the pattern.
Returns a new pattern with the same structure where each value is replaced by a list of indices representing the path from root to that position.
Examples
>>>p = pattern "root" [point "a", point "b"]>>>indicesAt pPattern [] [Pattern [0] [],Pattern [1] []]
Paramorphism Functions
para :: (Pattern v -> [r] -> r) -> Pattern v -> r Source #
Paramorphism: structure-aware folding over patterns.
Paramorphism enables folding over pattern structures while providing access to the full pattern subtree at each position. The folding function receives:
- The current pattern subtree (
Pattern v) - The list of recursively computed results from children (
[r])
This extends Foldable (value-only folding) to provide structure-aware folding,
just as Comonad extends Functor to provide structure-aware transformation.
Paramorphism enables structure-aware aggregations that consider structural properties (depth, element count, nesting level) in addition to values.
Examples
Depth-weighted sum:
>>>p = pattern 10 [point 5, point 3]>>>para (\pat rs -> value pat * depth pat + sum rs) p10
Element-count-aware aggregation:
>>>p = pattern 10 [point 5, point 3]>>>para (\pat rs -> value pat * length (elements pat) + sum (map value (elements pat)) + sum rs) p28
Structure-preserving transformation during fold:
>>>p = pattern 10 [point 5, point 3]>>>para (\pat rs -> Pattern (value pat * depth pat) rs) pPattern 10 [Pattern 0 [],Pattern 0 []]
Relationship to Other Operations
Foldable: Provides value-only folding (foldr,foldl,foldMap). Use when you only need values, not structural information.
- Paramorphism: Provides structure-aware folding (
para). Use when you need structure-aware aggregations (depth-weighted sums, nesting-level statistics, element-count-based aggregations). Comonad: Provides structure-aware transformation (extend). Use when you need structure-aware transformation (not aggregation).
Since: 0.1.0