Terminología correcta en la teoría de tipos: tipos, constructores de tipos, tipos / clases y valores.


14

En una respuesta a una pregunta anterior , se inició un pequeño debate sobre la terminología correcta para ciertas construcciones. Como no encontré una pregunta (aparte de esto o aquello , que no es lo correcto) para abordar esto claramente, estoy haciendo esta nueva.

Los términos cuestionables y sus relaciones son: tipo, constructor de tipo, parámetro de tipo, tipos o clases, y valores .

También revisé Wikipedia para la teoría de tipos, pero eso tampoco lo aclaró mucho.

Entonces, en aras de tener una buena respuesta de referencia y verificar mi propio entendimiento:

  • ¿Cómo se definen estas cosas correctamente?
  • ¿Cuál es la diferencia entre cada una de estas cosas?
  • ¿Cómo es que están relacionados?

Respuestas:


13

Muy bien, vamos uno por uno.

Valores

Los valores son los datos concretos que los programas evalúan y hacen malabares. Nada de lujos, algunos ejemplos podrían ser

  • 1
  • true
  • "fizz buzz foo bar"

Tipos

Una buena descripción para un tipo es "un clasificador para un valor". Un tipo es un poco de información sobre cuál será ese valor en tiempo de ejecución, pero indicado en tiempo de compilación.

Por ejemplo, si me dices eso e : boolen tiempo de compilación, y sabré que ees trueo falsedurante el tiempo de ejecución, ¡nada más! Debido a que los tipos clasifican valores muy bien como este, podemos usar esta información para determinar algunas propiedades básicas de su programa.

Por ejemplo, si alguna vez te veo agregando ey e'cuándo e : inty e' : String, entonces sé que algo está un poco mal. De hecho, puedo marcar esto y arrojar un error en el momento de la compilación, diciendo "¡Hey, eso no tiene ningún sentido!".

Un sistema de tipos más potente permite tipos más interesantes que clasifican valores más interesantes. Por ejemplo, consideremos alguna función

f = fun x -> x

Está bastante claro eso f : Something -> Something, pero ¿qué debería Somethingser? En un sistema de tipo aburrido, tendríamos que especificar algo arbitrario, como Something = int. En un sistema de tipos más flexible, podríamos decir

f : forall a. a -> a

Es decir "para cualquiera a, fasigna un an aa un a". Esto nos permite usar de manera fmás general y escribir programas más interesantes.

Además, el compilador comprobará si realmente satisface el clasificador que le hemos dado, si f = fun x -> truetenemos un error y el compilador lo dirá.

Entonces como tldr; un tipo es una restricción de tiempo de compilación en los valores que una expresión puede ser en tiempo de ejecución.

Constructor de tipos

Algunos tipos están relacionados. Por ejemplo, una lista de enteros es muy similar a una lista de cadenas. Esto es casi como sortpara los enteros es casi como sortpara las cadenas. Podemos imaginar una especie de fábrica que construya estos tipos casi iguales generalizando sobre sus diferencias y construyéndolas a pedido. Eso es un constructor de tipo. Es como una función de tipos a tipos, pero un poco más limitada.

El ejemplo clásico es una lista genérica. Un constructor de tipos para es solo la definición genérica

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

¡Ahora Listes una función que asigna un tipo aa una lista de valores de ese tipo! En Java-land creo que a estas quizás se les llame "clases genéricas"

Parámetros de tipo

Un parámetro de tipo es solo el tipo pasado a un constructor de tipo (o función). Al igual que en el nivel de valor, diríamos que foo(a)tiene un parámetro aigual que cómo List atiene un parámetro de tipo a.

Tipos

Los tipos son un poco complicados. La idea básica es que ciertos tipos son similares. Por ejemplo, tenemos todos los tipos primitivos de Java int, char, float..., que todos se comportan como si tuvieran el mismo "tipo". Excepto, cuando hablamos de los clasificadores para los tipos en sí, llamamos a los clasificadores tipos. Así int : Prim, String : Box, List : Boxed -> Boxed.

Este sistema proporciona buenas reglas concretas sobre qué tipo de tipos podemos usar dónde, al igual que cómo los tipos gobiernan los valores. Claramente sería una tontería decir

 List<List>

o

 List<int>

¡En Java ya Listque debe aplicarse a un tipo concreto para usarse así! Si miramos sus tipos List : Boxed -> Boxedy desde entonces Boxed -> Boxed /= Boxed, ¡lo anterior es un error amable!

La mayoría de las veces no pensamos realmente en los tipos y simplemente los tratamos como "sentido común", pero con los sistemas de tipos más sofisticados es algo importante en lo que pensar.

Una pequeña ilustración de lo que he estado diciendo hasta ahora

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

Mejor lectura que Wikipedia

Si está interesado en este tipo de cosas, le recomiendo invertir un buen libro de texto. La teoría de tipos y PLT en general es bastante amplia y sin una base coherente de conocimiento, usted (o al menos yo) puede deambular sin llegar a ningún lado durante meses.

Dos de mis libros favoritos son

  • Tipos y lenguaje de programación - Ben Pierce
  • Fundamentos prácticos de los lenguajes de programación - Bob Harper

Ambos son excelentes libros que presentan lo que acabo de hablar y mucho más con detalles hermosos y bien explicados.


1
Los tipos son conjuntos? Me gusta más el "clasificador", pero no explicas lo que esto significa, y sin una buena comprensión de qué es un tipo, el resto de tu respuesta se cae.
Robert Harvey

@RobertHarvey ¿Cómo se ve ahora? He eliminado todas las menciones de los sets :)
Daniel Gratzer

1
Mucho mejor ...
Robert Harvey

@RobertHarvey Creo que la vista de tipos como conjuntos es muy intuitiva. Por ejemplo, el tipo inten Java consiste en un conjunto de 2 ^ 64 valores distintos. La analogía con los conjuntos se rompe cuando los subtipos se involucran, pero es una intuición inicial lo suficientemente buena, especialmente una vez que considera los tipos de datos algebraicos (por ejemplo, una unión de dos tipos puede contener cualquiera de los miembros de cualquier tipo; es la unión de esos conjuntos) .
Doval

@Doval: Si escribo una clase que describe a un Cliente, probablemente representará un "conjunto" de clientes, ya que voy a hacer una colección de instancias. Pero decir que un cliente es un tipo porque describe un "conjunto" de clientes es una tautología; Parece obvio. Lo que es más interesante es que un tipo de Cliente describe las características de un cliente. Usar "set" para explicar esto parece más ... abstracto de lo que realmente es. A menos que, tal vez, seas un matemático.
Robert Harvey

2

¿Cómo se definen estas cosas correctamente?

Están debidamente definidos por un respaldo matemático rígido y académico, que proporciona fuertes afirmaciones de lo que son, cómo funcionan y qué está garantizado.

Pero los programadores en gran medida no necesitan saber eso. Necesitan entender los conceptos.

Valores

Comencemos con los valores, ya que todo se construye a partir de ahí. Los valores son los datos utilizados en informática. Dependiendo del enfoque, son los valores con los que todos están familiarizados: 42, 3.14, "Cómo ahora la vaca marrón", el registro de personal para Jenny en Contabilidad, etc.

Otras interpretaciones de valores son símbolos . La mayoría de los programadores entienden que estos símbolos son los "valores" de una enumeración. Lefty Rightson símbolos para la enumeración Handedness(ignorando las personas y los peces ambidiestros).

Independientemente de la implementación, los valores son las diferentes cosas con las que trabaja el lenguaje para realizar los cálculos.

Tipos

El problema con los valores es que no todos los cálculos son legales para todos los valores. 42 + goatRealmente no tiene sentido.

Aquí es donde entran en juego los tipos. Los tipos son metadatos que definen subconjuntos de valores. La Handednessenumeración anterior es un buen ejemplo. Este tipo dice "solo Lefty Rightpuede usarse aquí". Esto permite a los programas determinar muy pronto que ciertas operaciones darán como resultado un error.

Otro uso práctico a considerar es que, bajo el capó, las computadoras trabajan con bytes. El byte 42 podría significar el número 42, o podría significar el carácter *, o podría significar Jenny de Contabilidad. Los tipos también (en uso práctico, no tanto teórico) ayudan a definir la codificación para la colección subyacente de bytes utilizados por las computadoras.

Tipos

Y aquí es donde empezamos a salir un poco. Por lo tanto, cuando un lenguaje de programación tiene una variable que hace referencia a un tipo, el tipo tiene que tener?

En Java y C #, por ejemplo, tiene el tipo Type(que tiene el tipo Type, que tiene ... y así sucesivamente). Este es el concepto detrás de los tipos . En algunos lenguajes, puede hacer cosas un poco más útiles con una variable Tipo que Java y C #. Una vez que eso sucede, se vuelve útil decir "Quiero un valor que sea un Tipo, pero que también sea algún tipo de IEnumerable<int>". Ta-da! Tipos.

La mayoría de los programadores pueden pensar en tipos como las restricciones genéricas de Java y C #. Considere public class Foo<T> where T: IComparable{}. En un lenguaje con tipos, la T: kindOf(IComparable)declaración variable se convierte en legal; no solo una cosa especial que puede hacer en las declaraciones de clase y función.

Constructores tipo

Quizás, como era de esperar, los constructores de tipos son simplemente constructores de tipos . "¿Pero cómo se construye un tipo? Los tipos simplemente son ". Eh ... no tanto.

También, como era de esperar, es bastante difícil construir todos los diferentes subconjuntos de valores útiles que cualquier programa de computadora usará. Los constructores de tipos trabajan para ayudar a los programadores a "construir" esos subconjuntos de manera significativa.

El ejemplo más ubicua de un constructor tipo es una definición de matriz: int[4]. Aquí está especificando 4el constructor de tipos, que utiliza el valor para crear una matriz de ints con 4 entradas. Si especificó un tipo de entrada diferente, obtendría un tipo de salida diferente.

Los genéricos son otra forma de constructor de tipos, tomando otro tipo como su entrada.

En muchos idiomas hay un constructor de tipos como P -> Rconstruir un tipo que representa una función que toma tipo Py devuelve tipo R.

Ahora, el contexto determinará si una "función que devuelve un tipo" es un constructor de tipo o no. En mi experiencia (ciertamente limitada), la línea es "¿puedes usar este tipo en tiempo de compilación?". ¿Si? Constructor de tipos. ¿No? Solo una función.

Parámetro de tipo

¿Entonces recuerdas los parámetros pasados ​​a Type Constructors? Son comúnmente conocidos como parámetros de tipo, ya que la forma común de un constructor de tipo es Type[param]o Type<param>.


1
¿Podría aclarar / ampliar la sección sobre 'Tipos'? En Haskell, un tipo tiene kind *, mientras que un constructor de tipos (con un argumento) tiene kind * -> *. Las restricciones como (Num a) => a(que significa "cualquier tipo aque sea una instancia de la Numclase de tipos") no son tipos en sí mismas. La clase de tipos Numno es un "tipo" en sí, sino que tiene el tipo * -> Constraint. Me resulta difícil relacionar la idea de Haskell de un 'tipo' (que supongo que está estrechamente relacionada con los tipos en la teoría de tipos) con los ejemplos que da.
John Bartholomew

Debo decir que el :kindcomando de ghci da el tipo de Numas * -> Constraint. Eso podría ser específico para GHC, no lo sé.
John Bartholomew

@JohnBartholomew - Los tipos de Haskell son más "firmas para constructores de tipos". Desafortunadamente, mi Haskell no está tan cerca del punto en que me sentiría cómodo hablando demasiado sobre los detalles.
Telastyn
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.