31

HaskellNet 库中的一个示例:

data MailboxInfo = MboxInfo { _mailbox :: MailboxName
                            , _exists :: Integer
                            , _recent :: Integer
                            , _flags :: [Flag]
                            , _permanentFlags :: [Flag]
                            , _isWritable :: Bool
                            , _isFlagWritable :: Bool
                            , _uidNext :: UID
                            , _uidValidity :: UID
                            }
                 deriving (Show, Eq)

字段名称中的下划线是否意味着什么,如果不是编译器,那么至少根据 Haskell 约定?

4

4 回答 4

27

通过类比下划线表示不相关的模式,例如fst (x, _) = x,下划线前缀(在记录字段上或其他)用于指示标识符应该被任何阅读代码的人忽略,或者可能被编译器忽略以用于某些类型的用户交互,即使它因某种原因被命名。

请注意,这不仅仅是一个约定,而是基于Haskell 报告中明确说明的内容:

下划线“_”被视为小写字母,可以出现在小写字母可以出现的任何位置。但是,“_”本身就是一个保留标识符,在模式中用作通配符。鼓励为未使用的标识符提供警告的编译器禁止对以下划线开头的标识符发出此类警告。这允许程序员将“_foo”用于他们希望不使用的参数。

一个示例是旨在供 Template Haskell 使用的定义,然后定义不带下划线的等效标识符,如基于记录字段生成镜头的常见示例(我猜这是您的示例正在做的事情)。在这种情况下,标识符比实际定义更多地输入到 TH;TH 生成的代码实际上可能使用也可能不使用下划线前缀标识符。

但是,除了上述之外,下划线前缀与常规小写标识符没有任何不同。

于 2012-10-05T14:05:21.930 回答
12

模板 Haskell 代码有时会查找以下划线开头的标识符。

例如,下划线用于自动生成镜头。

于 2012-10-05T12:27:41.587 回答
3

这只是一个很好的编程习惯。

由于 Haskell 中的记录字段标签实际上是顶级命名函数,它们污染了模块命名空间。为字段标签添加下划线意味着您可以自由定义另一个具有相同名称的函数。

于 2012-10-05T14:07:27.400 回答
3

最近我发现了一些与你的问题相关的东西。

我想控制我的类型实例的构造位置,以证明每个值都是有效的。所以我在它自己的模块中声明了它:

module Coords (Coords(), -- hide the constructor
               x,y,buildCoords) where

data Coords = Coords { x :: Int, y :: Int }

buildCoords :: Int -> Int -> Coords
buildCoords x y | x < 0 || y < 0 = error "omg"
buildCoords x y = Coords { x = x, y = y }

然后,我推断,在这个模块之外,没有代码可以创建无效的坐标。

我错了!x并且y是公开的,因此只需使用let c = buildCoords 1 1 in c { x = -1 }即可获得无效的 Coords 值!

但这种语法之所以可行,是因为 x 和 y 是该类型的记录选择器。只允许有效值的方法如下:

module Coords (Coords(), -- hide the constructor
               x,y,buildCoords) where

data Coords = Coords { _x :: Int, _y :: Int }
x = _x
y = _y

buildCoords :: Int -> Int -> Coords
buildCoords x y | x < 0 || y < 0 = error "omg"
buildCoords x y = Coords { _x = x, _y = y }

现在 x 和 y 只是常规函数。语法不会编译,c { x = -1 }并且其他模块无权访问记录选择器_x。

问题已通过下划线解决;-)

于 2016-01-25T19:10:21.137 回答