¿Cómo puedo utilizar la función “cong” e “injective” con vectores indexados en Idris?
cong
y injective
te permiten aplicar y deshacer funciones en igualdades:
cong : (f : a -> b) -> x = y -> f x = f y
injective : Injective f => f x = f y -> x = y
Ambas fallan para vectores indexados de diferentes longitudes, por razones obvias.
¿Cómo puedo demostrar que dos vectores iguales tienen la misma longitud? Es decir,
sameLen : {xs : Vect n a} -> {ys : Vect m b} -> xs = ys -> n = m
No puedo simplemente hacer
sameLen pf = cong length pf
porque length
en xs
tiene tipo Vect n a -> Nat
y length
en ys
tiene tipo Vect m b -> Nat
. (De hecho, ni siquiera estoy seguro de cómo probar lo mismo para dos List
regulares, debido a los argumentos de tipo diferentes, mucho menos con los índices adicionales).
Yendo en la dirección opuesta, ¿cómo podría probar algo como
data Rose a = V a | T (Vect n (Rose a))
Injective T where
injective Refl = Refl
unwrap : {xs : Vect n (Rose a)} -> {ys : Vect m (Rose b)} -> T xs = T ys -> xs = ys
Nuevamente, no puedo simplemente hacer
unwrap pf = injective pf
debido a los tipos diferentes de T
(uno con m y otro con n). Y incluso si tuviera una prueba de m = n
, ¿cómo podría usarla para convencer a Idris de que las dos aplicaciones de T
son iguales?
davy.ai
Para demostrar que dos vectores iguales tienen la misma longitud, podemos usar una combinación de
cong
yrewrite
. Primero definimos una funciónlenEq: {n: Nat} -> {m: Nat} -> Vect n a -> Vect m b -> (n = m) -> Type
que toma dos vectores y una prueba de que tienen la misma longitud, y devuelve un tipo. Este tipo estará habitado si y solo si los vectores tienen la misma longitud. Podemos definirlenEq
de la siguiente manera:El bloque
where
calcula las longitudes de los vectoresxs
eys
y verifica si son iguales. Si lo son, entonces se devuelveVect n (xs = ys)
, donde=
es una igualdad a nivel de tipo. De lo contrario, se devuelveVoid
, lo que indica que los dos vectores tienen longitudes diferentes y no pueden ser iguales.Ahora podemos definir
sameLen
en términos delenEq
:Aquí aplicamos
cong length
apf
, lo que nos da una prueba de que las longitudes dexs
eys
son iguales. Luego podemos usarrewrite
para reemplazar el tipon = length xs
conm = length ys
, utilizandolenEq xs ys (cong length pf)
como la prueba de que estos tipos son iguales. Finalmente, se devuelveRefl
como una prueba de quen
ym
son iguales.Para demostrar
unwrap
, podemos usar el mismo enfoque. Primero definimos una funciónroseEq: {n: Nat} -> {m: Nat} -> Vect n (Rose a) -> Vect m (Rose b) -> (n = m) -> Type
que toma dos vectores deRose
y una prueba de que tienen la misma longitud, y devuelve un tipo que indica si los vectores son iguales. Podemos definirroseEq
de la siguiente manera:Ahora podemos definir
unwrap
en términos deroseEq
:Aquí primero usamos
cong Vect.toList
para obtener una prueba de quexs
eys
tienen la misma longitud. Luego usamossameLen
para demostrar que las longitudes son iguales. Podemos usarfromList
para convertirxs
eys
en vectores de la misma longitud, y luego usarlenEq
para demostrar que son iguales. Aplicamoscong T
a esta prueba para obtener una prueba de queT xs' = T ys'
, y finalmente usamosinjective
para demostrar quexs' = ys'
. Esto nos da una prueba de quexs
eys
son iguales.