Skip to Content

Programas Funcionales

Especificaciones (PF)

Suponiendo que sabemos la definición de un programa dado:

 sum:[Num]Num  sum.[]0 sum.(xxs)x+sum.xs\begin{aligned} &\Big\vert\ sum : [Num] \to Num \\ &\overline{\Big\vert \; sum.[] \doteq 0} \\ &\Big\vert\ sum.(x \triangleright xs) \doteq x + sum.xs \end{aligned}

Por la definición de la función o por el problema que se nos plantea, podemos escribir una especificación mediante una expresión cuantificada:

sum.xs=  i:0i<#xs:xs.i  sum.xs = \bigl \langle \; \sum i : 0 \leq i < \# xs : xs.i \; \bigr \rangle

Ya tenemos una una descripción formal de la tarea que el programa tiene que realizar

Derivaciones (PF)

Podemos no disponer de la definición de la función, pero sí de una especificación. En este caso, podemos derivar la definición de la función a partir de la especificación.

Por ejemplo, para encontrar el programa de la función sumsum a partir de la especificación:

sum.xs=  i:0i<#xs:xs.i  sum.xs = \bigl \langle \; \sum i : 0 \leq i < \# xs : xs.i \; \bigr \rangle

Caso base (cuanto vale sum.[]sum.[])

sum.[]{ Especificacioˊn de sum  }  i:0i<#[]:[].i  { Definicioˊn de #  }  i:0i<0:[].i  { Aritmeˊtica }  i:False:[].i  { Rango vacıˊ}0\begin{aligned} &\underline{sum.[]} \\ &\\ &\equiv \{ \textnormal{ Especificación de } sum \; \} \\ &\\ &\bigl \langle \; \sum i : 0 \leq i < \underline{ \# []} : [].i \; \bigr \rangle \\ &\\ &\equiv \{ \textnormal{ Definición de } \# \; \} \\ &\\ &\bigl \langle \; \sum i : \underline{0 \leq i < 0 }: [].i \; \bigr \rangle \\ &\\ &\equiv \{ \textnormal{ Aritmética } \} \\ &\\ &\bigl \langle \; \sum i : \underline{False} : [].i \; \bigr \rangle \\ &\\ &\equiv \{ \textnormal{ Rango vacío } \} \\ &\\ &0 \end{aligned}

Por lo tanto, sum.[]=0sum.[] = 0

Paso inductivo (cuanto vale sum.(xxs)sum.(x \triangleright xs))

HI:sum.xs=  i:0i<#xs:xs.i  HI : sum.xs = \bigl \langle \; \sum i : 0 \leq i < \# xs : xs.i \; \bigr \rangle sum.(xxs){ Especificacioˊn de sum  }  i:0i<#(xxs):(xxs).i  { Definicioˊn de #  }  i:0i<1+#xs:(xxs).i  { Separacioˊn de un teˊrmino }(xxs).0+  i:0i<#xs:(xxs).(i+1)  { Definicioˊn de .  }x+  i:0i<#xs:xs.i  { Hipoˊtesis inductiva }x+sum.xs\begin{aligned} &\underline{sum.(x \triangleright xs)} \\ &\\ &\equiv \{ \textnormal{ Especificación de } sum \; \} \\ &\\ &\bigl \langle \; \sum i : 0 \leq i < \underline{\# (x \triangleright xs)} : (x \triangleright xs).i \; \bigr \rangle \\ &\\ &\equiv \{ \textnormal{ Definición de } \# \; \} \\ &\\ &\underline{\bigl \langle \; \sum i : 0 \leq i < 1 + \# xs : (x \triangleright xs).i \; \bigr \rangle \\} \\ &\\ &\equiv \{ \textnormal{ Separación de un término } \} \\ &\\ &\underline{(x \triangleright xs).0} + \bigl \langle \; \sum i : 0 \leq i < \# xs : \underline{(x \triangleright xs).(i + 1)} \; \bigr \rangle \\ &\\ &\equiv \{ \textnormal{ Definición de } . \; \} \\ &\\ &x + \underline{\bigl \langle \; \sum i : 0 \leq i < \# xs : xs.i \; \bigr \rangle} \\ &\\ &\equiv \{ \textnormal{ Hipótesis inductiva } \} \\ &\\ &x + sum.xs \end{aligned}

Por lo tanto, sum.(xxs)=x+sum.xssum.(x \triangleright xs) = x + sum.xs

El programa sería:

 sum:[Num]Num  sum.[]0 sum.(xxs)x+sum.xs\begin{aligned} &\Big\vert\ sum : [Num] \to Num \\ &\overline{\Big\vert \; sum.[] \doteq 0} \\ &\Big\vert\ sum.(x \triangleright xs) \doteq x + sum.xs \end{aligned}

Podemos recurrir a otras técnicas para derivar, estas se encuentran más abajo.


Análisis por casos

Supongamos que nuestro programa tiene la siguiente especificación:

sum_par.n+  i:0inpar.i:i  sum \_ par.n + \bigl \langle \; \sum i : 0 \leq i \leq n \land par.i : i \; \bigr \rangle

Y en nuestro paso inductivo (n+1)(n + 1) llegamos a la siguiente expresión:

sum_par.n+  i:i=n+1par.(n+1):i  sum \_ par.n + \bigl \langle \; \sum i : i = n + 1 \land par.(n + 1) : i \; \bigr \rangle

Observemos que la expresión par.(n+1)par.(n + 1) puede ser verdadera o falsa, por lo que debemos analizar ambos casos:

Caso 1: par.(n+1)par.(n + 1)

sum_par.n+  i:i=n+1par.(n+1):i  {  Caso 1:  par.(n+1)  }sum_par.n+  i:i=n+1True:i  ...sum_par.n+n+1\begin{aligned} &sum \_ par.n + \bigl \langle \; \sum i : i = n + 1 \land \underline{par.(n + 1)} : i \; \bigr \rangle \\ &\\ &\equiv \{ \; \textnormal{Caso 1:} \; par.(n + 1) \; \} \\ &\\ &sum \_ par.n + \bigl \langle \; \sum i : i = n + 1 \land True : i \; \bigr \rangle \\ &\\ &... \\ &\\ &sum \_ par.n + n + 1 \end{aligned}

Caso 2: ¬par.(n+1)\neg par.(n + 1)

sum_par.n+  i:i=n+1par.(n+1):i  {  Caso 2:  ¬par.(n+1)  }sum_par.n+  i:i=n+1False:i  ...sum_par.n\begin{aligned} &sum \_ par.n + \bigl \langle \; \sum i : i = n + 1 \land \underline{par.(n + 1)} : i \; \bigr \rangle \\ &\\ &\equiv \{ \; \textnormal{Caso 2:} \; \neg par.(n + 1) \; \} \\ &\\ &sum \_ par.n + \bigl \langle \; \sum i : i = n + 1 \land False : i \; \bigr \rangle \\ &\\ &... \\ &\\ &sum \_ par.n \end{aligned}

Nuestra definición final sería:

 sum_par:NumNum  sum_par.00 sum_par.(n+1)(   par.(n+1)sum_par.n+n+1   ¬par.(n+1)sum_par.n )\begin{aligned} &\Big\vert\ sum \_ par : Num \to Num \\ &\overline{\Big\vert \; sum \_ par.0 \doteq 0} \\ &\Big\vert\ sum \_ par.(n + 1) \doteq ( \\ &\Big\vert\ \Box \; par.(n+1) → sum \_ par.n + n + 1 \\ &\Big\vert\ \Box \; \neg par.(n+1) → sum \_ par.n \\ &\Big\vert\ ) \end{aligned}

Modularización

Supongamos que nuestro programa tiene la siguiente especificación:

f.x.n=  i:0in:xi  f.x.n = \bigl \langle \; \sum i : 0 \leq i \leq n : x^i \; \bigr \rangle

Y en nuestro paso inductivo (n+1)(n + 1) llegamos a la siguiente expresión:

f.x.n+xnf.x.n + \textcolor{darkred}{x^n}

La expresión xnx^n tiene sentido en el lenguaje de la matemática, no de los programas.
Podemos modularizar la expresión derivando otra función tal que:

exp.x.n=xnexp.x.n = x^n

Tras derivarla obtenemos:

 exp:NumNumNum  exp.x.01 exp.x.(n+1)nexp.x.n\begin{aligned} &\Big\vert\ exp : Num \to Num \to Num \\ &\overline{\Big\vert \; exp.x.0 \doteq 1} \\ &\Big\vert\ exp.x.(n + 1) \doteq n * exp.x.n \end{aligned}

Y podemos reemplazar la expresión en nuestra definición:

 f:NumNumNum  f.x.0x f.x.(n+1)f.x.n+exp.x.n\begin{aligned} &\Big\vert\ f : Num \to Num \to Num \\ &\overline{\Big\vert \; f.x.0 \doteq x} \\ &\Big\vert\ f.x.(n + 1) \doteq f.x.n + exp.x.n \end{aligned}

Generalización

Supongamos que nuestro programa tiene la siguiente especificación:

psum.xs=  i:0i<#xs:sum.(xsi)0  psum.xs = \bigl \langle \; \forall i : 0 \leq i < \# xs : sum.(xs↑i) \geq 0 \; \bigr \rangle

Al seguir en el paso inductivo (xxs)(x \triangleright xs), llegamos a la siguiente expresión:

psum.(xxs){ Especificacioˊn de psum}  i:0i<#(xxs):sum.((xxs)i)0  { Definicioˊn de #}  i:0i<1+#xs:sum.((xxs)i)0  { Aritmeˊtica }  i:i=01i<#xs+1:sum.((xxs)i)0  { Particioˊn de Rango }  i:i=0:sum.((xxs)i)0        i:1i<#xs+1:sum.((xxs)i)0  { Rango unitario, Cambio de Variable: i /leftarrow i + 1 }sum.((xxs)0)0      i:1i<#xs+1:sum.((xxs)(i+1))0  { Definicioˊn de , Aritmeˊtica }sum.[]0  i:0i<#xs:sum.((x(xsi)))0  { Definicioˊn de sum}00  i:0i<#xs:x+sum.(xsi)0  { Aritmeˊtica, Elemento neutro de }  i:0i<#xs:x+sum.(xsi)0  \begin{aligned} &\underline{psum}.(x \triangleright xs) \\ &\\ &\equiv \{ \textnormal{ Especificación de } psum \} \\ &\\ &\bigl \langle \; \forall i : 0 \leq i < \underline{\# (x \triangleright xs)} : sum.((x \triangleright xs)↑i) \geq 0 \; \bigr \rangle \\ &\\ &\equiv \{ \textnormal{ Definición de } \# \} \\ &\\ &\bigl \langle \; \forall i : \underline{0 \leq i < 1 + \# xs} : sum.((x \triangleright xs)↑i) \geq 0 \; \bigr \rangle \\ &\\ &\equiv \{ \textnormal{ Aritmética } \} \\ &\\ &\bigl \langle \; \forall i : \underline{i = 0 \lor 1 \leq i < \# xs + 1} : sum.((x \triangleright xs)↑i) \geq 0 \; \bigr \rangle \\ &\\ &\equiv \{ \textnormal{ Partición de Rango } \} \\ &\\ &\underline{\bigl \langle \; \forall i : i = 0 : sum.((x \triangleright xs)↑i) \geq 0 \; \bigr \rangle \; \land \; \bigl \langle \; \forall i : 1 \leq i < \# xs + 1 : sum.((x \triangleright xs)↑i) \geq 0 \; \bigr \rangle} \\ &\\ &\equiv \{ \textnormal{ Rango unitario, Cambio de Variable: i /leftarrow i + 1 } \} \\ &\\ &sum.((\underline{x \triangleright xs)↑0}) \geq 0 \; \land \; \bigl \langle \; \forall i : 1 \leq i < \# xs + 1 : sum.(\underline{(x \triangleright xs)↑(i + 1)}) \geq 0 \; \bigr \rangle \\ &\\ &\equiv \{ \textnormal{ Definición de } ↑, \textnormal{ Aritmética } \} \\ &\\ &\underline{sum.[]} \geq 0 \land \bigl \langle \; \forall i : 0 \leq i < \# xs : \underline{sum.((x \triangleright (xs↑i)))} \geq 0 \; \bigr \rangle \\ &\\ &\equiv \{ \textnormal{ Definición de } sum \} \\ &\\ &\underline{0 \geq 0} \land \bigl \langle \; \forall i : 0 \leq i < \# xs : x + sum.(xs↑i) \geq 0 \; \bigr \rangle \\ &\\ &\equiv \{ \textnormal{ Aritmética, Elemento neutro de } \land \} \\ &\\ &\bigl \langle \; \forall i : 0 \leq i < \# xs : x + sum.(xs↑i) \geq 0 \; \bigr \rangle \end{aligned}

No aplicar nuestra Hipótesis Inductiva, ya que tenemos:

  i:0i<#xs:sum.(xsi)0    (HI)  i:0i<#xs:x+sum.(xsi)0  \begin{aligned} &\bigl \langle \; \forall i : 0 \leq i < \# xs : sum.(xs↑i) \geq 0 \; \bigr \rangle \; (HI) \\ &\\ &\bigl \langle \; \forall i : 0 \leq i < \# xs : \textcolor{darkred}{x} + sum.(xs↑i) \geq 0 \; \bigr \rangle \end{aligned}

Podemos generalizar psumpsum definiendo una nueva función gpsumgpsum, de forma tal que:

gpsum.n.xs=  i:0i<n:n+sum.(xsi)0  gpsum.n.xs = \bigl \langle \; \forall i : 0 \leq i < n : \textcolor{darkred}{n} + sum.(xs↑i) \geq 0 \; \bigr \rangle

Podemos decir que psum.xs=gpsum.0.xspsum.xs = gpsum.0.xs, ya que:

gpsum.0.xs{ Especificacioˊn de gpsum}  i:0i<0:0+sum.(xsi)0  { Aritmeˊtica }  i:0i<0:sum.(xsi)0  { Especificacioˊn de psum}psum.xs\begin{aligned} &\underline{gpsum}.0.xs \\ &\\ &\equiv \{ \textnormal{ Especificación de } gpsum \} \\ &\\ &\bigl \langle \; \forall i : 0 \leq i < \underline{0} : \underline{0 + sum.(xs↑i)} \geq 0 \; \bigr \rangle \\ &\\ &\equiv \{ \textnormal{ Aritmética } \} \\ &\\ &\underline{\bigl \langle \; \forall i : 0 \leq i < 0 : sum.(xs↑i) \geq 0 \; \bigr \rangle} \\ &\\ &\equiv \{ \textnormal{ Especificación de } psum \} \\ &\\ &psum.xs \end{aligned}  psum:[Num]Bool  psum.xsgpsum.0.xs\begin{aligned} &\Big\vert\ psum : [Num] \to Bool \\ &\overline{\Big\vert \; psum.xs} \doteq gpsum.0.xs \end{aligned}

Una vez derivado gpsumgpsum, tendremos dos programas finales:

 gpsum:Num[Num]Bool  gpsum.n.[]... gpsum.n.(xxs)...\begin{aligned} &\Big\vert\ gpsum : Num \to [Num] \to Bool \\ &\overline{\Big\vert \; gpsum.n.[]} \doteq ... \\ &\Big\vert\ gpsum.n.(x \triangleright xs) \doteq ... \end{aligned}  psum:[Num]Bool  psum.xsgpsum.0.xs\begin{aligned} &\Big\vert\ psum : [Num] \to Bool \\ &\overline{\Big\vert \; psum.xs} \doteq gpsum.0.xs \end{aligned}

Esquemas de Inducción

En algunos casos los esquemas inductivos convencionales no son los necesarios para derivar.

En el caso de la inducción con naturales, tenemos:

Inducción Básica:

f.0  ?f.(n+1)  ?\begin{aligned} f.0 &\doteq \; ? \\ f.(n + 1) &\doteq \; ? \end{aligned}

Inducción a lo Fibonacci:

fib.00fib.11fib.(n+2)fib.(n+1)+fib.n\begin{aligned} fib.0 &\doteq 0 \\ fib.1 &\doteq 1 \\ fib.(n + 2) &\doteq fib.(n + 1) + fib.n \end{aligned}

En el caso de la inducción con listas, tenemos:

Inducción básica: (sumsum, prodprod, etc.)

f.[]?f.(xxs)?\begin{aligned} f.[] &\doteq ? \\ f.(x \triangleright xs) &\doteq ? \end{aligned}

Inducción con dos o más elementos: (funciones igualesiguales, minimominimo y crecientecreciente)

f.[]?f.[x]?f.(xyxs)?\begin{aligned} f.[] &\doteq ? \\ f.[x] &\doteq ? \\ f.(x \triangleright y \triangleright xs) &\doteq ? \end{aligned}

Ejemplo:

minimo.xs=  Min  i:0i<#xs:xs.iminimo.xs = \bigl \langle \; \textnormal{Min} \; i : 0 \leq i < \# xs : xs.i \bigr \rangle

Si derivamos y el caso base es [][] , tendremos como resultado \infty.
Necesitamos reemplazar el caso base por [x][x] y el Paso inductivo por (xyxs)(x \triangleright y \triangleright xs).


Segmentos de listas

Podemos buscar un segmento inicial de una lista derivando la siguiente especificación.

Q.xs.ys=  bs::ys=xs    bs  Q.xs.ys = \bigl \langle \; \exists bs :: ys = xs \; \textnormal{⧺} \; bs \; \bigr \rangle

Para derivarlo, nuestro esquema inductivo debe ser el siguiente:

Caso Base 1: (xs=[],ysxs = [], ys)

Caso Base 2: (xs,ys=[]xs, ys = [])

Paso Inductivo: (xxs,yysx \triangleright xs, y \triangleright ys)


Ejercicios resueltos - Derivaciones y evaluaciones (PF)

1.

Calcular el resultado para la lista [1,2,3,4][1, 2, 3, 4] dada la siguiente especificación:

sum.xs=  i:0i<#xs:xs.i  sum.xs = \bigl \langle \; \sum i : 0 \leq i < \# xs : xs.i \; \bigr \rangle

Aplicamos la especificación de sumsum para la lista [1,2,3,4][1, 2, 3, 4]:

sum.[1,2,3,4]{ Especificacioˊn de sum  }  i:0i<#[1,2,3,4]:[1,2,3,4].i  { Calculo rango sabiendo #xs=4  }  i:i{0,1,2,3}:[1,2,3,4].i  { Aplico el teˊrmino a cada elemento del rango }[1,2,3,4].0+[1,2,3,4].1+[1,2,3,4].2+[1,2,3,4].3{ Evaluˊo indexaciones }1+2+3+4{ Aritmeˊtica }10\begin{aligned} &\underline{sum}.[1, 2, 3, 4] \\ &\\ &\equiv \{ \textnormal{ Especificación de } sum \; \} \\ &\\ &\bigl \langle \; \sum i : \underline{0 \leq i < \# [1, 2, 3, 4]} : [1, 2, 3, 4].i \; \bigr \rangle \\ &\\ &\equiv \{ \textnormal{ Calculo rango sabiendo } \#xs = 4 \; \} \\ &\\ &\bigl \langle \; \underline{\sum i : i \in \{0, 1, 2, 3\} : [1, 2, 3, 4].i} \; \bigr \rangle \\ &\\ &\equiv \{ \textnormal{ Aplico el término a cada elemento del rango } \} \\ &\\ &\underline{[1, 2, 3, 4].0} + \underline{[1, 2, 3, 4].1} + \underline{[1, 2, 3, 4].2} + \underline{[1, 2, 3, 4].3} \\ &\\ &\equiv \{ \textnormal{ Evalúo indexaciones } \} \\ &\\ &\underline{1 + 2 + 3 + 4} \\ &\\ &\equiv \{ \textnormal{ Aritmética } \} \\ &\\ &10 \end{aligned}

El resultado para la lista [1,2,3,4][1, 2, 3, 4] es 1010.


2.

Derivar la función pin8pin8 a partir de la especificación (donde prodprod es una función que devuelve el producto de los elementos de una lista):

pin8.xs=  as,bs:xs=as    bs:prod.as=8  pin8.xs = \bigl \langle \; \exists as, bs : xs = as \; \textnormal{⧺} \; bs : prod.as = 8 \; \bigr \rangle

Primero evaluamos el caso base, xs=[]xs = []:

pin8.[]{ Especificacioˊn de pin8  }  as,bs:[]=as    bs:prod.as=8  { Propiedad de     }  as,bs:as=[]bs=[]:prod.as=8  { Eliminacioˊn de variable as  }  bs:bs=[]:prod.[]=8  { Rango unitario  }prod.[]=8{ Definicioˊn de prod  }1=8{ Aritmeˊtica }False\begin{aligned} &\underline{pin8}.[] \\ &\\ &\equiv \{ \textnormal{ Especificación de } pin8 \; \} \\ &\\ &\bigl \langle \; \exists as, bs : \underline{ [] = as \; \textnormal{⧺} \; bs }: prod.as = 8 \; \bigr \rangle \\ &\\ &\equiv \{ \textnormal{ Propiedad de } \; \textnormal{⧺} \; \} \\ &\\ &\bigl \langle \; \exists as, bs : \underline{as} = [] \land bs = [] : prod.\underline{as} = 8 \; \bigr \rangle \\ &\\ &\equiv \{ \textnormal{ Eliminación de variable } as \; \} \\ &\\ &\bigl \langle \; \exists bs : \underline{bs = []} : prod.[] = 8 \; \bigr \rangle \\ &\\ &\equiv \{ \textnormal{ Rango unitario} \; \} \\ &\\ &\underline{prod.[]} = 8 \\ &\\ &\equiv \{ \textnormal{ Definición de } prod \; \} \\ &\\ &\underline{1 = 8} \\ &\\ &\equiv \{ \textnormal{ Aritmética } \} \\ &\\ &False \end{aligned}

Por lo tanto, pin8.[]=Falsepin8.[] = False

Para el paso inductivo, seguimos con xs=(xxs)xs = (x \triangleright xs):

pin8.(xxs){ Especificacioˊn de pin8  }  as,bs:(xxs)=as    bs:prod.as=8  { Tercero excluido de as  }  as,bs:(xxs)=as    bs(as=[]aschar"338=[]):prod.as=8  { Distributividad de   con    }  as,bs:(xxs)=as    bsas=[](xxs)=as    bsaschar"338=[]:prod.as=8  { Particioˊn de rango, eliminacioˊn de variable as  }  bs:(xxs)=[]    bs:prod.[]=8    as,bs:(xxs)=as    bs:prod.as=8  { Definicioˊn de   ,   Cambio de variable: as(aas)  }  as,bs:(xxs)=bs:prod.[]=8    a,as,bs:(xxs)=(aas)    bs:prod.(aas)=8  { Rango unitario, Propiedad de las []  }prod.[]=8      a,as,bs:x=axs=as    bs:prod.(aas)=8  { Eliminacioˊn de una variable }prod.[]=8      a,as,bs:xs=as    bs:prod.(xas)=8  { Definicioˊn de prod  }prod.[]=8      a,as,bs:xs=as    bs:xas=8  \begin{aligned} &\underline{pin8}.(x \triangleright xs) \\ &\\ &\equiv \{ \textnormal{ Especificación de } pin8 \; \} \\ &\\ &\bigl \langle \; \exists as, bs : (x \triangleright xs) = \underline{as} \; \textnormal{⧺} \; bs : prod.as = 8 \; \bigr \rangle \\ &\\ &\equiv \{ \textnormal{ Tercero excluido de } as \; \} \\ &\\ &\bigl \langle \; \exists as, bs : \underline{(x \triangleright xs) = as \; \textnormal{⧺} \; bs \land (as = [] \lor as \not= [])} : prod.as = 8 \; \bigr \rangle \\ &\\ &\equiv \{ \textnormal{ Distributividad de } \land \; \textnormal{con} \; \lor \; \} \\ &\\ &\bigl \langle \; \exists as, bs : \underline{(x \triangleright xs) = as \; \textnormal{⧺} \; bs \land as = [] \lor (x \triangleright xs) = as \; \textnormal{⧺} \; bs \land as \not= []} : prod.as = 8 \; \bigr \rangle \\ &\\ &\equiv \{ \textnormal{ Partición de rango, eliminación de variable } as \; \} \\ &\\ &\bigl \langle \; \exists bs : (x \triangleright xs) = \underline{[]} \; \textnormal{⧺} \; bs : prod.[] = 8 \; \bigr \rangle \\ &\lor \bigl \langle \; \exists as, bs : (x \triangleright xs) = \underline{as} \; \textnormal{⧺} \; bs : prod.as = 8 \; \bigr \rangle \\ &\\ &\equiv \{ \textnormal{ Definición de } \; \textnormal{⧺}, \; \textnormal{ Cambio de variable: } as \rightarrow (a \triangleright as) \; \} \\ &\\ &\bigl \langle \; \exists as, bs : \underline{(x \triangleright xs) = bs} : prod.[] = 8 \; \bigr \rangle \\ &\lor \bigl \langle \; \exists a, as, bs : \underline{(x \triangleright xs) = (a \triangleright as) \; \textnormal{⧺} \; bs} : prod.(a \triangleright as) = 8 \; \bigr \rangle \\ &\\ &\equiv \{ \textnormal{ Rango unitario, Propiedad de las } [] \; \} \\ &\\ &prod.[] = 8 \; \lor \; \bigl \langle \; \exists a, as, bs : \underline{x = a} \land xs = as \; \textnormal{⧺} \; bs : prod.(a \triangleright as) = 8 \; \bigr \rangle \\ &\\ &\equiv \{ \textnormal{ Eliminación de una variable } \} \\ &\\ &prod.[] = 8 \; \lor \; \bigl \langle \; \exists a, as, bs : xs = as \; \textnormal{⧺} \; bs : \underline{prod.(x \triangleright as)} = 8 \; \bigr \rangle \\ &\\ &\equiv \{ \textnormal{ Definición de } prod \; \} \\ &\\ &prod.[] = 8 \; \lor \; \bigl \langle \; \exists a, as, bs : xs = as \; \textnormal{⧺} \; bs : \textcolor{darkred}{x} * as = 8 \; \bigr \rangle \end{aligned}

Es necesario generalizar la función pin8pin8 para poder derivarla. Definimos una nueva función gpin8gpin8 tal que:

gpin8.1.xs=  as,bs:xs=as    bs:prod.as=8  gpin8.1.xs = \bigl \langle \; \exists as, bs : xs = as \; \textnormal{⧺} \; bs : prod.as = 8 \; \bigr \rangle gpin8.n.xs=  as,bs:xs=as    bs:nprod.as=8  gpin8.n.xs = \bigl \langle \; \exists as, bs : xs = as \; \textnormal{⧺} \; bs : \textcolor{darkred}{n} * prod.as = 8 \; \bigr \rangle

Evaluamos el caso base de gpin8gpin8:

gpin8.n.[]{ Especificacioˊn de gpin8  }  as,bs:[]=as    bs:nprod.as=8  { Propiedad de       }  as,bs:as=[]bs=[]:nprod.as=8  { Eliminacioˊn de variable as  }  bs:[]=bs:nprod.[]=8  { Rango unitario }nprod.[]=8{ Definicioˊn de prod  }n1=8{ Aritmeˊtica }n=8\begin{aligned} &\underline{gpin8}.n.[] \\ &\\ &\equiv \{ \textnormal{ Especificación de } gpin8 \; \} \\ &\\ &\bigl \langle \; \exists as, bs : \underline{ [] = as \; \textnormal{⧺} \; bs } : n * prod.as = 8 \; \bigr \rangle \\ &\\ &\equiv \{ \textnormal{ Propiedad de } \; \textnormal{⧺} \; \; \} \\ &\\ &\bigl \langle \; \exists \underline{as}, bs : \underline{as} = [] \land bs = [] : n * prod.\underline{as} = 8 \; \bigr \rangle \\ &\\ &\equiv \{ \textnormal{ Eliminación de variable } as \; \} \\ &\\ &\bigl \langle \; \exists bs : \underline{[] = bs} : n * prod.[] = 8 \; \bigr \rangle \\ &\\ &\equiv \{ \textnormal{ Rango unitario } \} \\ &\\ &n * \underline{prod.[]} = 8 \\ &\\ &\equiv \{ \textnormal{ Definición de } prod \; \} \\ &\\ &\underline{n * 1} = 8 \\ &\\ &\equiv \{ \textnormal{ Aritmética } \} \\ &\\ &n = 8 \end{aligned}

Seguimos con el paso inductivo de gpin8gpin8:

gpin8.n.(xxs){ Especificacioˊn de gpin8  }  as,bs:(xxs)=as    bs:nprod.as=8  { Tercero excluido de as  }  as,bs:(xxs)=as    bs(as=[]aschar"338=[]):nprod.as=8  { Distributividad de   con    }  as,bs:(xxs)=as    bsas=[](xxs)=as    bsaschar"338=[]:nprod.as=8  { Particioˊn de rango, eliminacioˊn de variable as  }  bs:(xxs)=[]    bs:nprod.[]=8    as,bs:(xxs)=as    bs:nprod.as=8  { Definicioˊn de   ,   Cambio de variable: as(aas)  }  as,bs:(xxs)=bs:nprod.[]=8    a,as,bs:(xxs)=(aas)    bs:nprod.(aas)=8  { Rango unitario, Propiedad de las []  }nprod.[]=8      a,as,bs:x=axs=as    bs:nprod.(aas)=8  { Eliminacioˊn de variable a  }nprod.[]=8      as,bs:xs=as    bs:nprod.(xas)=8  { Definicioˊn de prod  }n1=8      as,bs:xs=as    bs:nxprod.as=8  { Aritmeˊtica, hipoˊtesis inductiva con n=(nx)  }n=8    gpin8.(nx).xs\begin{aligned} &\underline{gpin8}.n.(x \triangleright xs) \\ &\\ &\equiv \{ \textnormal{ Especificación de } gpin8 \; \} \\ &\\ &\bigl \langle \; \exists as, bs : (x \triangleright xs) = \underline{as} \; \textnormal{⧺} \; bs : n * prod.as = 8 \; \bigr \rangle \\ &\\ &\equiv \{ \textnormal{ Tercero excluido de } as \; \} \\ &\\ &\bigl \langle \; \exists as, bs : \underline{(x \triangleright xs) = as \; \textnormal{⧺} \; bs \land (as = [] \lor as \not= [])} : n * prod.as = 8 \; \bigr \rangle \\ &\\ &\equiv \{ \textnormal{ Distributividad de } \land \; \textnormal{con} \; \lor \; \} \\ &\\ &\bigl \langle \; \exists as, bs : \underline{(x \triangleright xs) = as \; \textnormal{⧺} \; bs \land as = [] \lor (x \triangleright xs) = as \; \textnormal{⧺} \; bs \land as \not= []} : n * prod.as = 8 \; \bigr \rangle \\ &\\ &\equiv \{ \textnormal{ Partición de rango, eliminación de variable } as \; \} \\ &\\ &\bigl \langle \; \exists bs : (x \triangleright xs) = \underline{[]} \; \textnormal{⧺} \; bs : n * prod.[] = 8 \; \bigr \rangle \\ &\lor \bigl \langle \; \exists as, bs : (x \triangleright xs) = \underline{as} \; \textnormal{⧺} \; bs : n * prod.as = 8 \; \bigr \rangle \\ &\\ &\equiv \{ \textnormal{ Definición de } \; \textnormal{⧺}, \; \textnormal{ Cambio de variable: } as \rightarrow (a \triangleright as) \; \} \\ &\\ &\bigl \langle \; \exists as, bs : \underline{(x \triangleright xs) = bs} : n * prod.[] = 8 \; \bigr \rangle \\ &\lor \bigl \langle \; \exists a, as, bs : \underline{(x \triangleright xs) = (a \triangleright as) \; \textnormal{⧺} \; bs} : n * prod.(a \triangleright as) = 8 \; \bigr \rangle \\ &\\ &\equiv \{ \textnormal{ Rango unitario, Propiedad de las } [] \; \} \\ &\\ &n * prod.[] = 8 \; \lor \; \bigl \langle \; \exists \underline{a}, as, bs : \underline{x = a} \land xs = as \; \textnormal{⧺} \; bs : n * prod.(\underline{a} \triangleright as) = 8 \; \bigr \rangle \\ &\\ &\equiv \{ \textnormal{ Eliminación de variable } a \; \} \\ &\\ &n * \underline{prod.[]} = 8 \; \lor \; \bigl \langle \; \exists as, bs : xs = as \; \textnormal{⧺} \; bs : \underline{n * prod.(x \triangleright as) = 8} \; \bigr \rangle \\ &\\ &\equiv \{ \textnormal{ Definición de } prod \; \} \\ &\\ &\underline{n * 1} = 8 \; \lor \; \underline{\bigl \langle \; \exists as, bs : xs = as \; \textnormal{⧺} \; bs : n * x * prod.as = 8 \; \bigr \rangle} \\ &\\ &\equiv \{ \textnormal{ Aritmética, hipótesis inductiva con } n = (n * x) \; \} \\ &\\ &n = 8 \; \lor \; gpin8.(n * x).xs \end{aligned}

Los programas son:

 pin8:[Num]Bool pin8.(xxs)gpin8.1.(xxs)\begin{aligned} &\Big\vert\ pin8 : [Num] \to Bool \\ &\overline{\Big\vert\ pin8.(x \triangleright xs)} \doteq gpin8.1.(x \triangleright xs) \end{aligned}  gpin8:Num[Num]Bool  gpin8.n.xsn=8 gpin8.n.(xxs)n=8    gpin8.(nx).xs\begin{aligned} &\Big\vert\ gpin8 : Num \to [Num] \to Bool \\ &\overline{\Big\vert \; gpin8.n.xs} \doteq n = 8 \\ &\Big\vert\ gpin8.n.(x \triangleright xs) \doteq n = 8 \; \lor \; gpin8.(n * x).xs \end{aligned}

3.

Derivar la función minimominimo a partir de la especificación:

minimo.xs=  Min  i:0i<#xs:xs.i  minimo.xs = \bigl \langle \; \textnormal{Min} \; i : 0 \leq i < \# xs : xs.i \; \bigr \rangle

Primero evaluamos el caso base, xs=[]xs = []:

minimo.[]{ Especificacioˊn de minimo  }  Min  i:0i<#[]:[].i  { Definicioˊn de #  }  Min  i:0i<0:[].i  { Aritmeˊtica }  Min  i:False:[].i  { Rango vacıˊ}+\begin{aligned} &\underline{minimo}.[] \\ &\\ &\equiv \{ \textnormal{ Especificación de } minimo \; \} \\ &\\ &\bigl \langle \; \textnormal{Min} \; i : 0 \leq i < \underline{\# []} : [].i \; \bigr \rangle \\ &\\ &\equiv \{ \textnormal{ Definición de } \# \; \} \\ &\\ &\bigl \langle \; \textnormal{Min} \; i : \underline{0 \leq i < 0} : [].i \; \bigr \rangle \\ &\\ &\equiv \{ \textnormal{ Aritmética } \} \\ &\\ &\bigl \langle \; \textnormal{Min} \; i : \underline{False} : [].i \; \bigr \rangle \\ &\\ &\equiv \{ \textnormal{ Rango vacío } \} \\ &\\ &+\infty \end{aligned}

No podemos computar ++\infty, por lo que necesitamos cambiar nuestro esquema inductivo. Nuestra lista vacía no puede ser evaluada, por lo que necesitamos evaluar [x][x].

minimo.[x]{ Especificacioˊn de minimo  }  Min  i:0i<#[x]:[x].i  { Definicioˊn de #  }  Min  i:0i<1:[x].i  { Loˊgica }  Min  i:i=0:[x].i  { Rango unitario }[x].0{ Definicioˊn de .  }x\begin{aligned} &\underline{minimo}.[x] \\ &\\ &\equiv \{ \textnormal{ Especificación de } minimo \; \} \\ &\\ &\bigl \langle \; \textnormal{Min} \; i : 0 \leq i < \underline{\# [x]} : [x].i \; \bigr \rangle \\ &\\ &\equiv \{ \textnormal{ Definición de } \# \; \} \\ &\\ &\bigl \langle \; \textnormal{Min} \; i : \underline{0 \leq i < 1} : [x].i \; \bigr \rangle \\ &\\ &\equiv \{ \textnormal{ Lógica } \} \\ &\\ &\bigl \langle \; \textnormal{Min} \; i : \underline{i = 0} : [x].i \; \bigr \rangle \\ &\\ &\equiv \{ \textnormal{ Rango unitario } \} \\ &\\ &\underline{[x].0} \\ &\\ &\equiv \{ \textnormal{ Definición de } . \; \} \\ &\\ &x \end{aligned}

Ahora seguimos con el paso inductivo xs=(xyxs)xs = (x \triangleright y \triangleright xs):

minimo.(xyxs){ Especificacioˊn de minimo  }  Min  i:0i<#(xyxs):(xyxs).i  { Definicioˊn de #  }  Min  i:0i<1+#(yxs):(xyxs).i  { Separacioˊn de un teˊrmino }(xyxs).0+  Min  i:0i<#(yxs):(xyxs).(i+1)  { Definicioˊn de .  }x  min    Min  i:0i<#(yxs):(yxs).i  { Hipoˊtesis Inductiva con (yxs)  }x  min  minimo.(yxs)\begin{aligned} &\underline{minimo}.(x \triangleright y \triangleright xs) \\ &\\ &\equiv \{ \textnormal{ Especificación de } minimo \; \} \\ &\\ &\bigl \langle \; \textnormal{Min} \; i : 0 \leq i < \underline{\# (x \triangleright y \triangleright xs)} : (x \triangleright y \triangleright xs).i \; \bigr \rangle \\ &\\ &\equiv \{ \textnormal{ Definición de } \# \; \} \\ &\\ &\underline{ \bigl \langle \; \textnormal{Min} \; i : 0 \leq i < 1 + \# (y \triangleright xs) : (x \triangleright y \triangleright xs).i \; \bigr \rangle} \\ &\\ &\equiv \{ \textnormal{ Separación de un término } \} \\ &\\ &\underline{(x \triangleright y \triangleright xs).0} + \bigl \langle \; \textnormal{Min} \; i : 0 \leq i < \# (y \triangleright xs) : \underline{(x \triangleright y \triangleright xs).(i + 1)} \; \bigr \rangle \\ &\\ &\equiv \{ \textnormal{ Definición de } . \; \} \\ &\\ &x \; \textnormal{min} \; \underline{\bigl \langle \; \textnormal{Min} \; i : 0 \leq i < \# (y \triangleright xs) : (y \triangleright xs).i \; \bigr \rangle} \\ &\\ &\equiv \{ \textnormal{ Hipótesis Inductiva con } (y \triangleright xs) \; \} \\ &\\ &x \; \textnormal{min} \; minimo.(y \triangleright xs) \end{aligned}

Nuestro programa final sería:

 minimo:[Num]Num  minimo.[x]x minimo.(xyxs)x  min  minimo.(yxs)\begin{aligned} &\Big\vert\ minimo : [Num] \to Num \\ &\overline{\Big\vert \; minimo.[x] \doteq x} \\ &\Big\vert\ minimo.(x \triangleright y \triangleright xs) \doteq x \; \textnormal{min} \; minimo.(y \triangleright xs) \end{aligned}

Verificación (PF)

Podemos demostrar que xs::P.xs\bigl \langle \forall xs :: P.xs \bigr \rangle

Cumple con:

P.xs:sum.xs=  i:0i<#xs:xs.i  P.xs : sum.xs = \bigl \langle \; \sum i : 0 \leq i < \# xs : xs.i \; \bigr \rangle

Para lograrlo podemos utilizar inducción matemática o inducción estructural sobre listas (en este caso, la segunda):

Caso base: (xs=[]xs = [])

Debemos demostrar que:

P.[]:sum.[]=  i:0i<#[]:[].i  P.[] : sum.[] = \bigl \langle \; \sum i : 0 \leq i < \# [] : [].i \; \bigr \rangle

Para ello podemos comenzar del lado derecho:

  i:0i<#[]:[].i  { Definicioˊn de #  }  i:0i<0:[].i  { Aritmeˊtica }  i:False:[].i  { Rango vacıˊ}0{ Definicioˊn de sum  }sum.[]\begin{aligned} &\bigl \langle \; \sum i : 0 \leq i < \underline{\#[]} : [].i \; \bigr \rangle \\ &\\ &\equiv \{ \textnormal{ Definición de } \# \; \} \\ &\\ &\bigl \langle \; \sum i : \underline{0 \leq i < 0} : [].i \; \bigr \rangle \\ &\\ &\equiv \{ \textnormal{ Aritmética } \} \\ &\\ &\bigl \langle \; \underline{\sum i : False : [].i} \; \bigr \rangle \\ &\\ &\equiv \{ \textnormal{ Rango vacío } \} \\ &\\ &\underline{0} \\ &\\ &\equiv \{ \textnormal{ Definición de } sum\; \} \\ &\\ &sum.[] \end{aligned}

Por lo tanto, probamos la propiedad P.[]P.[]

Paso inductivo: (xxsx \triangleright xs)

Debemos demostrar que:

P.xs:sum.xs=  i:0i<#xs:xs.i      P.(xxs):sum.(xxs)=  i:0i<#(xxs):(xxs).i  \begin{aligned} &P.xs : sum.xs = \bigl \langle \; \sum i : 0 \leq i < \# xs : xs.i \; \bigr \rangle \implies \\ &\\ &P.(x \triangleright xs) : sum.(x \triangleright xs) = \bigl \langle \; \sum i : 0 \leq i < \# (x \triangleright xs) : (x \triangleright xs).i \; \bigr \rangle \end{aligned}

Donde P.xsP.xs es la hipótesis inductiva.

Para ello podemos comenzar del lado derecho:

  i:0i<#(xxs):(xxs).i  { Definicioˊn de #  }  i:0i<1+#xs:(xxs).i  { Separacioˊn de un teˊrmino }(xxs).0+  i:0i<#xs:(xxs).(i+1)  { Definicioˊn de .  }x+  i:0i<#xs:xs.i  { Hipoˊtesis inductiva }x+sum.xs\begin{aligned} &\bigl \langle \; \sum i : 0 \leq i < \underline{ \# (x \triangleright xs) } : (x \triangleright xs).i \; \bigr \rangle \\ &\\ &\equiv \{ \textnormal{ Definición de } \# \; \} \\ &\\ &\bigl \langle \; \underline{ \sum i : 0 \leq i < 1 + \# xs : (x \triangleright xs).i } \; \bigr \rangle \\ &\\ &\equiv \{ \textnormal{ Separación de un término } \} \\ &\\ &\underline{ (x \triangleright xs).0 } + \bigl \langle \; \sum i : 0 \leq i < \# xs : \underline{(x \triangleright xs).(i + 1)} \; \bigr \rangle \\ &\\ &\equiv \{ \textnormal{ Definición de } .\; \} \\ &\\ &x + \underline{\bigl \langle \; \sum i : 0 \leq i < \# xs : xs.i \; \bigr \rangle} \\ &\\ &\equiv \{ \textnormal{ Hipótesis inductiva } \} \\ &\\ &x + sum.xs \end{aligned}

Por lo tanto, probamos la propiedad P.(xxs)P.(x \triangleright xs), y su validez en cualquier lista.

Última vez actualizado el