F# 区分并集中的类型约束

F# 区分并集中的类型约束,f#,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);

考虑一下

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
我知道它显然不起作用。这对我来说是很自然的事情


非常感谢你的帮助

不能对“区分联合”使用泛型类型约束。但是,您可以将特定类型固定到受歧视的联合,如下所示

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) ] )

这回答了你的问题吗?

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

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) )
在F#type系统中,您可能不会说“这是一些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"]) ]
类型Foo=I of int | S of string
let(| F | L |)(o:obj)=
匹配
| :? Foo as v->F v
| :? 列表为v->L v
|带有“未知类型”的故障
;;
设f=函数
|F u->“Foo”
|L->“食品清单”
;;
List.mapf[box(i1);box(S“stuff”);box([i2;S“foo”)]

如果I和S真的对自己感兴趣,也就是说,你想从S列表中知道I列表,那么为什么不明确一点呢

type I = int
type S = string

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

好球!我同意用我的方式去做可以让你将子列表加入到主列表中,同时定义第二个受歧视的联盟可以避免混乱。谢谢Chris和Brian!事实上,这并不是我想要做的。我正在寻找一种方法来约束列表中的元素,使其仅来自我的示例中所示的特定类型。它不允许Foo有L([L([I(42)]))))。不,因为我希望FooAtom有所有相同的子类型,[A(I(5));A(S(“S”)]不应该编译。所有的东西都应该是I,或者所有的东西都应该是S,但不是混合。你真的不应该这样做:-/动态类型测试(:?)会导致相当大的性能损失,而且由于您正在装箱这些项,您将失去类型安全性-因此您可以在运行时命中“failwith”案例,而不会得到F#编译器的任何支持。是的,事实上,这就是我所做的。谢谢你指出这一点!但问题更多的是F#type系统是否能够处理这一问题。