哈斯克尔:哪里与让
我是Haskell的新手,我很困惑Where vs. Let 。 他们似乎都提供了类似的目的。 我已经阅读了Where vs. Let之间的一些比较,但我无法辨别何时使用它们。 是否有人可以提供一些背景知识,或者可以举几个例子来说明何时使用这些背景?
在哪里与让
where
子句只能在函数定义的级别定义。 通常,这与let
定义的范围相同。 唯一的区别是警卫正在使用。 where
子句的范围覆盖所有警卫。 相比之下, let
表达式的范围只是当前的函数子句和守卫(如果有的话)。
Haskell备忘单
Haskell Wiki非常详细,提供了各种案例,但它使用假设的例子。 我觉得它的解释对于初学者来说太简短了。
Let的优点 :
f :: State s a
f = State $ x -> y
where y = ... x ...
Control.Monad.State
将不起作用,因为where引用了模式匹配f =,其中x不在范围内。 相反,如果你已经开始放手,那么你就不会遇到麻烦。
Haskell Wiki关于Let的优点
f :: State s a
f = State $ x ->
let y = ... x ...
in y
其中的优点 :
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 ...
更新
对于稍后通过此线程发布的内容,我在这里找到了最好的解释:“Haskell的简洁介绍”。
让表达式。
只要需要嵌套的绑定集合,Haskell的let表达式就很有用。 作为一个简单的例子,考虑:
let y = a*b
f x = (x+y)/y
in f c + f d
由let表达式创建的一组绑定是相互递归的,并且模式绑定被视为懒惰模式(即它们带有隐式〜)。 唯一允许的声明是类型签名,函数绑定和模式绑定。
条款。
有时候,将绑定范围限制在几个有保护的方程中是很方便的,这需要一个where子句:
f x y | y>z = ...
| y==z = ...
| y<z = ...
where z = x*x
请注意,这不能用一个let表达式来完成,该表达式只覆盖它所包含的表达式。 where子句只允许在一组方程或案例表达式的顶层。 let表达式中绑定的相同属性和约束适用于where子句中的绑定。 这两种嵌套作用域看起来非常相似,但请记住let表达式是一个表达式,而where子句则不是 - 它是函数声明和case表达式语法的一部分。
1:这个例子中的问题
f :: State s a
f = State $ x -> y
where y = ... x ...
是参数x
。 where
子句中的东西只能引用函数f
(没有)和外部作用域中的东西的参数。
2:要在第一个示例中使用where
,可以引入第二个命名函数,它将x
作为参数,如下所示:
f = State f'
f' x = y
where y = ... x ...
或者像这样:
f = State f'
where
f' x = y
where y = ... x ...
3:这是一个没有...
的完整例子:
module StateExample where
data State a s = State (s -> (a, s))
f1 :: State Int (Int, Int)
f1 = State $ state@(a, b) ->
let
hypot = a^2 + b^2
result = (hypot, state)
in result
f2 :: State Int (Int, Int)
f2 = State f
where
f state@(a, b) = result
where
hypot = a^2 + b^2
result = (hypot, state)
4:什么时候使用let
或者where
是味道的问题。 我使用let
来强调一个计算(通过将它移到前面)以及where
强调程序流(通过将计算移到后面)。
虽然在ephedient指出的警卫方面存在技术上的差异,但是您是否想在主要公式的前面添加额外的变量( where
定义)或者是否想要预先定义所有内容并将下面的公式( let
)。 每种风格都有不同的侧重点,你可以在数学论文,教科书等中看到它们。一般来说,如果没有它们,公式没有意义,那么这些变量足够不直观,应该在上面定义; 由于上下文或他们的名字而直观的变量应该在下面定义。 例如,在ephemient的hasVowel例如,意义vowels
是显而易见的,所以它不需要其使用上述定义(忽略的事实, let
不会因警卫工作)。
法律:
main = print (1 + (let i = 10 in 2 * i + 1))
不合法:
main = print (1 + (2 * i + 1 where i = 10))
法律:
hasVowel [] = False
hasVowel (x:xs)
| x `elem` vowels = True
| otherwise = False
where vowels = "AEIOUaeiou"
不合法:(不像ML)
let vowels = "AEIOUaeiou"
in hasVowel = ...
链接地址: http://www.djcxy.com/p/33205.html
下一篇: Is there a constraint that restricts my generic method to numeric types?