在Discriminated Union中键入约束

时间:2009-09-01 00:32:04

标签: f#

考虑一下

type Foo =
  | I of int
  | S of string



let test = [ I(5); I(9); I(7)]

它有效,但现在我希望'test'也属于Foo类型,并且仍然是I或S的列表。例如

let test = L( [ I(5); I(9); I(42) ] ) //works!
let test2 = L( [ I(5); I(9); S("stuff") ] ) //type error
let test3 = L( [ I(5); I(9); L([]) ] ) //type error

我试试..

type Foo =
  | I of int
  | S of string
  | L of 'T list when 'T :> Foo

我知道它显然不起作用。这对我来说是一件很自然的事情。

非常感谢你的帮助!!

4 个答案:

答案 0 :(得分:7)

您不能对'区别联盟'使用泛型类型约束。但是你可以将特定类型固定到Discriminated union,如下所示。

type Foo = 
    | I of int 
    | S of string
    | L of Foo list


// Usage
let test = L( [ I(5); I(9); S("stuff"); L([]); I(42) ] )

这会回答你的问题吗?

答案 1 :(得分:5)

克里斯有一个很好的答案。如果你不希望列表嵌套,你也可以这样做

type FooAtom = 
    | I of int 
    | S of string

type Foo = 
    | A of FooAtom
    | L of FooAtom list

let test  = L( [ I(5); I(9); S("stuff"); I(42) ] )
let test2 = A( I(5) )

答案 2 :(得分:2)

如果我和S本身真的很有趣,也就是说你想知道我从S列表中列出的,那么为什么不明确?

type I = int
type S = string

type Foo =
    | I
    | S
    | LI of I list
    | LS of S list

答案 3 :(得分:1)

就F#类型系统而言,你可能不会说“这是Foo的一些成员和其他(不是Foo)事物的列表”。 但是你可以使用运行时和另一个间接层:

type Foo = I of int | S of string

let (|F|L|) (o: obj) =
  match o with
  | :? Foo as v -> F v
  | :? list<Foo> as v -> L v
  | _ -> failwith "unknown type"
;;

let f = function
  | F _ -> "Foo"
  | L _ -> "List of Foos"
;;

List.map f [ box (I 1); box (S "stuff"); box ([I 2; S "foo"]) ]