我对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不会报告任何错误,但是我怀疑它是否正确。
答案 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 子句中声明了变量“利润”,然后我们使用了它