F#歧视联盟中的共享案例

Mau*_*Mau 6 f# types discriminated-union

我想写这样的东西:

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
Run Code Online (Sandbox Code Playgroud)

编译器抱怨之间的冲突NumExp,并ExpgetValue.即便是以下失败:

let getValue (nn : NumExp) = match nn with | Num(n) -> n
Run Code Online (Sandbox Code Playgroud)

有没有办法在两个有功能的歧视联盟中使用相同的案例?DU定义本身没问题.

我想使用相同的情况来避免添加一个间接级别

type Exp =
    | NumExpExp of NumExp
    | Dot of NumExp * NumExp
    | Op of string * Exp * Exp
Run Code Online (Sandbox Code Playgroud)

Exp定义中.我觉得我在这里缺少一些非常基本的东西.

我之所以NumExp是我希望能够"即插即用" 2 Exps转换为Dot(而不是2个漂浮),因为它使生成的表达更容易,但他们不能有任何Exp,只是数值.

编辑:我真正想知道的是两个DU中的两个案例是否可以被视为同一个实体(有点像Exp"包括" NumExp).我现在意识到Exp.Num并且NumExp.Num是完全独立的实体.Tomas提供了一种区分下面两种情况的好方法.

Tom*_*cek 14

如果您有两个具有相互冲突的案例名称的歧视联盟,您可以使用受歧视的联合案例的完全限定名称:

 let getValue (NumExp.Num(n)) = n  
Run Code Online (Sandbox Code Playgroud)

更完整的示例如下所示:

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
Run Code Online (Sandbox Code Playgroud)

这总是使用完全限定的名称,如果名称足够简单并且存在冲突的情况(这可能导致混淆),这可能是一个好主意.

编辑:关于案例的共享 - 没有自动的方法,但你可以在你的案例中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
Run Code Online (Sandbox Code Playgroud)

在编写eval函数时,您将编写(请注意,我们不再存在名称冲突问题,因此我们不需要完全限定名称):

| NumExp(Num f) -> f
| Op(op, e1, e2) -> // ...
Run Code Online (Sandbox Code Playgroud)

  • @Mau:我添加了一些关于在不同的歧视联盟之间分享案件的信息.这是不可能的,但你可以在另一个中包含一个. (2认同)