Скажем, у меня есть значительная иерархия классов:
Tag
ControlFlowTag
IfTag
ForTag
JumpTag
HTMLTag
DivTag
и я хочу составить список с вкраплениями этих и строк.
let MyList = [tagA, tagB, "some text", tagC]
и я думал, что могу различить союз
type Node =
| Tag of Tag
| String of String
let MyList: list<Node> = [tagA, tagB, "some text", tagC]
но увы без
let MyList: list<Node> = [Tag tagA, Tag tagB, String "some text", Tag tagC]
Очевидно, что Tag и String, описанные в Node, ортогональны и отделены от существующих классов Tag / String. Наведение указателя мыши дает мне типы Node.Tag
и Node.String
, чего я не хочу.
Теперь у меня есть функция t
, которая создает StringTag
, который наследуется от Tag
, давая мне
let MyList : list<Tag> = [tagA, tagB, t"some text", tagC]
что довольно приятно, но лишнее t
добавляет визуального шума. На самом деле мне нужен строго типизированный «список двух разных типов», с которым я мог бы работать, используя операторы match
. Я думал, что это и есть суть Discriminated Unions, но их неспособность использовать существующие иерархии типов является проблемой, поскольку существующая иерархия (в данном случае Tag
) достаточно сложна, я думаю, что подход полного объектно-ориентированного наследования к этому подмножеству типов более ясен чем чистый подход Дискриминационного союза
Один из вариантов - просто составить список из obj
и разыграть все до / во время match
, но это не очень хорошо. Есть ли другие подходы?