suma que propiedades propiedad para niños neutro elemento ejemplos conmutativa asociativa haskell functional-programming agda dependent-type

haskell - que - Comprobación de tipos de Agda y conmutatividad/asociatividad de+



que es conmutativa asociativa y elemento neutro (1)

Dado que la Operación _+_ para Nat generalmente se define recursivamente en el primer argumento, es obvio que no es trivial para que el verificador de tipos sepa que i + 0 == i . Sin embargo, con frecuencia me encuentro con este problema cuando escribo funciones en vectores de tamaño fijo.

Un ejemplo: ¿Cómo puedo definir una función Agda?

swap : {A : Set}{m n : Nat} -> Vec A (n + m) -> Vec A (m + n)

¿Qué pone los primeros n valores al final del vector?

Dado que una solución simple en Haskell sería

swap 0 xs = xs swap n (x:xs) = swap (n-1) (xs ++ [x])

Lo intenté análogamente en Agda así:

swap : {A : Set}{m n : Nat} -> Vec A (n + m) -> Vec A (m + n) swap {_} {_} {zero} xs = xs swap {_} {_} {suc i} (x :: xs) = swap {_} {_} {i} (xs ++ (x :: []))

Pero el verificador de tipo falla con el mensaje (que se relaciona con el caso {zero} en el swap anterior -Definición):

.m != .m + zero of type Nat when checking that the expression xs has type Vec .A (.m + zero)

Entonces, mi pregunta: ¿Cómo enseñar a Agda, que m == m + zero ? ¿Y cómo escribir una función de swap en Agda?


Enseñar a Agda que m == m + zero no es demasiado difícil. Por ejemplo, utilizando el tipo estándar para pruebas de igualdad, podemos escribir esta prueba:

rightIdentity : (n : Nat) -> n + 0 == n rightIdentity zero = refl rightIdentity (suc n) = cong suc (rightIdentity n)

Luego podemos decirle a Agda que use esta prueba usando la palabra clave rewrite :

swap : {A : Set} {m n : Nat} -> Vec A (n + m) -> Vec A (m + n) swap {_} {m} {zero} xs rewrite rightIdentity m = xs swap {_} {_} {suc i} (x :: xs) = ?

Sin embargo, proporcionar las pruebas necesarias para la segunda ecuación es mucho más difícil. En general, es una idea mucho mejor intentar que la estructura de sus cálculos coincida con la estructura de sus tipos . De esa manera, puede salirse con mucha menos prueba de teoremas (o ninguna en este caso).

Por ejemplo, asumiendo que tenemos

drop : {A : Set} {m : Nat} -> (n : Nat) -> Vec A (n + m) -> Vec A m take : {A : Set} {m : Nat} -> (n : Nat) -> Vec A (n + m) -> Vec A n

(Ambos se pueden definir sin ninguna prueba de teorema), Agda aceptará felizmente esta definición sin ningún problema:

swap : {A : Set} {m n : Nat} -> Vec A (n + m) -> Vec A (m + n) swap {_} {_} {n} xs = drop n xs ++ take n xs