在哪里`where`子句在Haskell中派上用场

时间:2011-05-17 14:17:54

标签: haskell syntax coding-style where-clause

我发现我很少遇到需要使用where子句的情况。但是,我确实发现我过去经常使用它。何时使用where子句(即它使用的是什么情况)?我应该在什么情况下使用它?

6 个答案:

答案 0 :(得分:11)

Haskell Wiki上有两个很好的答案:

http://haskell.org/haskellwiki/Declaration_vs._expression_style http://haskell.org/haskellwiki/Let_vs._Where

两者都用于创建本地定义,这些定义可能使用传递到其封闭函数范围内的值,并且当然不能在封闭函数的上下文之外使用。它们促进代码重用并最大限度地减少重复给定fix和lambda,两者都可以完全消失。通常,我尽可能使用where子句,并且在使用前一行中通过do提取的值时,只倾向于在lambda或case块内使用let子句,或者使用<-表示法。总的来说,我认为声明式风格现在比惯用现代Haskell代码中的表达风格更为普遍。

答案 1 :(得分:3)

我发现它很重要的一个具体例子 - 一个返回递归定义数组的函数。

lucas :: (Integral a) => a -> Array a
lucas n = a where
            a = array (0,n) ((0,2):(1,1):[(i,a!!(i-1) + a!!(i-2)) | i<-[1..n])])

对于卢卡斯数字1到n(斐波那契太明显= P)

重要的一点是,如果没有where子句,数组将不会在函数体内部具有名称,并且您无法递归定义。

答案 2 :(得分:1)

这主要是风格问题。即使它们并不完全相同,但通常不一定要使用其中一种。相反,这取决于你,你认为看起来更好。

答案 3 :(得分:0)

我的经验法则 - 如果您在函数的顶层定义某些内容,请使用“where”。如果要定义具有多个子句的辅助函数,请务必使用“where”。在其他地方,只需选择一个!

答案 4 :(得分:0)

根据我的经验,wherelet更具可读性,因为它通常与英语类似。 例如:

myFun x = aCoefficient * (10 ** anExponent)  
          where aCoefficient = 100 - x  
                anExponent = x - 2  

在英语中,我将其描述为“myFun of x是系数乘以(10到指数),其中系数是100减x,指数是x减2”

答案 5 :(得分:0)

使用where的两个风格优势:

  • 它将您定义的东西的值放在其名称(和类型)附近。

    func x = part1 . part2 (something x)
      where part1 = ...
            part2 = ...
    

    而不是

    func x = let part1 =
                 part2 =
             in part1 . part2 (something x)
    
  • 它鼓励编写可以读作“报纸风格”的代码,其中重要的东西首先出现,所有细节都会在以后出现。这样,只要您觉得不需要了解其余细节,就可以停止阅读。

    func x = highlevel1 . highlevel2 (x + 42)
      where highlevel1 = medium (...)
            highlevel2 = medium (...)
    
            medium = ...
    

当绑定本身比表达式更有趣时,我主要使用let,它们很短。例如,绑定只是为了进行模式匹配:

func x = let (MyData y _ _) = something in y

在我看来,这看起来比

更好
func x = y
  where (MyData y _ _) = something