Vejo go
muito quando leio material ou fonte de Haskell, mas nunca me senti muito confortável com isso - (acho que tem a conotação negativa de "goto" em minha mente). Comecei a aprender Haskell com LYAH, e foi aí que peguei a tendência de usar acc
e step
escrever dobras. De onde vem a convenção para escrever go
?
Mais importante, o que exatamente o nome go
implica?
haskell
naming-conventions
Dan Burton
fonte
fonte
loop
vez disso, geralmente chamo minha função .go
em nenhum material Haskell que li. Você pode dar um exemplo / referência?Respostas:
Hmm! Alguma arqueologia!
Desde cerca de 2004, usei
go
como nome genérico para loops de trabalho recursivos de cauda, ao fazer uma transformação de trabalhador / wrapper de uma função recursiva. Comecei a usá-lo amplamente embytestring
, por exemplofoldr :: (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 #-}
era de
bytestring
agosto de 2005.Isso foi escrito no RWH e provavelmente foi popularizado a partir daí. Além disso, na biblioteca de fusão de fluxo , Duncan Coutts e eu começamos a fazer muito isso.
Das fontes GHC
O idioma é mais antigo.
foldr
em GHC.Base é dado como:foldr k z = go where go [] = z go (y:ys) = y `k` go ys
que foi provavelmente onde aprendi o truque (pensei que fosse da tese de Andy Gill, mas não consigo encontrar nenhuma utilidade
go
nela). Não é fornecido nesta forma no Gofer, então acho que apareceu pela primeira vez na base de código do GHC.Em 2001, Simon Marlow estava usando
go
em alguns dos códigos de nível de sistema, então podemos colocar a culpa em algum lugar no GHC, e essa pista nos leva à fonte do GHC , ondego
é amplamente usado nas funções de trabalho: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 e Glasgow
Desenterrando versões antigas do GHC, vemos que no GHC 0.29 esse idioma não aparece, mas pela série GHC 3.02 (1998), o
go
idioma aparece em todos os lugares. Um exemplo, emNumeric.lhs
, na definição deshowInt
, datado de 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' }}
esta é uma implementação diferente daquela fornecida no relatório H98 . Explorando a implementação de "Numeric.lhs" , no entanto, descobrimos que não é o mesmo que a versão que foi adicionada ao GHC 2.06 em 1997, e um patch muito interessante de Sigbjorne Finne aparece, em abril de 1998, adicionando um
go
loop para Numeric.lhs.Isso diz que pelo menos em 1998, Sigbjorne estava adicionando
go
loops à biblioteca "std" do GHC, enquanto, simultaneamente, muitos módulos no núcleo do compilador GHC tinhamgo
loops. Indo mais longe, este commit muito interessante de Will Partain em julho de 1996 adiciona um loop "go" no GHC - o código vem de Simon PJ embora!Então, vou chamar isso de uma expressão idiomática de Glasgow inventada por pessoas em Glasgow que trabalharam com GHC em meados dos anos 90, como Simon Marlow , Sigbjorn Finne , Will Partain e Simon Peyton Jones .
fonte
f
, eu normalmente usareif'
como nome para esse tipo de coisa, embora usargo
como uma espécie de idioma quase-palavra-chave seja algo que eu possa tentar escolher. Interessante notar queshowInt
usa o idioma para evitar avaliar o mesmo guarda várias vezes.goto
, e em passar o controle para uma função auxiliar.loop
menos que esteja modificando o código que já usa ago
convenção. Sempre pensei que a intenção era literalmente "ir", como em "ir ao redor do loop".Obviamente, a resposta de Don é a correta. Deixe-me apenas adicionar um pequeno detalhe (já que parece ser a minha escrita que você está se referindo diretamente): go é bom porque tem apenas duas letras.
Ah, e a razão pela qual o livro de Yesod dedica tanto conteúdo ao pacote do enumerador é porque eu já escrevi o tutorial de três partes do enumerador como uma série de postagens de blog, então decidi que também posso incluí-lo no livro. O pacote de enumerador é usado em vários lugares em Yesod, por isso é relevante.
fonte
Eu esperava que esse idioma fosse aplicável não apenas a estruturas lineares (e, portanto, "loops"), mas também a estruturas ramificadas (semelhantes a árvores).
Eu me pergunto com que frequência o
go
padrão corresponde aos parâmetros de acumulação e, de maneira mais geral, às estratégias de codificação de continuação que Mitch Wand explorou no artigo Estratégias de Transformação de Programas Baseados em Continuação (um dos meus artigos favoritos de todos os tempos). Nesses casos, ago
função tem um significado particular, que pode ser usado para derivar código eficiente de uma especificação elegante.fonte
add_x
ouconsOnto_xs
.