De esta referencia: positividad estricta
La condición de positividad estricta descarta declaraciones como
data Bad : Set where
bad : (Bad → Bad) → Bad
A B C
-- A is in a negative position, B and C are OK
¿Por qué A es negativo? ¿También por qué B está permitido? Entiendo por qué C está permitido.
type-theory
inductive-datatypes
Pushpa
fuente
fuente
A
y explotar la pila eventualmente (en lenguajes basados en pila).Respuestas:
Primero una explicación terminológica: las posiciones negativas y positivas provienen de la lógica. Son alrededor de una asimetría en conectores lógicos: en al A se comporta de manera diferente de B . Algo similar sucede en la teoría de categorías, donde decimos contravariante y covariante en lugar de negativo y positivo, respectivamente. En física, hablan de cantidades que se comportan "covariablemente" y "contrariamente, también. Así que este es un fenómeno muy general. Un programador podría pensar en ellas como" entrada "y" salida ".A ⇒ B UN si
Ahora en tipos de datos inductivos.
Piensa en un tipo de datos inductiva como una especie de estructura algebraica: constructores son las operaciones que tienen elementos de T como argumentos y producen nuevos elementos de T . Esto es muy similar al álgebra ordinaria: la suma toma dos números y produce un número.T T T
En álgebra, es costumbre que una operación tome un número finito de argumentos, y en la mayoría de los casos toma cero (constante), uno (unario) o dos (binarios) argumentos. Es conveniente generalizar esto para constructores de tipos de datos. Supongamos que
c
es un constructor para un tipo de datosT
:c
es una constante, podemos pensar en ella como una funciónunit -> T
, o de manera equivalente(empty -> T) -> T
,c
es unario, podemos considerarlo como una funciónT -> T
, o de manera equivalente(unit -> T) -> T
,c
es binario, podemos considerarlo como una funciónT -> T -> T
, o de manera equivalenteT * T -> T
o equivalente(bool -> T) -> T
,c
que tomara siete argumentos, podríamos verlo como una función(seven -> T) -> T
dondeseven
hay algún tipo previamente definido con siete elementos.c
que tome innumerables argumentos, que sería una función(nat -> T) -> T
.Estos ejemplos muestran que la forma general de un constructor debe ser
donde llamamos a
A
la aridad dec
y pensamos quec
es un constructor que tomaA
-muchos argumentos de tipoT
para producir un elemento deT
.Aquí hay algo muy importante: las aridades deben definirse antes de que las definamos
T
, o de lo contrario no podemos saber qué deben hacer los constructores. Si alguien intenta tener un constructorentonces la pregunta "¿cuántos argumentos
broken
lleva?" No tiene una buena respuesta. Puede intentar responderlo con "se necesitanT
muchos argumentos", pero eso no servirá, porqueT
aún no está definido. Podríamos tratar de salir del cunundrum usando una teoría elegante de punto fijo para encontrar un tipoT
y una función inyectiva(T -> T) -> T
, y tendríamos éxito, pero también romperíamos el principio de inducción enT
el camino. Entonces, es una mala idea intentar tal cosa.c
B
De hecho, muchos constructores se pueden reescribir de esta forma, pero no todos, necesitamos un paso más, es decir, debemos permitir
A
que dependerá deB
:Esta es la forma final de un constructor para un tipo inductivo. También es precisamente lo que son los tipos W. ¡La forma es tan general que solo necesitamos un solo constructor
c
! De hecho, si tenemos dos de ellosentonces podemos combinarlos en uno
dónde
Por cierto, si cambiamos la forma general, vemos que es equivalente a
que está más cerca de lo que la gente realmente escribe en asistentes de prueba. Los asistentes de prueba nos permiten escribir los constructores de manera conveniente, pero son equivalentes a la forma general anterior (¡ejercicio!).
fuente
La primera aparición de
Bad
se llama 'negativa' porque representa un argumento de función, es decir, se encuentra a la izquierda de la flecha de función (vea Philip Wadler los tipos recursivos de forma gratuita ). Supongo que el origen del término 'posición negativa' proviene de la noción de contravarianza ('contra' significa opuesto).No se permite que el tipo se defina en posición negativa porque uno puede escribir programas sin terminación usándolo, es decir, una fuerte normalización falla en su presencia (más sobre esto a continuación). Por cierto, esta es la razón del nombre de la regla 'positividad estricta': no permitimos posiciones negativas.
Permitimos la segunda aparición de,
Bad
ya que no causa la no terminación y queremos usar el tipo que se define (Bad
) en algún momento en un tipo de datos recursivo ( antes de la última flecha de su constructor).Es importante comprender que la siguiente definición no viola la estricta regla de positividad.
La regla se aplica solo a los argumentos del constructor (que son ambos
Good
en este caso) y no a un constructor en sí mismo (véase también " Programación certificada con tipos dependientes " de Adam Chlipala ).Otro ejemplo que viola la positividad estricta:
También es posible que desee verificar esta respuesta sobre las posiciones negativas.
Más información sobre la no terminación ... La página a la que hizo referencia contiene algunas explicaciones (junto con un ejemplo en Haskell):
Aquí hay un ejemplo análogo en Ocaml, que muestra cómo implementar un comportamiento recursivo sin (!) Usando la recursión directamente:
La
nonTerminating
función "desempaqueta" una función de su argumento y la transfiere al argumento original. Lo importante aquí es que la mayoría de los sistemas de tipos no permiten pasar funciones a sí mismos, por lo que un término comof f
no mecanografiará, ya que no hay ningún tipo paraf
satisfacer el mecanografiado. Una de las razones por las que se introdujeron los sistemas de tipos es para deshabilitar la auto aplicación (ver aquí ).Los tipos de datos de envoltura como el que presentamos anteriormente se pueden usar para sortear este obstáculo en el camino hacia la inconsistencia.
Quiero agregar que los cálculos sin terminación introducen inconsistencias en los sistemas lógicos. En el caso de Agda y Coq, el
False
tipo de datos inductivo no tiene ningún constructor, por lo que nunca se puede construir un término de prueba de tipo False. Pero si se permitieran los cálculos sin terminación, uno podría hacerlo, por ejemplo, de esta manera (en Coq):Luego
loop 0
escribiría chequesloop 0 : False
, por lo que, según la correspondencia de Curry-Howard, significaría que probamos una proposición falsa.Resultado : la estricta regla de positividad para las definiciones inductivas evita los cálculos sin terminación que son desastrosos para la lógica.
fuente