【问题标题】:Avoid temporary variables by using name shadowing通过使用名称阴影来避免临时变量
【发布时间】:2012-05-17 19:40:17
【问题描述】:

我在 Haskell 中创建了很多临时变量:

main = do
    let nums'' = [1..10]
    let nums' = a . bunch . of_ . functions $ nums''
    let nums = another . bunch . of_ . functions $ nums'
    print nums

也就是说,我不想像这样写一长串函数:

let nums = another . bunch . of_ . functions . a . bunch . of_ . functions $ [1..10]

因为它对我来说变得不可读,所以我尝试根据它们的作用对函数进行分组。在此过程中,我最终创建了一堆丑陋的临时变量,例如 nums''nums'(我可以给它们起更有意义的名称,但重点仍然存在……每一个新行都意味着一个新变量)。 在这种情况下,阴影变量会导致代码更清晰。我想做类似的事情:

let nums = [1..10]
nums = a . bunch . of_ . functions $ nums
nums = another . bunch . of_ . functions $ nums

即与上面完全相同,但没有临时变量。在 Haskell 中有什么方法可以做到这一点吗?也许整个事情都可以包装在一个“交易”中:

atomically $ do
  (...this code...)
  return nums

可以让 Haskell 知道本节中的代码包含阴影变量,它应该只关心最终结果。这可能吗?

【问题讨论】:

  • 如果你想传递一个没有变异的值而不创建一堆名字,你也可以使用 State monad
  • 我可能会争辩说(a)如果你有有意义的名字来给出中间步骤,那就没有问题; (b) 如果您没有有意义的名称来给出中间步骤,那么分解它们没有任何好处。从(a)和(b)我们可以得出没有问题的结论。当然,这取决于您是否接受前提。
  • 我不同意为不同目的重复使用相同的名称必然会使其更具可读性。现在读者必须弄清楚每次出现引用哪个变量绑定。
  • 我不认为阴影可以避免创建临时变量。相反,您正在创建相同数量的临时变量,它们都具有相同的名称,这似乎是概念复杂性的增加,而不是减少。我还会查看一系列较小的变化,例如 numsnums'nums''nums1nums2nums3 等,因为没有 内容 在任何名称中,但您至少可以引用它们中的任何一个,这与一系列阴影变量不同。

标签: haskell syntax composition


【解决方案1】:

这种风格很常见:

let nums = another
         . bunch
         . of_
         . functions
         . a
         . bunch
         . of_
         . functions
         $ [1..10]

它清楚地描述了代码;而. 则代替临时变量名。

它避免了当您开始隐藏变量名称时可能发生的危险问题——不小心引用错误的x 迟早会给您带来麻烦。

【讨论】:

    【解决方案2】:

    这是我不时使用的其他人没有给出的建议:您可能喜欢命名您的函数而不是命名您的值!例如,也许你可以写:

    let runningSum = a . bunch . of_ . functions
        weight     = another . bunch . of_ . functions
    in weight . runningSum $ [1..10]
    

    【讨论】:

      【解决方案3】:

      如果你绝对必须,这是可能的,但不是惯用的。改用 Don 或 luqui 的建议。

      main = do
          nums <- return [1..10]
          nums <- return $ a . bunch . of_ . functions $ nums
          nums <- return $ another . bunch . of_ . functions $ nums
          print nums
      

      如果你不在 monad 中,你总是可以在 identity monad 中开始一个新的 do 块。

      【讨论】:

        【解决方案4】:

        由于您的名称(numsnums'nums''、...)没有传达有关分组的信息,您可以只使用换行符对功能进行分组并传达相同的信息:

        main =
            let nums = a . bunch . of_ . functions
                     . another . bunch . of_ . functions
                     $ [1..10]
            in print nums
        

        但是,我建议不要这样做,而是给子计算命名,确实传达信息,例如。 normalizedNumsaverage 等。然后没有丑陋的阴影问题,因为您使用了不同的名称。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-01-20
          • 2018-08-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多