Хм! Немного археологии!
Примерно с 2004 года я использовал goв качестве общего имени для хвостовых рекурсивных рабочих циклов, когда выполнял преобразование рабочий / оболочка рекурсивной функции. Я начал широко использовать его 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
{-# INLINE foldr #-}
был с bytestringавгуста 2005 года.
Об этом написали в RWH и, вероятно, оттуда популяризировали. Кроме того, в библиотеке слияния потоков мы с Дунканом Куттсом много начали этим заниматься.
Из источников GHC
Однако идиома уходит корнями в далекое прошлое. foldrв GHC.Base задается как:
foldr k z = go
where
go [] = z
go (y:ys) = y `k` go ys
вероятно, именно здесь я и взял уловку (я думал, что это из диссертации Энди Гилла, но не нашел там никакого применения go). В Gofer его нет в такой форме, поэтому я думаю, что он впервые появился в базе кода GHC.
К 2001 году Саймон Марлоу использовал 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)
GHC 3.02 и Глазго
Раскапывая старые версии GHC, мы видим, что в GHC 0.29 эта идиома не появляется, но в серии GHC 3.02 (1998 г.) она goпоявляется везде. Например, Numeric.lhsв определении showInt, датированном 1996-1997 гг .:
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# ->
let
r' = C# c# : r
in
if n' == 0 then r' else go n' r'
}}
это реализация, отличная от той, что дана в отчете H98 . Однако, копаясь в реализации "Numeric.lhs" , мы обнаруживаем, что это не то же самое, что версия, которая была добавлена к GHC 2.06 в 1997 году, и очень интересный патч от Sigbjorne Finne появляется в апреле 1998 года, добавляя goцикл к Numeric.lhs.
Это говорит о том, что по крайней мере к 1998 году Sigbjorne добавлял goциклы в библиотеку «std» GHC, в то время как одновременно многие модули в ядре компилятора GHC имели goциклы. Если копать дальше, то этот очень интересный коммит, сделанный Уиллом Партейном в июле 1996 года, добавляет цикл "go" в GHC - хотя код исходит от Simon PJ!
Я назову это идиомой Глазго, придуманной людьми из Глазго, которые работали над GHC в середине 90-х, такими как Саймон Марлоу , Сигбьорн Финн , Уилл Партейн и Саймон Пейтон Джонс .
loopВместо этого я обычно вызываю свою функцию .