# Algebraic type

Algebraic types are types that are generated by operating types by treating them like algebra. Operations handled by them include Union, Intersection, Diff, Complement, and so on. Normal classes can only perform Union, and other operations will result in a type error.

## Union

Union types can give multiple possibilities for types. As the name suggests, they are generated by the `or` operator. A typical Union is the `Option` type. The `Option` type is a `T or NoneType` patch type, primarily representing values that may fail.

``````IntOrStr = Int or Str
assert dict.get("some key") in (Int or NoneType)

Option T = T or NoneType
``````

Note that Union types are commutative but not associative. That is, `X or Y or Z` is `(X or Y) or Z`, not `X or (Y or Z)`. Allowing this would result in, for example, `Int or Option(Str)`, `Option(Int) or Str` and `Option(Int or Str)` being of the same type.

## Intersection

Intersection types are got by combining types with the `and` operation.

``````Num = Add and Sub and Mul and Eq
``````

As mentioned above, normal classes cannot be combined with the `and` operation. This is because instances belong to only one class.

## Diff

Diff types are got by `not` operation. It is better to use `and not` as a closer notation to English text, but it is recommended to use just `not` because it fits better alongside `and` and `or`.

``````CompleteNum = Add and Sub and Mul and Div and Eq and Ord
Num = CompleteNum not Div not Ord

True = Bool not {False}
OneTwoThree = {1, 2, 3, 4, 5, 6} - {4, 5, 6, 7, 8, 9, 10}
``````

## Complement

Complement types is got by the `not` operation, which is a unary operation. The `not T` type is a shorthand for `{=} not T`. Intersection with type `not T` is equivalent to Diff, and Diff with type `not T` is equivalent to Intersection. However, this way of writing is not recommended.

``````# the simplest definition of the non-zero number type
NonZero = Not {0}
# deprecated styles
{True} == Bool and not {False} # 1 == 2 + - 1
Bool == {True} not not {False} # 2 == 1 - -1
``````

## True Algebraic type

There are two algebraic types: apparent algebraic types that can be simplified and true algebraic types that cannot be further simplified. The "apparent algebraic types" include `or` and `and` of Enum, Interval, and the Record types. These are not true algebraic types because they are simplified, and using them as type specifiers will result in a Warning; to eliminate the Warning, you must either simplify them or define their types.

``````assert {1, 2, 3} or {2, 3} == {1, 2, 3}
assert {1, 2, 3} and {2, 3} == {2, 3}
assert -2..-1 or 1..2 == {-2, -1, 1, 2}

i: {1, 2} or {3, 4} = 1 # TypeWarning: {1, 2} or {3, 4} can be simplified to {1, 2, 3, 4}
p: {x = Int, ...} and {y = Int; ...} = {x = 1; y = 2; z = 3}
# TypeWaring: {x = Int, ...} and {y = Int; ...} can be simplified to {x = Int; y = Int; ...}

Point1D = {x = Int; ...}
Point2D = Point1D and {y = Int; ...} # == {x = Int; y = Int; ...}
q: Point2D = {x = 1; y = 2; z = 3}
``````

True algebraic types include the types `Or` and `And`. Classes such as `or` between classes are of type `Or`.

``````assert Int or Str == Or(Int, Str)
assert Int and Marker == And(Int, Marker)
``````

Diff, Complement types are not true algebraic types because they can always be simplified.