【问题标题】:Where clause in HaskellHaskell 中的 Where 子句
【发布时间】:2019-03-22 07:18:36
【问题描述】:

我对 Haskell 中的 where 子句 在特定情况下的工作方式感到困惑。

我最大的问题是,是否有可能声明一个变量where 子句中执行某些操作,然后 使用返回通过另一个变量在 where 子句中声明?

例如:

someFunc :: somefunc
.
| (guard expression)
| (guard expression)
where a = 1+3
      b = a + 2 --using back 'a' variable which was also declared in the where clause.

这可能吗?当我这样做时,haskell 不会报告任何错误,但我怀疑它是否正确。

【问题讨论】:

  • 你试过了吗?是的,有可能,b 的定义甚至不需要在a 的定义之后; ... where { b = a + 2; a = 1 + 3 } 也可以。
  • 是的,你甚至可以使用 same 变量,比如a = 1 + a,这有点危险,但例如where lst = 1 : lst有时用于声明一个用于某些操作的无限列表需要恒定内存。
  • 你们为什么要在 cmets 中回答?!?!
  • @Libby: 因为它在语法上看起来像问题的where 子句:)
  • @Libby 我在 cmets 中回答了,因为这不是一个很好的问题。 OP 询问完美的代码是否可以在没有明显尝试的情况下工作。

标签: haskell


【解决方案1】:

是的。 where子句中的变量可以看到同一个where子句中的其他变量。

如有疑问,可以用更简单的结构测试一下,看它是否给出了正确的值:

testing = b
  where
    a = 1000
    b = a + 234

main = print testing

是否按预期打印出 1234?

【讨论】:

    【解决方案2】:

    是的,甚至可以在表达式中使用 same 变量作为您定义的变量。

    也可以。本质上,变量只是对“表达式”的引用。因此,对于您的情况,您构建的内容如下所示:

        ┏━━━━━━━┓
    b──>┃  (+)  ┃
        ┣━━━┳━━━┫   ┏━━━┓
        ┃ o ┃ o─╂──>┃ 2 ┃
        ┗━┿━┻━━━┛   ┗━━━┛
          │
          v
        ┏━━━━━━━┓
    a──>┃  (+)  ┃
        ┣━━━┳━━━┫   ┏━━━┓
        ┃ o ┃ o─╂──>┃ 3 ┃
        ┗━┿━┻━━━┛   ┗━━━┛
          │
          │         ┏━━━┓
          ╰────────>┃ 1 ┃
                    ┗━━━┛
    

    因此,该表达式树包含指向其他表达式树的函数。 Haskell 默认计算这些表达式:这些表达式是惰性计算的:只有当你必须计算这些时,你才会计算相应的值。此外,例如,如果您对b 的值感兴趣,那么您将计算a 的值,因此1+3 表达式只会被计算一次。在相反的方向上也是如此:如果您首先评估a,然后评估b 将受益于a 已经被计算的事实。例如,您可以根据彼此定义两个变量,例如:

    foo :: Int
    foo = a
        where a = 1 + b
              b = 1 + a
    

    但这会陷入无限循环,因为您将创建一个看起来像 1 + (1 + (1 + (...))) 的表达式。

    我们甚至可以根据自身定义一个变量。例如下面的函数生成一个无限列表:

    ones :: [Int]
    ones = lst
        where lst = 1 : lst
    

    这将表示为:

          ┏━━━━━━━┓
    lst──>┃  (:)  ┃<─╮
          ┣━━━┳━━━┫  │
          ┃ o ┃ o─╂──╯
          ┗━┿━┻━━━┛
            │
            v
          ┏━━━┓
          ┃ 1 ┃
          ┗━━━┛
    

    【讨论】:

    • 不错的艺术。我希望有人会举一个像lst 这样的例子。
    【解决方案3】:
    calcProfit revenue cost= if revenue - cost >0
                             then revenue - cost
                             else 0
    

    在这个例子中,我们重复(revenuw-cost)你的计算。这是一项廉价的操作,但如果这是一项昂贵的操作,您将浪费资源。为了防止这种情况,我们使用where 子句:

    calcProfit revenue cost = if profit >0 
                              then profit
                              else 0
               where profit= revenue-cost
    

    使用“where”子句,我们颠倒了用于写入变量的正常顺序。在大多数编程语言中,变量是在使用之前声明的。在 Haskell 中,由于引用透明性,变量顺序不是问题。

    如你所见,我们在 where 子句中声明了变量“profit”,然后我们使用了它

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-11-20
      • 2016-12-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-01
      • 1970-01-01
      相关资源
      最近更新 更多