(define b 1) (define a b) (define prova (lambda (x) (+ 1 pippo

(define b 1)
(define a b)
(define prova
(lambda (x) (+ 1 pippo)))
(define prova2
(lambda (x) (+ x "pippo")))
(define q (+ 1 "pippo"))
www.dimi.uniud.it/alessi/sprog.html
=======================================
tipi di dato numerico: tipi fondamentali sono:
integer, rational, real, complex.
Vale la regola per cui un numero di un tipo piu' a sinistra e'
utilizzabile
da tutte le procedure che lavorono con i tipi piu' a destra.
IMPORTANTE: i numeri interi e razionali hanno precisione
sostanzialmente illimitata
(i numeri razionali vengono rappresentanti come frazioni,
ossia come coppie di numeri interi)
In particolare entrambi soddisfano la cosiddetta proprieta'
di exacteness.
(ossia non ci sono margini di approssimazione).
Per i numeri reali la situazione e' differente. Si usa una
rappresentazione (in genere)
a 64 bit, e quindi tutte le relative operazioni che si fanno
soffrono di un certo grado
di approssimazione.
In particolare i numeri reali NON sono esatti.
==========================
Precisazione su definizioni "induttive" e "ricorsive".
OSS: spesso i due termini si usano come sinonimi senza
creare equivoci.
E quindi, si trova spesso scritto:
la funzione f:N->N fattoriale viene definita induttivamente
dalla formula bla bla....
oppure
la funzione f:N->N fattoriale viene definita ricorsivamente
dalla formula bla bla....
Ricorsivo: di successione di funzioni, formule o
dimostrazioni, in cui ogni
elemento si puo' ricavare dal precedente.
Induzione: procedimento per cui, partendo da dati empirici
fra loro uniformi, si arriva
alla formulazione di una regola generale.
per noi vuol dire questo: procedimento per cui, partendo
da casi "base", si arriva
alla definizione dei casi generali.
La definizioni ricorsive sembrano essere piu' generali di
quelle induttive, che sono
univoche e precise.
Le definizioni induttive usano quasi sempre il "formato
ricorsivo".
Formato ricorsivo:
definire <qualcosa> "a sinistra", ma <qualcosa> compare
anche nella espressione
di destra che dovrebbe definire <qualcosa> stesso.
Esempio di definizione in formato ricorsiva : la funziona
fatt:N->N
fatt(n) =
se n = 0 allora 1 , altrimenti
<====== defin
fatt(n-1) * n
Altro esempio di definizione ricorsiva ma non induttiva:
g(n) = se n = 0
allora 1, altrimenti
g(n+1)
===============================
PROCEDURE RICORSIVE: si definisce una procedura
che richiama se stessa
nel suo corpo.
ESEMPIO: scrivere un programma che calcola la funzione
fattoriale (fatt nell' esempio sopra)
In realta' una definizione piu' chiara di fattoriale e' questa:
fatt(n) = 1*2*3*4.....*n
OSS: il fattoriale puo' essere definito anche secondo le
"vecchie" e care definizioni
fatt(4) = 1*2*3*4 = 24
Per convenzione si assume che fatt(0) sia definito e valga
1.
(Questa e' utile per la definizione ricorsiva).
Altra definizione (del tutto equivalente) e' quella vista
prima:
fatt(n) =
fatt(n-1)
if
(n=0)
then
1
else
n*
(define FATTORIALE
(lambda (n)
(if (= n 0)
1
(* n (FATTORIALE (- n 1))))))
Come viene valutata una espressione che coinvolge una
procedura ricorsiva?
[meccanismo e' il solito: si procede a sostituire fino a
esaurimento casi della procedura)
ESEMPIO : valutazione a mano di (FATTORIALE 3)
(FATTORIALE 3) ===>
( (lambda (n) <corpo>)
3)
===>
(if (= 3 0) 1 (* 3 (FATTORIALE 2))) )
(* 3 (FATTORIALE 2) )
====>
===>
(* 3 ( (lambda (n) <corpo>) 2) ) ====>
(* 3 (if (= 2 0) 1 (* 2 (FATTORIALE 1))) ) ) ===>
(* 3 (* 2 (FATTORIALE 1))) ====>
(* 3 (* 2 ( (lambda (n) <corpo>) 1) ) )
===>
(* 3 (* 2 (if (= 1 0) 1 (* 1 (FATTORIALE 0))) )
(* 3 (* 2 (* 1 (FATTORIALE 0))))
====>
=====>
(* 3 (* 2 (* 1 ( (lambda (n) <corpo>) 0 )))) ====>
(* 3 (* 2 * (1 (if (= 0 0) 1 (* 0 (FATTORIALE -1))) )
===>
(* 3 (* 2 * (1 1))) ==>
))
6
============================================
Esercizio: scrivere una procedura che stabilisce (fornendo
come risposta
true/false) se una stringa costituita da zeri e uno, contiene
un numero pari
di uno oppure no (nel primo caso deve dare true come
risposta).
"01101"
oss1: i singoli caratteri della stringa vanno scanditi uno a
uno.
(oss2: niente cicli "while")
Proponiamo una soluzione ricorsiva che deve basarsi su:
- devono esistere uno o piu' casi base dove la risposta e'
immediata;
- il caso generale (di una stringa come quella sopra) deve
essere scomposto
in uno o piu' casi (forse ancora generali) dove pero' la
"distanza" dai casi base
diminuisce.
PER LE STRINGHE: spesso i casi base vengono
individuati come quelli relativi
alla stringa vuota o a stringhe di un carattere.
Casi semplici:
sicuramente e' semplicissimo il caso della stringa ""
(parity-check "") = true
Osserviamo inoltre questo: se abbiamo una stringa non
vuota s, sara' di questi due forme possibili
s = "0_u"
<====== intendo: s inizia con uno 0 e poi
prosegue come vuole, il pezzo successivo e' la
stringa che abbiamo
chiamato u
s = "1_v" <====== ossia s inizia con un 1 e poi
prosegue con il restante segmento chiamato v.
SE s = 01101
s = 0_u
dove u = 1101
allora: se s = 0_u
(parity-check s) <=====> (parity-check u)
se invece s = 1_v
(parity-check s) <======> (not (parity-check v))
esempio di questo secondo caso
false = (parity-check "10011") = (not ((parity-check
"0011") = true) ) = (not (parity-check "011")) =
(not (parity-check ("11"))) = (not (not (parity-check "1"))) =
(not (not (not (parity-check ""))) = false
Sintetizzando:
se (parity-check "" ) = true
<================
caso base
se (parity-check "0_u")
= (parity-check u)
se (parity-check "1_v")
= (not (parity-check v))
Lo schemino sopra costituisce il cuore della procedura
parity-check:
(char=? (string-ref s 0) #\0) ) corrisponde a chiedersi se s
e' del tipo 0_u etc etc
(define parity-check
(lambda (s)
(cond ((string=? s "")) #t)
((char=? (string-ref s 0) #\0) (parity-check
(substring s 1)))
(else (not (parity-check (substring s 1)))))))
======================================
ESERCIZI per casa:
- Scrivere un programma first-a? che stabilisce (risultato:
booleano) se
il primo carattere di una stringa e' una "a" (minuscola)
(first-a? "amico" ) ---> true
sulla stringa vuota: decidete cosa preferite: se rispondere
false oppure mandare un msg di errore
(sotto forma di stringa)
- Scrivere un programma detect-a, che stabilisce se in una
stringa compaiono delle "a"
(detect-a "pranzo") ===> true
(detect-a "pollo") ==> false
- Scrivere un programma quante-a? che stabilisce quante
#\a compaiono in una stringa.