Terminologia correta na teoria dos tipos: tipos, construtores de tipos, tipos / tipos e valores


14

Em resposta a uma pergunta anterior , iniciou-se um pequeno debate sobre a terminologia correta para certas construções. Como não encontrei uma pergunta (além desta ou daquela , que não é a coisa certa) para abordar isso claramente, estou fazendo essa nova.

Os termos questionáveis ​​e seus relacionamentos são: tipo, construtor de tipos, parâmetro de tipo, tipos ou classificações e valores .

Também verifiquei na wikipedia a teoria dos tipos, mas isso também não esclareceu muito.

Portanto, para ter uma boa resposta de referência e verificar meu próprio entendimento:

  • Como essas coisas são definidas corretamente?
  • Qual é a diferença entre cada uma dessas coisas?
  • Como eles se relacionam?

Respostas:


13

Tudo bem, vamos um por um.

Valores

Os valores são os dados concretos que os programas avaliam e manipulam. Nada extravagante, alguns exemplos podem ser

  • 1
  • true
  • "fizz buzz foo bar"

Tipos

Uma boa descrição para um tipo é "um classificador para um valor". Um tipo é um pouco de informação sobre qual será esse valor em tempo de execução, mas indicado em tempo de compilação.

Por exemplo, se você me disser isso e : boolem tempo de compilação, e eu saberei que eé trueoufalse durante durante o tempo de execução, nada mais! Como os tipos classificam valores dessa maneira, podemos usar essas informações para determinar algumas propriedades básicas do seu programa.

Por exemplo, se eu vejo você adicionando ee e'quando e : intee' : String , então sei que algo está um pouco errado! Na verdade, posso sinalizar isso e gerar um erro no momento da compilação, dizendo "Ei, isso não faz nenhum sentido!".

Um sistema de tipos mais poderoso permite tipos mais interessantes que classificam valores mais interessantes. Por exemplo, vamos considerar alguma função

f = fun x -> x

É bem claro isso f : Something -> Something, mas o que deveria Somethingser? Em um sistema de tipo chato, teríamos que especificar algo arbitrário, como Something = int. Em um sistema de tipo mais flexível, poderíamos dizer

f : forall a. a -> a

Ou seja, "para qualquer a, fmapeia um apara um a". Isso vamos usarf mais geral e escrever programas mais interessantes.

Além disso, o compilador verificará realmente satisfazendo o classificador que fornecemos, se f = fun x -> true tivermos um bug e o compilador o dirá!

Então, como um tldr; um tipo é uma restrição de tempo de compilação nos valores que uma expressão pode estar no tempo de execução.

Tipo Construtor

Alguns tipos estão relacionados. Por exemplo, uma lista de números inteiros é muito semelhante a uma lista de seqüências de caracteres. É quase como se sortfor números inteiros é quase como sortpara strings. Podemos imaginar um tipo de fábrica que constrói esses tipos quase iguais generalizando suas diferenças e construindo-as sob demanda. Isso é o que é um construtor de tipos. É como uma função de tipos para tipos, mas um pouco mais limitada.

O exemplo clássico é uma lista genérica. Um construtor de tipo para é apenas a definição genérica

 data List a = Cons a (List a) | Nil

Agora Listé uma função que mapeia um tipoa para uma lista de valores desse tipo! Na terra de Java, acho que essas talvez sejam chamadas de "classes genéricas"

Parâmetros de tipo

Um parâmetro de tipo é apenas o tipo passado para um construtor de tipo (ou função). Assim como no nível de valor, diríamos que foo(a)tem um parâmetro, aassim como o List aparâmetro de tipo a.

Tipos

Tipos são um pouco complicados. A idéia básica é que certos tipos são semelhantes. Por exemplo, nós temos todos os tipos primitivos em java int, char, float... que todos se comportam como se eles têm o mesmo "tipo". Exceto, quando falamos dos classificadores para os próprios tipos, chamamos os tipos de classificadores. Assim int : Prim, String : Box, List : Boxed -> Boxed.

Esse sistema fornece boas regras concretas sobre que tipo de tipos podemos usar onde, exatamente como os tipos governam os valores. Seria claramente um absurdo dizer

 List<List>

ou

 List<int>

Em Java, desde que Listprecisa ser aplicado a um tipo concreto para ser usado assim! Se olharmos para os seus tipos List : Boxed -> Boxede Boxed -> Boxed /= Boxed, desde então , o erro acima é um tipo!

Na maioria das vezes, não pensamos nos tipos e apenas os tratamos como "senso comum", mas com sistemas de tipos mais sofisticados é algo importante para se pensar.

Uma pequena ilustração do que venho dizendo até agora

 value   : type : kind  : ...
 true    : bool : Prim  : ...
 new F() : Foo  : Boxed : ...

Melhor leitura que a Wikipedia

Se você estiver interessado nesse tipo de coisa, eu recomendo investir um bom livro. A teoria dos tipos e o PLT em geral são bastante vastos e sem uma base coerente de conhecimento, você (ou pelo menos eu) pode passear sem chegar a lugar nenhum por meses.

Dois dos meus livros favoritos são

  • Tipos e linguagem de programação - Ben Pierce
  • Fundamentos práticos de linguagens de programação - Bob Harper

Ambos são excelentes livros que apresentam o que acabei de falar e muito mais em detalhes bonitos e bem explicados.


1
Tipos são conjuntos? Gosto mais de "classificador", mas você não explica o que isso significa e, sem uma boa compreensão do que é um tipo, o restante da sua resposta cai.
Robert Harvey

@RobertHarvey Como ele se parece agora, eu deixei cair todas as menções de conjuntos :)
Daniel Gratzer

1
Muito melhor ...
Robert Harvey

@RobertHarvey Acho a visão dos tipos como conjuntos muito intuitiva. Por exemplo, o tipo intem Java consiste em um conjunto de 2 ^ 64 valores distintos. A analogia com os conjuntos é quebrada quando os subtipos são envolvidos, mas é uma intuição inicial suficientemente boa, especialmente quando você considera os tipos de dados algébricos (por exemplo, uma união de dois tipos pode conter qualquer membro de qualquer tipo; é a união desses conjuntos) .
Doval

@Doval: Se eu escrever uma classe que descreva um Cliente, provavelmente representará um "conjunto" de clientes, pois vou fazer uma coleção de instâncias. Mas dizer que um Cliente é um Tipo porque descreve um "conjunto" de clientes é uma tautologia; parece óbvio. O mais interessante é que um tipo de cliente descreve as características de um cliente. Usar "set" para explicar isso parece mais ... abstrato do que realmente é. A menos que, talvez, você seja um matemático.
Robert Harvey

2

Como essas coisas são definidas corretamente?

Eles são definidos adequadamente por um apoio matemático rígido e acadêmico, fornecendo fortes afirmações sobre o que são, como funcionam e o que é garantido.

Mas os programadores em grande parte não precisam saber disso. Eles precisam entender os conceitos.

Valores

Vamos começar com valores, pois tudo se constrói a partir daí. Valores são os dados usados ​​na computação. Dependendo da abordagem, são os valores com os quais todos estão familiarizados: 42, 3,14, "Como agora vaca marrom", o registro de pessoal de Jenny na Contabilidade, etc.

Outras interpretações de valores são símbolos . A maioria dos programadores entende esses símbolos como os "valores" de uma enumeração. Lefte Rightsão símbolos para o enum Handedness(ignorando pessoas ambidestras e peixes).

Independentemente da implementação, os valores são as diferentes coisas com as quais a linguagem trabalha para realizar cálculos.

Tipos

O problema com os valores é que nem todos os cálculos são válidos para todos os valores. 42 + goatrealmente não faz sentido.

É aqui que os tipos entram em cena. Tipos são metadados que definem subconjuntos de valores. O Handednessenum acima é um bom exemplo. Este tipo diz "somente Lefte Rightpode ser usado aqui". Isso permite que os programas determinem muito cedo que determinadas operações resultarão em erro.

Outro uso prático a considerar é que, sob o capô, os computadores trabalham com bytes. O byte 42 pode significar o número 42, ou o caractere *, ou Jenny, da Contabilidade. Os tipos também (em uso prático, não muito teórico) ajudam a definir a codificação para a coleção subjacente de bytes usados ​​pelos computadores.

Tipos

E é aqui que começamos a sair um pouco por aí. Portanto, quando uma linguagem de programação possui uma variável que se refere a um tipo, que tipo ela possui?

Em Java e C #, por exemplo, ele tem o tipo Type(que tem o tipo Type, que possui ... e assim por diante). Este é o conceito por trás dos tipos . Em algumas linguagens, você pode fazer coisas um pouco mais úteis com uma variável Type do que Java e C #. Quando isso acontece, torna-se útil dizer "Quero um valor que é um Tipo, mas também é algum tipo de IEnumerable<int>". Ta-da! Tipos.

A maioria dos programadores pode pensar em tipos como restrições genéricas de Java e C #. Considere public class Foo<T> where T: IComparable{}. Em uma linguagem com tipos, a T: kindOf(IComparable)declaração da variável se torna legal; não apenas uma coisa especial que você pode fazer nas declarações de classe e função.

Tipo Construtores

Talvez sem surpresa, os construtores de tipos são simplesmente construtores de tipos . "Mas como você constrói um tipo? Os tipos simplesmente são ." Eh ... nem tanto.

Também sem surpresa, é muito difícil criar todos os diferentes subconjuntos úteis de valores que qualquer programa de computador jamais utilizará. Os construtores de tipos trabalham para ajudar os programadores a "construir" esses subconjuntos de maneiras significativas.

O exemplo mais ubíquos de um construtor de tipo é uma definição de matriz: int[4]. Aqui você está especificando 4o tipo de construtor, que usa o valor para criar uma matriz de ints com 4 entradas. Se você especificou um tipo de entrada diferente, obteria um tipo de saída diferente.

Os genéricos são outra forma de construtor de tipos, tendo outro tipo como entrada.

Em muitos idiomas, existe um construtor P -> Rde tipos que cria um tipo que representa uma função que aceita Pe retorna o tipo R.

Agora, o contexto determinará se uma "função que retorna um tipo" é um construtor de tipos ou não. Na minha experiência (reconhecidamente limitada), a linha é "você pode usar esse tipo em tempo de compilação?". Sim? Digite construtor. Não? Apenas uma função.

Parâmetro de tipo

Então você se lembra dos parâmetros passados ​​para os Construtores de Tipo? Eles são comumente conhecidos como Parâmetros de Tipo, pois a forma comum de um Construtor de Tipo é Type[param]ou Type<param>.


1
Você poderia esclarecer / estender a seção sobre 'Tipos'? Em Haskell, um tipo possui tipo *, enquanto um construtor de tipo (com um argumento) possui tipo * -> *. Restrições como (Num a) => a(significando "qualquer tipo aque seja uma instância da Numclasse") não são elas próprias. A classe de Numtipo não é um 'tipo' em si, mas tem o tipo * -> Constraint. Acho difícil relacionar a idéia de Haskell de um 'tipo' (que eu assumo está intimamente relacionada a tipos na teoria dos tipos?) Com os exemplos que você fornece.
9788 John Mayholomew

Devo dizer que o :kindcomando de ghci fornece o tipo de Numcomo * -> Constraint. Isso pode ser específico para o GHC, eu não sei.
John Bartholomew

@JohnBartholomew - Os tipos Haskell são mais "assinaturas para construtores de tipos". Infelizmente, meu Haskell não chega nem ao ponto de me sentir confortável falando demais sobre os detalhes.
Telastyn 10/09/14
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.