24 dias de Hackage, 2015 - dia 6 - Encontrando utilitários com Hoogle e Hayoo: MissingH, extra
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.
Dia 6
Nunca será o caso que tudo que todos consideram “útil” vai estar na “biblioteca
padrão” de qualquer ecossistema de uma linguagem. Uma das funcionalidades mais
legais do ecossistema do Haskell (que impressiona todos os não-Haskellers a
quem eu a mostro) é a habilidade de pesquisar por funções pela sua assinatura
de tipo, usando o
Hoogle
ou o
Hayoo
.
Você também pode usar outros critérios, como nomes; isso pode ser útil se você
tiver um chute do nome de alguma função que precise.
Parecem haver duas filosofias para bibliotecas de utilitários:
- Re-uso é ótimo, vamos fazer isso
- Todas as dependencias são um problema em potencial, então vamos reinventar ou copiar e colar, ao invés de usar algo que pode não ter qualidade ou não ser mantido
Eu tendo a preferir o re-uso, mas já copiei (e até modifiquei) trechos de código que precisava, só porque não queria o resto de uma biblioteca enorme que depende de mais outras coisas que não preciso. Eu acho que esse é um problema de granularidade. Já que temos a Web hoje, muitas pessoas propuseram a ideia de que o conceito de uma “biblioteca” deveria virar obsoleto dando lugar a “micro-bibliotecas”, talvez até no nível de um único indentificador exportado, mas o tópico está fora do escopo desse artigo. (Para uma dessas ideias, veja o “The internet of code” do Gabriel Gonzalez).
[N.T. A HaskellBR pode contribuir com isso! Ajude em haskellbr/missingh]
A situação fica complicada pelo fato de que frequentemente, podemos reinventar um monte de coisas com só algumas linhas de Haskell, então porque se importar em procurar pela implementação de outros no primeiro lugar?
De qualquer forma, vamos assumir que o propósito desse artigo é que você está
interessado em encontrar e usar bibliotecas de utilitários. Eu vou mostrar como
encontrar algumas funções de exemplo e chegar em duas bibliotecas de
utilitários que uso, espertamente e informativamente chamadas de
MissingH
e
extra
.
Um exemplo de listas/strings
Algum tempo atrás estava manipulando strings (eu tinha uma String
, não um
Text
ou uma ByteString
) e precisava substituir todas as ocorrências de uma
substring em um path com outra substring. Por exemplo, como um teste do HSpec
para uma função hipotética chamada replace
:
Claro, não seria difícil escrever o código para fazer isso, mas porque não procurar por algo pronto que eu possa usar?
Por qual assinatura deveríamos procurar? Talvez:
Ou seja (com algo próximo de sua documentação Haddock):
Ok, vamos tentar essa assinatura como uma busca no Hayoo. Hmm, os resultados não são promissores. No topo está alguma coisa extranha e não documentada sobre regexes, que provavelmente não é o que queremos.
Uma técnica de busca importante: assuma o menor número de coisas possível
Provavelmente a dica mais importante para conseguir resultados bons para uma busca a partir de um tipo é fazer o tipo tão genérico quanto possível: quanto mais variáveis de tipo, o melhor, e também só use constraints de type-class que você precisar de fato. A operação que nós queremos na verdade não é restrita a strings. Na verdade, é uma operação sobre listas. Então o tipo que nós queremos é:
Essa função utilitária assume o menor número coisas necessárias para fazer o
trabalho para String
s, já que String
é só um nome para [Char]
e Char
é
uma instância da type-class Eq
. Para o propósito de substituir sub-listas,
nós não nos importamos se comparamos characteres: só importa que qualquer que
seja o tipo dos elementos nas listas e sub-listas possa ser comparado por
igualdade.
A
busca no Hayoo
imediatamente retorna resultados mais promissores do que a antiga com String
,
com pacotes como utility-ht
, MissingH
e extra
. O pandoc
também apareceu,
mas ele é uma
ferramenta enorme de processamento de texto, não uma
biblioteca que eu incluiria só por uma função utilitária pequena! (Note que
pandoc
foi coberto em um
dia de Hackage de 2013.
A
busca no Hoogle em hoogle.haskell.org
funciona bem também.
(Note que a busca do Hoogle no site antigo
dá resultados ruins.)
Modificando nossos testes para checar a função genérica
Eu passei brevemente por refatorar testes do HSpec no
dia 3.
Aqui está como testar muitas implementações da mesma função (vamos ir com
MissingH
e extra
), e também testar replace
com tipos de input diferentes:
tanto String
(que não passa de [Char]
) e [Int]
:
Mas o código não compila! Por que?
Uma nota no uso de higher-rank types para refatorar
O erro é útil se você sabe o que está acontecendo, mas não muito caso contrário. Sim, nós precisamos de higher-rank types.
Higher-rank types são uma extensão ao GHC discutida em um Dia de Extensões do GHC 2014. Higher-rank types são muito úteis e uma funcionalidade faltando nos sistemas de tipos da maior parte das outras linguagens.
Resumidamente, a função replace
que queremos tem tipo:
aqui nós quantificamos a variável de tipo a
para que o constraint Eq
se
aplique dentro do seu escopo. Leia o tipo como “para todos os tipos a
onde
a
é um membro da type-class Eq
, [a] -> [a] -> [a] -> [a]
”. Haskell
normal sem a extensão, não permite usar esse tipo como um parâmetro para outra
função, porque ele não tem um forall
explícito e insere um forall
para
você, implicitamente, no escopo do topo da assinatura, o que é o escopo
incorreto para o que queremos.
Então precisamos adicionar a diretiva e mudar o tipo do parâmetro "A
implementação de replace"
para ter quantificação explícita e está tudo ok:
Uma nota sobre quantificação implícita em Haskell e linguagens relacionadas
Eu gostaria que a quantificação de variáveis de tipo fosse explíta em Haskell,
que anotações forall
fossem necessárias, como o
PureScript
faz,
porque entender quantificação de variáveis de tipo é importante para entender
completamente o que acontece a nível dos tipos em linguagens como ML e Haskell.
Por exemplo, esse um bom artigo sobre como entender a restrição de valores e a restrição de monomorfismo, que pode ser desafiador se você não tem um modelo mental do que acontece nos bastidores.
O prazer de explorar bibliotecas
Uma coisa que pode acontecer se você encontrar uma função utilitária útil, é
que você pode explorar o módulo que a contem ou a biblioteca inteira, só
procurando por mais coisas que podem ser úteis no futuro. Por exemplo, eu acho
a biblioteca do Neil Mitchell extra
agradável o suficiente (bons nomes, boa
documentação no Hackage) que eu a uso quando posso e recomendo dar uma olhada
nela. O repositório no GitHub do MissingH
sugere que ela não está mais sendo
mantida, então eu estou tentando evitar seu uso.
No mundo de livros e revistas físicas, eu ainda vou até a livraria e fico olhando as prateleiras de livros/revistas/DVDs novos e acabo olhando na prateleira de algum item que eu tenha encontrado para ver se há alguma outra coisa relacionada que eu possa querer conferir.
Cavando mais fundo
Note que se você está na busca de bibliotecas potencialmente úteis, mas sem
necessidade imediata, você também pode as encontrar só olhando para a lista de
dependências de bibliotecas populares. Eu confesso que as vezes eu me perco
clicando nas dependências de uma página do Hackage. Se você ficar clicando nas
dependências do pacote
lens
de Edward Kmett vai acabar encontrando um número impressinante de bibliotecas
úteis, porque ele é um mestre do universo de re-uso de código.
A analogia com livros ou papel existe aqui, claro, e é olhar nas referências ou bibliografia de algo para encontrar mais coisas para ler.
Conclusão
Para o dia 6, dei um exemplo de como buscar por uma função no Hoogle ou no
Hayoo e passei um pouco por como generalizar assinaturas propriamente. Eu
recomendo o uso da biblioteca de utilitários extra
.
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.