哈斯克尔:在哪里与让
我是Haskell的新手,我很迷惑Where- Let 。 他们似乎都提供了类似的目的。 我已经读了几个比较之间的比较,但我很难辨别什么时候使用每个。 有人可以提供一些上下文,或者可以举几个例子来说明什么时候使用一个吗?
在哪里与让
where
子句只能在函数定义的级别上定义。 通常,这与let
定义的范围是一致的。 唯一的区别是当警卫正在使用 。where
子句的范围遍及所有的守卫。 相比之下,let
expression式的范围只是当前的函数子句和守卫(如果有的话)。
Haskell备忘单
Haskell维基是非常详细的,并提供了各种情况,但它使用假设的例子。 我觉得它的解释对于初学者来说太简单了。
Let的优点 :
f :: State sa f = State $ \x -> y where y = ... x ...
Control.Monad.State
将不起作用,因为where引用了模式匹配f =,其中x不在范围内。 相反,如果你开始放手,那么你就不会有麻烦了。
Haskell Wiki关于Let的优点
f :: State sa f = State $ \x -> let y = ... x ... in y
其中的优点 :
fx | cond1 x = a | cond2 x = ga | otherwise = f (hxa) where a = wx fx = let a = wx in case () of _ | cond1 x = a | cond2 x = ga | otherwise = f (hxa)
宣言与expression
Haskell wiki提到Where子句是声明式的,而Letexpression式是expression式的。 除了风格,他们如何performance不同呢?
Declaration style | Expression-style --------------------------------------+--------------------------------------------- where clause | let expression arguments LHS: fx = 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 ...
- 在第一个例子中,为什么是在范围内,但哪里不是?
- 是否可以申请在哪里第一个例子?
- 一些可以应用这个真实的例子,variables代表实际的expression式吗?
- 是否有遵循何时使用每一个一般的经验法则?
更新
对于后来的这个线程,我发现这里最好的解释是:“ 对Haskell的一个温和的介绍 ”。
让expression式。
只要需要嵌套的绑定,Haskell的letexpression式就很有用。 作为一个简单的例子,考虑:
let y = a*b fx = (x+y)/y in fc + fd
由letexpression式创build的一组绑定是相互recursion的,模式绑定被视为懒惰模式(即它们带有隐式〜)。 唯一允许的声明是types签名,函数绑定和模式绑定。
何处条款。
有时,将绑定范围限制在几个有保护的方程上是很方便的,这需要一个where子句:
fxy | y>z = ... | y==z = ... | y<z = ... where z = x*x
请注意,这不能用一个letexpression式来完成,该expression式只覆盖它所包含的expression式。 where子句只允许在一组方程或者expression式的顶层。 letexpression式中绑定的相同属性和约束适用于where子句中的绑定。 这两种forms的嵌套作用域似乎非常相似,但请记住letexpression式是一个expression式,而where子句不是 – 它是函数声明和大小写expression式语法的一部分。
1:这个例子中的问题
f :: State sa 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 as = 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
强调程序stream(通过将计算移到后面)。
虽然在ephedient指出的警卫方面存在技术上的差异,但是您是否想在主要公式的前面添加下面定义的额外variables( where
)或者是否想要预先定义所有内容,下面的公式( let
)。 每种风格都有不同的侧重点,你可以在math论文,教科书等中看到。一般而言,如果没有它们,公式没有意义的variables足够不直观, 由于上下文或他们的名字而变得直观的variables应该在下面定义。 例如,在ephemient的元音例子中, vowels
的含义是显而易见的,所以它不需要被定义在它的使用之上(不pipe由于警卫而不工作的事实)。
法律:
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 = ...
我从LYHFGG中find这个例子很有帮助:
ghci> 4 * (let a = 9 in a + 1) + 2 42
let
是一个expression式,所以你可以放任何地方(!)expression式可以去。
换句话说,在上面的例子中,不可能使用where
简单地replacelet
(也许没有使用与where
结合的更详细的case
expression式)。