Safe Haskell | Safe |
---|---|
Language | Haskell2010 |
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.
- 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 {}
Partial semigroup
class PartialSemigroup a where Source #
A PartialSemigroup
is like a Semigroup
, but with an operator returning
rather than Maybe
aa
.
For comparison:
(<>
) ::Semigroup
a => a -> a -> a (<>?
) ::PartialSemigroup
a => a -> a ->Maybe
a
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
:
Minimal complete definition
Instances
PartialSemigroup () Source # | |
PartialSemigroup [a] Source # | |
PartialSemigroup a => PartialSemigroup (Identity a) Source # | |
PartialSemigroup a => PartialSemigroup (ZipList a) Source # | |
Num a => PartialSemigroup (Sum a) Source # | |
Num a => PartialSemigroup (Product a) Source # | |
Semigroup a => PartialSemigroup (Total a) Source # | |
(PartialSemigroup a, PartialSemigroup b) => PartialSemigroup (Either a b) Source # | |
(PartialSemigroup a, PartialSemigroup b) => PartialSemigroup (a, b) Source # | |
PartialSemigroup b => PartialSemigroup (AppendRight a b) Source # | |
PartialSemigroup a => PartialSemigroup (AppendLeft a b) Source # | |
(PartialSemigroup a, PartialSemigroup b, PartialSemigroup c) => PartialSemigroup (a, b, c) Source # | |
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
(Eq a, Eq b) => Eq (AppendLeft a b) Source # | |
(Ord a, Ord b) => Ord (AppendLeft a b) Source # | |
(Read a, Read b) => Read (AppendLeft a b) Source # | |
(Show a, Show b) => Show (AppendLeft a b) Source # | |
PartialSemigroup a => PartialSemigroup (AppendLeft a b) Source # | |
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
(Eq a, Eq b) => Eq (AppendRight a b) Source # | |
(Ord a, Ord b) => Ord (AppendRight a b) Source # | |
(Read a, Read b) => Read (AppendRight a b) Source # | |
(Show a, Show b) => Show (AppendRight a b) Source # | |
PartialSemigroup b => PartialSemigroup (AppendRight a b) Source # | |
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 <>? y
Just (Left "abcd",Right "hijk")
>>>
x = (Left "ab", Right "hi")
>>>
y = (Left "cd", Left "jk")
>>>
x <>? y
Nothing
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 ys
Just [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 ys
Nothing
If the lists have different lengths, then we get Nothing
.
>>>
xs = [Left "a", Left "b", Right "c"]
>>>
ys = [Left "1", Left "2"]
>>>
partialZip xs ys
Nothing
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 ys
Just (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 ys
Nothing
If the lists have different lengths, then we get Nothing
.
>>>
xs = Left "a" :| [Left "b", Right "c"]
>>>
ys = Left "1" :| [Left "2"]
>>>
partialZip1 xs ys
Nothing
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
Just
x <>Just
y = 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.