24 dias de Hackage, 2015 - dia 21 - hood, GHood, Hoed: Debugging orientado à observação no Haskell
por Franklin Chen
traduzido por Pedro Yamada
Esse é um artigo escrito por Franklin Chen e traduzido para o português. Ler original.
Índice de toda a série
O índice de toda a série está no topo do artigo para o dia 1.
Encontro HaskellBR São Paulo
Vamos nos encontrar em São Paulo em Janeiro de 2016. Marque sua presença e comente se não puder vir.
Vote se o encontro terá workshops, um dojo ou palestras.
Dia 21
Como você debugga seu código Haskell?
Eu tenho que confessar de cara que não tenho uma boa resposta para a questão de como debuggar Haskell.
Não sou a pessoa certa para falar sobre debuggers, porque a última vez que
usei uma ferramenta de debugging oficial foi quando estava desenvolvendo C e
C++ e usava ferramentas como o gdb
e interfaces de mais alto-nível para ele,
e desde então, meu processo de debugging para muitas linguagens tem envolvido
olhar a stack traces e logs, inserir expressões “print”, escrever testes
melhores e refatorar o código para encontrar a causa do problema. Eu não uso
mais aplicações de debugging oficiais tanto assim (com breakpoints,
stepping, etc.). Mas será que eu deveria?
A questão fica ainda mais complicada quando estamos trabalhando em Haskell, porque eu acho que é honesto dizer que Haskell não tem uma boa história com debugging.
Eu dei uma olhada em uma família de ferramentas de debugging para o haskell,
incluindo hood
GHood
, e
Hoed
, todos baseados no mesmo conceito:
anotações manuais no código fonte, de forma que traces mais úteis possam ser
gerados e analisados de formas interessantes.
Hood
Vamos dar uma olhada no hood
antes,
que significa “Haskell Object Observation Debugger”. É tudo sobre observação
por meio da type-class Observable a
e uma função de instrumentação
observe
:
Efeitos colaterais secretos!
Atenção! Apesar da sua assinatura de tipo, essa função realiza efeitos por
usando o unsafePerformIO
, então você deve tomar cuidado quanto a como
escrever código que usa o observe
, para conseguir os traces que quer.
Exemplo de instrumentação de uma pipeline
Vamos instrumentar a pipeline de contagens de palavras do
dia 8 .
Nós importamos Debug.Hood.Observe
e copiamos e colamos o código original com
modificações para inserir chamadas para o observe
.
(Peço desculpas pelo boilerplate sem sentido na descrição tipo String
de cada
ponto de observação: poderíamos escrever um wrapper usando Template Haskell, eu
imagino, se desejado)
Aqui eu escolhi só instrumentar os “estágios” naturais dos dados na
pipeline. Se quisesse, também podería instrumentar qualquer outro nível, e.g. o
resultado de chamar summarizeWordCount
(com summarizeWordCount >> observe
"summarizeWordCount"
), ou muitos outros níveis poderosos, tais como
instrumentar uma função, não só o resultado de uma chamada a uma função, e.g.
observe "summarizeWordCountfunction" summarizeWordCount
, que resulta na
coleção de todas as chamadas para a função.
Implementando uma type-class Observable
Irritantemente, porque tudo é baseado na type-class Observable
, ignoramos
avisos do GHC e criamos
instâncias órfãs
para várias tipos (a alternativa, adicionando um wrapper newtype
em todos os
lugares é um pouco trabalhosa nessa situação):
Saída de exemplo
Para simplicidade, vamos usar printO :: Show a => a -> IO ()
para executar
de forma que um trace seja impresso. Mais genéricamente, há um runO
que
executa uma ação IO
arbitrária.
A saída (eu só rodei isso no GHCi):
Isso definitivamente pode ser uma forma útil de debuggar pipelines, ou só
gerar traces para fins educacionais. Por exemplo, aqui nós podemos ver
imediatamente que não recebemos a resposta que queríamos (classificar “don’t”
como uma palavra) porque no terceiro estágio, nós recebemos “don”, o que
significa que algo deu errado nos estágios anteriores. No caso só havia um
outro, a remoção de caracteres que não fizessem parte de palavras - como o
'
.
Há muito mais que podemos fazer com o hood
, mas isso dá um gostinho.
GHood
Agora, nós mudamos o olhar brevemente para o
GHood
, que tem a mesma
interface com Observable
do hood
, exceto que nós importamos Debug.Observe
ao invés de Debug.Hood.Observe
. Não vou mostrar código de exemplo porque ele
é literalmente só copiar/colar o código antigo e mudar o import. Problemas com
cópia e cola como essa (que também apareceram no
dia 15 sobre IOSpec
)
de fato me fazem desejar que o Haskell tivesse módulos parametrizados como o
ML. (E o problema com a instância orfã de Observable
também, onde módulos
estilo ML são a forma natural de plugar formas diferentes de observar o
mesmo tipo de dados como for desejado).
GHood
é um backend gráfico escrito em Java para o hood
. Quando você
instala o GHood
, ele vem com um arquivo Java JAR. O Java lê um arquivo de
logs ObserveEvents.log
que é gerado a partir do código instrumentalizado pelo
hood
. Você pode animar, dar pulos para trás e para frente e os traces são
mostrados em uma estrutura de árvore, incluindo mostrar a avaliação dos
thunks. É uma prova-de-conceito interessante de 2001, mas é um pouco
primitiva. Eu decidi não tentar incluir um screenshot de uma execução de
exemplo, porque a saída do app Java Swing vai bem para a direita da janela e
não é muito customizável.
Hoed
Hoed
tem uma API baseada no hood
mas
é um projeto muito mais moderno, sofisticado e ativo. Ele permite
“debugging algorítmo” fornecendo uma aplicação web interativa, onde usa uma
estrutura de árvore para perguntar repetidamente ao usuário se os resultados
estão corretos, para isolar e identificar a fonte do erro baseado no seu
feedback.
Além disso, ele vem incluso com suporte para QuickCheck e debugging baseado propriedades. Confira a documentação e screenshots.
Hoed
começa um servidor web local que você pode acessar com um browser
na porta 10000. O repositório no GitHub contém
um monte de
exemplos.
Infelizmente, meu tempo acabou antes de que eu conseguisse o fazer funcionar da
forma que eu queria para mostrar como um sistema de debugging interativo
aqui, então, o que eu posso dizer é que o Hoed
é muito interessante e que
planejo ir mais fundo nisso quando tiver o tempo. Vou atualizar esse post mais
tarde.
Conclusão
Eu não usei muitas ferramentas de debugging nos útilmos anos, mas eu gostaria
de mudar isso na medida em que encontrar formas de usar novas ferramentas que
sejam fáceis de usar. Sistemas baseados no hood
parecem úteis como formas de
coletar informação durante a execução sem ter que reestruturar o código
radicalmente.
Todo o código
Todo o código para a série estará nesse repositório do GitHub.
Nota do tradutor
Se você quer ajudar com esse tipo de coisa, agora é a hora. Entre no
Slack ou no
IRC da HaskellBR e
contribua. Esse blog e outros projetos associados estão na
organização haskellbr
no GitHub e em
haskellbr.com/git.