Я go
многое вижу, когда читаю материал или исходный код Haskell, но я никогда не чувствовал себя комфортно в этом - (я полагаю, это имеет негативный оттенок "goto" в моем сознании). Я начал изучать Haskell с LYAH, и именно здесь я уловил тенденцию использовать acc
и step
при написании складок. Откуда взялось условное обозначение письма go
?
Самое главное, что именно go
должно означать это имя ?
haskell
naming-conventions
Дэн Бертон
источник
источник
loop
Вместо этого я обычно вызываю свою функцию .go
в материалах по Haskell, которые я читал. Можете привести пример / ссылку?Ответы:
Хм! Немного археологии!
Примерно с 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 -- tail recursive {-# 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# -> -- stricter than necessary 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-х, такими как Саймон Марлоу , Сигбьорн Финн , Уилл Партейн и Саймон Пейтон Джонс .
источник
f
я лично обычно используюf'
как имя для такого рода вещей, хотя использованиеgo
в качестве своего рода идиомы, близкой к ключевому слову, - это то, что я мог бы попытаться подобрать. Интересно отметить, чтоshowInt
используется идиома, чтобы не оценивать один и тот же охранник несколько раз.goto
передачу управления вспомогательной функции.loop
если я не изменяю код, который уже использует этоgo
соглашение. Я всегда думал, что это должно означать буквально «идти», как «идти по кругу».Очевидно, ответ Дона правильный. Позвольте мне добавить небольшую деталь (поскольку, похоже, вы прямо имеете в виду мое письмо): go - это хорошо, потому что это всего две буквы.
Да, и причина, по которой книга Yesod посвящает так много контента пакету enumerator, заключается в том, что я уже написал трехчастное руководство по enumerator в виде серии сообщений в блоге, поэтому решил, что могу также включить его в книгу. Пакет enumerator используется во многих местах Yesod, поэтому он актуален.
источник
Я ожидал, что эта идиома будет применима не только к линейным структурам (и, следовательно, «циклам»), но также и к ветвящимся (древовидным) структурам.
Интересно, как часто
go
паттерн соответствует параметрам накопления и, в более общем плане, стратегиям кодирования продолжения, которые Митч Ванд исследовал в статье « Стратегии преобразования программ, основанных на продолжении» (одна из моих самых любимых статей). В этих случаяхgo
функция имеет особое значение, которое затем можно использовать для получения эффективного кода из элегантной спецификации.источник
add_x
илиconsOnto_xs
.