Acciones

Diferencia entre revisiones de «Razonamiento sobre programas en Isabelle/HOL»

De Lógica matemática y fundamentos (2018-19)

Línea 1: Línea 1:
 
<source lang="isabelle">
 
<source lang="isabelle">
chapter {* Tema 6: Razonamiento sobre programas *}
+
chapter ‹Tema 6: Razonamiento sobre programas›
  
 
theory T6_Razonamiento_sobre_programas
 
theory T6_Razonamiento_sobre_programas
Línea 6: Línea 6:
 
begin
 
begin
  
text {*
+
text ‹En este tema se demuestra con Isabelle las propiedades de los
  En este tema se demuestra con Isabelle las propiedades de los
 
 
   programas funcionales de tema 6 http://bit.ly/2Za6YWY
 
   programas funcionales de tema 6 http://bit.ly/2Za6YWY
  
 
   Para cada propiedades se presentan distintos tipos de demostraciones:
 
   Para cada propiedades se presentan distintos tipos de demostraciones:
   automáticas, aplicativas y declarativas. *}
+
   automáticas, aplicativas y declarativas.
  
declare [[names_short]]
+
(* declare [[names_short]] *)
  
section {* Razonamiento ecuacional *}
+
section ‹Razonamiento ecuacional›
  
text {* ----------------------------------------------------------------
+
text ‹-----------------------------------------------------------------
 
   Ejemplo 1. Definir, por recursión, la función
 
   Ejemplo 1. Definir, por recursión, la función
 
     longitud :: 'a list ⇒ nat
 
     longitud :: 'a list ⇒ nat
 
   tal que (longitud xs) es la longitud de la listas xs. Por ejemplo,
 
   tal que (longitud xs) es la longitud de la listas xs. Por ejemplo,
 
     longitud [a,c,d] = 3
 
     longitud [a,c,d] = 3
   ------------------------------------------------------------------- *}
+
   --------------------------------------------------------------------›
  
 
fun longitud :: "'a list ⇒ nat" where
 
fun longitud :: "'a list ⇒ nat" where
Línea 30: Línea 29:
 
value "longitud [a,c,d] = 3"
 
value "longitud [a,c,d] = 3"
  
text {* ---------------------------------------------------------------  
+
text ---------------------------------------------------------------  
 
   Ejemplo 2. Demostrar que  
 
   Ejemplo 2. Demostrar que  
 
     longitud [a,c,d] = 3
 
     longitud [a,c,d] = 3
   ------------------------------------------------------------------- *}
+
   -------------------------------------------------------------------
  
 
lemma "longitud [a,c,d] = 3"
 
lemma "longitud [a,c,d] = 3"
Línea 42: Línea 41:
 
   by simp
 
   by simp
  
text {* ---------------------------------------------------------------  
+
text ---------------------------------------------------------------  
 
   Ejemplo 3. Definir la función
 
   Ejemplo 3. Definir la función
 
     fun intercambia :: 'a × 'b ⇒ 'b × 'a
 
     fun intercambia :: 'a × 'b ⇒ 'b × 'a
Línea 48: Línea 47:
 
   componentes del par p. Por ejemplo,
 
   componentes del par p. Por ejemplo,
 
     intercambia (u,v) = (v,u)
 
     intercambia (u,v) = (v,u)
   ------------------------------------------------------------------ *}
+
   ------------------------------------------------------------------
  
 
fun intercambia :: "'a × 'b ⇒ 'b × 'a" where
 
fun intercambia :: "'a × 'b ⇒ 'b × 'a" where
Línea 55: Línea 54:
 
value "intercambia (u,v) = (v,u)"
 
value "intercambia (u,v) = (v,u)"
  
text {*
+
text ‹La definición de la función intercambia genera una regla de
  La definición de la función intercambia genera una regla de
 
 
   simplificación
 
   simplificación
 
   · intercambia.simps: intercambia (x,y) = (y,x)
 
   · intercambia.simps: intercambia (x,y) = (y,x)
Línea 62: Línea 60:
 
   Se puede ver con  
 
   Se puede ver con  
 
   · thm intercambia.simps  
 
   · thm intercambia.simps  
*}
+
  
 
thm intercambia.simps
 
thm intercambia.simps
 
(* da intercambia (?x, ?y) = (?y, ?x) *)
 
(* da intercambia (?x, ?y) = (?y, ?x) *)
  
text {* ---------------------------------------------------------------  
+
text ---------------------------------------------------------------  
 
   Ejemplo 4. (p.6) Demostrar que  
 
   Ejemplo 4. (p.6) Demostrar que  
 
     intercambia (intercambia (x,y)) = (x,y)
 
     intercambia (intercambia (x,y)) = (x,y)
   ------------------------------------------------------------------- *}
+
   -------------------------------------------------------------------
  
 
(* Demostración automática *)
 
(* Demostración automática *)
Línea 92: Línea 90:
 
lemma "intercambia (intercambia (x,y)) = (x,y)"
 
lemma "intercambia (intercambia (x,y)) = (x,y)"
 
proof -
 
proof -
   have "intercambia (intercambia (x,y)) = intercambia (y,x)"  by simp
+
   have "intercambia (intercambia (x,y)) = intercambia (y,x)"   
   also have "... = (x,y)" by simp  
+
    by simp
   finally show "intercambia (intercambia (x,y)) = (x,y)" by simp
+
   also have "= (x,y)"  
 +
    by simp  
 +
   finally show "intercambia (intercambia (x,y)) = (x,y)"  
 +
    by simp
 
qed
 
qed
  
(* Demostración declarativa 2 *)
+
(* Demostración detallada *)
 
lemma "intercambia (intercambia (x,y)) = (x,y)"
 
lemma "intercambia (intercambia (x,y)) = (x,y)"
 
proof -
 
proof -
 
   have "intercambia (intercambia (x,y)) = intercambia (y,x)"   
 
   have "intercambia (intercambia (x,y)) = intercambia (y,x)"   
 
     by (simp only: intercambia.simps)
 
     by (simp only: intercambia.simps)
   also have "... = (x,y)"  
+
   also have "= (x,y)"  
 
     by (simp only: intercambia.simps)
 
     by (simp only: intercambia.simps)
 
   finally show "intercambia (intercambia (x,y)) = (x,y)"  
 
   finally show "intercambia (intercambia (x,y)) = (x,y)"  
Línea 108: Línea 109:
 
qed
 
qed
  
text {*
+
text ‹Notas sobre el lenguaje: En la demostración anterior se ha usado
  Notas sobre el lenguaje: En la demostración anterior se ha usado
 
 
   · "proof" para iniciar la prueba,
 
   · "proof" para iniciar la prueba,
 
   · "-" (después de "proof") para no usar el método por defecto,
 
   · "-" (después de "proof") para no usar el método por defecto,
Línea 117: Línea 117:
 
     intercambia,
 
     intercambia,
 
   · "also" para encadenar pasos ecuacionales,
 
   · "also" para encadenar pasos ecuacionales,
   · "..." para representar la derecha de la igualdad anterior en un
+
   · "" para representar la derecha de la igualdad anterior en un
 
     razonamiento ecuacional,
 
     razonamiento ecuacional,
 
   · "finally" para indicar el último pasa de un razonamiento ecuacional,
 
   · "finally" para indicar el último pasa de un razonamiento ecuacional,
 
   · "show" para establecer la conclusión.
 
   · "show" para establecer la conclusión.
 
   · "by simp" para indicar el método de demostración por simplificación y  
 
   · "by simp" para indicar el método de demostración por simplificación y  
   · "qed" para terminar la pruebas,
+
   · "qed" para terminar la pruebas.›
*}
 
  
text {*
+
text ---------------------------------------------------------------  
  Nota: La diferencia entre las dos demostraciones es que en los dos
 
  primeros pasos no se explicita la regla de simplificación.
 
*}
 
 
 
text {* ---------------------------------------------------------------  
 
 
   Ejemplo 5. Definir, por recursión, la función
 
   Ejemplo 5. Definir, por recursión, la función
 
     inversa :: 'a list ⇒ 'a list
 
     inversa :: 'a list ⇒ 'a list
Línea 136: Línea 130:
 
   elementos de xs. Por ejemplo,
 
   elementos de xs. Por ejemplo,
 
     inversa [a,d,c] = [c,d,a]
 
     inversa [a,d,c] = [c,d,a]
   ------------------------------------------------------------------ *}
+
   ------------------------------------------------------------------
  
 
fun inversa :: "'a list ⇒ 'a list" where
 
fun inversa :: "'a list ⇒ 'a list" where
Línea 144: Línea 138:
 
value "inversa [a,d,c] = [c,d,a]"
 
value "inversa [a,d,c] = [c,d,a]"
  
text {* ---------------------------------------------------------------  
+
text ---------------------------------------------------------------  
 
   Ejemplo 6. (p. 9) Demostrar que  
 
   Ejemplo 6. (p. 9) Demostrar que  
 
     inversa [x] = [x]
 
     inversa [x] = [x]
   ------------------------------------------------------------------- *}
+
   -------------------------------------------------------------------
  
 
(* La demostración automática es *)
 
(* La demostración automática es *)
Línea 158: Línea 152:
 
   done
 
   done
  
text {*
+
text ‹En la demostración anterior se usaron las siguientes reglas:
  En la demostración anterior se usaron las siguientes reglas:
 
 
   · inversa.simps(1): inversa [] = []
 
   · inversa.simps(1): inversa [] = []
 
   · inversa.simps(2): inversa (x#xs) = inversa xs @ [x]
 
   · inversa.simps(2): inversa (x#xs) = inversa xs @ [x]
 
   · append_Nil:      [] @ ys = ys
 
   · append_Nil:      [] @ ys = ys
 
   Vamos a explicitar su aplicación.
 
   Vamos a explicitar su aplicación.
*}
+
 +
 
 +
find_theorems
 +
find_theorems "_ @ _ = _"
 +
find_theorems "[] @ _ = _"
  
 
(* La demostración aplicativa detallada es *)
 
(* La demostración aplicativa detallada es *)
Línea 173: Línea 170:
 
   done
 
   done
  
(* La demostración declarativa es *)
+
(* La demostración declarativa simplificada es *)
 
lemma "inversa [x] = [x]"
 
lemma "inversa [x] = [x]"
 
proof -
 
proof -
 
   have "inversa [x] = inversa (x#[])" by simp
 
   have "inversa [x] = inversa (x#[])" by simp
   also have "... = (inversa []) @ [x]" by (simp only: inversa.simps(2))
+
   also have "= (inversa []) @ [x]" by simp
   also have "... = [] @ [x]" by (simp only: inversa.simps(1))
+
   also have "= [] @ [x]" by simp
   also have "... = [x]" by (simp only: append_Nil)
+
   also have "= [x]" by simp  
 
   finally show "inversa [x] = [x]" by simp
 
   finally show "inversa [x] = [x]" by simp
 
qed
 
qed
  
(* La demostración declarativa simplificada es *)
+
(* La demostración declarativa detallada es *)
 
lemma "inversa [x] = [x]"
 
lemma "inversa [x] = [x]"
 
proof -
 
proof -
   have "inversa [x] = inversa (x#[])" by simp
+
   have "inversa [x] = inversa (x#[])"
   also have "... = (inversa []) @ [x]" by simp
+
    by simp
   also have "... = [] @ [x]" by simp
+
   also have "= (inversa []) @ [x]"  
   also have "... = [x]" by simp  
+
    by (simp only: inversa.simps(2))
 +
   also have "= [] @ [x]"  
 +
    by (simp only: inversa.simps(1))
 +
   also have "= [x]"  
 +
    by (simp only: append_Nil)
 
   finally show "inversa [x] = [x]" by simp
 
   finally show "inversa [x] = [x]" by simp
 
qed
 
qed
  
section {* Razonamiento por inducción sobre los naturales *}
+
section ‹Razonamiento por inducción sobre los naturales
  
text {*
+
text [Principio de inducción sobre los naturales] Para demostrar una
  [Principio de inducción sobre los naturales] Para demostrar una
 
 
   propiedad P para todos los números naturales basta probar que el 0
 
   propiedad P para todos los números naturales basta probar que el 0
 
   tiene la propiedad P y que si n tiene la propiedad P, entonces n+1
 
   tiene la propiedad P y que si n tiene la propiedad P, entonces n+1
Línea 205: Línea 205:
 
   formalizado en el teorema nat.induct y puede verse con
 
   formalizado en el teorema nat.induct y puede verse con
 
     thm nat.induct
 
     thm nat.induct
*}
+
 +
 
 +
thm nat.induct
  
text {* ---------------------------------------------------------------  
+
text ---------------------------------------------------------------  
 
   Ejemplo 7. Definir la función
 
   Ejemplo 7. Definir la función
 
     repite :: nat ⇒ 'a ⇒ 'a list
 
     repite :: nat ⇒ 'a ⇒ 'a list
Línea 213: Línea 215:
 
   x. Por ejemplo,  
 
   x. Por ejemplo,  
 
     repite 3 a = [a,a,a]
 
     repite 3 a = [a,a,a]
   ------------------------------------------------------------------ *}
+
   ------------------------------------------------------------------
  
 
fun repite :: "nat ⇒ 'a ⇒ 'a list" where
 
fun repite :: "nat ⇒ 'a ⇒ 'a list" where
Línea 221: Línea 223:
 
value "repite 3 a = [a,a,a]"
 
value "repite 3 a = [a,a,a]"
  
text {* ---------------------------------------------------------------  
+
text ---------------------------------------------------------------  
 
   Ejemplo 8. (p. 18) Demostrar que  
 
   Ejemplo 8. (p. 18) Demostrar que  
 
     longitud (repite n x) = n
 
     longitud (repite n x) = n
   ------------------------------------------------------------------- *}
+
   -------------------------------------------------------------------
  
 
(* La demostración aplicativa es *)
 
(* La demostración aplicativa es *)
Línea 251: Línea 253:
 
lemma "longitud (repite n x) = n"
 
lemma "longitud (repite n x) = n"
 
proof (induct n)
 
proof (induct n)
   show "longitud (repite 0 x) = 0" by simp
+
   show "longitud (repite 0 x) = 0"  
 +
    by simp
 
next  
 
next  
 
   fix n
 
   fix n
Línea 257: Línea 260:
 
   have "longitud (repite (Suc n) x) = longitud (x # (repite n x))"  
 
   have "longitud (repite (Suc n) x) = longitud (x # (repite n x))"  
 
     by simp
 
     by simp
   also have "... = 1 + longitud (repite n x)" by simp
+
   also have "= 1 + longitud (repite n x)"  
   also have "... = 1 + n" using HI by simp
+
    by simp
   finally show "longitud (repite (Suc n) x) = Suc n" by simp
+
   also have "= 1 + n"  
 +
    using HI by simp
 +
   finally show "longitud (repite (Suc n) x) = Suc n"  
 +
    by simp
 
qed
 
qed
  
text {*
+
text ‹Comentarios sobre la demostración anterior:
  Comentarios sobre la demostración anterior:
 
 
   · A la derecha de proof se indica el método de la demostración.
 
   · A la derecha de proof se indica el método de la demostración.
 
   · (induct n) indica que la demostración se hará por inducción en n.
 
   · (induct n) indica que la demostración se hará por inducción en n.
Línea 276: Línea 281:
 
   · assume HI: "longitud (repite n x) = n" indica «supongamos que  
 
   · assume HI: "longitud (repite n x) = n" indica «supongamos que  
 
     "longitud (repite n x) = n" y sea HI la etiqueta de este supuesto».
 
     "longitud (repite n x) = n" y sea HI la etiqueta de este supuesto».
   · "using HI" usando la propiedad etiquetada con HI.  
+
   · "using HI" usando la propiedad etiquetada con HI.
*}
+
 
 +
(* La demostración declarativa detallada es *)
 +
lemma "longitud (repite n x) = n"
 +
proof (induct n)
 +
  show "longitud (repite 0 x) = 0"
 +
    by (simp only: repite.simps(1)
 +
                  longitud.simps(1))
 +
next
 +
  fix n
 +
  assume HI: "longitud (repite n x) = n"
 +
  have "longitud (repite (Suc n) x) = longitud (x # (repite n x))"
 +
    by (simp only: repite.simps(2))
 +
  also have "… = 1 + longitud (repite n x)"
 +
    by (simp only: longitud.simps(2))
 +
  also have "… = 1 + n"
 +
    by (simp only: HI)
 +
  also have "… = Suc n"
 +
    find_theorems "Suc _ = _ + _"
 +
    by (simp only: Suc_eq_plus1_left)
 +
  finally show "longitud (repite (Suc n) x) = Suc n"
 +
    by this
 +
qed
  
section {* Razonamiento por inducción sobre listas *}
+
section ‹Razonamiento por inducción sobre listas
  
text {*
+
text ‹Para demostrar una propiedad para todas las listas basta demostrar
  Para demostrar una propiedad para todas las listas basta demostrar
 
 
   que la lista vacía tiene la propiedad y que al añadir un elemento a
 
   que la lista vacía tiene la propiedad y que al añadir un elemento a
 
   una lista que tiene la propiedad se obtiene otra lista que también
 
   una lista que tiene la propiedad se obtiene otra lista que también
Línea 292: Línea 317:
 
       ⋀x xs. P xs ⟹ P (x#xs)⟧  
 
       ⋀x xs. P xs ⟹ P (x#xs)⟧  
 
     ⟹ P xs
 
     ⟹ P xs
*}
+
 +
 
 +
thm list.induct
  
text {* ---------------------------------------------------------------  
+
text ---------------------------------------------------------------  
 
   Ejemplo 9. Definir la función
 
   Ejemplo 9. Definir la función
 
     conc :: 'a list ⇒ 'a list ⇒ 'a list
 
     conc :: 'a list ⇒ 'a list ⇒ 'a list
Línea 300: Línea 327:
 
   ejemplo,  
 
   ejemplo,  
 
     conc [a,d] [b,d,a,c] = [a,d,b,d,a,c]
 
     conc [a,d] [b,d,a,c] = [a,d,b,d,a,c]
   ------------------------------------------------------------------ *}
+
   ------------------------------------------------------------------
  
 
fun conc :: "'a list ⇒ 'a list ⇒ 'a list" where
 
fun conc :: "'a list ⇒ 'a list ⇒ 'a list" where
Línea 308: Línea 335:
 
value "conc [a,d] [b,d,a,c] = [a,d,b,d,a,c]"
 
value "conc [a,d] [b,d,a,c] = [a,d,b,d,a,c]"
  
text {* ---------------------------------------------------------------  
+
text ---------------------------------------------------------------  
 
   Ejemplo 10. (p. 24) Demostrar que  
 
   Ejemplo 10. (p. 24) Demostrar que  
 
     conc xs (conc ys zs) = (conc xs ys) zs
 
     conc xs (conc ys zs) = (conc xs ys) zs
   ------------------------------------------------------------------- *}
+
   -------------------------------------------------------------------
  
 
(* La demostración aplicativa es *)
 
(* La demostración aplicativa es *)
Línea 331: Línea 358:
 
lemma "conc xs (conc ys zs) = conc (conc xs ys) zs"
 
lemma "conc xs (conc ys zs) = conc (conc xs ys) zs"
 
proof (induct xs)
 
proof (induct xs)
   show "conc [] (conc ys zs) = conc (conc [] ys) zs" by simp
+
   show "conc [] (conc ys zs) = conc (conc [] ys) zs"  
 +
    by simp
 
next
 
next
 
   fix x xs
 
   fix x xs
 
   assume HI: "conc xs (conc ys zs) = conc (conc xs ys) zs"  
 
   assume HI: "conc xs (conc ys zs) = conc (conc xs ys) zs"  
   have "conc (x # xs) (conc ys zs) = x # (conc xs (conc ys zs))" by simp
+
   have "conc (x # xs) (conc ys zs) = x # (conc xs (conc ys zs))"  
   also have "... = x # (conc (conc xs ys) zs)" using HI by simp
+
    by simp
   also have "... = conc (conc (x # xs) ys) zs" by simp
+
   also have "= x # (conc (conc xs ys) zs)"  
 +
    using HI by simp
 +
   also have "= conc (conc (x # xs) ys) zs"  
 +
    by simp
 
   finally show "conc (x # xs) (conc ys zs) = conc (conc (x # xs) ys) zs"  
 
   finally show "conc (x # xs) (conc ys zs) = conc (conc (x # xs) ys) zs"  
 
     by simp
 
     by simp
 
qed
 
qed
  
text {* ---------------------------------------------------------------  
+
(* La demostración declarativa detallada es *)
 +
lemma "conc xs (conc ys zs) = conc (conc xs ys) zs"
 +
proof (induct xs)
 +
  show "conc [] (conc ys zs) = conc (conc [] ys) zs"
 +
    by (simp only: conc.simps(1))
 +
next
 +
  fix x xs
 +
  assume HI: "conc xs (conc ys zs) = conc (conc xs ys) zs"
 +
  have "conc (x # xs) (conc ys zs) = x # (conc xs (conc ys zs))"
 +
    by (simp only: conc.simps(2))
 +
  also have "… = x # (conc (conc xs ys) zs)"
 +
    using HI by (simp only:)
 +
  also have "… = conc (conc (x # xs) ys) zs"
 +
    by (simp only: conc.simps(2))
 +
  finally show "conc (x # xs) (conc ys zs) = conc (conc (x # xs) ys) zs"
 +
    by this
 +
qed
 +
 
 +
text ---------------------------------------------------------------  
 
   Ejemplo 11. Refutar que  
 
   Ejemplo 11. Refutar que  
 
     conc xs ys = conc ys xs
 
     conc xs ys = conc ys xs
   ------------------------------------------------------------------- *}
+
   -------------------------------------------------------------------
  
 
lemma "conc xs ys = conc ys xs"
 
lemma "conc xs ys = conc ys xs"
Línea 351: Línea 400:
 
   oops
 
   oops
  
text {* Encuentra el contraejemplo,  
+
text Encuentra el contraejemplo,  
 
   xs = [a2]
 
   xs = [a2]
   ys = [a1] *}
+
   ys = [a1]
  
text {* ---------------------------------------------------------------  
+
text ---------------------------------------------------------------  
 
   Ejemplo 12. (p. 28) Demostrar que  
 
   Ejemplo 12. (p. 28) Demostrar que  
 
     conc xs [] = xs
 
     conc xs [] = xs
   ------------------------------------------------------------------- *}
+
   -------------------------------------------------------------------
  
 
(* La demostración aplicativa es *)
 
(* La demostración aplicativa es *)
Línea 380: Línea 429:
 
   fix x xs
 
   fix x xs
 
   assume HI: "conc xs [] = xs"  
 
   assume HI: "conc xs [] = xs"  
   have "conc (x # xs) [] = x # (conc xs [])" by simp
+
   have "conc (x # xs) [] = x # (conc xs [])"  
   also have "... = x # xs" using HI by simp
+
    by simp
   finally show "conc (x # xs) [] = x # xs" by simp
+
   also have "… = x # xs"
 +
    using HI by simp
 +
  finally show "conc (x # xs) [] = x # xs"
 +
    by simp
 +
qed
 +
 
 +
(* declare [[show_types]] *)
 +
 
 +
(* La demostración declarativa es *)
 +
lemma "conc xs [] = xs"
 +
proof (induct xs)
 +
  show "conc [] [] = []" by simp
 +
next
 +
  fix x :: "'a" and xs :: "'a list"
 +
  assume HI: "conc xs [] = xs"
 +
  have "conc (x # xs) [] = x # (conc xs [])"
 +
    by simp
 +
  also have "… = x # xs"
 +
    using HI by simp
 +
  finally show "conc (x # xs) [] = x # xs"
 +
    by simp
 +
qed
 +
 
 +
(* La demostración declarativa detallada es *)
 +
lemma "conc xs [] = xs"
 +
proof (induct xs)
 +
  show "conc [] [] = []"
 +
    by (simp only: conc.simps(1))
 +
next
 +
  fix x :: "'a" and xs :: "'a list"
 +
  assume HI: "conc xs [] = xs"
 +
  have "conc (x # xs) [] = x # (conc xs [])"
 +
    by (simp only: conc.simps(2))
 +
  also have "… = x # xs"  
 +
    using HI by (simp only:)
 +
   finally show "conc (x # xs) [] = x # xs"  
 +
    by this
 
qed
 
qed
  
text {* ---------------------------------------------------------------  
+
text ---------------------------------------------------------------  
 
   Ejemplo 13. (p. 30) Demostrar que  
 
   Ejemplo 13. (p. 30) Demostrar que  
 
     longitud (conc xs ys) = longitud xs + longitud ys
 
     longitud (conc xs ys) = longitud xs + longitud ys
   ------------------------------------------------------------------- *}
+
   -------------------------------------------------------------------
  
 
(* La demostración aplicativa es *)
 
(* La demostración aplicativa es *)
Línea 415: Línea 500:
 
   have "longitud (conc (x # xs) ys) = longitud (x # (conc xs ys))"  
 
   have "longitud (conc (x # xs) ys) = longitud (x # (conc xs ys))"  
 
     by simp
 
     by simp
   also have "... = 1 + longitud (conc xs ys)" by simp
+
   also have "= 1 + longitud (conc xs ys)"  
   also have "... = 1 + longitud xs + longitud ys" using HI by simp
+
    by simp
   also have "... = longitud (x # xs) + longitud ys" by simp
+
   also have "= 1 + longitud xs + longitud ys"  
 +
    using HI by simp
 +
   also have "= longitud (x # xs) + longitud ys"  
 +
    by simp
 
   finally show "longitud (conc (x # xs) ys) =  
 
   finally show "longitud (conc (x # xs) ys) =  
                 longitud (x # xs) + longitud ys" by simp
+
                 longitud (x # xs) + longitud ys"  
 +
    by simp
 
qed
 
qed
  
section {* Inducción correspondiente a la definición recursiva *}
+
(* La demostración declarativa detallada es *)
 +
lemma "longitud (conc xs ys) = longitud xs + longitud ys"
 +
proof (induct xs)
 +
  show "longitud (conc [] ys) = longitud [] + longitud ys"
 +
    by (simp only: conc.simps(1)
 +
                  longitud.simps(1))
 +
next
 +
  fix x xs
 +
  assume HI: "longitud (conc xs ys) = longitud xs + longitud ys"
 +
  have "longitud (conc (x # xs) ys) = longitud (x # (conc xs ys))"
 +
    by (simp only: conc.simps(2))
 +
  also have "… = 1 + longitud (conc xs ys)"
 +
    by (simp only: longitud.simps(2))
 +
  also have "… = 1 + longitud xs + longitud ys"
 +
    using HI by (simp only:)
 +
  also have "… = longitud (x # xs) + longitud ys"
 +
    by (simp only: longitud.simps(2))
 +
  finally show "longitud (conc (x # xs) ys) =
 +
                longitud (x # xs) + longitud ys"
 +
    by this
 +
qed
 +
 
 +
section ‹Inducción correspondiente a la definición recursiva
  
text {* ---------------------------------------------------------------  
+
text ---------------------------------------------------------------  
 
   Ejemplo 14. Definir la función
 
   Ejemplo 14. Definir la función
 
     coge :: nat ⇒ 'a list ⇒ 'a list
 
     coge :: nat ⇒ 'a list ⇒ 'a list
Línea 430: Línea 541:
 
   ejemplo,  
 
   ejemplo,  
 
     coge 2 [a,c,d,b,e] = [a,c]
 
     coge 2 [a,c,d,b,e] = [a,c]
   ------------------------------------------------------------------ *}
+
   ------------------------------------------------------------------
  
 
fun coge :: "nat ⇒ 'a list ⇒ 'a list" where
 
fun coge :: "nat ⇒ 'a list ⇒ 'a list" where
Línea 439: Línea 550:
 
value "coge 2 [a,c,d,b,e] = [a,c]"
 
value "coge 2 [a,c,d,b,e] = [a,c]"
  
text {* ---------------------------------------------------------------  
+
text ---------------------------------------------------------------  
 
   Ejemplo 15. Definir la función
 
   Ejemplo 15. Definir la función
 
     elimina :: nat ⇒ 'a list ⇒ 'a list
 
     elimina :: nat ⇒ 'a list ⇒ 'a list
Línea 445: Línea 556:
 
   elementos de xs. Por ejemplo,  
 
   elementos de xs. Por ejemplo,  
 
     elimina 2 [a,c,d,b,e] = [d,b,e]
 
     elimina 2 [a,c,d,b,e] = [d,b,e]
   ------------------------------------------------------------------ *}
+
   ------------------------------------------------------------------
  
 
fun elimina :: "nat ⇒ 'a list ⇒ 'a list" where
 
fun elimina :: "nat ⇒ 'a list ⇒ 'a list" where
Línea 454: Línea 565:
 
value "elimina 2 [a,c,d,b,e] = [d,b,e]"
 
value "elimina 2 [a,c,d,b,e] = [d,b,e]"
  
text {*
+
text
 
   La definición coge genera el esquema de inducción coge.induct:
 
   La definición coge genera el esquema de inducción coge.induct:
 
     ⟦⋀n. P n [];  
 
     ⟦⋀n. P n [];  
Línea 461: Línea 572:
 
     ⟹ P n x
 
     ⟹ P n x
  
   Puede verse usando "thm coge.induct". *}
+
   Puede verse usando "thm coge.induct".
 +
 
 +
thm coge.induct
  
text {* ---------------------------------------------------------------  
+
text ---------------------------------------------------------------  
 
   Ejemplo 16. (p. 35) Demostrar que  
 
   Ejemplo 16. (p. 35) Demostrar que  
 
     conc (coge n xs) (elimina n xs) = xs
 
     conc (coge n xs) (elimina n xs) = xs
   ------------------------------------------------------------------- *}
+
   -------------------------------------------------------------------
  
 
(* La demostración aplicativa es *)
 
(* La demostración aplicativa es *)
Línea 490: Línea 603:
 
proof (induct rule: coge.induct)
 
proof (induct rule: coge.induct)
 
   fix n
 
   fix n
   show "conc (coge n []) (elimina n []) = []" by simp
+
   show "conc (coge n []) (elimina n []) = []"  
 +
    by simp
 
next
 
next
   fix x xs
+
   fix x :: "'a" and xs :: "'a list"
   show "conc (coge 0 (x#xs)) (elimina 0 (x#xs)) = x#xs" by simp
+
   show "conc (coge 0 (x#xs)) (elimina 0 (x#xs)) = x#xs"  
 +
    by simp
 
next
 
next
   fix n x xs
+
   fix n and x :: "'a" and xs :: "'a list"
 
   assume HI: "conc (coge n xs) (elimina n xs) = xs"
 
   assume HI: "conc (coge n xs) (elimina n xs) = xs"
 
   have "conc (coge (Suc n) (x#xs)) (elimina (Suc n) (x#xs)) =  
 
   have "conc (coge (Suc n) (x#xs)) (elimina (Suc n) (x#xs)) =  
         conc (x#(coge n xs)) (elimina n xs)" by simp
+
         conc (x#(coge n xs)) (elimina n xs)"  
   also have "... = x#(conc (coge n xs) (elimina n xs))" by simp
+
    by simp
   also have "... = x#xs" using HI by simp   
+
   also have "= x#(conc (coge n xs) (elimina n xs))"  
 +
    by simp
 +
   also have "= x#xs"  
 +
    using HI by simp   
 
   finally show "conc (coge (Suc n) (x#xs)) (elimina (Suc n) (x#xs)) =  
 
   finally show "conc (coge (Suc n) (x#xs)) (elimina (Suc n) (x#xs)) =  
 
                 x#xs"
 
                 x#xs"
Línea 506: Línea 624:
 
qed
 
qed
  
text {*
+
text ‹Comentario sobre la demostración anterior:
  Comentario sobre la demostración anterior:
 
 
   · (induct rule: coge.induct) indica que el método de demostración es
 
   · (induct rule: coge.induct) indica que el método de demostración es
 
     por el esquema de inducción correspondiente a la definición de la
 
     por el esquema de inducción correspondiente a la definición de la
Línea 517: Línea 634:
 
             conc (coge n xs) (elimina n xs) = xs ⟹
 
             conc (coge n xs) (elimina n xs) = xs ⟹
 
             conc (coge (Suc n) (x#xs)) (elimina (Suc n) (x#xs)) = x#xs
 
             conc (coge (Suc n) (x#xs)) (elimina (Suc n) (x#xs)) = x#xs
*}
+
  
section {* Razonamiento por casos *}
+
(* La demostración declarativa detallada es *)
 +
lemma "conc (coge n xs) (elimina n xs) = xs"
 +
proof (induct rule: coge.induct)
 +
  fix n
 +
  show "conc (coge n []) (elimina n []) = []"
 +
    by (simp only: coge.simps(1)
 +
                  elimina.simps(1)
 +
                  conc.simps(1))
 +
next
 +
  fix x :: "'a" and xs :: "'a list"
 +
  show "conc (coge 0 (x#xs)) (elimina 0 (x#xs)) = x#xs"
 +
    by (simp only: coge.simps(2)
 +
                  elimina.simps(2)
 +
                  conc.simps(1))
 +
next
 +
  fix n and x :: "'a" and xs :: "'a list"
 +
  assume HI: "conc (coge n xs) (elimina n xs) = xs"
 +
  have "conc (coge (Suc n) (x#xs)) (elimina (Suc n) (x#xs)) =
 +
        conc (x#(coge n xs)) (elimina n xs)"
 +
    by (simp only: coge.simps(3)
 +
                  elimina.simps(3))
 +
  also have "… = x#(conc (coge n xs) (elimina n xs))"
 +
    by (simp only: conc.simps(2))
 +
  also have "… = x#xs"
 +
    using HI by (simp only:)
 +
  finally show "conc (coge (Suc n) (x#xs)) (elimina (Suc n) (x#xs)) =
 +
                x#xs"
 +
    by this
 +
qed
 +
 
 +
section ‹Razonamiento por casos
  
text {* ---------------------------------------------------------------  
+
text ---------------------------------------------------------------  
 
   Ejemplo 17. Definir la función
 
   Ejemplo 17. Definir la función
 
     esVacia :: 'a list ⇒ bool
 
     esVacia :: 'a list ⇒ bool
Línea 527: Línea 674:
 
     esVacia []  = True
 
     esVacia []  = True
 
     esVacia [1] = False
 
     esVacia [1] = False
   ------------------------------------------------------------------ *}
+
   ------------------------------------------------------------------
  
 
fun esVacia :: "'a list ⇒ bool" where
 
fun esVacia :: "'a list ⇒ bool" where
Línea 536: Línea 683:
 
value "esVacia [a] = False"
 
value "esVacia [a] = False"
  
text {* ---------------------------------------------------------------  
+
text ---------------------------------------------------------------  
 
   Ejemplo 18 (p. 39) . Demostrar que  
 
   Ejemplo 18 (p. 39) . Demostrar que  
 
     esVacia xs = esVacia (conc xs xs)
 
     esVacia xs = esVacia (conc xs xs)
   ------------------------------------------------------------------- *}
+
   -------------------------------------------------------------------
  
 
(* La demostración aplicativa es *)
 
(* La demostración aplicativa es *)
Línea 559: Línea 706:
 
proof (cases xs)
 
proof (cases xs)
 
   assume "xs = []"
 
   assume "xs = []"
   then show "esVacia xs = esVacia (conc xs xs)" by simp
+
   then show "esVacia xs = esVacia (conc xs xs)"  
 +
    by simp
 
next
 
next
 
   fix y ys
 
   fix y ys
 
   assume "xs = y#ys"
 
   assume "xs = y#ys"
   then show "esVacia xs = esVacia (conc xs xs)" by simp
+
   then show "esVacia xs = esVacia (conc xs xs)"  
 +
    by simp
 
qed
 
qed
  
text {*
+
text ‹Comentarios sobre la demostración anterior:
  Comentarios sobre la demostración anterior:
 
 
   · "(cases xs)" es el método de demostración por casos según xs.
 
   · "(cases xs)" es el método de demostración por casos según xs.
 
   · Se generan dos subobjetivos  correspondientes a los dos
 
   · Se generan dos subobjetivos  correspondientes a los dos
Línea 574: Línea 722:
 
     · 2. ⋀y ys. xs = y#ys ⟹ esVacia xs = esVacia (conc xs xs)
 
     · 2. ⋀y ys. xs = y#ys ⟹ esVacia xs = esVacia (conc xs xs)
 
   · "then" indica "usando la propiedad anterior"
 
   · "then" indica "usando la propiedad anterior"
*}
+
 +
 
 +
(* La demostración declarativa detallada es *)
 +
lemma "esVacia xs = esVacia (conc xs xs)"
 +
proof (cases xs)
 +
  assume "xs = []"
 +
  then show "esVacia xs = esVacia (conc xs xs)"
 +
    by (simp only: conc.simps(1))
 +
next
 +
  fix y ys
 +
  assume "xs = y#ys"
 +
  then show "esVacia xs = esVacia (conc xs xs)"
 +
    by (simp only: esVacia.simps(2)
 +
                  conc.simps(2))
 +
qed
  
 
(* La demostración declarativa simplificada es *)
 
(* La demostración declarativa simplificada es *)
Línea 580: Línea 742:
 
proof (cases xs)
 
proof (cases xs)
 
   case Nil
 
   case Nil
   then show "esVacia xs = esVacia (conc xs xs)" by simp
+
   then show "esVacia xs = esVacia (conc xs xs)"  
 +
    by simp
 
next
 
next
 
   case Cons
 
   case Cons
   then show "esVacia xs = esVacia (conc xs xs)" by simp
+
   then show "esVacia xs = esVacia (conc xs xs)"  
 +
    by simp
 
qed
 
qed
  
text {*
+
text
 
   Comentarios sobre la demostración anterior:
 
   Comentarios sobre la demostración anterior:
 
   · "case Nil" es una abreviatura de "assume xs = []"
 
   · "case Nil" es una abreviatura de "assume xs = []"
   · "case Cons" es una abreviatura de "fix y ys assume xs = y#ys"
+
   · "case Cons" es una abreviatura de "fix y ys assume xs = y#ys"
  · "thus" es una abreviatura de "then show".
 
*}
 
  
 
(* La demostración con el patrón sugerido es *)
 
(* La demostración con el patrón sugerido es *)
Línea 603: Línea 765:
 
qed
 
qed
  
section {* Heurística de generalización *}
+
section ‹Heurística de generalización
  
text {* ---------------------------------------------------------------  
+
text ---------------------------------------------------------------  
 
   Ejemplo 19. Definir la función
 
   Ejemplo 19. Definir la función
 
     inversaAc :: 'a list ⇒ 'a list
 
     inversaAc :: 'a list ⇒ 'a list
Línea 611: Línea 773:
 
   acumuladores. Por ejemplo,  
 
   acumuladores. Por ejemplo,  
 
     inversaAc [a,c,b,e] = [e,b,c,a]
 
     inversaAc [a,c,b,e] = [e,b,c,a]
   ------------------------------------------------------------------ *}
+
   ------------------------------------------------------------------
  
 
fun inversaAcAux :: "'a list ⇒ 'a list ⇒ 'a list" where
 
fun inversaAcAux :: "'a list ⇒ 'a list ⇒ 'a list" where
Línea 622: Línea 784:
 
value "inversaAc [a,c,b,e] = [e,b,c,a]"
 
value "inversaAc [a,c,b,e] = [e,b,c,a]"
  
text {*
+
text ‹Lema. [Ejemplo de equivalencia entre las definiciones]
  Lema. [Ejemplo de equivalencia entre las definiciones]
 
 
   La inversa de [a,b,c] es lo mismo calculada con la primera definición
 
   La inversa de [a,b,c] es lo mismo calculada con la primera definición
   que con la segunda.
+
   que con la segunda.
*}
 
  
 
lemma "inversaAc [a,b,c] = inversa [a,b,c]"
 
lemma "inversaAc [a,b,c] = inversa [a,b,c]"
 
   by (simp add: inversaAc_def)
 
   by (simp add: inversaAc_def)
  
text {*
+
text ‹Nota. [Ejemplo fallido de demostración por inducción]
  Nota. [Ejemplo fallido de demostración por inducción]
 
 
   El siguiente intento de demostrar que para cualquier lista xs, se
 
   El siguiente intento de demostrar que para cualquier lista xs, se
   tiene que  "inversaAc xs = inversa xs" falla.
+
   tiene que  "inversaAc xs = inversa xs" falla.
*}
 
  
 
lemma "inversaAc xs = inversa xs"
 
lemma "inversaAc xs = inversa xs"
 
proof (induct xs)
 
proof (induct xs)
   show "inversaAc [] = inversa []" by (simp add: inversaAc_def)
+
   show "inversaAc [] = inversa []"  
 +
    by (simp add: inversaAc_def)
 
next
 
next
   fix a xs assume HI: "inversaAc xs = inversa xs"
+
   fix a :: "'b" and xs :: "'b list"
 +
  assume HI: "inversaAc xs = inversa xs"
 
   have "inversaAc (a#xs) = inversaAcAux (a#xs) []"  
 
   have "inversaAc (a#xs) = inversaAcAux (a#xs) []"  
 
     by (simp add: inversaAc_def)
 
     by (simp add: inversaAc_def)
   also have "… = inversaAcAux xs [a]" by simp
+
   also have "… = inversaAcAux xs [a]"  
 +
    by simp
 
   also have "… = inversa (a#xs)"
 
   also have "… = inversa (a#xs)"
 
   (* Problema: la hipótesis de inducción no es aplicable. *)
 
   (* Problema: la hipótesis de inducción no es aplicable. *)
 
oops
 
oops
  
text {*
+
text ‹Nota. [Heurística de generalización]
  Nota. [Heurística de generalización]
 
 
   Cuando se use demostración estructural, cuantificar universalmente las  
 
   Cuando se use demostración estructural, cuantificar universalmente las  
 
   variables libres (o, equivalentemente, considerar las variables libres
 
   variables libres (o, equivalentemente, considerar las variables libres
Línea 658: Línea 818:
 
   Para toda lista ys se tiene  
 
   Para toda lista ys se tiene  
 
     inversaAcAux xs ys = (inversa xs) @ ys
 
     inversaAcAux xs ys = (inversa xs) @ ys
*}
+
  
text {* ---------------------------------------------------------------  
+
text ---------------------------------------------------------------  
 
   Ejemplo 20. (p. 44) Demostrar que  
 
   Ejemplo 20. (p. 44) Demostrar que  
 
     inversaAcAux xs ys = (inversa xs) @ ys
 
     inversaAcAux xs ys = (inversa xs) @ ys
   ------------------------------------------------------------------- *}
+
   -------------------------------------------------------------------
  
 
(* La demostración aplicativa es *)
 
(* La demostración aplicativa es *)
Línea 681: Línea 841:
  
 
(* La demostración declarativa es *)
 
(* La demostración declarativa es *)
lemma inversaAcAux_es_inversa:
+
lemma
 
   "inversaAcAux xs ys = (inversa xs) @ ys"
 
   "inversaAcAux xs ys = (inversa xs) @ ys"
 
proof (induct xs arbitrary: ys)
 
proof (induct xs arbitrary: ys)
   show "⋀ys. inversaAcAux [] ys = (inversa [])@ys" by simp
+
   show "⋀ys. inversaAcAux [] ys = (inversa [])@ys"  
 +
    by simp
 
next
 
next
   fix a xs  
+
   fix a :: "'b" and xs :: "'b list"
 
   assume HI: "⋀ys. inversaAcAux xs ys = inversa xs@ys"
 
   assume HI: "⋀ys. inversaAcAux xs ys = inversa xs@ys"
 
   show "⋀ys. inversaAcAux (a#xs) ys = inversa (a#xs)@ys"
 
   show "⋀ys. inversaAcAux (a#xs) ys = inversa (a#xs)@ys"
 
   proof -
 
   proof -
 
     fix ys
 
     fix ys
     have "inversaAcAux (a#xs) ys = inversaAcAux xs (a#ys)" by simp
+
     have "inversaAcAux (a#xs) ys = inversaAcAux xs (a#ys)"  
     also have "… = inversa xs@(a#ys)" using HI by simp
+
      by simp
     also have "… = inversa (a#xs)@ys" using [[simp_trace]] by simp  
+
     also have "… = inversa xs@(a#ys)"  
     finally show "inversaAcAux (a#xs) ys = inversa (a#xs)@ys" by simp
+
      using HI by simp
 +
     also have "… = inversa (a#xs)@ys" using [[simp_trace]]  
 +
      by simp  
 +
     finally show "inversaAcAux (a#xs) ys = inversa (a#xs)@ys"  
 +
      by simp
 
   qed
 
   qed
 
qed
 
qed
  
text {*
+
text ‹Comentarios sobre la demostración anterior:
  Comentarios sobre la demostración anterior:
 
 
   · "(induct xs arbitrary: ys)" es el método de demostración por
 
   · "(induct xs arbitrary: ys)" es el método de demostración por
 
     inducción sobre xs usando ys como variable arbitraria.
 
     inducción sobre xs usando ys como variable arbitraria.
Línea 708: Línea 872:
 
   · Dentro de una demostración se pueden incluir otras demostraciones.
 
   · Dentro de una demostración se pueden incluir otras demostraciones.
 
   · Para demostrar la propiedad universal "⋀ys. P(ys)" se elige una
 
   · Para demostrar la propiedad universal "⋀ys. P(ys)" se elige una
     lista arbitraria (con "fix ys") y se demuestra "P(ys)".  
+
     lista arbitraria (con "fix ys") y se demuestra "P(ys)".
*}
 
  
text {*
+
text ‹Nota. En el paso "inversa xs@(a#ys) = inversa (a#xs)@ys" se usan
  Nota. En el paso "inversa xs@(a#ys) = inversa (a#xs)@ys" se usan
 
 
   lemas de la teoría List. Se puede observar, insertano  
 
   lemas de la teoría List. Se puede observar, insertano  
 
     using [[simp_trace]]
 
     using [[simp_trace]]
Línea 722: Línea 884:
  
 
   En la siguiente demostración se detallan los lemas utilizados.
 
   En la siguiente demostración se detallan los lemas utilizados.
*}
+
  
 
― ‹Demostración aplicativa›
 
― ‹Demostración aplicativa›
Línea 736: Línea 898:
 
   done
 
   done
  
― ‹Demostración declarativa›
+
― ‹Demostración declarativa detallada del lema auxiliar›
lemma "(inversa xs)@(a#ys) = (inversa (a#xs))@ys"
+
lemma auxiliar: "(inversa xs)@(a#ys) = (inversa (a#xs))@ys"
 
proof -
 
proof -
 
   have "(inversa xs)@(a#ys) = (inversa xs)@(a#([]@ys))"  
 
   have "(inversa xs)@(a#ys) = (inversa xs)@(a#([]@ys))"  
 
     by (simp only: append.simps(1))
 
     by (simp only: append.simps(1))
   also have "… = (inversa xs)@([a]@ys)" by (simp only: append.simps(2))
+
   also have "… = (inversa xs)@([a]@ys)"  
   also have "… = ((inversa xs)@[a])@ys" by (simp only: append_assoc)
+
    by (simp only: append.simps(2))
   also have "… = (inversa (a#xs))@ys" by (simp only: inversa.simps(2))
+
   also have "… = ((inversa xs)@[a])@ys"  
   finally show ?thesis .
+
    by (simp only: append_assoc)
 +
   also have "… = (inversa (a#xs))@ys"  
 +
    by (simp only: inversa.simps(2))
 +
   finally show ?thesis  
 +
    by this
 
qed
 
qed
  
text {* ---------------------------------------------------------------  
+
(* La demostración declarativa detallada es *)
 +
lemma inversaAcAux_es_inversa:
 +
  "inversaAcAux xs ys = (inversa xs) @ ys"
 +
proof (induct xs arbitrary: ys)
 +
  fix ys :: "'b list"
 +
  show "inversaAcAux [] ys = (inversa [])@ys"
 +
    by (simp only: inversaAcAux.simps(1)
 +
                  inversa.simps(1)
 +
                  append.simps(1))
 +
next
 +
  fix a :: "'b" and xs :: "'b list"
 +
  assume HI: "⋀ys. inversaAcAux xs ys = inversa xs@ys"
 +
  show "⋀ys. inversaAcAux (a#xs) ys = inversa (a#xs)@ys"
 +
  proof -
 +
    fix ys
 +
    have "inversaAcAux (a#xs) ys = inversaAcAux xs (a#ys)"
 +
      by (simp only: inversaAcAux.simps(2))
 +
    also have "… = inversa xs@(a#ys)"
 +
      using HI by (simp only:)
 +
    also have "… = inversa (a#xs)@ys"
 +
      by (rule auxiliar)
 +
    finally show "inversaAcAux (a#xs) ys = inversa (a#xs)@ys"
 +
      by this
 +
  qed
 +
qed
 +
 
 +
text ---------------------------------------------------------------  
 
   Ejemplo 21. (p. 43) Demostrar que  
 
   Ejemplo 21. (p. 43) Demostrar que  
 
     inversaAc xs = inversa xs
 
     inversaAc xs = inversa xs
   ------------------------------------------------------------------- *}
+
   -------------------------------------------------------------------
  
 
(* La demostración aplicativa es *)
 
(* La demostración aplicativa es *)
Línea 761: Línea 953:
 
   by (simp add: inversaAcAux_es_inversa inversaAc_def)
 
   by (simp add: inversaAcAux_es_inversa inversaAc_def)
  
text {*
+
text ‹Comentario de la demostración anterior:
  Comentario de la demostración anterior:
 
 
   · "(simp add: inversaAcAux_es_inversa inversaAc_def)" es el método de  
 
   · "(simp add: inversaAcAux_es_inversa inversaAc_def)" es el método de  
 
     demostración por simplificación usando como regla de simplificación  
 
     demostración por simplificación usando como regla de simplificación  
     las propiedades inversaAcAux_es_inversa e inversaAc_def.  
+
     las propiedades inversaAcAux_es_inversa e inversaAc_def.
*}
+
 
+
section ‹Demostración por inducción para funciones de orden superior
section {* Demostración por inducción para funciones de orden superior *}
 
  
text {* ---------------------------------------------------------------  
+
text ---------------------------------------------------------------  
 
   Ejemplo 22. Definir la función
 
   Ejemplo 22. Definir la función
 
     sum :: nat list ⇒ nat
 
     sum :: nat list ⇒ nat
 
   tal que (sum xs) es la suma de los elementos de xs. Por ejemplo,
 
   tal que (sum xs) es la suma de los elementos de xs. Por ejemplo,
 
     sum [3,2,5] = 10
 
     sum [3,2,5] = 10
   ------------------------------------------------------------------ *}
+
   ------------------------------------------------------------------
  
 
fun sum :: "nat list ⇒ nat" where
 
fun sum :: "nat list ⇒ nat" where
Línea 783: Línea 973:
 
value "sum [3,2,5] = 10"
 
value "sum [3,2,5] = 10"
  
text {* ---------------------------------------------------------------  
+
text ---------------------------------------------------------------  
 
   Ejemplo 23. Definir la función
 
   Ejemplo 23. Definir la función
 
     map :: ('a ⇒ 'b) ⇒ 'a list ⇒ 'b list
 
     map :: ('a ⇒ 'b) ⇒ 'a list ⇒ 'b list
Línea 789: Línea 979:
 
   elementos de xs. Por ejemplo,
 
   elementos de xs. Por ejemplo,
 
     map (λx. 2*x) [3::nat,2,5] = [6,4,10]
 
     map (λx. 2*x) [3::nat,2,5] = [6,4,10]
     map (( * ) 2) [3::nat,2,5] = [6,4,10]
+
     map ((*) 2) [3::nat,2,5] = [6,4,10]
 
     map ((+) 2)  [3::nat,2,5] = [5,4,7]
 
     map ((+) 2)  [3::nat,2,5] = [5,4,7]
   ------------------------------------------------------------------ *}
+
   ------------------------------------------------------------------
  
 
fun map :: "('a ⇒ 'b) ⇒ 'a list ⇒ 'b list" where
 
fun map :: "('a ⇒ 'b) ⇒ 'a list ⇒ 'b list" where
Línea 798: Línea 988:
  
 
value "map (λx. 2*x) [3::nat,2,5] = [6,4,10]"
 
value "map (λx. 2*x) [3::nat,2,5] = [6,4,10]"
value "map (( * ) 2) [3::nat,2,5] = [6,4,10]"
+
value "map ((*) 2)   [3::nat,2,5] = [6,4,10]"
 
value "map ((+) 2)  [3::nat,2,5] = [5,4,7]"
 
value "map ((+) 2)  [3::nat,2,5] = [5,4,7]"
  
text {* ---------------------------------------------------------------  
+
text ---------------------------------------------------------------  
 
   Ejemplo 24. (p. 45) Demostrar que  
 
   Ejemplo 24. (p. 45) Demostrar que  
     sum (map (( * ) 2) xs) = 2 * (sum xs)
+
     sum (map ((*) 2) xs) = 2 * (sum xs)
   ------------------------------------------------------------------- *}
+
   -------------------------------------------------------------------
  
 
(* La demostración aplicativa es *)
 
(* La demostración aplicativa es *)
lemma "sum (map (( * ) 2) xs) = 2 * (sum xs)"
+
lemma "sum (map ((*) 2) xs) = 2 * (sum xs)"
 
   apply (induct xs)  
 
   apply (induct xs)  
 
     (* 1. sum (map (( * ) 2) []) = 2 * sum []
 
     (* 1. sum (map (( * ) 2) []) = 2 * sum []
Línea 817: Línea 1007:
  
 
(* La demostración automática es *)
 
(* La demostración automática es *)
lemma "sum (map (( * ) 2) xs) = 2 * (sum xs)"
+
lemma "sum (map ((*) 2) xs) = 2 * (sum xs)"
 
   by (induct xs) simp_all
 
   by (induct xs) simp_all
  
 
(* La demostración declarativa es *)
 
(* La demostración declarativa es *)
lemma "sum (map (( * ) 2) xs) = 2 * (sum xs)"
+
lemma "sum (map ((*) 2) xs) = 2 * (sum xs)"
 
proof (induct xs)
 
proof (induct xs)
   show "sum (map (( * ) 2) []) = 2 * (sum [])" by simp
+
   show "sum (map ((*) 2) []) = 2 * (sum [])" by simp
 
next
 
next
 
   fix a xs
 
   fix a xs
   assume HI: "sum (map (( * ) 2) xs) = 2 * (sum xs)"
+
   assume HI: "sum (map ((*) 2) xs) = 2 * (sum xs)"
   have "sum (map (( * ) 2) (a#xs)) = sum ((2*a)#(map (( * ) 2) xs))"  
+
   have "sum (map ((*) 2) (a#xs)) = sum ((2*a)#(map ((*) 2) xs))"
 +
    by simp
 +
  also have "… = 2*a + sum (map ((*) 2) xs)"
 +
    by simp
 +
  also have "… = 2*a + 2*(sum xs)"
 +
    using HI by simp
 +
  also have "… = 2*(a + sum xs)"
 +
    by simp
 +
  also have "… = 2*(sum (a#xs))"
 +
    by simp
 +
  finally show "sum (map ((*) 2) (a#xs)) = 2*(sum (a#xs))"  
 
     by simp
 
     by simp
  also have "... = 2*a + sum (map (( * ) 2) xs)" by simp
 
  also have "... = 2*a + 2*(sum xs)" using HI by simp
 
  also have "... = 2*(a + sum xs)" by simp
 
  also have "... = 2*(sum (a#xs))" by simp
 
  finally show "sum (map (( * ) 2) (a#xs)) = 2*(sum (a#xs))" by simp
 
 
qed
 
qed
  
text {* ---------------------------------------------------------------  
+
(* La demostración declarativa detallada es *)
 +
lemma "sum (map ((*) 2) xs) = 2 * (sum xs)"
 +
proof (induct xs)
 +
  show "sum (map ((*) 2) []) = 2 * (sum [])"
 +
    by (simp only: map.simps(1)
 +
                  sum.simps(1))
 +
next
 +
  fix a xs
 +
  assume HI: "sum (map ((*) 2) xs) = 2 * (sum xs)"
 +
  have "sum (map ((*) 2) (a#xs)) = sum ((2*a)#(map ((*) 2) xs))"
 +
    by (simp only: map.simps(2))
 +
  also have "… = 2*a + sum (map ((*) 2) xs)"
 +
    by (simp only: sum.simps(2))
 +
  also have "… = 2*a + 2*(sum xs)"
 +
    using HI by (simp only:)
 +
  also have "… = 2*(a + sum xs)"
 +
    find_theorems "_ * (_ + _)"
 +
    by (simp only: add_mult_distrib2)
 +
  also have "… = 2*(sum (a#xs))"
 +
    by (simp only: sum.simps(2))
 +
  finally show "sum (map ((*) 2) (a#xs)) = 2*(sum (a#xs))"
 +
    by this
 +
qed
 +
 
 +
text ---------------------------------------------------------------  
 
   Ejemplo 25. (p. 48) Demostrar que  
 
   Ejemplo 25. (p. 48) Demostrar que  
 
     longitud (map f xs) = longitud xs
 
     longitud (map f xs) = longitud xs
   ------------------------------------------------------------------- *}
+
   -------------------------------------------------------------------
  
 
(* La demostración aplicativa es *)
 
(* La demostración aplicativa es *)
Línea 858: Línea 1077:
 
lemma "longitud (map f xs) = longitud xs"
 
lemma "longitud (map f xs) = longitud xs"
 
proof (induct xs)
 
proof (induct xs)
   show "longitud (map f []) = longitud []" by simp
+
   show "longitud (map f []) = longitud []"  
 +
    by simp
 +
next
 +
  fix a xs
 +
  assume HI: "longitud (map f xs) = longitud xs"
 +
  have "longitud (map f (a#xs)) = longitud (f a # (map f xs))"
 +
    by simp
 +
  also have "… = 1 + longitud (map f xs)"
 +
    by simp
 +
  also have "… = 1 + longitud xs"
 +
    using HI by simp
 +
  also have "… = longitud (a#xs)"
 +
    by simp
 +
  finally show "longitud (map f (a#xs)) = longitud (a#xs)"
 +
    by simp
 +
qed
 +
 
 +
(* La demostración declarativa detallada es *)
 +
lemma "longitud (map f xs) = longitud xs"
 +
proof (induct xs)
 +
  show "longitud (map f []) = longitud []"
 +
    by (simp only: map.simps(1)
 +
                  longitud.simps(1))
 
next
 
next
 
   fix a xs
 
   fix a xs
 
   assume HI: "longitud (map f xs) = longitud xs"
 
   assume HI: "longitud (map f xs) = longitud xs"
   have "longitud (map f (a#xs)) = longitud (f a # (map f xs))" by simp
+
   have "longitud (map f (a#xs)) = longitud (f a # (map f xs))"  
   also have "... = 1 + longitud (map f xs)" by simp
+
    by (simp only: map.simps(2))
   also have "... = 1 + longitud xs" using HI by simp
+
   also have "= 1 + longitud (map f xs)"  
   also have "... = longitud (a#xs)" by simp
+
    by (simp only: longitud.simps(2))
   finally show "longitud (map f (a#xs)) = longitud (a#xs)" by simp
+
   also have "= 1 + longitud xs"  
 +
    using HI by (simp only:)
 +
   also have "= longitud (a#xs)"  
 +
    by (simp only: longitud.simps(2))
 +
   finally show "longitud (map f (a#xs)) = longitud (a#xs)"  
 +
    by this
 
qed
 
qed
  
section {* Referencias *}
+
section ‹Referencias›
  
text {*
+
text
 
   · J.A. Alonso. "Razonamiento sobre programas" http://goo.gl/R06O3
 
   · J.A. Alonso. "Razonamiento sobre programas" http://goo.gl/R06O3
 
   · G. Hutton. "Programming in Haskell". Cap. 13 "Reasoning about
 
   · G. Hutton. "Programming in Haskell". Cap. 13 "Reasoning about
Línea 879: Línea 1125:
 
   · L. Paulson. "ML for the Working Programmer, 2nd Edition". Cap. 6.  
 
   · L. Paulson. "ML for the Working Programmer, 2nd Edition". Cap. 6.  
 
     "Reasoning about functional programs".  
 
     "Reasoning about functional programs".  
*}
+
  
 
end
 
end
 
</source>
 
</source>

Revisión del 07:17 16 abr 2020

chapter Tema 6: Razonamiento sobre programas

theory T6_Razonamiento_sobre_programas
imports Main 
begin

text En este tema se demuestra con Isabelle las propiedades de los
  programas funcionales de tema 6 http://bit.ly/2Za6YWY

  Para cada propiedades se presentan distintos tipos de demostraciones:
  automáticas, aplicativas y declarativas. 

(* declare [[names_short]] *)

section Razonamiento ecuacional

text -----------------------------------------------------------------
  Ejemplo 1. Definir, por recursión, la función
     longitud :: 'a list  nat
  tal que (longitud xs) es la longitud de la listas xs. Por ejemplo,
     longitud [a,c,d] = 3
  --------------------------------------------------------------------

fun longitud :: "'a list ⇒ nat" where
  "longitud []     = 0"
| "longitud (x#xs) = 1 + longitud xs"
   
value "longitud [a,c,d] = 3"

text  --------------------------------------------------------------- 
  Ejemplo 2. Demostrar que 
     longitud [a,c,d] = 3
  ------------------------------------------------------------------- 

lemma "longitud [a,c,d] = 3"
  apply simp
  done

lemma "longitud [a,c,d] = 3"
  by simp

text  --------------------------------------------------------------- 
  Ejemplo 3. Definir la función
     fun intercambia :: 'a × 'b  'b × 'a
  tal que (intercambia p) es el par obtenido intercambiando las
  componentes del par p. Por ejemplo,
     intercambia (u,v) = (v,u)
  ------------------------------------------------------------------ 

fun intercambia :: "'a × 'b ⇒ 'b × 'a" where
  "intercambia (x,y) = (y,x)"

value "intercambia (u,v) = (v,u)"

text La definición de la función intercambia genera una regla de
  simplificación
  · intercambia.simps: intercambia (x,y) = (y,x)
  
  Se puede ver con 
  · thm intercambia.simps 


thm intercambia.simps
(* da intercambia (?x, ?y) = (?y, ?x) *)

text  --------------------------------------------------------------- 
  Ejemplo 4. (p.6) Demostrar que 
     intercambia (intercambia (x,y)) = (x,y)
  ------------------------------------------------------------------- 

(* Demostración automática *)
lemma "intercambia (intercambia (x,y)) = (x,y)"
  by auto

(* Demostración automática 1 *)
lemma "intercambia (intercambia (x,y)) = (x,y)"
  by simp 

(* Demostración automática 2 *)
lemma "intercambia (intercambia (x,y)) = (x,y)"
  by (simp only: intercambia.simps)

(* Demostración aplicativa *)
lemma "intercambia (intercambia (x,y)) = (x,y)"
  apply (simp only: intercambia.simps)
  done

(* Demostración declarativa 1 *)
lemma "intercambia (intercambia (x,y)) = (x,y)"
proof -
  have "intercambia (intercambia (x,y)) = intercambia (y,x)"  
    by simp
  also have "… = (x,y)" 
    by simp 
  finally show "intercambia (intercambia (x,y)) = (x,y)" 
    by simp
qed

(* Demostración detallada *)
lemma "intercambia (intercambia (x,y)) = (x,y)"
proof -
  have "intercambia (intercambia (x,y)) = intercambia (y,x)"  
    by (simp only: intercambia.simps)
  also have "… = (x,y)" 
    by (simp only: intercambia.simps)
  finally show "intercambia (intercambia (x,y)) = (x,y)" 
    by simp
qed

text Notas sobre el lenguaje: En la demostración anterior se ha usado
  · "proof" para iniciar la prueba,
  · "-" (después de "proof") para no usar el método por defecto,
  · "have" para establecer un paso,
  · "by (simp only: intercambia.simps)" para indicar que sólo se usa
    como regla de escritura la correspondiente a la definición de
    intercambia,
  · "also" para encadenar pasos ecuacionales,
  · "…" para representar la derecha de la igualdad anterior en un
    razonamiento ecuacional,
  · "finally" para indicar el último pasa de un razonamiento ecuacional,
  · "show" para establecer la conclusión.
  · "by simp" para indicar el método de demostración por simplificación y 
  · "qed" para terminar la pruebas.

text --------------------------------------------------------------- 
  Ejemplo 5. Definir, por recursión, la función
     inversa :: 'a list  'a list
  tal que (inversa xs) es la lista obtenida invirtiendo el orden de los
  elementos de xs. Por ejemplo,
     inversa [a,d,c] = [c,d,a]
  ------------------------------------------------------------------ 

fun inversa :: "'a list ⇒ 'a list" where
  "inversa []     = []"
| "inversa (x#xs) = inversa xs @ [x]"

value "inversa [a,d,c] = [c,d,a]"

text  --------------------------------------------------------------- 
  Ejemplo 6. (p. 9) Demostrar que 
     inversa [x] = [x]
  ------------------------------------------------------------------- 

(* La demostración automática es *)
lemma "inversa [x] = [x]"
  by simp

(* La demostración aplicativa es *)
lemma "inversa [x] = [x]"
  apply simp
  done

text En la demostración anterior se usaron las siguientes reglas:
  · inversa.simps(1): inversa [] = []
  · inversa.simps(2): inversa (x#xs) = inversa xs @ [x]
  · append_Nil:       [] @ ys = ys
  Vamos a explicitar su aplicación.


find_theorems
find_theorems "_ @ _ = _"
find_theorems "[] @ _ = _"

(* La demostración aplicativa detallada es *)
lemma "inversa [x] = [x]"
  apply (simp only: inversa.simps(2)) (* inversa [] @ [x] = [x] *)
  apply (simp only: inversa.simps(1)) (* [] @ [x] = [x] *)
  apply (simp only: append_Nil)       (* No subgoals! *)
  done

(* La demostración declarativa simplificada es *)
lemma "inversa [x] = [x]"
proof -
  have "inversa [x] = inversa (x#[])" by simp
  also have "… = (inversa []) @ [x]" by simp
  also have "… = [] @ [x]" by simp
  also have "… = [x]" by simp 
  finally show "inversa [x] = [x]" by simp
qed

(* La demostración declarativa detallada es *)
lemma "inversa [x] = [x]"
proof -
  have "inversa [x] = inversa (x#[])"  
    by simp
  also have "… = (inversa []) @ [x]" 
    by (simp only: inversa.simps(2))
  also have "… = [] @ [x]" 
    by (simp only: inversa.simps(1))
  also have "… = [x]" 
    by (simp only: append_Nil) 
  finally show "inversa [x] = [x]" by simp
qed

section Razonamiento por inducción sobre los naturales 

text [Principio de inducción sobre los naturales] Para demostrar una
  propiedad P para todos los números naturales basta probar que el 0
  tiene la propiedad P y que si n tiene la propiedad P, entonces n+1
  también la tiene.  
     P 0; n. P n  P (Suc n)  P m

  En Isabelle el principio de inducción sobre los naturales está
  formalizado en el teorema nat.induct y puede verse con
     thm nat.induct


thm nat.induct

text --------------------------------------------------------------- 
  Ejemplo 7. Definir la función
     repite :: nat  'a  'a list
  tal que (repite n x) es la lista formada por n copias del elemento
  x. Por ejemplo, 
     repite 3 a = [a,a,a]
  ------------------------------------------------------------------ 

fun repite :: "nat ⇒ 'a ⇒ 'a list" where
  "repite 0 x       = []"
| "repite (Suc n) x = x # (repite n x)"

value "repite 3 a = [a,a,a]"

text  --------------------------------------------------------------- 
  Ejemplo 8. (p. 18) Demostrar que 
     longitud (repite n x) = n
  ------------------------------------------------------------------- 

(* La demostración aplicativa es *)
lemma "longitud (repite n x) = n"
  apply (induct n) (* 1. longitud (repite 0 x) = 0
                      2. ⋀n. longitud (repite n x) = n ⟹
                         longitud (repite (Suc n) x) = Suc n *)
   apply simp      (* 1. ⋀n. longitud (repite n x) = n ⟹
                         longitud (repite (Suc n) x) = Suc n *)
  apply simp       (* No subgoals *)
  done

(* La demostración aplicativa con simp_all es *)
lemma "longitud (repite n x) = n"
  apply (induct n) (* 1. longitud (repite 0 x) = 0
                      2. ⋀n. longitud (repite n x) = n ⟹
                         longitud (repite (Suc n) x) = Suc n *)
   apply simp_all  (* No subgoals *)
  done

(* La demostración automática es *)
lemma "longitud (repite n x) = n"
  by (induct n) simp_all

(* La demostración declarativa es *)
lemma "longitud (repite n x) = n"
proof (induct n)
  show "longitud (repite 0 x) = 0" 
    by simp
next 
  fix n
  assume HI: "longitud (repite n x) = n"
  have "longitud (repite (Suc n) x) = longitud (x # (repite n x))" 
    by simp
  also have "… = 1 + longitud (repite n x)" 
    by simp
  also have "… = 1 + n" 
    using HI by simp
  finally show "longitud (repite (Suc n) x) = Suc n" 
    by simp
qed

text Comentarios sobre la demostración anterior:
  · A la derecha de proof se indica el método de la demostración.
  · (induct n) indica que la demostración se hará por inducción en n.
  · Se generan dos subobjetivos correspondientes a la base y el paso de
    inducción:
    1. longitud (repite 0 x) = 0
    2. n. longitud (repite n x) = n  
            longitud (repite (Suc n) x) = Suc n
    donde n se lee "para todo n".  
  · "next" indica el siguiente subobjetivo.
  · "fix n" indica "sea n un número natural cualquiera"
  · assume HI: "longitud (repite n x) = n" indica «supongamos que 
    "longitud (repite n x) = n" y sea HI la etiqueta de este supuesto».
  · "using HI" usando la propiedad etiquetada con HI. 

(* La demostración declarativa detallada es *)
lemma "longitud (repite n x) = n"
proof (induct n)
  show "longitud (repite 0 x) = 0"
    by (simp only: repite.simps(1)
                   longitud.simps(1))
next 
  fix n
  assume HI: "longitud (repite n x) = n"
  have "longitud (repite (Suc n) x) = longitud (x # (repite n x))" 
    by (simp only: repite.simps(2))
  also have "… = 1 + longitud (repite n x)" 
    by (simp only: longitud.simps(2))
  also have "… = 1 + n" 
    by (simp only: HI)
  also have "… = Suc n"
    find_theorems "Suc _ = _ + _"
    by (simp only: Suc_eq_plus1_left)
  finally show "longitud (repite (Suc n) x) = Suc n" 
    by this
qed

section Razonamiento por inducción sobre listas 

text Para demostrar una propiedad para todas las listas basta demostrar
  que la lista vacía tiene la propiedad y que al añadir un elemento a
  una lista que tiene la propiedad se obtiene otra lista que también
  tiene la propiedad. 

  En Isabelle el principio de inducción sobre listas está formalizado
  mediante el teorema list.induct 
     P []; 
      x xs. P xs  P (x#xs) 
      P xs


thm list.induct

text --------------------------------------------------------------- 
  Ejemplo 9. Definir la función
     conc :: 'a list  'a list  'a list
  tal que (conc xs ys) es la concatención de las listas xs e ys. Por
  ejemplo, 
     conc [a,d] [b,d,a,c] = [a,d,b,d,a,c]
  ------------------------------------------------------------------ 

fun conc :: "'a list ⇒ 'a list ⇒ 'a list" where
  "conc []     ys = ys"
| "conc (x#xs) ys = x # (conc xs ys)"

value "conc [a,d] [b,d,a,c] = [a,d,b,d,a,c]"

text  --------------------------------------------------------------- 
  Ejemplo 10. (p. 24) Demostrar que 
     conc xs (conc ys zs) = (conc xs ys) zs
  ------------------------------------------------------------------- 

(* La demostración aplicativa es *)
lemma "conc xs (conc ys zs) = conc (conc xs ys) zs"
  apply (induct xs) (*  1. conc [] (conc ys zs) = conc (conc [] ys) zs
                        2. ⋀a xs.
                              conc xs (conc ys zs) =
                              conc (conc xs ys) zs ⟹
                              conc (a # xs) (conc ys zs) =
                              conc (conc (a # xs) ys) zs *)
   apply simp_all   (* No subgoals! *)
  done  

(* La demostración automática es *)
lemma "conc xs (conc ys zs) = conc (conc xs ys) zs"
  by (induct xs) simp_all

(* La demostración declarativa es *)
lemma "conc xs (conc ys zs) = conc (conc xs ys) zs"
proof (induct xs)
  show "conc [] (conc ys zs) = conc (conc [] ys) zs" 
    by simp
next
  fix x xs
  assume HI: "conc xs (conc ys zs) = conc (conc xs ys) zs" 
  have "conc (x # xs) (conc ys zs) = x # (conc xs (conc ys zs))" 
    by simp
  also have "… = x # (conc (conc xs ys) zs)" 
    using HI by simp
  also have "… = conc (conc (x # xs) ys) zs" 
    by simp
  finally show "conc (x # xs) (conc ys zs) = conc (conc (x # xs) ys) zs" 
    by simp
qed

(* La demostración declarativa detallada es *)
lemma "conc xs (conc ys zs) = conc (conc xs ys) zs"
proof (induct xs)
  show "conc [] (conc ys zs) = conc (conc [] ys) zs" 
    by (simp only: conc.simps(1))
next
  fix x xs
  assume HI: "conc xs (conc ys zs) = conc (conc xs ys) zs" 
  have "conc (x # xs) (conc ys zs) = x # (conc xs (conc ys zs))" 
    by (simp only: conc.simps(2))
  also have "… = x # (conc (conc xs ys) zs)" 
    using HI by (simp only:)
  also have "… = conc (conc (x # xs) ys) zs" 
    by (simp only: conc.simps(2))
  finally show "conc (x # xs) (conc ys zs) = conc (conc (x # xs) ys) zs" 
    by this
qed

text --------------------------------------------------------------- 
  Ejemplo 11. Refutar que 
     conc xs ys = conc ys xs
  ------------------------------------------------------------------- 

lemma "conc xs ys = conc ys xs"
  quickcheck
  oops

text  Encuentra el contraejemplo, 
  xs = [a2]
  ys = [a1] 

text --------------------------------------------------------------- 
  Ejemplo 12. (p. 28) Demostrar que 
     conc xs [] = xs
  ------------------------------------------------------------------- 

(* La demostración aplicativa es *)
lemma "conc xs [] = xs"
  apply (induct xs) (* 1. conc [] [] = []
                       2. ⋀a xs.
                             conc xs [] = xs ⟹
                             conc (a # xs) [] = a # xs *)
   apply simp_all   (* No subgoals! *)
  done  

(* La demostración automática es *)
lemma "conc xs [] = xs"
  by (induct xs) simp_all

(* La demostración declarativa es *)
lemma "conc xs [] = xs"
proof (induct xs)
  show "conc [] [] = []" by simp
next 
  fix x xs
  assume HI: "conc xs [] = xs" 
  have "conc (x # xs) [] = x # (conc xs [])" 
    by simp
  also have "… = x # xs" 
    using HI by simp
  finally show "conc (x # xs) [] = x # xs" 
    by simp
qed

(* declare [[show_types]] *)

(* La demostración declarativa es *)
lemma "conc xs [] = xs"
proof (induct xs)
  show "conc [] [] = []" by simp
next 
  fix x :: "'a" and xs :: "'a list"
  assume HI: "conc xs [] = xs" 
  have "conc (x # xs) [] = x # (conc xs [])" 
    by simp
  also have "… = x # xs" 
    using HI by simp
  finally show "conc (x # xs) [] = x # xs" 
    by simp
qed

(* La demostración declarativa detallada es *)
lemma "conc xs [] = xs"
proof (induct xs)
  show "conc [] [] = []" 
    by (simp only: conc.simps(1))
next 
  fix x :: "'a" and xs :: "'a list"
  assume HI: "conc xs [] = xs" 
  have "conc (x # xs) [] = x # (conc xs [])" 
    by (simp only: conc.simps(2))
  also have "… = x # xs" 
    using HI by (simp only:)
  finally show "conc (x # xs) [] = x # xs" 
    by this
qed

text --------------------------------------------------------------- 
  Ejemplo 13. (p. 30) Demostrar que 
     longitud (conc xs ys) = longitud xs + longitud ys
  ------------------------------------------------------------------- 

(* La demostración aplicativa es *)
lemma "longitud (conc xs ys) = longitud xs + longitud ys"
  apply (induct xs) (* 1. longitud (conc [] ys) =
                          longitud [] + longitud ys
                       2. ⋀a xs.
                             longitud (conc xs ys) =
                             longitud xs + longitud ys ⟹
                             longitud (conc (a # xs) ys) =
                             longitud (a # xs) + longitud ys *) 
   apply simp_all   (* No subgoals! *)
  done  

(* La demostración automática es *)
lemma "longitud (conc xs ys) = longitud xs + longitud ys"
  by (induct xs) simp_all

(* La demostración declarativa es *)
lemma "longitud (conc xs ys) = longitud xs + longitud ys"
proof (induct xs)
  show "longitud (conc [] ys) = longitud [] + longitud ys" by simp
next
  fix x xs
  assume HI: "longitud (conc xs ys) = longitud xs + longitud ys"
  have "longitud (conc (x # xs) ys) = longitud (x # (conc xs ys))" 
    by simp
  also have "… = 1 + longitud (conc xs ys)" 
    by simp
  also have "… = 1 + longitud xs + longitud ys" 
    using HI by simp
  also have "… = longitud (x # xs) + longitud ys" 
    by simp
  finally show "longitud (conc (x # xs) ys) = 
                longitud (x # xs) + longitud ys" 
    by simp
qed

(* La demostración declarativa detallada es *)
lemma "longitud (conc xs ys) = longitud xs + longitud ys"
proof (induct xs)
  show "longitud (conc [] ys) = longitud [] + longitud ys" 
    by (simp only: conc.simps(1)
                   longitud.simps(1))
next
  fix x xs
  assume HI: "longitud (conc xs ys) = longitud xs + longitud ys"
  have "longitud (conc (x # xs) ys) = longitud (x # (conc xs ys))" 
    by (simp only: conc.simps(2))
  also have "… = 1 + longitud (conc xs ys)" 
    by (simp only: longitud.simps(2))
  also have "… = 1 + longitud xs + longitud ys" 
    using HI by (simp only:)
  also have "… = longitud (x # xs) + longitud ys" 
    by (simp only: longitud.simps(2))
  finally show "longitud (conc (x # xs) ys) = 
                longitud (x # xs) + longitud ys" 
    by this
qed

section Inducción correspondiente a la definición recursiva 

text --------------------------------------------------------------- 
  Ejemplo 14. Definir la función
     coge :: nat  'a list  'a list
  tal que (coge n xs) es la lista de los n primeros elementos de xs. Por 
  ejemplo, 
     coge 2 [a,c,d,b,e] = [a,c]
  ------------------------------------------------------------------ 

fun coge :: "nat ⇒ 'a list ⇒ 'a list" where
  "coge n []           = []"
| "coge 0 xs           = []"
| "coge (Suc n) (x#xs) = x # (coge n xs)"

value "coge 2 [a,c,d,b,e] = [a,c]"

text --------------------------------------------------------------- 
  Ejemplo 15. Definir la función
     elimina :: nat  'a list  'a list
  tal que (elimina n xs) es la lista obtenida eliminando los n primeros
  elementos de xs. Por ejemplo, 
     elimina 2 [a,c,d,b,e] = [d,b,e]
  ------------------------------------------------------------------ 

fun elimina :: "nat ⇒ 'a list ⇒ 'a list" where
  "elimina n []           = []"
| "elimina 0 xs           = xs"
| "elimina (Suc n) (x#xs) = elimina n xs"

value "elimina 2 [a,c,d,b,e] = [d,b,e]"

text  
  La definición coge genera el esquema de inducción coge.induct:
     ⟦⋀n. P n []; 
      x xs. P 0 (x#xs); 
      n x xs. P n xs  P (Suc n) (x#xs)
      P n x

  Puede verse usando "thm coge.induct". 

thm coge.induct

text --------------------------------------------------------------- 
  Ejemplo 16. (p. 35) Demostrar que 
     conc (coge n xs) (elimina n xs) = xs
  ------------------------------------------------------------------- 

(* La demostración aplicativa es *)
lemma "conc (coge n xs) (elimina n xs) = xs"
  apply (induct rule: coge.induct) 
      (*  1. ⋀n. conc (coge n []) (elimina n []) = []
          2. ⋀v va. conc (coge 0 (v # va)) (elimina 0 (v # va)) =
                     v # va
          3. ⋀n x xs. conc (coge n xs) (elimina n xs) = xs ⟹
                       conc (coge (Suc n) (x # xs)) 
                            (elimina (Suc n) (x # xs)) =
                       x # xs *)
    apply simp_all
      (* No subgoals! *)
  done

(* La demostración automática es *)
lemma "conc (coge n xs) (elimina n xs) = xs"
  by (induct rule: coge.induct) simp_all

(* La demostración declarativa es *)
lemma "conc (coge n xs) (elimina n xs) = xs"
proof (induct rule: coge.induct)
  fix n
  show "conc (coge n []) (elimina n []) = []" 
    by simp
next
  fix x :: "'a" and xs :: "'a list"
  show "conc (coge 0 (x#xs)) (elimina 0 (x#xs)) = x#xs" 
    by simp
next
  fix n and x :: "'a" and xs :: "'a list"
  assume HI: "conc (coge n xs) (elimina n xs) = xs"
  have "conc (coge (Suc n) (x#xs)) (elimina (Suc n) (x#xs)) = 
        conc (x#(coge n xs)) (elimina n xs)" 
    by simp
  also have "… = x#(conc (coge n xs) (elimina n xs))" 
    by simp
  also have "… = x#xs" 
    using HI by simp  
  finally show "conc (coge (Suc n) (x#xs)) (elimina (Suc n) (x#xs)) = 
                x#xs"
    by simp
qed

text Comentario sobre la demostración anterior:
  · (induct rule: coge.induct) indica que el método de demostración es
    por el esquema de inducción correspondiente a la definición de la
    función coge.
  · Se generan 3 subobjetivos:
    · 1. n. conc (coge n []) (elimina n []) = []
    · 2. x xs. conc (coge 0 (x#xs)) (elimina 0 (x#xs)) = x#xs
    · 3. n x xs. 
            conc (coge n xs) (elimina n xs) = xs 
            conc (coge (Suc n) (x#xs)) (elimina (Suc n) (x#xs)) = x#xs


(* La demostración declarativa detallada es *)
lemma "conc (coge n xs) (elimina n xs) = xs"
proof (induct rule: coge.induct)
  fix n
  show "conc (coge n []) (elimina n []) = []" 
    by (simp only: coge.simps(1)
                   elimina.simps(1)
                   conc.simps(1))
next
  fix x :: "'a" and xs :: "'a list"
  show "conc (coge 0 (x#xs)) (elimina 0 (x#xs)) = x#xs" 
    by (simp only: coge.simps(2)
                   elimina.simps(2)
                   conc.simps(1))
next
  fix n and x :: "'a" and xs :: "'a list"
  assume HI: "conc (coge n xs) (elimina n xs) = xs"
  have "conc (coge (Suc n) (x#xs)) (elimina (Suc n) (x#xs)) = 
        conc (x#(coge n xs)) (elimina n xs)" 
    by (simp only: coge.simps(3)
                   elimina.simps(3))
  also have "… = x#(conc (coge n xs) (elimina n xs))" 
    by (simp only: conc.simps(2))
  also have "… = x#xs" 
    using HI by (simp only:) 
  finally show "conc (coge (Suc n) (x#xs)) (elimina (Suc n) (x#xs)) = 
                x#xs"
    by this
qed

section Razonamiento por casos 

text  --------------------------------------------------------------- 
  Ejemplo 17. Definir la función
     esVacia :: 'a list  bool
  tal que (esVacia xs) se verifica si xs es la lista vacía. Por ejemplo,
     esVacia []  = True
     esVacia [1] = False
  ------------------------------------------------------------------ 

fun esVacia :: "'a list ⇒ bool" where
  "esVacia []     = True"
| "esVacia (x#xs) = False"

value "esVacia []  = True"
value "esVacia [a] = False"

text --------------------------------------------------------------- 
  Ejemplo 18 (p. 39) . Demostrar que 
     esVacia xs = esVacia (conc xs xs)
  ------------------------------------------------------------------- 

(* La demostración aplicativa es *)
lemma "esVacia xs = esVacia (conc xs xs)"
  apply (cases xs) 
     (* 1. xs = [] ⟹ esVacia xs = esVacia (conc xs xs)
        2. ⋀a list. xs = a # list ⟹
                    esVacia xs = esVacia (conc xs xs) *)
   apply simp_all
     (* No subgoals! *)
  done

(* La demostración automática es *)
lemma "esVacia xs = esVacia (conc xs xs)"
  by (cases xs) simp_all

(* La demostración declarativa es *)
lemma "esVacia xs = esVacia (conc xs xs)"
proof (cases xs)
  assume "xs = []"
  then show "esVacia xs = esVacia (conc xs xs)" 
    by simp
next
  fix y ys
  assume "xs = y#ys"
  then show "esVacia xs = esVacia (conc xs xs)" 
    by simp
qed

text Comentarios sobre la demostración anterior:
  · "(cases xs)" es el método de demostración por casos según xs.
  · Se generan dos subobjetivos  correspondientes a los dos
    constructores de listas:
    · 1. xs = []  esVacia xs = esVacia (conc xs xs)
    · 2. y ys. xs = y#ys  esVacia xs = esVacia (conc xs xs)
  · "then" indica "usando la propiedad anterior"


(* La demostración declarativa detallada es *)
lemma "esVacia xs = esVacia (conc xs xs)"
proof (cases xs)
  assume "xs = []"
  then show "esVacia xs = esVacia (conc xs xs)" 
    by (simp only: conc.simps(1))
next
  fix y ys
  assume "xs = y#ys"
  then show "esVacia xs = esVacia (conc xs xs)" 
    by (simp only: esVacia.simps(2)
                   conc.simps(2))
qed

(* La demostración declarativa simplificada es *)
lemma "esVacia xs = esVacia (conc xs xs)"
proof (cases xs)
  case Nil
  then show "esVacia xs = esVacia (conc xs xs)" 
    by simp
next
  case Cons
  then show "esVacia xs = esVacia (conc xs xs)" 
    by simp
qed

text 
  Comentarios sobre la demostración anterior:
  · "case Nil" es una abreviatura de "assume xs = []"
  · "case Cons" es una abreviatura de "fix y ys assume xs = y#ys"

(* La demostración con el patrón sugerido es *)
lemma "esVacia xs = esVacia (conc xs xs)"
proof (cases xs)
  case Nil
  then show ?thesis by simp
next
  case (Cons x xs)
  then show ?thesis by simp
qed

section Heurística de generalización 

text --------------------------------------------------------------- 
  Ejemplo 19. Definir la función
     inversaAc :: 'a list  'a list
  tal que (inversaAc xs) es a inversa de xs calculada usando
  acumuladores. Por ejemplo, 
     inversaAc [a,c,b,e] = [e,b,c,a]
  ------------------------------------------------------------------ 

fun inversaAcAux :: "'a list ⇒ 'a list ⇒ 'a list" where
  "inversaAcAux [] ys     = ys"
| "inversaAcAux (x#xs) ys = inversaAcAux xs (x#ys)"

definition inversaAc :: "'a list ⇒ 'a list" where
  "inversaAc xs = inversaAcAux xs []"

value "inversaAc [a,c,b,e] = [e,b,c,a]"

text Lema. [Ejemplo de equivalencia entre las definiciones]
  La inversa de [a,b,c] es lo mismo calculada con la primera definición
  que con la segunda.

lemma "inversaAc [a,b,c] = inversa [a,b,c]"
  by (simp add: inversaAc_def)

text Nota. [Ejemplo fallido de demostración por inducción]
  El siguiente intento de demostrar que para cualquier lista xs, se
  tiene que  "inversaAc xs = inversa xs" falla.

lemma "inversaAc xs = inversa xs"
proof (induct xs)
  show "inversaAc [] = inversa []" 
    by (simp add: inversaAc_def)
next
  fix a :: "'b" and xs :: "'b list" 
  assume HI: "inversaAc xs = inversa xs"
  have "inversaAc (a#xs) = inversaAcAux (a#xs) []" 
    by (simp add: inversaAc_def)
  also have "… = inversaAcAux xs [a]" 
    by simp
  also have "… = inversa (a#xs)"
  (* Problema: la hipótesis de inducción no es aplicable. *)
oops

text Nota. [Heurística de generalización]
  Cuando se use demostración estructural, cuantificar universalmente las 
  variables libres (o, equivalentemente, considerar las variables libres
  como variables arbitrarias).

  Lema. [Lema con generalización]
  Para toda lista ys se tiene 
     inversaAcAux xs ys = (inversa xs) @ ys


text --------------------------------------------------------------- 
  Ejemplo 20. (p. 44) Demostrar que 
     inversaAcAux xs ys = (inversa xs) @ ys
  ------------------------------------------------------------------- 

(* La demostración aplicativa es *)
lemma "inversaAcAux xs ys = (inversa xs)@ys"
  apply (induct xs arbitrary: ys) 
     (* 1. ⋀ys. inversaAcAux [] ys = inversa [] @ ys
        2. ⋀a xs ys.
              (⋀ys. inversaAcAux xs ys = inversa xs @ ys) ⟹
              inversaAcAux (a # xs) ys = inversa (a # xs) @ ys *)
   apply simp_all
     (* No subgoals! *)
  done

(* La demostración automática es *)
lemma "inversaAcAux xs ys = (inversa xs)@ys"
  by (induct xs arbitrary: ys) simp_all

(* La demostración declarativa es *)
lemma
  "inversaAcAux xs ys = (inversa xs) @ ys"
proof (induct xs arbitrary: ys)
  show "⋀ys. inversaAcAux [] ys = (inversa [])@ys" 
    by simp
next
  fix a :: "'b" and xs :: "'b list" 
  assume HI: "⋀ys. inversaAcAux xs ys = inversa xs@ys"
  show "⋀ys. inversaAcAux (a#xs) ys = inversa (a#xs)@ys"
  proof -
    fix ys
    have "inversaAcAux (a#xs) ys = inversaAcAux xs (a#ys)" 
      by simp
    also have "… = inversa xs@(a#ys)" 
      using HI by simp
    also have "… = inversa (a#xs)@ys" using [[simp_trace]] 
      by simp 
    finally show "inversaAcAux (a#xs) ys = inversa (a#xs)@ys" 
      by simp
  qed
qed

text Comentarios sobre la demostración anterior:
  · "(induct xs arbitrary: ys)" es el método de demostración por
    inducción sobre xs usando ys como variable arbitraria.
  · Se generan dos subobjetivos:
    · 1. ys. inversaAcAux [] ys = inversa [] @ ys
    · 2. a xs ys. (ys. inversaAcAux xs ys = inversa xs @ ys) 
                    inversaAcAux (a # xs) ys = inversa (a # xs) @ ys
  · Dentro de una demostración se pueden incluir otras demostraciones.
  · Para demostrar la propiedad universal "⋀ys. P(ys)" se elige una
    lista arbitraria (con "fix ys") y se demuestra "P(ys)". 

text Nota. En el paso "inversa xs@(a#ys) = inversa (a#xs)@ys" se usan
  lemas de la teoría List. Se puede observar, insertano 
     using [[simp_trace]]
  entre la igualdad y by simp, que los lemas usados son 
  · List.append_simps_1: []@ys = ys
  · List.append_simps_2: (x#xs)@ys = x#(xs@ys)
  · List.append_assoc:   (xs @ ys) @ zs = xs @ (ys @ zs)
  Las dos primeras son las ecuaciones de la definición de append.

  En la siguiente demostración se detallan los lemas utilizados.


 Demostración aplicativa
lemma "(inversa xs)@(a#ys) = (inversa (a#xs))@ys"
  apply (simp only: inversa.simps(2))
    (* inversa xs @ (a # ys) = (inversa xs @ [a]) @ ys*)
  apply (simp only: append_assoc)
    (* inversa xs @ (a # ys) = inversa xs @ ([a] @ ys) *)
  apply (simp only: append.simps(2))
    (* inversa xs @ (a # ys) = inversa xs @ (a # ([] @ ys)) *)
  apply (simp only: append.simps(1))
    (* *)
  done

 Demostración declarativa detallada del lema auxiliar
lemma auxiliar: "(inversa xs)@(a#ys) = (inversa (a#xs))@ys"
proof -
  have "(inversa xs)@(a#ys) = (inversa xs)@(a#([]@ys))" 
    by (simp only: append.simps(1))
  also have "… = (inversa xs)@([a]@ys)" 
    by (simp only: append.simps(2))
  also have "… = ((inversa xs)@[a])@ys" 
    by (simp only: append_assoc)
  also have "… = (inversa (a#xs))@ys" 
    by (simp only: inversa.simps(2))
  finally show ?thesis 
    by this
qed

(* La demostración declarativa detallada es *)
lemma inversaAcAux_es_inversa:
  "inversaAcAux xs ys = (inversa xs) @ ys"
proof (induct xs arbitrary: ys)
  fix ys :: "'b list"
  show "inversaAcAux [] ys = (inversa [])@ys" 
    by (simp only: inversaAcAux.simps(1)
                   inversa.simps(1)
                   append.simps(1))
next
  fix a :: "'b" and xs :: "'b list"
  assume HI: "⋀ys. inversaAcAux xs ys = inversa xs@ys"
  show "⋀ys. inversaAcAux (a#xs) ys = inversa (a#xs)@ys"
  proof -
    fix ys
    have "inversaAcAux (a#xs) ys = inversaAcAux xs (a#ys)" 
      by (simp only: inversaAcAux.simps(2))
    also have "… = inversa xs@(a#ys)" 
      using HI by (simp only:)
    also have "… = inversa (a#xs)@ys" 
      by (rule auxiliar) 
    finally show "inversaAcAux (a#xs) ys = inversa (a#xs)@ys" 
      by this
  qed
qed

text --------------------------------------------------------------- 
  Ejemplo 21. (p. 43) Demostrar que 
     inversaAc xs = inversa xs
  ------------------------------------------------------------------- 

(* La demostración aplicativa es *)
corollary "inversaAc xs = inversa xs"
  apply (simp add: inversaAcAux_es_inversa inversaAc_def)
  done 

(* La demostración automática es *)
corollary "inversaAc xs = inversa xs"
  by (simp add: inversaAcAux_es_inversa inversaAc_def)

text Comentario de la demostración anterior:
  · "(simp add: inversaAcAux_es_inversa inversaAc_def)" es el método de 
    demostración por simplificación usando como regla de simplificación 
    las propiedades inversaAcAux_es_inversa e inversaAc_def. 
 
section Demostración por inducción para funciones de orden superior 

text  --------------------------------------------------------------- 
  Ejemplo 22. Definir la función
     sum :: nat list  nat
  tal que (sum xs) es la suma de los elementos de xs. Por ejemplo,
     sum [3,2,5] = 10
  ------------------------------------------------------------------ 

fun sum :: "nat list ⇒ nat" where
  "sum []     = 0"
| "sum (x#xs) = x + sum xs"

value "sum [3,2,5] = 10"

text --------------------------------------------------------------- 
  Ejemplo 23. Definir la función
     map :: ('a  'b)  'a list  'b list
  tal que (map f xs) es la lista obtenida aplicando la función f a los
  elementos de xs. Por ejemplo,
     map (λx. 2*x) [3::nat,2,5] = [6,4,10]
     map ((*) 2) [3::nat,2,5] = [6,4,10]
     map ((+) 2)   [3::nat,2,5] = [5,4,7]
  ------------------------------------------------------------------ ›

fun map :: "('a ⇒ 'b) ⇒ 'a list ⇒ 'b list" where
  "map f []     = []"
| "map f (x#xs) = (f x) # map f xs"

value "map (λx. 2*x) [3::nat,2,5] = [6,4,10]"
value "map ((*) 2)   [3::nat,2,5] = [6,4,10]"
value "map ((+) 2)   [3::nat,2,5] = [5,4,7]"

text ‹--------------------------------------------------------------- 
  Ejemplo 24. (p. 45) Demostrar que 
     sum (map ((*) 2) xs) = 2 * (sum xs)
  ------------------------------------------------------------------- ›

(* La demostración aplicativa es *)
lemma "sum (map ((*) 2) xs) = 2 * (sum xs)"
  apply (induct xs) 
     (* 1. sum (map (( * ) 2) []) = 2 * sum []
        2. ⋀a xs. sum (map (( * ) 2) xs) = 2 * sum xs ⟹
                  sum (map (( * ) 2) (a # xs)) = 2 * sum (a # xs) *)
   apply simp_all
     (* No subgoals! *)
  done

(* La demostración automática es *)
lemma "sum (map ((*) 2) xs) = 2 * (sum xs)"
  by (induct xs) simp_all

(* La demostración declarativa es *)
lemma "sum (map ((*) 2) xs) = 2 * (sum xs)"
proof (induct xs)
  show "sum (map ((*) 2) []) = 2 * (sum [])" by simp
next
  fix a xs
  assume HI: "sum (map ((*) 2) xs) = 2 * (sum xs)"
  have "sum (map ((*) 2) (a#xs)) = sum ((2*a)#(map ((*) 2) xs))" 
    by simp
  also have "… = 2*a + sum (map ((*) 2) xs)" 
    by simp
  also have "… = 2*a + 2*(sum xs)" 
    using HI by simp
  also have "… = 2*(a + sum xs)" 
    by simp
  also have "… = 2*(sum (a#xs))" 
    by simp
  finally show "sum (map ((*) 2) (a#xs)) = 2*(sum (a#xs))" 
    by simp
qed

(* La demostración declarativa detallada es *)
lemma "sum (map ((*) 2) xs) = 2 * (sum xs)"
proof (induct xs)
  show "sum (map ((*) 2) []) = 2 * (sum [])" 
    by (simp only: map.simps(1)
                   sum.simps(1))
next
  fix a xs
  assume HI: "sum (map ((*) 2) xs) = 2 * (sum xs)"
  have "sum (map ((*) 2) (a#xs)) = sum ((2*a)#(map ((*) 2) xs))" 
    by (simp only: map.simps(2))
  also have "… = 2*a + sum (map ((*) 2) xs)" 
    by (simp only: sum.simps(2))
  also have "… = 2*a + 2*(sum xs)" 
    using HI by (simp only:)
  also have "… = 2*(a + sum xs)" 
    find_theorems "_ * (_ + _)"
    by (simp only: add_mult_distrib2)
  also have "… = 2*(sum (a#xs))" 
    by (simp only: sum.simps(2))
  finally show "sum (map ((*) 2) (a#xs)) = 2*(sum (a#xs))" 
    by this
qed

text ‹ --------------------------------------------------------------- 
  Ejemplo 25. (p. 48) Demostrar que 
     longitud (map f xs) = longitud xs
  ------------------------------------------------------------------- ›

(* La demostración aplicativa es *)
lemma "longitud (map f xs) = longitud xs"
  apply (induct xs) 
     (* 1. longitud (map f []) = longitud []
        2. ⋀a xs. longitud (map f xs) = longitud xs ⟹
                   longitud (map f (a # xs)) = longitud (a # xs) *)
   apply simp_all
     (* No subgoals! *)
  done

(* La demostración automática es *)
lemma "longitud (map f xs) = longitud xs"
  by (induct xs) simp_all

(* La demostración declarativa es *)
lemma "longitud (map f xs) = longitud xs"
proof (induct xs)
  show "longitud (map f []) = longitud []" 
    by simp
next
  fix a xs
  assume HI: "longitud (map f xs) = longitud xs"
  have "longitud (map f (a#xs)) = longitud (f a # (map f xs))" 
    by simp
  also have "… = 1 + longitud (map f xs)" 
    by simp
  also have "… = 1 + longitud xs" 
    using HI by simp
  also have "… = longitud (a#xs)" 
    by simp
  finally show "longitud (map f (a#xs)) = longitud (a#xs)" 
    by simp
qed

(* La demostración declarativa detallada es *)
lemma "longitud (map f xs) = longitud xs"
proof (induct xs)
  show "longitud (map f []) = longitud []" 
    by (simp only: map.simps(1)
                   longitud.simps(1))
next
  fix a xs
  assume HI: "longitud (map f xs) = longitud xs"
  have "longitud (map f (a#xs)) = longitud (f a # (map f xs))" 
    by (simp only: map.simps(2))
  also have "… = 1 + longitud (map f xs)" 
    by (simp only: longitud.simps(2))
  also have "… = 1 + longitud xs" 
    using HI by (simp only:)
  also have "… = longitud (a#xs)" 
    by (simp only: longitud.simps(2))
  finally show "longitud (map f (a#xs)) = longitud (a#xs)" 
    by this
qed

section ‹Referencias›

text ‹
  · J.A. Alonso. "Razonamiento sobre programas" http://goo.gl/R06O3
  · G. Hutton. "Programming in Haskell". Cap. 13 "Reasoning about
    programms". 
  · S. Thompson. "Haskell: the Craft of Functional Programming, 3rd
    Edition. Cap. 8 "Reasoning about programms". 
  · L. Paulson. "ML for the Working Programmer, 2nd Edition". Cap. 6. 
    "Reasoning about functional programs". 


end