繁体   English   中英

受歧视的工会的F#限制

[英]F# limitations of discriminated unions

我试图将一个小编译器从C#移植到F#,以利用模式匹配和区分联合等功能。 目前,我使用基于System.Linq.Expressions的模式对AST进行建模:一个抽象基础“Expression”类,每个表达式类型的派生类,以及允许在没有大量转换的情况下切换表达式的NodeType枚举。 我曾希望使用F#区别联盟大大减少这种情况,但我遇到了几个看似有限的问题:

  • 强制公共默认构造函数(我想对表达式构造进行类型检查和参数验证,因为System.Linq.Expressions使用它的静态工厂方法)
  • 缺少命名属性(似乎这在F#3.1中已修复)
  • 无法直接引用案例类型。 例如,似乎我不能声明一个只从联合中获取一个类型的函数(例如, let f (x : TYPE) = xExpression (联合类型)编译,但不为AddExpression.Add编译。这似乎比我的C#方法牺牲了一些类型安全性。

对于这些或设计模式是否有良好的解决方法,使它们不那么令人沮丧?

我认为,对于DU是一个类层次结构的想法,你有点过分了。 将它真实地视为数据更有帮助。 因此:

  • 强制公共默认构造函数(我想对表达式构造进行类型检查和参数验证,因为System.Linq.Expressions使用它的静态工厂方法)

DU只是数据,非常类似于字符串或数字,而不是功能。 为什么不创建一个函数来返回Expression option来表示您的数据可能无效。

  • 缺少命名属性(似乎这在F#3.1中已修复)

如果您觉得需要命名属性,则可能有一个不合适的类型,例如string * string * string * int * float作为Expression的数据。 更好地创建一个记录,比如AddInfo并让你使用DU的情况,比如说| Add of AddInfo | Add of AddInfo 这样你就可以在模式匹配,智能感知等方面拥有属性。

  • 无法直接引用案例类型。 例如,似乎我不能声明一个只从联合中获取一个类型的函数(例如,让f(x:TYPE)= x为表达式(联合类型)编译,但不为Add或Expression.Add编译。这似乎比我的C#方法牺牲了一些类型安全性。

你不能要求一些东西成为Add case,但你绝对可以编写一个带有AddInfo的函数。 此外,您始终可以以monadic方式执行此操作,并且具有采用任何Expression功能,并且只返回option 在这种情况下,您可以模式匹配,您的输入是适当的类型,如果不是,则返回None 在调用站点,您可以使用Option.bind函数在好的情况下“使用”该值。

基本上尽量不要将DU视为一组类,但实际上只是数据的情况。 有点像枚举。

您可以将实现设为私有。 这使您可以在实现中充分发挥DU的功能,但对API的消费者提供有限的视图。 有关记录的相关问题,请参阅此答案 (尽管它也适用于DUs)。

编辑

我在MSDN上找不到语法,但这里是:

type T =
  private
  | A
  | B

private在这里意味着“私有模块”。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM