Eu li que o Go realmente não tem inferência de tipo verdadeira, no sentido de que linguagens funcionais como ML ou Haskell têm, mas não consegui encontrar uma comparação simples de entender das duas versões. Alguém poderia explicar em termos básicos como a inferência de tipo no Go difere da inferência de tipo em Haskell e os prós / contras de cada um?
Consulte esta resposta StackOverflow sobre a inferência de tipo do Go. Eu não estou familiarizado com Go, mas com base nessa resposta, parece uma "dedução de tipo" unidirecional (para emprestar alguma teminologia em C ++). Isso significa que se você tiver:
x := y + z
então o tipo de xé deduzido por descobrir o tipo de y + z, o que é uma coisa relativamente trivial a ser feita pelo compilador. Para fazer isso, os tipos ye zprecisam ser conhecidos a priori : isso pode ser feito através de anotações de tipo ou deduzido dos literais atribuídos a eles.
Por outro lado, a maioria das linguagens funcionais possui inferência de tipo que utiliza todas as informações possíveis dentro de um módulo (ou função, se o algoritmo de inferência for local) para derivar o tipo das variáveis. Algoritmos de inferência complicados (como Hindley-Milner) geralmente envolvem alguma forma de unificação de tipo (um pouco como resolver equações) nos bastidores. Por exemplo, em Haskell, se você escrever:
let x = y + z
Haskell pode inferir o tipo não apenas, xmas também ye zsimplesmente, com base no fato de que você está realizando adição neles. Nesse caso:
x :: Num a => a
y :: Num a => a
z :: Num a => a
(As letras minúsculas aaqui denotam um tipo polimórfico , geralmente chamado de "genéricos" em outros idiomas como C ++. A Num a =>parte é uma restrição para indicar que o asuporte ao tipo tem alguma noção de adição.)
Aqui está um exemplo mais interessante: o combinador de ponto fixo que permite definir qualquer função recursiva:
let fix f = f (fix f)
Observe que em nenhum lugar especificamos o tipo de f, nem o tipo de fix, mas o compilador Haskell pode descobrir automaticamente que:
f :: t -> t
fix :: (t -> t) -> t
Isto diz que:
O parâmetro fdeve ser uma função de algum tipo arbitrário tpara o mesmo tipo t.
fixé uma função que recebe um parâmetro do tipo t -> te retorna um resultado do tipo t.
mais exatamente, Haskell pode dizer que x, y, zsão o mesmo Numtipo de eric, mas eles ainda podem ser Integers, Doubles, Ratio Integers ... Haskell está disposto a fazer uma escolha arbitrária entre tipos numéricos, mas não para outros typeclasses.
John Dvorak
7
A inferência de tipo no Go é extremamente limitada e extremamente simples. Ele funciona apenas em uma construção de idioma (declaração de variável) e simplesmente pega o tipo do lado direito e o usa como o tipo da variável no lado esquerdo.
A inferência de tipo no Haskell pode ser usada em qualquer lugar, pode ser usada para inferir os tipos para todo o programa. É baseado na unificação, o que significa que (conceitualmente) todos os tipos são inferidos "de uma só vez" e todos podem influenciar um ao outro: no Go, as informações do tipo só podem fluir do lado direito de uma declaração de variável para o lado esquerdo. lado da mão, nunca na outra direção e nunca fora de uma declaração variável; em Haskell, as informações do tipo fluem livremente em todas as direções durante todo o programa.
No entanto, o sistema de tipos de Haskell é tão poderoso que a inferência de tipos pode, na verdade, deixar de inferir um tipo (ou mais precisamente: restrições precisam ser implementadas para que um tipo sempre possa ser inferido). O sistema de tipos Go é tão simples (sem subtipagem, sem polimorfismo paramétrico) e sua inferência tão limitada que sempre é bem-sucedida.
"em Haskell, as informações do tipo fluem livremente em todas as direções ao longo de todo o programa": acho que isso dá uma boa intuição. +1
Giorgio
As alegações que esta resposta faz no último parágrafo são um pouco enganadoras. Haskell não tem subtipo. Além disso, o polimorfismo paramétrico não causa nenhum problema para a completude da inferência de tipo: Hindley-Milner no cálculo lambda polimórfico sempre encontra o tipo mais geral. Haskell pode falhar ao inferir tipos, mas isso ocorrerá em recursos sofisticados do sistema de tipos, como GADTs, onde, quando formulados de maneira ingênua, não existe nenhum tipo principal (ou seja, "melhor escolha").
x
,y
,z
são o mesmoNum
tipo de eric, mas eles ainda podem serInteger
s,Double
s,Ratio Integer
s ... Haskell está disposto a fazer uma escolha arbitrária entre tipos numéricos, mas não para outros typeclasses.A inferência de tipo no Go é extremamente limitada e extremamente simples. Ele funciona apenas em uma construção de idioma (declaração de variável) e simplesmente pega o tipo do lado direito e o usa como o tipo da variável no lado esquerdo.
A inferência de tipo no Haskell pode ser usada em qualquer lugar, pode ser usada para inferir os tipos para todo o programa. É baseado na unificação, o que significa que (conceitualmente) todos os tipos são inferidos "de uma só vez" e todos podem influenciar um ao outro: no Go, as informações do tipo só podem fluir do lado direito de uma declaração de variável para o lado esquerdo. lado da mão, nunca na outra direção e nunca fora de uma declaração variável; em Haskell, as informações do tipo fluem livremente em todas as direções durante todo o programa.
No entanto, o sistema de tipos de Haskell é tão poderoso que a inferência de tipos pode, na verdade, deixar de inferir um tipo (ou mais precisamente: restrições precisam ser implementadas para que um tipo sempre possa ser inferido). O sistema de tipos Go é tão simples (sem subtipagem, sem polimorfismo paramétrico) e sua inferência tão limitada que sempre é bem-sucedida.
fonte