Хм! Немного археологии!
Примерно с 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
Вместо этого я обычно вызываю свою функцию .