Li *_*oyi 2 f# discriminated-union
假设我有一个重要的类层次结构:
Tag
ControlFlowTag
IfTag
ForTag
JumpTag
HTMLTag
DivTag
Run Code Online (Sandbox Code Playgroud)
我想制作一个穿插这些和字符串的列表.
let MyList = [tagA, tagB, "some text", tagC]
Run Code Online (Sandbox Code Playgroud)
我以为我可以区别对待它
type Node =
| Tag of Tag
| String of String
let MyList: list<Node> = [tagA, tagB, "some text", tagC]
Run Code Online (Sandbox Code Playgroud)
但唉,没有它就行不通
let MyList: list<Node> = [Tag tagA, Tag tagB, String "some text", Tag tagC]
Run Code Online (Sandbox Code Playgroud)
显然,Node中描述的Tag和String是正交的,与现有的Tag/String类分开.鼠标悬停给了我类型Node.Tag和Node.String,这不是我想要的.
我现在已经是一个功能t它创建了一个StringTag从继承Tag,给我
let MyList : list<Tag> = [tagA, tagB, t"some text", tagC]
Run Code Online (Sandbox Code Playgroud)
这是非常好的,但额外t增加了视觉噪音.我真正想要的是一个强类型的"两种不同类型的列表",我可以使用它来处理match.我认为这是Discriminated Unions的重点,但是他们无法使用现有的类型层次结构是一个问题,因为现有的层次结构(在这种情况下Tag)足够复杂我认为对该类型子集的完整OO继承方法比一种纯粹的歧视联盟方法
一个选择是在它obj之前/期间将其列为一个列表并投射所有内容match,但这并不是很好.还有其他方法吗?
如果你有两个不同的DU,比如说
type Node =
| Tag of Tag
| String of String
Run Code Online (Sandbox Code Playgroud)
和
type Foo =
| Bar of Tag
| Name of String
Run Code Online (Sandbox Code Playgroud)
编译器如何知道以下列表是哪种类型的?
[tagA; tagB; "some text"; tagC]
Run Code Online (Sandbox Code Playgroud)
正如斯维克所说,鉴别者是必要的.如果你使用类而不是你需要向上转换为基类型,所以我不确定你是否节省了击键次数.
如果你正在使用词典,这是一个很好的选择,以减少拳击的句法噪音.也许你可以为列表做类似的事情.
我不知道这有多大帮助,但是如果合适的话,你可以使用Active Patterns以类似DU的方式匹配类层次结构.
[<AbstractClass>]
type Animal() =
abstract Talk : string
type Cat() =
inherit Animal()
override this.Talk = "Meow"
type Dog() =
inherit Animal()
override this.Talk = "Woof"
type SuperCat(s) =
inherit Cat()
override this.Talk = s
let animals : list<Animal> =
[Dog(); Cat(); SuperCat("MEOW")]
let (|SCSaid|_|) (a:Animal) = // Active Pattern
match a with
| :? SuperCat as sc -> Some sc.Talk
| _ -> None
for a in animals do
match a with
| :? Dog -> printfn "dog"
| SCSaid s -> printfn "SuperCat said %s" s // looks like DU
| _ -> printfn "other"
//dog
//other
//SuperCat said MEOW
Run Code Online (Sandbox Code Playgroud)