我是Haskell的新手,我对 Where 与 Let 感到非常困惑 . 它们似乎都提供了类似的目的 . 我已经阅读了 Where 与 Let 之间的一些比较,但我无法辨别何时使用每个 . 有人可以提供一些上下文或者一些示例,说明何时使用一个而不是另一个?
Where与Let一个where子句只能在函数定义的级别定义 . 通常,这与let定义的范围相同 . 唯一的区别是使用防护装置 . where子句的范围扩展到所有警卫 . 相反,let表达式的范围只是当前的函数子句和guard,如果有的话 .
Haskell Wiki非常详细,提供了各种案例,但它使用了假设的例子 . 我觉得它的解释对初学者来说太简短了 .
Advantages of Let :
f :: State s a
f = State $ \x -> y
where y = ... x ...
不起作用,因为where指的是模式匹配f =,其中没有x在范围内 . 相反,如果你开始使用let,那么你就不会有麻烦了 .
Haskell Wiki on Advantages of Let
f :: State s a
f = State $ \x ->
let y = ... x ...
in y
Advantages of Where :
f x
| cond1 x = a
| cond2 x = g a
| otherwise = f (h x a)
where
a = w x
f x
= let a = w x
in case () of
_ | cond1 x = a
| cond2 x = g a
| otherwise = f (h x a)
Haskell wiki提到 Where 子句是声明性的,而 Let 表达式是表达性的 . 除了风格,它们的表现如何不同?
Declaration style | Expression-style
--------------------------------------+---------------------------------------------
where clause | let expression
arguments LHS: f x = x*x | Lambda abstraction: f = \x -> x*x
Pattern matching: f [] = 0 | case expression: f xs = case xs of [] -> 0
Guards: f [x] | x>0 = 'a' | if expression: f [x] = if x>0 then 'a' else ...
-
在第一个例子中,为什么 Let 在范围内但 Where 不是?
-
是否可以将 Where 应用于第一个示例?
-
有些人可以将此应用于变量代表实际表达式的实例吗?
-
是否有一般的经验法则可以遵循何时使用?
更新
对于那些稍后通过这个帖子来的人,我找到了最好的解释:“A Gentle Introduction to Haskell” .
让表达 . 只要需要嵌套的绑定集,Haskell的let表达式就很有用 . 举个简单的例子,考虑:让y = a * b
f x =(x y)/ y
在f c f d
由let表达式创建的绑定集是相互递归的,并且模式绑定被视为惰性模式(即它们带有隐式〜) . 允许的唯一类型的声明是类型签名,函数绑定和模式绑定 . 条款 . 有时,将绑定范围扩展到几个保护方程是很方便的,这需要一个where子句:f x y | y> z = ...
| y == z = ...
| y <z = ...
其中z = x * x
请注意,这不能通过let表达式来完成,该表达式仅覆盖它所包含的表达式 . where子句仅允许在一组方程或case表达式的顶层 . let表达式中绑定的相同属性和约束适用于where子句中的绑定 . 这两种形式的嵌套作用域看起来非常相似,但请记住let表达式是一个表达式,而where子句则不是 - 它是函数声明和case表达式语法的一部分 .
4 回答
1:示例中的问题
是参数
x
.where
子句中的内容只能引用函数f
(没有)的参数和外部作用域中的内容 .2:要在第一个示例中使用
where
,您可以引入第二个命名函数,该函数将x
作为参数,如下所示:或者像这样:
3:这是一个没有
...
的完整示例:4:何时使用
let
或where
是品味问题 . 我使用let
强调计算(通过将其移动到前面)和where
来强调程序流(通过将计算移动到后面) .我从LYHFGG中发现这个例子很有帮助:
let
是一个表达式,所以你可以放一个let
anywhere(!) 表达式 .换句话说,在上面的例子中, not 可以使用
where
来简单地替换let
(没有使用更复杂的case
表达式和where
) .法律:
不合法:
法律:
不合法:(与ML不同)
虽然ephemient所指出的守卫方面存在技术差异,但是你是否想要将主要公式预先设置为下面定义的额外变量(
where
),或者是否要预先定义所有内容并放置公式如下(let
) . 每种风格都有不同的重点,你会看到它们都用在数学论文,教科书等中 . 一般来说,变量足够不直观,公式不具有例子,vowels
的含义是显而易见的,因此不需要在其上面定义用法(无视let
由于警卫而无法工作的事实) .