F# 中表达式的最佳表示
我正在开发一个库,用于从 LINQ 表达式(基本上是 LINQ-to-SQL 的修改子集)生成 SQL。我使用可区分联合来对 SQL 表达式进行建模,但遇到了一些(感知到的?)限制。我想做类似以下的事情(注意最后一行):
type SqlSourceExpression =
| Table of string
| Join of JoinType * SqlSourceExpression * SqlSourceExpression * SqlExpression //ie, left, right, predicate
and SqlExpression =
| Source of SqlSourceExpression
| OrderBy of SqlExpression * SortDirection
| Select of SqlSourceExpression * SqlExpression * OrderBy list //can't do this
我可以执行以下操作:
type SqlOrderByExpression = SqlExpression * SortDirection
...并将最后两行更改为:
| OrderBy of SqlOrderByExpression
| Select of SqlSourceExpression * SqlExpression * SqlOrderByExpression list
但这似乎有两个问题:
SqlOrderByExpression 不是 SqlExpression。这使得访问者模式很难使用(也许问题就在这里?)。这意味着在遍历 Select 表达式时,我无法迭代 order by 表达式列表,将每个表达式传递给 Visit(expr:SqlExpression)。
SqlOrderByExpression 只是元组的类型别名,因此不会保留任何类型信息。在我看来,这会损害可读性。
有更好的方法来建模吗?我尝试了继承路线,但我认为 DU 更容易使用(除非提到的困难)。
I'm working on a library to generate SQL from LINQ expressions (basically a modified subset of LINQ-to-SQL). I'm using discriminated unions to model the SQL expressions, but have encountered some (perceived?) limitations. I want to do something like the following (note the last line):
type SqlSourceExpression =
| Table of string
| Join of JoinType * SqlSourceExpression * SqlSourceExpression * SqlExpression //ie, left, right, predicate
and SqlExpression =
| Source of SqlSourceExpression
| OrderBy of SqlExpression * SortDirection
| Select of SqlSourceExpression * SqlExpression * OrderBy list //can't do this
I could do the following:
type SqlOrderByExpression = SqlExpression * SortDirection
...and change the last two lines to:
| OrderBy of SqlOrderByExpression
| Select of SqlSourceExpression * SqlExpression * SqlOrderByExpression list
But that appears to have two problems:
SqlOrderByExpression is not a SqlExpression. This makes it hard to use the visitor pattern (maybe herein lies the problem?). Which means when traversing a Select expression I can't iterate over the list of order by expressions passing each one to Visit(expr:SqlExpression).
SqlOrderByExpression is merely a type alias for a tuple, so no type information is preserved. That hurts readability IMO.
Is there a better way to model this? I tried the inheritance route, but I think DUs are MUCH easier to work with (barring the noted difficulty).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
当您使用 FP 技术 (DU) 时,您不需要记住 OOP 模式,只需使用高阶函数(折叠、地图、拉链等)。
如果您只想查看匹配代码的特定视图,可以使用以下活动模式:
As you work with FP technique (DU), as you don't need to remember OOP patterns, just use high-order functions (fold, map, zippers, etc).
In case you just want to specific view for your matching code, there is active patterns:
我不确定为什么
SqlExpression
作为一个可区分联合,有OrderBy
和Select
的情况。OrderBy
中允许包含哪些内容?我认为受歧视的工会让这件事变得比实际需要的更加困难。我认为
SqlSourceExpression
、SqlOrderByExpression
和SqlSelectExpression
可以是不同的类型。如果您担心元组难以阅读,您可以将它们记录下来(这就是我在您的情况下会做的事情)。我认为,当您开始表示像
(1 + SUM(ISNULL(Value1, Value2))) / COUNT(*)
这样的表达式树时,SqlExpression
可区分联合将会很有用。 ,其中语法更加灵活。I'm not sure why
SqlExpression
, as a discriminated union, has cases forOrderBy
andSelect
. What's allowed to go inside anOrderBy
?I think discriminated unions are making this more difficult than it needs to be. I think
SqlSourceExpression
,SqlOrderByExpression
andSqlSelectExpression
can be different types. You can make them records if you're worried about tuples being difficult to read (this is what I'd do in your situation).I think an
SqlExpression
discriminated union will come in useful when you start to represent expression trees like(1 + SUM(ISNULL(Value1, Value2))) / COUNT(*)
, where the syntax is more flexible.