In
type Cell = Player | Empty
Player
не тип, а значение типа Cell
. Однако вы также можете указать ему аргумент, и в этом случае это будет конструктор значения, который при получении аргумента возвращает значение типа Cell
. Таким образом, в
type Player = X | O
type Cell = Player Player | Empty
первый Player
в Player Player
по сути является функцией, которая при задании значения типа Player
будет возвращать значение типа Cell
. Или Player -> Cell
в типе-говорить.
Обратите также внимание, что и тип, и конструктор могут иметь одно и то же имя, поскольку они находятся в разных доменах. Они не конфликтуют, потому что они ссылаются на разные вещи, одна ссылается на тип, а другая на значение (конструктор). Но тот факт, что вы можете сделать это, не обязательно означает, что вы должны это делать, поскольку это может быть довольно запутанным.
Затем вы можете сопоставить шаблон с Cell
и вложенным Player
следующим образом:
type Player = X | O
type Cell = Player Player | Empty
viewCell: Cell -> String
viewCell cell =
case cell of
Player X -> "X"
Player O -> "O"
Empty -> " "
Player
и Empty
здесь относятся к конструкторам / вариантам Cell
, а не к типам. И аналогично X
и O
относятся к вариантам Player
, которые также не являются типами.