我是Haskell的新手,我对Where vs. Let感到非常困惑.它们似乎都提供了类似的目的.我已经阅读了Where与Let之间的一些比较,但我无法辨别何时使用每个.有人可以提供一些上下文或者一些示例,说明何时使用其中一个?
哪里与让
甲
where子句只能在一个函数定义的电平来定义.通常,这与let定义的范围相同.唯一的区别是使用警卫时.该where条款的范围扩展到所有警卫.相反,let表达式的范围只是当前的函数子句和guard,如果有的话.
该哈斯克尔维基是非常详细,并提供各种案件,但它使用的假设的例子.我觉得它的解释对初学者来说太简短了.
让我们的优势:
f :: State s a
f = State $ \x -> y
where y = ... x ...
Run Code Online (Sandbox Code Playgroud)
将无法工作,因为where指的是模式匹配f =,其中没有x在范围内.相比之下,如果你开始使用let,那么你就不会遇到麻烦了.
f :: State s a
f = State $ \x ->
let y = ... x ...
in y
Run Code Online (Sandbox Code Playgroud)
其中的优点:
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)
Run Code Online (Sandbox Code Playgroud)
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 ...
Run Code Online (Sandbox Code Playgroud)
对于那些后来通过这个帖子的人,我找到了最好的解释:" Haskell的温和介绍 ".
表达.
只要需要嵌套的绑定集,Haskell的let表达式就很有用.举个简单的例子,考虑一下:
Run Code Online (Sandbox Code Playgroud)let y = a*b f x = (x+y)/y in f c + f d由let表达式创建的绑定集是相互递归的,并且模式绑定被视为惰性模式(即它们带有隐式〜).允许的唯一类型的声明是类型签名,函数绑定和模式绑定.
条款.
有时,将绑定范围扩展到几个保护方程是很方便的,这需要where子句:
Run Code Online (Sandbox Code Playgroud)f x y | y>z = ... | y==z = ... | y<z = ... where z = x*x请注意,这不能通过let表达式来完成,该表达式仅覆盖它所包含的表达式.where子句仅允许在一组方程或case表达式的顶层.let表达式中绑定的相同属性和约束适用于where子句中的绑定.这两种形式的嵌套作用域看起来非常相似,但请记住,let表达式是一个表达式,而where子句则不是 - 它是函数声明和case表达式语法的一部分.
ant*_*kos 37
1:示例中的问题
f :: State s a
f = State $ \x -> y
where y = ... x ...
Run Code Online (Sandbox Code Playgroud)
是参数x.在物联网where子句只能指函数的参数f(没有),事情在外部范围.
2:要where在第一个示例中使用a ,您可以引入第二个命名函数,该函数将xas作为参数,如下所示:
f = State f'
f' x = y
where y = ... x ...
Run Code Online (Sandbox Code Playgroud)
或者像这样:
f = State f'
where
f' x = y
where y = ... x ...
Run Code Online (Sandbox Code Playgroud)
3:这是一个没有...'s 的完整例子:
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)
Run Code Online (Sandbox Code Playgroud)
4:何时使用let或是where品味问题.我let用来强调计算(通过将其移动到前面)并where强调程序流程(通过将计算移动到后面).
gdj*_*gdj 26
虽然ephemient指出的守卫方面存在技术差异,但是你是否想要将主要公式预先设置为下面定义的额外变量(where或者是否要预先定义所有内容并放置公式),这也存在概念上的差异.下面(let).每种风格都有不同的重点,你会看到它们都用在数学论文,教科书等中.一般来说,如果没有它们,那么公式就没那么有意义的变量应该在上面定义; 由于上下文或其名称而直观的变量应在下面定义.例如,在ephemient的hasVowel示例中,含义vowels是显而易见的,因此无需在其使用之上定义(忽略let由于防护而无法工作的事实).
eph*_*ent 12
法律:
main = print (1 + (let i = 10 in 2 * i + 1))
Run Code Online (Sandbox Code Playgroud)
不合法:
main = print (1 + (2 * i + 1 where i = 10))
Run Code Online (Sandbox Code Playgroud)
法律:
hasVowel [] = False
hasVowel (x:xs)
| x `elem` vowels = True
| otherwise = False
where vowels = "AEIOUaeiou"
Run Code Online (Sandbox Code Playgroud)
不合法:(与ML不同)
let vowels = "AEIOUaeiou"
in hasVowel = ...
Run Code Online (Sandbox Code Playgroud)
可悲的是,这里的大多数答案对于初学者来说太技术性了。
LHYFGG有一个相关的章节 - 如果你还没有,你应该阅读它,但本质上:
where只是一个语法结构(不是糖),仅在函数定义时有用。let ... in是一个表达式本身,因此您可以在任何可以放置表达式的地方使用它们。作为表达式本身,它不能用于为守卫绑定事物。最后,您也可以let在列表推导式中使用:
calcBmis :: (RealFloat a) => [(a, a)] -> [a]
calcBmis xs = [bmi | (w, h) <- xs, let bmi = w / h ^ 2, bmi >= 25.0]
-- w: width
-- h: height
Run Code Online (Sandbox Code Playgroud)
我们在列表推导式中包含一个let ,就像我们在谓词中一样,只是它不过滤列表,它只绑定到名称。列表推导式中的 let 中定义的名称对输出函数( 之前的部分
|)以及绑定之后的所有谓词和部分可见。所以我们可以让我们的函数只返回大于等于 25 的人的 BMI:
我发现LYHFGG的这个示例很有帮助:
ghci> 4 * (let a = 9 in a + 1) + 2
42
Run Code Online (Sandbox Code Playgroud)
let是一个表达式,因此您可以将表达式放到let 任何地方(!)。
换句话说,在它上面的例子中是不可能使用where简单地替换let(不可能使用一些更详细的case表达联合where)。
| 归档时间: |
|
| 查看次数: |
41906 次 |
| 最近记录: |