混合 DU 和其他值时的 F# 模式匹配
表达以下代码最有效的方式是什么?
match cond.EvalBool() with
| true ->
match body.Eval() with
| :? ControlFlowModifier as e ->
match e with
| Break(scope) -> e :> obj //Break is a DU element of ControlFlowModifier
| _ -> next() //other members of CFM should call next()
| _ -> next() //all other values should call next()
| false -> null
cond.EvalBool 返回布尔结果,其中 false 应返回 null true 应该再次运行整个块(它包含在一个名为 next 的函数中) 或者如果找到了特殊的break值,那么循环应该退出并返回break值。
有什么方法可以将该代码块压缩为更小的代码吗?
What would be the most effective way to express the following code?
match cond.EvalBool() with
| true ->
match body.Eval() with
| :? ControlFlowModifier as e ->
match e with
| Break(scope) -> e :> obj //Break is a DU element of ControlFlowModifier
| _ -> next() //other members of CFM should call next()
| _ -> next() //all other values should call next()
| false -> null
cond.EvalBool returns a boolean result where false should return null
and true should either run the entire block again (its wrapped in a func called next)
or if the special value of break is found, then the loop should exit and return the break value.
Is there any way to compress that block of code to something smaller?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
我认为你写的代码很好。这是我稍微喜欢的另一种选择:
I think that the code that you have written is fine. Here's an alternative which I marginally prefer:
我想指出,
Eval
的结果类型似乎有一个子类型层次结构,如果它也是 DU,那么您可以对嵌套模式执行类似 Hurray 的操作。
I want to point out that it appears there's a subtype hierarchy for the result type of
Eval
, and if instead that were also a DU, then you could do something likeHurray for nested patterns.
我不太喜欢匹配布尔值而不是使用
if-else
。 符或者,如果您认为不需要特殊的
isBreak
函数(我理解),让我们尝试创建一个更通用的函数:C# 的as
运算I'm not too fond of matching booleans instead of using
if-else
. What aboutOr, if you think that special
isBreak
function shouldn't be necessary (I'd understand that), lets try creating a more general function: C#'sas
operator我最终为此创建了一个活动模式。
其他地方也存在类似的逻辑,因此我可以使其可重用,
看起来不错吗?
I ended up creating an active pattern for this.
Similar logic exist elsewhere so I could make it reusable
Looks decent?
要展平嵌套的
match
构造,您需要使用嵌套模式。这最适合受歧视的联合(正如 Brian 所指出的 - 我同意设计 F# 代码以主要使用受歧视的联合是你能做的最好的事情)。否则,如果您想使用
match
简洁地编写代码,则需要一些活动模式(ssp 发布了一个示例,其中显示了专门针对您的问题的活动模式)。但是,您可以使用以下两个可重用的活动模式来执行此操作:第一个类似于
:?
,但它允许您嵌套其他模式以匹配该值(这对于是不可能的) >如)。第二个强制评估惰性值(我认为它们都可以在 F# 库中声明,因为它们非常有用)。现在你可以写:
编辑:正如罗杰在评论中指出的那样,这个版本的代码可能不太可读。我认为更好的选择是仅使用
TryCast
并以稍微不同的方式格式化原始代码(尽管这不是完全标准的缩进,但它是正确的并且 F# 编译器可以很好地处理它):这可能是基于模式匹配的最可读选项,但您也可以使用
if
代替第一个match
,如 kvb 版本中所示,并将其与TryCast
结合使用> (这实际上取决于个人喜好):无论如何,我相信
TryCast
使代码更具可读性,因为您避免了一次嵌套(这是其他需要的,因为:? .. ..
)。To flatten the nested
match
constructs, you'll need to use nested patterns. This works best for discriminated unions (as pointed out by Brian - and I agree that designing F# code to use primarily discriminated unions is the best thing you can do).Otherwise, you'll need some active patterns if you want to write the code succinctly using
match
(ssp posted one example, which shows active patterns specifically for your problem). However, you can do this using the following two reusable active patterns:The first one is like
:?
, but it allows you to nest other patterns to match the value (which isn't possible withas
). The second one forces evaluation of lazy value (I suppose that both of them could be declared in F# libraries as they are quite useful). Now you can write:EDIT: As Roger pointed out in a comment, this version of the code may not be very readable. I think a better option would be to use only
TryCast
and format your original code slightly differently (although this isn't completely standard indentation, it is correct and F# compiler handles it fine):This is probably the most readable option based on pattern matching, but you could also use
if
instad of the firstmatch
as in the version by kvb and combine it withTryCast
(this really depends on personal preferences):In any case, I believe that
TryCast
makes the code more readable as you avoid one nesting (which is othervise required because of:? .. as ..
).如果你的意思是“最有效的方法”作为最短的代码,我也投票给美联社:
In case you mean "most effective way" as shortest code, i vote to AP too: