Хм! Якась археологія!
Приблизно з 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 , і, мабуть, було популярно звідти. Крім того, у бібліотеці потокового злиття , ми з Duncan Coutts почали це робити багато.
З джерел GHC
Ідіома повертається ще далі. foldr
в GHC. База подана як:
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 р. Додає цикл "йти" до GHC - проте код походить від Simon PJ!
Тож я збираюся називати це ідіомою Глазго, винайденою людьми у Глазго, які працювали над GHC у середині 90-х, такими як Саймон Марлоу , Зігбйорн Фінне , Уілл Партайн та Саймон Пейтон Джонс .
loop
Замість цього я зазвичай викликаю свою функцію .