哈斯克尔:哪里与让

我是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 ...
    

    是参数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 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

    上一篇: Haskell: Where vs. Let

    下一篇: Is there a constraint that restricts my generic method to numeric types?