Esercitazione E2

Argomento: Funzioni e Ricorsione

Framework da utilizzare: F-F

Fase 1) Semplice prova

In questo framework si definiscono funzioni, e poi si valuta una espressione che può utilizzare tali funzioni. Ad esempio la funzione "successivo" sui numeri interi può essere definita come segue:

int succ(int i){ return i+1;}

in tale dichiarazione, chiamiamo "signature" la parte di definizione "int succ(int i)", che ci dà tutte le informazioni necessarie sulla struttura "esterna" della funzione, ossia il nome, il tipo di ritorno, ed il tipo di ogni argomento. 

Per testare il funzionamento di una funzione di questo tipo:

Fase 2) La correttezza semantica delle dichiarazioni e invocazioni di funzioni

A) La correttezza di una dichiarazione di funzione può sempre essere collegata a due aspetti:

Si ricorda che la nozione di conversione implicita (per coercizione) di un valore di tipo T1 ad un certo tipo T2 è possibile quando:

Predicendo prima il risultato, e poi verificando col framework F-F, testare la correttezza semantica delle seguenti funzioni (come indicato al punto 1) tale correttezza è verificabile inserendo ogni funzione, una alla volta, nel box in alto, e valutando una qualunque espressione nel box in basso, es.: 1+2 ):

B) Invece, la correttezza di una invocazione di funzione può sempre essere collegata a due aspetti:

Considerando le due definizioni corrette:

e, una a una, le invocazioni qui sotto, predirre il loro risultato, e poi verificarlo valutando col framework (per almeno un esempio, disegnare l'AST e usarlo per effettuare Typing e Valutazione)

Fase 3) Analisi di funzioni date

            int fatt (int n){
                return n==0?1:n*fatt(n-1);
            }

            int f(int x,int y){ 
                return x<0 ? 0 : x%2==0? 1: -1 ; 
            }

          Dopo aver risposto alla domanda fare qualche test col framework, per verificare se la previsione era giusta.

            int f(int x){ 
                return x<0 ? 0 : (x==0 ? 1: f(x-2)); 
            }

          Dopo aver risposto alla domanda fare qualche test col framework, per verificare se la previsione era giusta.

            int f(int x,int y){ 
                return f2(x,y,x,y);
            }

            int f2(int x,int y,int z, int w){
                return (z==w)? z :
                          (z>w ? f2(x,y,z,w+y) : f2(x,y,z+x,w) );
            }

Predire quale algoritmo realizza la funzione f (che utilizza la funzione d'appoggio f2). Aiutarsi cercando di capire l'output producendo l'albero delle invocazioni relativo alle chiamate:

(seguire l'ordine proposto, e ogni volta verificare se il risultato è quello che ci si aspettava). Alla fine si dovrebbe aver capito quale risultato produce la funzione in generale. 

Fase 4) Test di funzioni

            int somma(int[] array){
                return somma(array,0);
            }

            int somma(int[] array,int start){
                return (start==array.length)
                ? 0
                : array[start]+somma(array,start+1);
            }

boolean test(){
        return   somma(new int[]{10,20,30})==60 &&
                    somma(new int[]{10,20,30,40})==100 &&
                    somma(new int[]{10})==10 &&
                    somma(new int[]{})==0;
}

Fase 5) Modifica di funzioni date

Fase 6) Progetto di nuove funzioni

Facoltativo) Come approfondimento. Con il linguaggio visto sino ad ora siete in grado di realizzare il riconoscitore di qualunque grammatica EBNF, quindi provare via via a realizzare i riconoscitori per