在OCaml模式匹配中哪个更好,' when '或' if-then-else ' ?



假设我们有一个类型d:

type d = D of int * int

我们想对它进行模式匹配,这样做是不是更好:

let dcmp = function 
| D (x, y) when x > y -> 1 
| D (x, y) when x < y -> -1
| _ -> 0

let dcmp = function 
| D (x, y) -> 
if x > y then 1 else if x < y then -1 else 0

一般来说,使用多个"当"case或匹配一个模式,然后加上&;if-then-else&;在吗?

我在哪里可以获得更多关于这些事情的信息,比如OCaml和语法糖等的良好实践?

这两种方法都有各自的优缺点,因此应该根据上下文使用它们。

when子句比if更容易理解,因为它只有一个分支,所以您可以一次消化一个分支。这样做的代价是,当我们分析一个子句以了解它的路径条件时,我们必须在它之前分析所有分支(并否定它们),例如,将你的变体与以下定义进行比较,这是等价的,

let dcmp = function 
| D (x, y) when x > y -> 1 
| D (x, y) when x = y -> 0
| _ -> -1

当然,if/then/else结构也是如此,只是在if/then/else表达式中不小心重新排列分支(例如,在重构期间)并完全改变表达式的逻辑更难。

此外,when守卫可能会阻止编译器执行决策树优化1,并混淆2的反驳机制。

鉴于此,在此特定示例中使用when而不是if的唯一优点是when语法看起来更吸引人,因为它完美地排列在一起,并且人类大脑更容易找到条件及其相应值的位置,即,它看起来更像一个真值表。然而,如果我们写

let dcmp (D (x,y)) = 
if x = y then 0 else
if x > y then 1 else -1

可以达到同样的可读性。

总而言之,当不可能或几乎不可能用if/then/else表示相同的代码时,最好使用when。为了提高可读性,最好将逻辑分解为具有可读名称的辅助函数。例如,对于dcmp,最好的解决方案是既不使用if也不使用when,例如

let dcmp (D (x,y)) = compare x y

1)在这种特殊情况下,编译器将为whenif/then/else生成相同的代码。但是在更一般的情况下,守卫可能会阻止匹配的编译器生成有效的代码,特别是在分支不连接的情况下。在我们的例子中,编译器只是注意到我们在重复相同的分支,并将它们合并成一个分支,并将其转换回if/then/else表达式,例如,下面是带有when保护的函数的cmm输出,

(if (> x y) 3 (if (< x y) -1 1))

dcmp函数的if/then/else版本生成的代码完全相同。

2)当然不是到它不会注意到缺失分支的状态,而是到它会不精确地报告缺失分支或要求您添加不必要分支的状态。

引用OCaml走向清晰和优雅的风格指南:

代码读的比写的多——让读者的生活更轻松

代码越少越好,代码越晦涩越糟

第一个让我认为具有多个when子句的版本是更好的选择,因为它可以在根据条件读取代码时轻松预测或评估结果。第二个更深入,与if-then-else相反,因为即使较短,当从远处看时也是模糊的。

同样,在函数一节中,我们发现& '模式匹配是定义函数的首选方式& ';

从一个Haskell函数式程序员的角度来看

相关内容

  • 没有找到相关文章

最新更新