【问题标题】:Standard ML style: is variable shadowing good style?标准 ML 风格:可变阴影是好的风格吗?
【发布时间】:2020-10-19 03:16:22
【问题描述】:

在标准 ML 中,一般情况下是否可以使用变量阴影,特别是在模式匹配可接受的情况下?对于这个玩具示例:

  case xs of
      [] => 0
    | x::xs => x + sum xs

下面的风格更好吗?

fun sum(xs) =
  case xs of
      [] => 0
    | x::xs' => x + sum xs'

如果没有阴影,则必须选择不同的名称,这会使代码混乱,尤其是在使用嵌套模式、let 函数绑定和其他语言结构时。 谢谢!

【问题讨论】:

  • 结构化代码很常见,因此它不使用嵌套模式和复杂的 let 构造,如果它变得笨拙,但我认为大多数人会选择y::ys 而不是您的任何建议。
  • 我认为这个问题有一个明确的答案——不,这不是很好的风格。但是,对此的解决方案是相当主观的,并且通常根据具体情况进行选择。此外,在总体方案中,代码库中还有比一些阴影变量或一些'-suffixed 更重要的东西(如果它们用于具有明确职责的小函数,我可以接受不好的变量命名)。
  • 我个人很喜欢它,当它不再有效时,通过引用阴影变量来出错是不可能的。我也喜欢它,因为它让我避免了我觉得非常混乱的带底漆的名字。 (虽然我不是 MLer)

标签: functional-programming sml ml


【解决方案1】:

可变阴影是好的风格吗?

没有。

xsxs' 也不好:它们具有相同的类型,因此很容易不小心使用其中一个而不是另一个。在您的情况下,这可能会导致无限递归,并且很快就会被检测到。但在其他情况下,它可能会导致更微妙的错误。此建议并非针对函数式编程。

编辑:总体而言,我包括了 molbdnilo 对 y::ys 的建议:

fun sum xs =
    case xs of
         [] => 0
       | y::ys => y + sum ys

另一种方法是仅进行模式匹配并绑定您实际需要的值。在您的 sum 示例中,除了拆分之外,您实际上不需要完整输入。所以你可以这样写

fun sum [] = 0
  | sum (x::xs) = x + sum xs

或者使用更隐式的模式匹配:

val sum = foldl op+ 0

另一个例子,Exercism's Bob exercise,可以通过首先清理输入然后对其进行分类来解决:

datatype diction = Yelling | Asking | YellingAsking | Whatever

fun strip message = ...

fun classify message = ...

fun answer diction = ...

val response = answer o classify o strip

这里,函数stripmessage 将包含未剥离的空格,而classify 函数的message 则不包含。因此,与其拥有多个 messages,一个有空格,另一个没有空格,不如将它们放在不同的函数范围内,做不同的事情。

【讨论】:

  • 建议 y::ys 非常适合泛型代码,但是当代码使用特定名称(例如 cardgrade 等)时,替换名称就成了一个挑战,而且很可能,我们必须使用 card'grade' 等名称。
  • 是的,所以y::ys 的好处是它在视觉上看起来与xs 完全不同。您可以对特定于域的值绑定(如 card)做类似的事情,将其命名为 cardHandgradeBefore 或任何澄清上下文的名称:如果它们在相同的命名空间,并且读取误用可能会触发“嘿,那是错误的。”
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-20
  • 2020-09-09
  • 2011-06-17
  • 1970-01-01
相关资源
最近更新 更多