升级 FParsec:升级可区分联合以满足新的相等/比较约束
因此,通过 嗨<在发生了一系列事件之后,我下载了 FParsec 源代码并尝试构建它。不幸的是,它与新的 1.9.9.9 不兼容。我解决了简单的问题,但有几个受歧视的工会仍然不起作用。
具体来说, Don Syme 的文章 解释了包含 obj
或 ->
类型项的可区分联合不会自动获得相等或比较约束,因为对象不支持比较,函数也不支持相等。 (目前尚不清楚自动生成的相等/比较之前是否有错误,但现在不再生成代码,代码甚至无法编译。)
以下是有问题的 DU 的一些示例:
type PrecedenceParserOp<'a,'u'> =
| PrefixOp of string * Parser<unit,'u> * int * bool * ('a -> 'a)
| others ...
type ErrorMessage =
| ...
| OtherError of obj
| ...
以下是违规用途:
member t.RemoveOperator (op: PrecedenceParserOp<'a, 'u>) =
// some code ...
if top.OriginalOp <> op then false // requires equality constraint
// etc etc ...
或者,对于比较约束
let rec printMessages (pos: Pos) (msgs: ErrorMessage list) ind =
// other code ...
for msg in Set.ofList msgs do // iterate over ordered unique messages
// etc etc ...
据我所知,Don 的解决方案是用唯一的 int 标记每个实例,这是实现自定义相等/比较约束的正确方法(或者可能是唯一的 int 元组,以便可以对 DU 的各个分支进行排序) )。但这对于DU的用户来说是不方便的。现在,DU 的构建需要调用函数来获取下一个标记。
是否有某种方法可以隐藏标签获取并向库的用户提供相同的构造函数?即改变实现而不改变接口?这一点尤其重要,因为(根据我对代码的理解)PrecedenceParserOp 似乎是一个公共类型。
So, by a hilarious series of events, I downloaded the FParsec source and tried to build it. Unfortunately, it's not compatible with the new 1.9.9.9. I fixed the easy problems, but there are a couple of discriminated unions that still don't work.
Specifically, Don Syme's post explains that discriminated unions containing items of type obj
or ->
don't automatically get equality or comparison constraints, since objects don't support comparison and functions don't support equality either. (It's not clear whether the automatically generated equality/comparison was buggy before, but the code won't even compile now that they're no longer generated.)
Here are some examples of the problematic DUs:
type PrecedenceParserOp<'a,'u'> =
| PrefixOp of string * Parser<unit,'u> * int * bool * ('a -> 'a)
| others ...
type ErrorMessage =
| ...
| OtherError of obj
| ...
Here are the offending uses:
member t.RemoveOperator (op: PrecedenceParserOp<'a, 'u>) =
// some code ...
if top.OriginalOp <> op then false // requires equality constraint
// etc etc ...
or, for the comparison constraint
let rec printMessages (pos: Pos) (msgs: ErrorMessage list) ind =
// other code ...
for msg in Set.ofList msgs do // iterate over ordered unique messages
// etc etc ...
As far I can tell, Don's solution of tagging each instance with a unique int is the Right Way to implement a custom equality/comparison constraint (or a maybe a unique int tuple so that individual branches of the DU can be ordered). But this is inconvenient for the user of the DU. Now, construction of the DU requires calling a function to get the next stamp.
Is there some way to hide the tag-getting and present the same constructors to users of the library? That is, to change the implementation without changing the interface? This is especially important because it appears (from what I understand of the code) that PrecedenceParserOp
is a public type.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您下载的 FParsec 来源是什么?我从 FParsec BitBucket 存储库 获取了最新版本,并且无需在全部转到 FParsec 源代码以使其在 VS 2010 RC 中进行编译。
编辑:我收回那句话。我确实从 InterpLexYacc 和 InterpFParsec 示例项目中遇到了构建错误,但核心 FParsec 和 FParsecCS 项目构建得很好。
What source did you download for FParsec? I grabbed the latest from the FParsec BitBucket repository, and I didn't have to make any changes at all to the FParsec source to get it to compile in VS 2010 RC.
Edit: I take that back. I did get build errors from the InterpLexYacc and InterpFParsec sample projects, but the core FParsec and FParsecCS projects build just fine.
您可以做的一件事是添加
[]
和[]
属性并定义您自己的.Equals
覆盖和IComparable
实现。当然,这需要您处理obj
和_ ->; _
以适当的方式自行组件,这可能可行,也可能不可能。如果您可以控制传递到OtherError
构造函数中的内容,则应该能够通过向下转换obj
来使该操作适用于ErrorMessage
类型其本身在结构上具有可比性。但是,PrecendenceParserOp 情况有点棘手 - 只要您不需要比较,您就可以在函数组件上使用引用相等。One thing you could do is add
[<CustomEquality>]
and[<CustomComparison>]
attributes and define your own.Equals
override andIComparable
implementation. Of course, this would require you to handle theobj
and_ -> _
components yourself in an appropriate way, which may or may not be possible. If you can control what's being passed into theOtherError
constructor, you ought to be able to make this work for theErrorMessage
type by downcasting theobj
to a type which is itself structurally comparable. However, thePrecendenceParserOp
case is a bit trickier - you might be able to get by with using reference equality on the function components as long as you don't need comparison as well.