我想写这样的东西:
type NumExp = Num of float
type Exp =
| Num of float
| Dot of NumExp * NumExp
| Op of string * Exp * Exp
let getValue (Num(n) : NumExp) = n
编译器抱怨NumExp
中Exp
和getValue
之间存在冲突。
甚至以下都失败了:
let getValue (nn : NumExp) = match nn with | Num(n) -> n
有没有办法在两个使用函数的区分联合中使用相同的案例? DU定义本身就可以。
我想使用相同的情况来避免添加像
这样的间接级别type Exp =
| NumExpExp of NumExp
| Dot of NumExp * NumExp
| Op of string * Exp * Exp
Exp
定义中的。 我觉得我在这里遗漏了一些非常基本的东西。
我NumExp
的原因是我希望能够将Exp
'插入'Dot
(而不是2个浮点数),因为它可以更容易地生成表达式,但它们不能是任何Exp
,只是数字。
编辑:我真正想知道的是两个DU中的两个案例是否可以被视为同一个实体(类似于Exp
“,包括”{{1} })。我意识到现在NumExp
和Exp.Num
是完全独立的实体。 Tomas提供了一种区分下面两种情况的好方法。
答案 0 :(得分:13)
如果您有两个具有相互冲突的案件名称的歧视联盟,您可以使用受歧视的工会案件的完全限定名称:
let getValue (NumExp.Num(n)) = n
更完整的示例如下所示:
let rec eval = function
| Exp.Num(f) -> f
| Exp.Dot(NumExp.Num(f1), NumExp.Num(f2)) ->
// whatever 'dot' represents
| Exp.Op(op, e1, e2) ->
// operator
这总是使用完全限定的名称,如果名称足够简单并且存在冲突的情况(可能导致混淆),这可能是一个好主意。
编辑:关于案例分享 - 没有自动执行此操作的方法,但您的Exp
中可能只包含NumExp
的值。例如:
type NumExp =
| Num of float
type Exp =
// first occurrence of NumExp is just a name, but F# allows us to reuse
// the name of the type, so we do that (you could use other name)
| NumExp of NumExp
// other cases
编写eval
函数时,您将编写(请注意,我们不再存在名称冲突问题,因此我们不需要完全限定名称):
| NumExp(Num f) -> f
| Op(op, e1, e2) -> // ...
答案 1 :(得分:2)
如果可能的话(例如在OCaml中使用多态变体),你可以用它做很多事情但是(遗憾的是)F#没有这种语言特性,所以它目前无法用联合类型表达你想要的东西。但是,您可以考虑使用OOP ......
答案 2 :(得分:2)
您可以使用interfaces as a substitute。 这增加了一些语法开销,但这是我发现这样做的最好方法。
type IExp = interface end
type NumExp =
| Num of float
interface IExp
type Exp =
| Dot of NumExp * NumExp
| Op of string * IExp * IExp
interface IExp
// This function accepts both NumExp and Exp
let f (x:IExp) = match x with
| :? NumExp as e -> match e with
| Num v -> "Num"
| :? Exp as e -> match e with
| Dot (e1,e2) -> "Dot"
| Op (op,e1,e2) -> "Op"
| _ -> invalidArg "x" "Unsupported expression type"
// This function accepts only NumExp
let g = function
| Num v -> "Num"
答案 3 :(得分:-1)
只是一个观察:为什么你需要以这种方式构建的工会?
我会选择以下两个选项之一:
type NumExp = Num of float
type Exp =
| Num of float
| Dot of float * float
| Op of string * Exp * Exp
更简单,或者
type NumExp = Num of float
type Exp =
| NumExp
| Dot of float * float
| Op of string * Exp * Exp
在第二种情况下,您的功能
let getValue (Num(n) : NumExp) = n
现在只有NumExp
的定义。