Haskell中的Where子句

时间:2018-10-17 14:52:44

标签: haskell

我对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不会报告任何错误,但是我怀疑它是否正确。

3 个答案:

答案 0 :(得分:6)

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

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

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

因此,此表达式树包含指向其他表达式树的函数。 Haskell默认情况下将 not 评估这些表达式:懒惰地评估这些表达式:仅当必须计算这些表达式时,才计算相应的值。此外,例如,如果您对b的值感兴趣,那么您将计算a的值,因此1+3表达式将仅被评估一次。 em>。相反的情况也一样:如果先评估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 ┃
      ┗━━━┛

答案 1 :(得分:5)

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

如有疑问,可以使用更简单的结构对其进行测试,以查看其是否提供正确的值:

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

main = print testing

它能按预期打印出1234吗?

答案 2 :(得分:0)

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

在本例中,我们重复(收入成本)您的计算。这是一个便宜的操作,但如果它是一个昂贵的操作,你就会浪费资源。为了防止这种情况,我们使用 where 子句:

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

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

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