哈斯克尔:在哪里与让

我是Haskell的新手,我很迷惑Where- Let 。 他们似乎都提供了类似的目的。 我已经读了几个比较之间的比较,但我很难辨别什么时候使用每个。 有人可以提供一些上下文,或者可以举几个例子来说明什么时候使用一个吗?

在哪里与让

where子句只能在函数定义的级别上定义。 通常,这与let定义的范围是一致的。 唯一的区别是当警卫正在使用where子句的范围遍及所有的守卫。 相比之下, letexpression式的范围只是当前的函数子句和守卫(如果有的话)。

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 ... 
  1. 在第一个例子中,为什么是在范围内,但哪里不是?
  2. 是否可以申请在哪里第一个例子?
  3. 一些可以应用这个真实的例子,variables代表实际的expression式吗?
  4. 是否有遵循何时使用每一个一般的经验法则?

更新

对于后来的这个线程,我发现这里最好的解释是:“ 对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 ... 

是参数xwhere子句中的东西只能引用函数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结合的更详细的caseexpression式)。