///|
pub(open) trait Semiring {
  zero() -> Self
  one() -> Self
  op_add(Self, Self) -> Self
  op_mul(Self, Self) -> Self
}

///|
pub(open) trait Ring: Semiring {
  op_sub(Self, Self) -> Self
  op_neg(Self) -> Self
}

///|
pub impl Semiring for Bool with one() {
  true
}

///|
pub impl Semiring for Bool with zero() {
  false
}

///|
pub impl Semiring for Bool with op_add(a, b) {
  a || b
}

///|
pub impl Semiring for Bool with op_mul(a, b) {
  a && b
}

///|
pub impl Semiring for Int with one() {
  1
}

///|
pub impl Semiring for Int with op_add(x, y) {
  x + y
}

///|
pub impl Semiring for Int with op_mul(x, y) {
  x * y
}

///|
pub impl Semiring for Int with zero() {
  0
}

///|
pub impl Ring for Int with op_sub(x, y) {
  x - y
}

///|
pub impl Ring for Int with op_neg(x) {
  -x
}

///|
pub impl Semiring for Byte with one() {
  1
}

///|
pub impl Semiring for Byte with zero() {
  0
}

///|
pub impl Semiring for Byte with op_add(x, y) {
  x + y
}

///|
pub impl Semiring for Byte with op_mul(x, y) {
  x * y
}