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

Posted

技术标签:

【中文标题】`where` 子句在 Haskell 中在哪里派上用场【英文标题】:where does the `where` clause come in handy in Haskell 【发布时间】:2011-08-27 07:02:21 【问题描述】:

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

【问题讨论】:

在适当的地方使用where 您可能会在这个相关问题中找到一些有用的信息:where vs. let 感谢@Thies Heidecke 甚至没有出现! 【参考方案1】:

Haskell Wiki 上也有这个问题的两个很好的答案:

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

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

【讨论】:

【参考方案2】:

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

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 子句,数组将没有函数体内的名称,并且您无法递归定义。

【讨论】:

【参考方案3】:

这主要是风格问题。即使它们不完全等效,您也不会经常使用其中一个。相反,这取决于您,您认为更好看。

【讨论】:

【参考方案4】:

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

【讨论】:

你的意思是在你说“where”的地方使用“let”吗? 不,我经常使用“where”:)【参考方案5】:

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

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

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

【讨论】:

【参考方案6】:

使用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

【讨论】:

以上是关于`where` 子句在 Haskell 中在哪里派上用场的主要内容,如果未能解决你的问题,请参考以下文章

Haskell:具有多个***绑定的“where”子句?

带有 Haskell 梁的简单 where 子句的类型错误

如何在 where 子句上基于 SqlCommand 或 SqlDataAdapter 填充 datagridview? SqlDataAdapter 不适用于哪里?

索引问题:Select * with WHERE 子句。在哪里以及如何创建索引

在 C/C++ 中在树莓派中播放 WAV,必须使用 dsp?

Haskell:绑定模式匹配的地方