| Safe Haskell | Safe-Inferred |
|---|---|
| Language | GHC2021 |
Data.PartialSemigroup
Description
A semigroup (Semigroup) is a set with a binary associative operation (<>).
This module defines a partial semigroup (PartialSemigroup), a
semigroup for which <> is not required to be defined over all inputs.
Synopsis
- class PartialSemigroup a where
- newtype AppendLeft a b = AppendLeft {
- unAppendLeft :: Either a b
- newtype AppendRight a b = AppendRight {
- unAppendRight :: Either a b
- groupAndConcat :: PartialSemigroup a => [a] -> [a]
- partialConcat :: PartialSemigroup a => [a] -> Maybe a
- partialConcat1 :: PartialSemigroup a => NonEmpty a -> Maybe a
- partialZip :: PartialSemigroup a => [a] -> [a] -> Maybe [a]
- partialZip1 :: PartialSemigroup a => NonEmpty a -> NonEmpty a -> Maybe (NonEmpty a)
- newtype Total a = Total {
- unTotal :: a
- newtype Partial a = Partial {}
- newtype One a = One {
- theOne :: a
- newtype AtMostOne a = AtMostOne {
- theOneMaybe :: Maybe a
Partial semigroup
class PartialSemigroup a where Source #
A PartialSemigroup is like a Semigroup, but with an operator returning
rather than Maybe aa.
For comparison:
(<>) ::Semigroupa => a -> a -> a (<>?) ::PartialSemigroupa => a -> a ->Maybea
The associativity axiom for partial semigroups
For all x, y, z:
Relationship to the semigroup associativity axiom
The partial semigroup associativity axiom is a natural adaptation of the semigroup associativity axiom
x<>(y<>z) = (x<>y)<>z
with a slight modification to accommodate situations where <> is undefined. We
may gain some insight into the connection between Semigroup and
PartialSemigroup by rephrasing the partial semigroup associativity in terms of
a partial <> operator thusly:
For all x, y, z:
Instances
Either
The exemplary nontrivial PartialSemigroup is Either, for which the append
operator produces a Just result only if both arguments are Left or both
arguments are Right.
>>>Left "ab" <>? Left "cd"Just (Left "abcd")
>>>Left "ab" <>? Right [1, 2]Nothing
newtype AppendLeft a b Source #
A wrapper for Either where the PartialSemigroup operator is defined
only over Left values.
Examples
>>>AppendLeft (Left "ab") <>? AppendLeft (Left "cd")Just (AppendLeft {unAppendLeft = Left "abcd"})
Anything else produces Nothing
>>>AppendLeft (Right "ab") <>? AppendLeft (Right "cd")Nothing
groupAndConcat combines consecutive Left values, leaving the Right values
unmodified.
>>>xs = [Left "a", Left "b", Right "c", Right "d", Left "e", Left "f"]>>>fmap unAppendLeft . groupAndConcat . fmap AppendLeft $ xs[Left "ab",Right "c",Right "d",Left "ef"]
Constructors
| AppendLeft | |
Fields
| |
Instances
newtype AppendRight a b Source #
A wrapper for Either where the PartialSemigroup operator is defined
only over Right values.
Examples
>>>AppendRight (Right "ab") <>? AppendRight (Right "cd")Just (AppendRight {unAppendRight = Right "abcd"})
Anything else produces Nothing
>>>AppendRight (Left "ab") <>? AppendRight (Left "cd")Nothing
groupAndConcat combines consecutive Right values, leaving the Left values
unmodified.
>>>xs = [Left "a", Left "b", Right "c", Right "d", Left "e", Left "f"]>>>fmap unAppendRight . groupAndConcat . fmap AppendRight $ xs[Left "a",Left "b",Right "cd",Left "e",Left "f"]
Constructors
| AppendRight | |
Fields
| |
Instances
Tuples
A tuple forms a partial semigroups when all of its constituent parts have
partial semigroups. The append operator returns a Just value when all of the
fields' append operators must return Just values.
>>>x = (Left "ab", Right "hi")>>>y = (Left "cd", Right "jk")>>>x <>? yJust (Left "abcd",Right "hijk")
>>>x = (Left "ab", Right "hi")>>>y = (Left "cd", Left "jk")>>>x <>? yNothing
Concatenation
groupAndConcat :: PartialSemigroup a => [a] -> [a] Source #
Apply a semigroup operation to any pairs of consecutive list elements where the semigroup operation is defined over them.
Examples
For Either, groupAndConcat combines contiguous sublists of Left and
contiguous sublists of Right.
>>>xs = [Left "a", Right "b", Right "c", Left "d", Left "e", Left "f"]>>>groupAndConcat xs[Left "a",Right "bc",Left "def"]
partialConcat :: PartialSemigroup a => [a] -> Maybe a Source #
If xs is nonempty and the partial semigroup operator is defined for all
pairs of values in xs, then produces a partialConcat xsJust result with
the combination of all the values. Otherwise, returns Nothing.
Examples
When all values can combine, we get a Just of their combination.
>>>partialConcat [Left "a", Left "b", Left "c"]Just (Left "abc")
When some values cannot be combined, we get Nothing.
>>>partialConcat [Left "a", Left "b", Right "c"]Nothing
When the list is empty, we get Nothing.
>>>partialConcat []Nothing
partialConcat1 :: PartialSemigroup a => NonEmpty a -> Maybe a Source #
Like partialConcat, but for non-empty lists.
Examples
When all values can combine, we get a Just of their combination.
>>>partialConcat1 (Left "a" :| [Left "b", Left "c"])Just (Left "abc")
When some values cannot be combined, we get Nothing.
>>>partialConcat1 (Left "a" :| [Left "b", Right "c"])Nothing
Zipping
partialZip :: PartialSemigroup a => [a] -> [a] -> Maybe [a] Source #
Examples
If lists are the same length and each pair of elements successfully, then we get
a Just result.
>>>xs = [Left "a", Left "b", Right "c"]>>>ys = [Left "1", Left "2", Right "3"]>>>partialZip xs ysJust [Left "a1",Left "b2",Right "c3"]
If the pairs do not all combine, then we get Nothing.
>>>xs = [Left "a", Left "b", Right "c"]>>>ys = [Left "1", Right "2", Right "3"]>>>partialZip xs ysNothing
If the lists have different lengths, then we get Nothing.
>>>xs = [Left "a", Left "b", Right "c"]>>>ys = [Left "1", Left "2"]>>>partialZip xs ysNothing
partialZip1 :: PartialSemigroup a => NonEmpty a -> NonEmpty a -> Maybe (NonEmpty a) Source #
Like partialZip, but for non-empty lists.
Examples
If lists are the same length and each pair of elements successfully, then we get
a Just result.
>>>xs = Left "a" :| [Left "b", Right "c"]>>>ys = Left "1" :| [Left "2", Right "3"]>>>partialZip1 xs ysJust (Left "a1" :| [Left "b2",Right "c3"])
If the pairs do not all combine, then we get Nothing.
>>>xs = Left "a" :| [Left "b", Right "c"]>>>ys = Left "1" :| [Right "2", Right "3"]>>>partialZip1 xs ysNothing
If the lists have different lengths, then we get Nothing.
>>>xs = Left "a" :| [Left "b", Right "c"]>>>ys = Left "1" :| [Left "2"]>>>partialZip1 xs ysNothing
Total to partial
For every type with a Semigroup, we can trivially construct a
PartialSemigroup as:
x<>?y =Just(x<>y)
Additionally, any type with a Semigroup can be treated as a PartialSemigroup
by lifting it into Total.
A wrapper to turn any value with a Semigroup instance into a value with a
PartialSemigroup instance whose <>? operator always returns Just.
Examples
>>>Total "ab" <>? Total "cd"Just (Total {unTotal = "abcd"})
>>>f = getProduct . unTotal>>>g = Total . Product>>>fmap f . partialConcat . fmap g $ [1..4]Just 24
Partial to total
For every type a with a PartialSemigroup, we can construct a total
Semigroup for as:Maybe a
Justx <>Justy = x<>?y _<>_ =Nothing
We don't actually define this instance for Maybe because it already has a
different Semigroup defined over it, but we do provide the Partial wrapper
which has this instance.
Instances
| PartialSemigroup a => Semigroup (Partial a) Source # | |
| Read a => Read (Partial a) Source # | |
| Show a => Show (Partial a) Source # | |
| Eq a => Eq (Partial a) Source # | |
| Ord a => Ord (Partial a) Source # | |
Refusing to combine
These are PartialSemigroup instances that don't really combine their values
at all; whenever more than one thing is present, <>? fails.
A partial semigroup operation which always fails.
Constructors
| AtMostOne | |
Fields
| |
Instances
| Read a => Read (AtMostOne a) Source # | |
| Show a => Show (AtMostOne a) Source # | |
| Eq a => Eq (AtMostOne a) Source # | |
| Ord a => Ord (AtMostOne a) Source # | |
Defined in Data.PartialSemigroup | |
| PartialSemigroup (AtMostOne a) Source # | |