【问题标题】:F# how to specify type restriction in recursive discriminated unionsF#如何在递归可区分联合中指定类型限制
【发布时间】:2017-05-12 06:19:57
【问题描述】:

我试图将我的语法定义为有区别的联合。它有两种可能的类型:intdatetime 以及AddMul 的数学运算符。 Add 适用于 intdatetime(在 int 中添加天数) Mul 仅适用于 int 而不适用于 datetime 语法可以递归

我的语法看起来像

type MyExpression =
|Integer of int
|Date of datetime
|Add of MyExpression * MyExpression
|Mul of MyExpression * MyExpression

我已经编写了一个解析器 (fparsec),它可以解析我的语法中的文本,但我不确定如何处理 Mul 可以递归但只能在 Integer 上递归的情况。

是否可以选择对我的 MyExpression 类型定义此限制,或者我是否必须在解析的输入中处理此限制?

【问题讨论】:

    标签: f# restriction f#-3.0


    【解决方案1】:

    Asti 建议的设计也是我的首选。根据您的要求,这可能就是您所需要的。

    不过,它也可以让你编译像

    这样的表达式
    Add(Val(System.Console.Out), Val(System.Console.Error))
    

    这可能不是你想要的。

    或者,您可以像这样为表达式建模:

    open System
    
    type IntExpression =
    | Integer of int
    | Mul of IntExpression * IntExpression
    | Add of IntExpression * IntExpression
    
    type DateTimeExpression =
    | Date of DateTime
    | Add of DateTimeExpression * DateTimeExpression
    
    type MyExpression =
    | IntExpression of IntExpression
    | DateTimeExpression of DateTimeExpression
    

    这显然是一个更详细的类型定义,但它确实体现了表达式可以包含整数或 DateTime 值的叶节点的规则,并且不能包含其他值 - 如果这是您想要强制执行的规则。

    我并不是说这更好;我只是提供一个替代方案。

    用法:

    > IntExpression(Mul(IntExpression.Add(Integer(1), Integer(2)),Integer 3));;
    val it : MyExpression =
      IntExpression (Mul (Add (Integer 1,Integer 2),Integer 3))
    > DateTimeExpression(Add(Date(DateTime.MinValue),Date(DateTime.MinValue)));;
    val it : MyExpression =
      DateTimeExpression
        (Add
           (Date 01.01.0001 00:00:00 {Date = 01.01.0001 00:00:00;
                                      Day = 1;
                                      DayOfWeek = Monday;
                                      DayOfYear = 1;
                                      Hour = 0;
                                      Kind = Unspecified;
                                      Millisecond = 0;
                                      Minute = 0;
                                      Month = 1;
                                      Second = 0;
                                      Ticks = 0L;
                                      TimeOfDay = 00:00:00;
                                      Year = 1;},
            Date 01.01.0001 00:00:00 {Date = 01.01.0001 00:00:00;
                                      Day = 1;
                                      DayOfWeek = Monday;
                                      DayOfYear = 1;
                                      Hour = 0;
                                      Kind = Unspecified;
                                      Millisecond = 0;
                                      Minute = 0;
                                      Month = 1;
                                      Second = 0;
                                      Ticks = 0L;
                                      TimeOfDay = 00:00:00;
                                      Year = 1;}))
    

    【讨论】:

      【解决方案2】:

      如果您有基于类型的约束,使用通用方法可能更容易:

      type MyExpression<'t> =
      |Val of 't
      |Mul of MyExpression<int> * MyExpression<int>
      |Add of MyExpression<'t> * MyExpression<'t>
      
      let Integer (x:int) = Val(x)
      let Date (x:DateTime) = Val(x)
      

      用法:

      Mul(Integer(1), Integer(2)) //compiles
      Mul(Date(DateTime.Now), Date(DateTime.Now)) //error
      

      【讨论】:

      • 这处理了一些限制,但不是全部 - 以下不是一个合理的表达式,但它会进行类型检查:Add(Date(DateTime.Now), Mul(Integer 1, Integer 2))
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-08-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-22
      相关资源
      最近更新 更多