Entender o erro de tipo: “assinatura esperada Int * INT> Int mas foi Int * INT> Int”

StackOverflow https://stackoverflow.com/questions/324612

  •  11-07-2019
  •  | 
  •  

Pergunta

Os comentários sobre Steve Yegge 's pós sobre server-side Javascript começaram a discutir os méritos de sistemas do tipo em línguas e este comentário descreve:

... exemplos de HM sistemas estilo onde você pode obter coisas como:

expected signature Int*Int->Int but got Int*Int->Int

Você pode dar um exemplo de uma definição de função (ou duas?) E uma chamada de função que produziria esse erro? Isso parece que pode ser bastante difícil de depuração em um programa de grande ish.

Além disso, eu poderia ter visto um erro semelhante na Miranda ? (Eu não tê-lo usado em 15 anos e por isso a minha memória dele é vaga)

Foi útil?

Solução

Eu levaria opiniões de Yegge (e Ola Bini) na tipagem estática com um grão de sal. Se você aprecia o que tipagem estática dá-lhe, você vai aprender como o sistema de tipos da linguagem de programação que você escolher obras.

IIRC, ML utiliza a '*' sintaxe para tuplas. * é um tipo tupla com dois elementos. Então, (1, 2) teria int * tipo int.

Ambos Haskell e uso ML -> para funções. Em ML, int * int -.> Int seria o tipo de uma função que recebe uma tupla de int e int e mapeia para um int

Uma das razões que você pode ver um erro que parece vagamente com o Ola citado quando chegar a ML de um idioma diferente, é se você tentar e passar argumentos usando parênteses e vírgulas, como se faria em C ou Pascal, a uma função que tem dois parâmetros.

O problema é que as linguagens funcionais geralmente funções modelo de mais de um parâmetro como funções retornando funções; todas as funções só ter um único argumento. Se a função deve levar dois argumentos, em vez recebe um argumento e retorna uma função de um único argumento, que devolve o resultado final, e assim por diante. Para fazer tudo isso, a aplicação de função legível é feito simplesmente conjunção (ou seja, colocando as expressões ao lado um do outro).

Assim, uma função simples em ML (nota: eu estou usando F # como meu ML) pode parecer um pouco como:

let f x y = x + y;;

Tem tipo:

val f : int -> int -> int

(A função de tomar um inteiro e retornar uma função que em si leva um inteiro e retorna um inteiro.)

No entanto, se você ingenuamente chamá-lo com uma tupla:

f(1, 2)

... você vai receber um erro, porque você passou um int * int a algo esperando um int.

Espero que este é o "problema" Ola estava tentando aspersions elenco em. Eu não acho que o problema é tão ruim quanto ele pensa, embora; certamente, é muito pior em modelos C ++.

Outras dicas

É possível que isso foi em referência a um compilador mal-escrito, que não conseguiu inserir parênteses para as mensagens de erro ambigüidade. Especificamente, a função esperada uma tupla de int e retornou um int, mas você passou uma tupla de int e uma função da int para int. Mais concretamente (em ML):

fun f g = g (1, 2);

f (42, fn x => x * 2)

Isto irá produzir um erro de tipo semelhante ao seguinte:

Tipo esperado int * int -> int, recebeu tipo de int * (int -> int)

Se os parênteses forem omitidas, este erro pode ser irritantemente ambíguo.

É importante notar que este problema está longe de ser específica para Hindley-Milner. Na verdade, eu não consigo pensar em qualquer tipo estranho erros , que são específicos para H-M. Pelo menos, nenhum como o exemplo dado. Eu suspeito que Ola estava apenas soprando fumaça.

Uma vez que muitos linguagem funcional permitem que você religar nomes de tipo, da mesma forma que você pode religar variáveis, é realmente muito fácil de acabar com um erro como este, especialmente se você usar nomes um tanto genéricos para os seus tipos (por exemplo, t) em módulos diferentes. Aqui está um exemplo simples em OCaml:

# let f x = x + 1;;
val f : int -> int = <fun>
# type int = Foo of string;;
type int = Foo of string
# f (Foo "hello");;
This expression has type int but is here used with type int

O que eu fiz aqui é religar o int tipo de identificador para um novo tipo que é incompatível com o built-in tipo int. Com um pouco mais de esforço, podemos ter mais ou menos o mesmo erro que acima:

# let f g x y = g(x,y) + x + y;;
val f : (int * int -> int) -> int -> int -> int = <fun>
# type int = Foo of int;;
type int = Foo of int
# let h (Foo a, Foo b) = (Foo a);;
val h : int * int -> int = <fun>
# f h;;
This expression has type int * int -> int but is here used with type
  int * int -> int
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top