Haskell tem uma noção de "funções genéricas" que tem alguma aparente semelhança com o lisp comum - não tendo experiência com Haskell nem com lisp comum, talvez eu seja muito aproximado aqui. Isso significa que é possível definir um to_string
recurso genérico para definir uma representação de string para todos os tipos. Obviamente, a instalação deve ser definida em casos especiais, mas existe uma to_string
função cuja assinatura é α → string
.
Os tipos são apagados no Haskell, assim como no OCaml? Se sim, como a implementação de “funções genéricas” em Haskell difere da do lisp comum, onde os tipos são dinâmicos e, portanto, não são apagados?
Entendo que os detalhes da implementação são específicos do compilador, mas provavelmente existem disposições comuns a muitas ou todas as implementações.
fonte
a -> String
. Você provavelmente teria uma restrição de tipo, comoShow a => a -> String
.Respostas:
A resposta até agora é enganosa.
É necessário fazer uma distinção entre polimorfismo "paramétrico" e "sobrecarga ad-hoc". Os parâmetros paramétricos "se comportam de maneira uniforme para todos os tipos a", enquanto "ad-hoc" - o que Simon chama de polimórfico - altera a implementação com base no tipo.
Exemplos de ambos são
reverse :: [a] -> [a]
, que é paramétrico eshow :: Show a => a -> String
que é "ad-hoc" sobrecarregado.Se você deseja mais uma intuição abstrata, acho que ajuda considerar as classes de verbos da linguagem natural que 'funcionam' para todos os objetos, como "possuir" ou "pensar em" que não apresentam restrições ao objeto, mas " abrir "requer que o que estamos falando possa ser aberto. Consigo "pensar em uma porta" e "abrir uma porta", enquanto não faz sentido, por exemplo, "abrir uma árvore". Para levar o exemplo ainda mais longe, "abrir" é "polimórfico ad-hoc" como "abrir uma janela" e "abrir um registro de reclamação com o atendimento ao cliente" são duas coisas muito diferentes. Se isso parece forçado - esqueça! Funciona para mim.
Ambos são resolvidos em tempo de compilação, no entanto, e de fato "apagados". Módulo várias extensões de GHC e Template Haskell, etc. De fato, os tipos são apagados no tempo de compilação e nunca são inspecionados no tempo de execução.
As funções parametricamente polimórficas se comportam de forma idêntica para todos os tipos, portanto, apenas um pedaço de código precisa ser gerado, enquanto o compilador decide em tempo de compilação qual versão de uma função "classificada como tipo" precisa ser executada em um ponto específico do programa. É também por isso que existe a restrição de uma instância por tipo por classe de tipo e a solução alternativa "newtype" correspondente.
A implementação está detalhada no livro didático de SPJs e no artigo Wadler e Blotts sobre classes de tipo .
fonte
forall
extensão GHC ).aviso: minha formação em CS não é muito forte, por isso nem sempre posso usar o vocabulário correto e posso estar errado em alguns pontos. Enfim, aqui está o meu entendimento:
Eu acho que você está confundindo genéricos com polimorfismo.
Tipos genéricos como
List<Foo>
são usados para descrever tipos que usam outros tipos como parâmetro e permitem uma verificação mais rica do tipo.Uma função genérica no haskell pode ser
count:: List a -> Int
. Ele aceita listas de qualquer tipo e retorna o número de elementos. Existe apenas uma implementação.Geralmente, ao definir Lista, você não pode assumir nada sobre T. Você só pode armazená-lo e devolvê-lo.
Sua
to_string
função é uma função polimórfica, o que significa que se comportará de maneira diferente em diferentes circunstâncias. Em haskell, isso é feito com classes de tipos, que funcionam como adjetivos para tipos.Você tem uma
Show
classe de tipo, que define umashow :: a -> String
função.Quando um tipo
Foo
implementa aShow
classe, deve fornecer a definição deshow
. Esse tipo pode ser usado em funções que exigem oShow
qualificador (como emShow a => a -> whatever
). Haskell não pode apagar tipos, pois essas funções precisam encontrar a implementação correta dashow
função.fonte