代码之家  ›  专栏  ›  技术社区  ›  Mau

歧视工会中的共同案件

  •  6
  • Mau  · 技术社区  · 14 年前

    我想写这样的东西:

    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
    

    费用 定义。 我觉得我错过了一些非常基本的东西。

    我的原因 纽马克 我想能插上2号插头吗? 费用 进入一个 Dot (而不是2个浮点)因为它使生成表达式更容易,但它们不能是任何 费用 ,只是数字。

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

    4 回复  |  直到 9 年前
        1
  •  13
  •   Tomas Petricek    14 年前

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

     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) -> // ...
    
        2
  •  2
  •   J D    14 年前

    如果可能的话(例如使用OCAML中的多态变体),您可以用它做很多事情,但(遗憾的是)F_没有这种语言特性,因此它目前无法使用联合类型表达您想要的内容。但是,您可以考虑使用OOP代替…

        3
  •  2
  •   dtech Ashtonian    9 年前

    你可以使用 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"
    
        4
  •  -1
  •   Muhammad Alkarouri    14 年前

    只是一个观察:你为什么需要这样建立工会?

    我会选择两个选项中的一个:

    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 现在。