2

假设我有一个重要的类层次结构:

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]

显然 Node 中描述的 Tag 和 String 是正交的,并且与现有的 Tag/String 类分开。将鼠标悬停给我类型Node.TagNode.String,这不是我想要的。

我现在拥有的是一个函数t,它创建一个StringTag继承自的函数Tag,给我

let MyList : list<Tag> = [tagA, tagB, t"some text", tagC]

这非常好,但额外t增加了视觉噪音。我真正想要的是一个强类型的“两种不同类型的列表”,我可以使用 usingmatch语句。我认为这是区分联合的重点,但是它们无法使用现有的类型层次结构是一个问题,因为现有的层次结构(在这种情况下Tag)足够复杂,我认为对该类型子集的完整 OO 继承方法比纯歧视联盟方法

obj一种选择是在 之前/期间将其列为列表并投射所有内容match,但这并不是很好。还有其他方法吗?

4

3 回答 3

8

我不知道这有多大帮助,但如果合适的话,您可以使用 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
于 2011-11-15T08:34:46.380 回答
8

如果您有两个不同的 DU,请说

type Node = 
  | Tag of Tag
  | String of String

type Foo = 
  | Bar of Tag
  | Name of String

编译器如何知道以下列表是哪种类型?

[tagA; tagB; "some text"; tagC]

正如 svick 所说,鉴别器是必要的。如果您改用类,则需要向上转换为基本类型,因此我不确定您是否可以节省击键。

如果您正在使用字典,这里有一个很好的选项来减少装箱的句法噪音。也许你可以为列表做类似的事情。

于 2011-11-15T03:39:09.440 回答
2

受歧视的工会就是这样 - 受歧视的(与例如 C 工会不同)。这意味着您必须始终添加鉴别器。

如果这是 C#,我会考虑从stringto进行隐式转换StringTag。但由于 F# 不支持隐式转换,我认为第二种方法是您最好的选择。虽然我会让函数的名称更具描述性,而不仅仅是t. 大多数时候,最好编写易于阅读的代码,而不是易于编写的代码。

于 2011-11-15T02:26:50.043 回答