Cha*_*ion 3 f# discriminated-union
我试图将一个小编译器从C#移植到F#,以利用模式匹配和区分联合等功能.目前,我使用基于System.Linq.Expressions的模式对AST进行建模:一个抽象基础"Expression"类,每个表达式类型的派生类,以及允许在没有大量转换的情况下切换表达式的NodeType枚举.我曾希望使用F#区别联盟大大减少这种情况,但我遇到了几个看似有限的问题:
let f (x : TYPE) = x编译为Expression(联合类型)而不是for Add或Expression.Add.这似乎比我的C#方法牺牲了一些类型安全性.对于这些或设计模式是否有良好的解决方法,使它们不那么令人沮丧?
Dan*_*ian 12
我认为,对于DU是一个类层次结构的想法,你有点过分了.将它真实地视为数据更有帮助.因此:
- 强制公共默认构造函数(我想对表达式构造进行类型检查和参数验证,因为System.Linq.Expressions使用它的静态工厂方法)
DU只是数据,非常类似于字符串或数字,而不是功能.你为什么不创建一个函数来返回你的Expression option表达,你的数据可能是无效的.
- 缺少命名属性(似乎这在F#3.1中已修复)
如果您觉得需要命名属性,可能会有一个不合适的类型,例如string * string * string * int * float您的数据Expression.更好地创建一个记录,类似的东西AddInfo,并使你的DU使用的情况相反,如说| Add of AddInfo.这样你就可以在模式匹配,智能感知等方面拥有属性.
- 无法直接引用案例类型.例如,似乎我不能声明一个只从联合中获取一个类型的函数(例如,让f(x:TYPE)= x为表达式(联合类型)编译,但不为Add或Expression.Add编译.这似乎比我的C#方法牺牲了一些类型安全性.
你不能要求某些东西是Add这样的,但你绝对可以写一个函数,需要一个AddInfo.此外,你总是可以以一元的方式做到这一点,并具有任何Expression只返回的功能option.在这种情况下,您可以模式匹配,您的输入是适当的类型,None如果不是,则返回.在呼叫站点,您可以使用像这样的函数"使用"好的情况下的值Option.bind.
基本上尽量不要将DU视为一组类,但实际上只是数据的情况.有点像枚举.
Dan*_*iel 10
您可以将实现设为私有.这使您可以在实现中充分发挥DU的功能,但对API的消费者提供有限的视图.有关记录的相关问题,请参阅此答案(尽管它也适用于DUs).
编辑
我在MSDN上找不到语法,但这里是:
type T =
private
| A
| B
Run Code Online (Sandbox Code Playgroud)
private 这里的意思是"模块私有".
| 归档时间: |
|
| 查看次数: |
1851 次 |
| 最近记录: |