Copyright | (c) Armando Santos 2019-2020 |
---|---|
Maintainer | armandoifsantos@gmail.com |
Stability | experimental |
Safe Haskell | None |
Language | Haskell2010 |
- Relation data type
- Constraint type synonyms
- Primitives
- Auxiliary type families
- Matrix construction and conversion
- Relational operations
- Taxonomy of binary relations
- Function division
- Relation division
- Relational pairing
- Relational coproduct
- Relational "currying"
- (Endo-)Relational properties
- Conditionals
- Relational composition and lifting
- Matrix printing
The AoP discipline generalises functions to relations which are Boolean matrices.
This module offers many of the combinators of the Algebra of Programming discipline. It is still under construction and very experimental.
This is an Internal module and it is no supposed to be imported.
Synopsis
- newtype Relation a b = R (Matrix Boolean (Normalize a) (Normalize b))
- type Boolean = Natural 0 1
- type Countable a = KnownNat (Count a)
- type CountableDimensions a b = (Countable a, Countable b)
- type CountableN a = KnownNat (Count (Normalize a))
- type CountableDimensionsN a b = (CountableN a, CountableN b)
- type FromListsN a b = FromLists Boolean (Normalize a) (Normalize b)
- type Liftable a b = (Bounded a, Bounded b, Enum a, Enum b, Eq b, Num Boolean, Ord Boolean)
- type Trivial a = Normalize a ~ Normalize (Normalize a)
- type TrivialP a b = Normalize (a, b) ~ Normalize (Normalize a, Normalize b)
- empty :: Relation Zero Zero
- one :: Boolean -> Relation One One
- junc :: Relation a c -> Relation b c -> Relation (Either a b) c
- (|||) :: Relation a c -> Relation b c -> Relation (Either a b) c
- split :: Relation c a -> Relation c b -> Relation c (Either a b)
- (===) :: Relation c a -> Relation c b -> Relation c (Either a b)
- type family FromNat (n :: Nat) :: Type where ...
- type family Count (d :: Type) :: Nat where ...
- type family Normalize (d :: Type) :: Type where ...
- class FromLists e cols rows
- fromLists :: FromListsN a b => [[Boolean]] -> Relation a b
- fromF :: (Liftable a b, CountableDimensionsN c d, FromListsN d c) => (a -> b) -> Relation c d
- fromF' :: (Liftable a b, CountableDimensionsN a b, FromListsN b a) => (a -> b) -> Relation a b
- toRel :: (Liftable a b, CountableDimensionsN a b, FromListsN b a) => (a -> b -> Bool) -> Relation a b
- toLists :: Relation a b -> [[Boolean]]
- toList :: Relation a b -> [Boolean]
- toBool :: Relation One One -> Bool
- pt :: (Liftable a b, Eq a, CountableDimensionsN a b, FromListsN a One, FromListsN b One) => Relation a b -> a -> List b
- belongs :: (Bounded a, Enum a, Eq a, CountableDimensionsN (List a) a, FromListsN a (List a)) => Relation (List a) a
- relationBuilder :: (FromListsN a b, CountableDimensionsN a b) => ((Int, Int) -> Boolean) -> Relation a b
- zeros :: (FromListsN a b, CountableDimensionsN a b) => Relation a b
- ones :: (FromListsN a b, CountableDimensionsN a b) => Relation a b
- bang :: (FromListsN a One, CountableN a) => Relation a One
- point :: (Bounded a, Enum a, Eq a, CountableN a, FromListsN a One) => a -> Relation One a
- conv :: Relation a b -> Relation b a
- intersection :: Relation a b -> Relation a b -> Relation a b
- union :: Relation a b -> Relation a b -> Relation a b
- sse :: Relation a b -> Relation a b -> Bool
- implies :: Relation a b -> Relation a b -> Relation a b
- iff :: Relation a b -> Relation a b -> Bool
- ker :: Relation a b -> Relation a a
- img :: Relation a b -> Relation b b
- injective :: (CountableN a, FromListsN a a) => Relation a b -> Bool
- entire :: (CountableN a, FromListsN a a) => Relation a b -> Bool
- simple :: (CountableN b, FromListsN b b) => Relation a b -> Bool
- surjective :: (CountableN b, FromListsN b b) => Relation a b -> Bool
- representation :: (CountableN a, FromListsN a a) => Relation a b -> Bool
- function :: (CountableDimensionsN a b, FromListsN a a, FromListsN b b) => Relation a b -> Bool
- abstraction :: (CountableN b, FromListsN b b) => Relation a b -> Bool
- injection :: (CountableDimensionsN a b, FromListsN a a, FromListsN b b) => Relation a b -> Bool
- surjection :: (CountableDimensionsN a b, FromListsN a a, FromListsN b b) => Relation a b -> Bool
- bijection :: (CountableDimensionsN a b, FromListsN b b, FromListsN a a) => Relation a b -> Bool
- domain :: (CountableN a, FromListsN a a) => Relation a b -> Relation a a
- range :: (CountableN b, FromListsN b b) => Relation a b -> Relation b b
- divisionF :: Relation a c -> Relation b c -> Relation a b
- divR :: Relation b c -> Relation b a -> Relation a c
- divL :: Relation c b -> Relation a b -> Relation a c
- divS :: Relation c a -> Relation b a -> Relation c b
- shrunkBy :: Relation b a -> Relation a a -> Relation b a
- overriddenBy :: (FromListsN b b, CountableN b) => Relation a b -> Relation a b -> Relation a b
- splitR :: (CountableDimensionsN a b, CountableN (a, b), FromListsN (a, b) a, FromListsN (a, b) b, TrivialP a b) => Relation c a -> Relation c b -> Relation c (a, b)
- p1 :: forall a b. (CountableDimensionsN a b, CountableN (a, b), FromListsN (a, b) a, TrivialP a b) => Relation (a, b) a
- p2 :: forall a b. (CountableDimensionsN a b, CountableN (a, b), FromListsN (a, b) b, TrivialP a b) => Relation (a, b) b
- (><) :: (CountableDimensionsN a b, CountableDimensionsN c d, CountableDimensionsN (a, c) (b, d), FromListsN (a, c) a, FromListsN (a, c) c, FromListsN (b, d) b, FromListsN (b, d) d, TrivialP a c, TrivialP b d) => Relation a b -> Relation c d -> Relation (a, c) (b, d)
- eitherR :: Relation a c -> Relation b c -> Relation (Either a b) c
- i1 :: (CountableDimensionsN a b, FromListsN b a, FromListsN a a) => Relation a (Either a b)
- i2 :: (CountableDimensionsN a b, FromListsN a b, FromListsN b b) => Relation b (Either a b)
- (-|-) :: (CountableDimensionsN b d, FromListsN b b, FromListsN d b, FromListsN b d, FromListsN d d) => Relation a b -> Relation c d -> Relation (Either a c) (Either b d)
- trans :: (CountableDimensionsN a b, CountableN c, CountableDimensionsN (a, b) (c, b), FromListsN (c, b) c, FromListsN (c, b) b, FromListsN (a, b) a, FromListsN (a, b) b, Trivial (a, b), Trivial (c, b), TrivialP a b, TrivialP c b) => Relation (a, b) c -> Relation a (c, b)
- untrans :: (CountableDimensionsN a b, CountableN c, CountableDimensionsN (a, b) (c, b), FromListsN (c, b) c, FromListsN (c, b) b, FromListsN (a, b) b, FromListsN (a, b) a, Trivial (a, b), Trivial (c, b), TrivialP a b, TrivialP c b) => Relation a (c, b) -> Relation (a, b) c
- reflexive :: (CountableN a, FromListsN a a) => Relation a a -> Bool
- coreflexive :: (CountableN a, FromListsN a a) => Relation a a -> Bool
- transitive :: Relation a a -> Bool
- symmetric :: Relation a a -> Bool
- antiSymmetric :: (CountableN a, FromListsN a a) => Relation a a -> Bool
- irreflexive :: (CountableN a, FromListsN a a) => Relation a a -> Bool
- connected :: (CountableN a, FromListsN a a) => Relation a a -> Bool
- preorder :: (CountableN a, FromListsN a a) => Relation a a -> Bool
- partialOrder :: (CountableN a, FromListsN a a) => Relation a a -> Bool
- linearOrder :: (CountableN a, FromListsN a a) => Relation a a -> Bool
- equivalence :: (CountableN a, FromListsN a a) => Relation a a -> Bool
- partialEquivalence :: (CountableN a, FromListsN a a) => Relation a a -> Bool
- difunctional :: Relation a b -> Bool
- equalizer :: (CountableN a, FromListsN a a) => Relation a b -> Relation a b -> Relation a a
- predR :: (Bounded a, Enum a, CountableN a, FromListsN a a, FromListsN Bool a) => Relation a Bool -> Relation a a
- guard :: (Bounded b, Enum b, CountableN b, FromListsN b b, FromListsN Bool b) => Relation b Bool -> Relation b (Either b b)
- cond :: (Bounded b, Enum b, CountableN b, FromListsN b b, FromListsN Bool b) => Relation b Bool -> Relation b c -> Relation b c -> Relation b c
- identity :: (FromListsN a a, CountableN a) => Relation a a
- comp :: Relation b c -> Relation a b -> Relation a c
- fromF :: (Liftable a b, CountableDimensionsN c d, FromListsN d c) => (a -> b) -> Relation c d
- fromF' :: (Liftable a b, CountableDimensionsN a b, FromListsN b a) => (a -> b) -> Relation a b
- pointAp :: (Liftable a b, Eq a, CountableDimensionsN a b, FromListsN a One, FromListsN b One) => a -> b -> Relation a b -> Relation One One
- pointApBool :: (Liftable a b, Eq a, CountableDimensionsN a b, FromListsN a One, FromListsN b One) => a -> b -> Relation a b -> Bool
- pretty :: CountableDimensionsN a b => Relation a b -> String
- prettyPrint :: CountableDimensionsN a b => Relation a b -> IO ()
Documentation
This definition makes use of the fact that Void
is
isomorphic to 0 and One
to 1 and captures matrix
dimensions as stacks of Either
s.
There exists two type families that make it easier to write
matrix dimensions: FromNat
and Count
. This approach
leads to a very straightforward implementation
of LAoP combinators.
Relation data type
Relation data type.
Instances
Category Relation Source # | It isn't possible to implement the Please use |
Eq (Relation a b) Source # | |
Num (Relation a b) Source # | |
Defined in LAoP.Relation.Internal (+) :: Relation a b -> Relation a b -> Relation a b # (-) :: Relation a b -> Relation a b -> Relation a b # (*) :: Relation a b -> Relation a b -> Relation a b # negate :: Relation a b -> Relation a b # abs :: Relation a b -> Relation a b # signum :: Relation a b -> Relation a b # fromInteger :: Integer -> Relation a b # | |
Ord (Relation a b) Source # | |
Defined in LAoP.Relation.Internal | |
Read (Matrix Boolean (Normalize a) (Normalize b)) => Read (Relation a b) Source # | |
Show (Relation a b) Source # | |
NFData (Relation a b) Source # | |
Defined in LAoP.Relation.Internal |
Constraint type synonyms
type Countable a = KnownNat (Count a) Source #
Constraint type synonyms to keep the type signatures less convoluted
type CountableDimensions a b = (Countable a, Countable b) Source #
type CountableDimensionsN a b = (CountableN a, CountableN b) Source #
Primitives
junc :: Relation a c -> Relation b c -> Relation (Either a b) c Source #
Boolean Matrix Junc
constructor, also known as relational coproduct.
See eitherR
.
(|||) :: Relation a c -> Relation b c -> Relation (Either a b) c infixl 3 Source #
Boolean Matrix Junc
constructor
See eitherR
.
split :: Relation c a -> Relation c b -> Relation c (Either a b) Source #
Boolean Matrix Split
constructor, also known as relational product.
(===) :: Relation c a -> Relation c b -> Relation c (Either a b) infixl 2 Source #
Boolean Matrix Split
constructor
Auxiliary type families
type family FromNat (n :: Nat) :: Type where ... Source #
Type family that computes of a given type dimension from a given natural
Thanks to Li-Yao Xia this type family is super fast.
type family Count (d :: Type) :: Nat where ... Source #
Type family that computes the cardinality of a given type dimension.
It can also count the cardinality of custom types that implement the
Generic
instance.
Count (Natural n m) = (m - n) + 1 | |
Count (List a) = (^) 2 (Count a) | |
Count (Either a b) = (+) (Count a) (Count b) | |
Count (a, b) = * (Count a) (Count b) | |
Count (a -> b) = (^) (Count b) (Count a) | |
Count (M1 _ _ f p) = Count (f p) | |
Count (K1 _ _ _) = 1 | |
Count (V1 _) = 0 | |
Count (U1 _) = 1 | |
Count ((:*:) a b p) = Count (a p) * Count (b p) | |
Count ((:+:) a b p) = Count (a p) + Count (b p) | |
Count d = Count (Rep d R) |
type family Normalize (d :: Type) :: Type where ... Source #
Type family that normalizes the representation of a given data structure
Matrix construction and conversion
class FromLists e cols rows Source #
Type class for defining the fromList
conversion function.
Given that it is not possible to branch on types at the term level type classes are needed very much like an inductive definition but on types.
Instances
FromLists e () () Source # | |
Defined in LAoP.Matrix.Internal | |
FromLists e Void Void Source # | |
(FromLists e () a, FromLists e () b, Countable a) => FromLists e () (Either a b) Source # | |
FromLists e () rows => FromLists e () (Either () rows) Source # | |
(FromLists e a (), FromLists e b (), Countable a) => FromLists e (Either a b) () Source # | |
FromLists e cols () => FromLists e (Either () cols) () Source # | |
(FromLists e (Either a b) c, FromLists e (Either a b) d, Countable c) => FromLists e (Either a b) (Either c d) Source # | |
fromLists :: FromListsN a b => [[Boolean]] -> Relation a b Source #
Build a matrix out of a list of list of elements. Throws a runtime error if the dimensions do not match.
fromF :: (Liftable a b, CountableDimensionsN c d, FromListsN d c) => (a -> b) -> Relation c d Source #
Lifts functions to matrices with arbitrary dimensions.
NOTE: Be careful to not ask for a matrix bigger than the cardinality of
types a
or b
allows.
fromF' :: (Liftable a b, CountableDimensionsN a b, FromListsN b a) => (a -> b) -> Relation a b Source #
Lifts functions to matrices with dimensions matching a
and b
cardinality's.
toRel :: (Liftable a b, CountableDimensionsN a b, FromListsN b a) => (a -> b -> Bool) -> Relation a b Source #
Lifts relation functions to Relation
pt :: (Liftable a b, Eq a, CountableDimensionsN a b, FromListsN a One, FromListsN b One) => Relation a b -> a -> List b Source #
Power transpose.
Maps a relation to a set valued function.
belongs :: (Bounded a, Enum a, Eq a, CountableDimensionsN (List a) a, FromListsN a (List a)) => Relation (List a) a Source #
Belongs relation
relationBuilder :: (FromListsN a b, CountableDimensionsN a b) => ((Int, Int) -> Boolean) -> Relation a b Source #
Matrix builder function. Constructs a matrix provided with a construction function.
zeros :: (FromListsN a b, CountableDimensionsN a b) => Relation a b Source #
ones :: (FromListsN a b, CountableDimensionsN a b) => Relation a b Source #
bang :: (FromListsN a One, CountableN a) => Relation a One Source #
The T (Top) row vector relation.
point :: (Bounded a, Enum a, Eq a, CountableN a, FromListsN a One) => a -> Relation One a Source #
Point constant relation
Relational operations
intersection :: Relation a b -> Relation a b -> Relation a b Source #
Relational intersection
Lifts pointwise conjunction.
(r `intersection
` s) `intersection
` t == r `intersection
` (s `intersection
` t) x `sse
` r `intersection
` s == x `intersection
` r && x `intersection
` s
implies :: Relation a b -> Relation a b -> Relation a b Source #
Relational implication (the same as
)sse
Taxonomy of binary relations
injective :: (CountableN a, FromListsN a a) => Relation a b -> Bool Source #
A Relation
r
is injective
iff
coreflexive
(ker
r)
entire :: (CountableN a, FromListsN a a) => Relation a b -> Bool Source #
simple :: (CountableN b, FromListsN b b) => Relation a b -> Bool Source #
A Relation
r
is simple
iff
coreflexive
(img
r)
surjective :: (CountableN b, FromListsN b b) => Relation a b -> Bool Source #
A Relation
r
is surjective
iff
reflexive
(img
r)
representation :: (CountableN a, FromListsN a a) => Relation a b -> Bool Source #
A Relation
r
is a representation
iff
injective
r && entire
r
function :: (CountableDimensionsN a b, FromListsN a a, FromListsN b b) => Relation a b -> Bool Source #
abstraction :: (CountableN b, FromListsN b b) => Relation a b -> Bool Source #
A Relation
r
is an abstraction
iff
surjective
r && simple
r
injection :: (CountableDimensionsN a b, FromListsN a a, FromListsN b b) => Relation a b -> Bool Source #
A Relation
r
is a injection
iff
function
r && representation
r
surjection :: (CountableDimensionsN a b, FromListsN a a, FromListsN b b) => Relation a b -> Bool Source #
A Relation
r
is a surjection
iff
function
r && abstraction
r
bijection :: (CountableDimensionsN a b, FromListsN b b, FromListsN a a) => Relation a b -> Bool Source #
A Relation
r
is an bijection
iff
injection
r && surjection
r
domain :: (CountableN a, FromListsN a a) => Relation a b -> Relation a a Source #
range :: (CountableN b, FromListsN b b) => Relation a b -> Relation b b Source #
Function division
Relation division
divR :: Relation b c -> Relation b a -> Relation a c Source #
Relational right division
is the largest relation divR
x yz
which,
pre-composed with y
, approximates x
.
shrunkBy :: Relation b a -> Relation a a -> Relation b a Source #
Relational shrinking.
r `
is the largest part of shrunkBy
` sr
such that,
if it yields an output for an input x
, it must be a maximum,
with respect to s
, among all possible outputs of x
by r
.
overriddenBy :: (FromListsN b b, CountableN b) => Relation a b -> Relation a b -> Relation a b Source #
Relational overriding.
r `
yields the relation which contains the
whole of overriddenBy
` ss
and that part of r
where s
is undefined.
zeros
`overriddenBy
` s == s r `overriddenBy
`zeros
== r r `overriddenBy
` r == r
Relational pairing
splitR :: (CountableDimensionsN a b, CountableN (a, b), FromListsN (a, b) a, FromListsN (a, b) b, TrivialP a b) => Relation c a -> Relation c b -> Relation c (a, b) Source #
Relational pairing.
NOTE: That this is not a true categorical product, see for instance:
|p1
`comp
`splitR
a b `sse
` asplitR
a b = | |p2
`comp
`splitR
a b `sse
` b
Emphasis on the sse
.
splitR
r s `comp
` f ==splitR
(r `comp
` f) (s `comp
` f) (R><
S) `comp
`splitR
p q ==splitR
(r `comp
` p) (s `comp
` q)conv
(splitR
r s) `comp
`splitR
x y == (conv
r `comp
` x) `intersection
` (conv
s `comp
` y)
eitherR
(splitR
r s) (splitR
t v) ==splitR
(eitherR
r t) (eitherR
s v)
Projections
p1 :: forall a b. (CountableDimensionsN a b, CountableN (a, b), FromListsN (a, b) a, TrivialP a b) => Relation (a, b) a Source #
p2 :: forall a b. (CountableDimensionsN a b, CountableN (a, b), FromListsN (a, b) b, TrivialP a b) => Relation (a, b) b Source #
Bifunctor
(><) :: (CountableDimensionsN a b, CountableDimensionsN c d, CountableDimensionsN (a, c) (b, d), FromListsN (a, c) a, FromListsN (a, c) c, FromListsN (b, d) b, FromListsN (b, d) d, TrivialP a c, TrivialP b d) => Relation a b -> Relation c d -> Relation (a, c) (b, d) infixl 4 Source #
Relational coproduct
Injections
i1 :: (CountableDimensionsN a b, FromListsN b a, FromListsN a a) => Relation a (Either a b) Source #
i2 :: (CountableDimensionsN a b, FromListsN a b, FromListsN b b) => Relation b (Either a b) Source #
Bifunctor
(-|-) :: (CountableDimensionsN b d, FromListsN b b, FromListsN d b, FromListsN b d, FromListsN d d) => Relation a b -> Relation c d -> Relation (Either a c) (Either b d) infixl 5 Source #
Relational "currying"
trans :: (CountableDimensionsN a b, CountableN c, CountableDimensionsN (a, b) (c, b), FromListsN (c, b) c, FromListsN (c, b) b, FromListsN (a, b) a, FromListsN (a, b) b, Trivial (a, b), Trivial (c, b), TrivialP a b, TrivialP c b) => Relation (a, b) c -> Relation a (c, b) Source #
Relational trans
Every n-ary relation can be expressed as a binary relation through 'trans'/'untrans'; more-over, where each particular attribute is placed (input/output) is irrelevant.
untrans :: (CountableDimensionsN a b, CountableN c, CountableDimensionsN (a, b) (c, b), FromListsN (c, b) c, FromListsN (c, b) b, FromListsN (a, b) b, FromListsN (a, b) a, Trivial (a, b), Trivial (c, b), TrivialP a b, TrivialP c b) => Relation a (c, b) -> Relation (a, b) c Source #
Relational untrans
Every n-ary relation can be expressed as a binary relation through 'trans'/'untrans'; more-over, where each particular attribute is placed (input/output) is irrelevant.
(Endo-)Relational properties
reflexive :: (CountableN a, FromListsN a a) => Relation a a -> Bool Source #
coreflexive :: (CountableN a, FromListsN a a) => Relation a a -> Bool Source #
A Relation
r
is coreflexive
iff
r `
sse
` identity
transitive :: Relation a a -> Bool Source #
A Relation
r
is transitive
iff
(r `
comp
` r) `sse
` r
antiSymmetric :: (CountableN a, FromListsN a a) => Relation a a -> Bool Source #
irreflexive :: (CountableN a, FromListsN a a) => Relation a a -> Bool Source #
A Relation
r
is irreflexive
iff
(r `
intersection
` identity
) == zeros
connected :: (CountableN a, FromListsN a a) => Relation a a -> Bool Source #
preorder :: (CountableN a, FromListsN a a) => Relation a a -> Bool Source #
A Relation
r
is a preorder
iff
reflexive
r && transitive
r
partialOrder :: (CountableN a, FromListsN a a) => Relation a a -> Bool Source #
A Relation
r
is a partial-order iff
antiSymmetric
r && preorder
r
linearOrder :: (CountableN a, FromListsN a a) => Relation a a -> Bool Source #
A Relation
r
is a linear-order iff
connected
r && partialOrder
r
equivalence :: (CountableN a, FromListsN a a) => Relation a a -> Bool Source #
A Relation
r
is an equivalence
iff
symmetric
r && preorder
r
partialEquivalence :: (CountableN a, FromListsN a a) => Relation a a -> Bool Source #
A Relation
r
is a partial-equivalence iff
partialOrder
r && equivalence
r
difunctional :: Relation a b -> Bool Source #
A Relation
r
is difunctional
or regular wherever
r `
comp
` conv
r `comp
` r == r
Conditionals
equalizer :: (CountableN a, FromListsN a a) => Relation a b -> Relation a b -> Relation a a Source #
McCarthy's Conditional
predR :: (Bounded a, Enum a, CountableN a, FromListsN a a, FromListsN Bool a) => Relation a Bool -> Relation a a Source #
guard :: (Bounded b, Enum b, CountableN b, FromListsN b b, FromListsN Bool b) => Relation b Bool -> Relation b (Either b b) Source #
cond :: (Bounded b, Enum b, CountableN b, FromListsN b b, FromListsN Bool b) => Relation b Bool -> Relation b c -> Relation b c -> Relation b c Source #
Relational McCarthy's conditional.
Relational composition and lifting
identity :: (FromListsN a a, CountableN a) => Relation a a Source #
fromF :: (Liftable a b, CountableDimensionsN c d, FromListsN d c) => (a -> b) -> Relation c d Source #
Lifts functions to matrices with arbitrary dimensions.
NOTE: Be careful to not ask for a matrix bigger than the cardinality of
types a
or b
allows.
fromF' :: (Liftable a b, CountableDimensionsN a b, FromListsN b a) => (a -> b) -> Relation a b Source #
Lifts functions to matrices with dimensions matching a
and b
cardinality's.
Relational application
pointAp :: (Liftable a b, Eq a, CountableDimensionsN a b, FromListsN a One, FromListsN b One) => a -> b -> Relation a b -> Relation One One Source #
pointApBool :: (Liftable a b, Eq a, CountableDimensionsN a b, FromListsN a One, FromListsN b One) => a -> b -> Relation a b -> Bool Source #
Matrix printing
prettyPrint :: CountableDimensionsN a b => Relation a b -> IO () Source #
Relation pretty printing