Haskell:为什么命名辅助函数的约定"go"?

Dan*_*ton 79 haskell naming-conventions

go在阅读Haskell材料或源代码时看到了很多,但我从来没有对它感到很自在 - (我想它在我的脑海中有"goto"的负面含义).我开始用LYAH学习Haskell,这就是我选择使用accstep写折叠时的倾向.写作的惯例go来自哪里?

最重要的是,该名称到底go意味着什么?

Don*_*art 134

哼!一些考古学!

从2004年左右开始,我在使用go递归函数的worker/wrapper转换时,将其用作尾递归工作循环的通用名称.我开始广泛使用它bytestring,例如

foldr :: (Word8 -> a -> a) -> a -> ByteString -> a
foldr k v (PS x s l) = inlinePerformIO $ withForeignPtr x $ \ptr ->
        go v (ptr `plusPtr` (s+l-1)) (ptr `plusPtr` (s-1))
    where
        STRICT3(go)
        go z p q | p == q    = return z
                 | otherwise = do c  <- peek p
                                  go (c `k` z) (p `plusPtr` (-1)) q -- tail recursive
{-# INLINE foldr #-}
Run Code Online (Sandbox Code Playgroud)

是从bytestring2005年8月.

这是用RWH写的,可能从那里开始普及.此外,在流融合库中,Duncan Coutts和我开始做很多事情.

来自GHC的消息来源

这个成语虽然可以追溯到更远的地方.foldr在GHC.Base中给出如下:

foldr k z = go
      where
         go []     = z
         go (y:ys) = y `k` go ys
Run Code Online (Sandbox Code Playgroud)

这可能是我接受诀窍的地方(我以为这是来自Andy Gill的论文,但在go那里找不到任何用处).它不是以这种形式给出GOFER,所以我觉得这个最早出现在GHC代码库.

到2001年,Simon Marlow正在使用go一些系统级代码,因此我们可能将责任归咎于GHC,这条线索引导我们进入GHC源,其中go广泛用于工作者函数:

myCollectBinders expr
  = go [] expr
  where
    go bs (Lam b e)          = go (b:bs) e
    go bs e@(Note (SCC _) _) = (reverse bs, e)
    go bs (Cast e _)         = go bs e
    go bs (Note _ e)         = go bs e
    go bs e                  = (reverse bs, e)
Run Code Online (Sandbox Code Playgroud)

GHC 3.02和格拉斯哥

挖掘GHC的旧版本,我们看到在GHC 0.29中这个成语没有出现,但是GHC 3.02系列(1998),这个go成语随处可见.1996-1997年Numeric.lhs定义中的一个例子showInt:

showInt n r
  | n < 0     = error "Numeric.showInt: can't show negative numbers"
  | otherwise = go n r
    where
     go n r =
      case quotRem n 10 of                 { (n', d) ->
      case chr (ord_0 + fromIntegral d) of { C# c# -> -- stricter than necessary
      let
    r' = C# c# : r
      in
      if n' == 0 then r' else go n' r'
      }}
Run Code Online (Sandbox Code Playgroud)

这是与H98报告中给出的不同的实现.挖掘到实施"Numeric.lhs",但是,我们发现,这是不一样的加入GHC 2.06在1997年的版本,并出现从Sigbjorne Finne一个非常有趣的补丁,在1998年4月,加入go循环到Numeric.lhs.

这说明至少到1998年,Sigbjorne正在go为GHC"std"库添加循环,同时,GHC编译器核心中的许多模块都有go循环.进一步深入,1996年7月Will Partain的这个非常有趣的提交为GHC添加了一个"go"循环 - 代码来自Simon PJ!

所以我打算把它称为格拉斯哥人在90年代中期从事GHC工作的格拉斯哥成语,比如Simon Marlow,Sigbjorn Finne,Will PartainSimon Peyton Jones.

  • 我模糊的回忆是,这是一个Simon PJ-ism.我倾向于使用`loop`,除非我修改已经使用`go`约定的代码.我一直认为这意味着字面意思是"走",就像"绕圈"一样. (24认同)
  • 我总是把"go"看作是对worker函数的命令,以开始它的脏递归劳动.无论如何,就个人而言,我从其中一个流融合幻灯片中选择了它,因为在函数名称中添加tick会始终存在我忘记勾号的问题. (5认同)
  • +1"尾部递归工作循环的通用名称",对于我见过的大多数用途来说,这似乎是正确的.对于函数`f`,我个人通常会使用`f'`作为这类事物的名称,尽管使用`go`作为一种近似关键词的习惯是我可能尝试去的东西.有趣的是,`showInt`使用成语来避免多次评估同一个警卫. (4认同)
  • 我相信它的起源早于Haskell.go是计划中名为let的常用名称(http://google.com/codesearch?as_q=%5C%28let%5C+go%5C+&as_lang=scheme,http://www.google.com/search? q =方案+%22let + 90%22 + - 让我们+汽车+ CDR) (4认同)

Mic*_*man 17

唐的回答显然是正确的.让我加上一个小细节(因为它似乎是我直接指的是我的写作):go很好,因为它只有两个字母.

哦,Yesod书中为调查器包提供了如此多的内容的原因是因为我已经将调查员的三部分教程编写为博客文章系列,因此我决定将其包含在书中.枚举器包在Yesod的许多地方使用,因此它是相关的.

  • +1"go"只有2个字母(并且仍然有意义)是一个容易被低估的事实.虽然我评论过Yesod书中使用"go"(对于那些例子来说这是一个很好的名字选择,imho),但实际上我正在阅读[StackOverflow答案](http://stackoverflow.com/questions/5841577/performance-当我觉得我应该问这个问题的时候,使用"go"的问题 - 与euler-problem-and-recursion-on-int64-types/5843344#5843344.我立即想起了Yesod书中的例子,因为它令人难忘.好东西! (6认同)

Con*_*nal 11

我希望这个成语不仅适用于线性结构(因此也适用于"循环"),而且适用于分支(树状)结构.

我想知道go模式多久经常与累积参数相对应,更常见的是,Mitch Wand在" 基于继续的程序转换策略"(我最喜欢的论文之一)中探讨了延续编码策略.在这些情况下,该go函数具有特定含义,然后可以使用该函数从优雅的规范中导出有效的代码.