6.11.1. Category Protocol

A category "c" shall support the following methods:
c.is_arrow(x)
Shall return 1 if the argument is an arrow of the category, and 0 otherwise.
c.is_object(x)
Shall return 1 if the argument is an object of the category, and 0 otherwise.
c.domain(x)
Shall return the domain object of arrow x.
c.codomain(x)
Shall return the codomain object of arrow x.
c.can_compose(x,y)
If x and y are arrows, shall return 1 if x can be composed with y, or 0 if they cannot be composed, else undefined.
c.compose(x,y)
Shall return the composition of x and y if x and y are composable.
c(x1, x2, ...)
Shall return the composition of the arguments if well defined.
The following methods are optional:
c.inverse(x)
Shall return the inverse of an arrow x if it has one.
c.get_arrows()
Shall return a sequence of all the arrows of a category. If defined, the representation of the category is said to be enumerable.
c.get_objects()
Shall return a sequence of all the objects of a category. Shall be defined if "get_arrows()" is defined.
c.get_nonobjects()
Shall return a sequence of all the non-object arrows of a category. Shall be defined if "get_arrows()" is defined.
Composition is a partial binary operator, and shall be associative. The objects shall be precisely theidentity arrows. In particular:
  if c.is_object(p):
    assert c.is_arrow(p)
  if c.is_arrow(x) and c.is_arrow(y) and c.is_arrow(z):
    if c.can_compose(x,y) and c.can_compose(y,z):
      assert c(c(x,y),z) == c(x,c(y,z) # associative
  if c.is_arrow(x):
    assert c.is_object(c.domain(x))    # domain and codomain are objects
    assert c.is_object(c.codomain(x))
    assert c.compose(c.domain(x), x) == x
    assert c.compose(x, c.codomain(x)) == x