Professional Documents
Culture Documents
Fukcionalno
Fukcionalno
Funkcionalno programiranje
1.1. Uvodni elementi o jezicima
Programski jezik :
- nain komunikacije ovek-raunar
- brojne podele po razliitim kriterijumima
- podela po stepenu razumljivosti za oveka
- jezici niskog nivoa
- jezici visokog nivoa
Jezici visokog nivoa : - iroko rasprostranjene kategorije
- proceduralni (kako se problem reava, najee korieni) Pascal,Modula,Fortran,...
- deklarativni ( opis ta se reava )
- logiki - Prolog,KLO,Mandola
- funkcionalni - LISP,Scheme,Iswim,Miranda,Haskell
g(x,y)=f(x)+2y
definicije funkcija
z(x)=g(x,2)-1
z(5)=g(5,2)-1=f(5)+2*2-1=5+1+2*2-1=9
Programi su :
- koncizni i jasni
- najee krai od proceduralnih ekvivalenata
- tee je napraviti greke - ako postoje lake ih je otkriti
- mogu se lako realizovati na paralelnim raunarima
- mogu je formalni dokaz korektnosti
END;
( strogo zadat redosled izraunavanja i izvravanja naredbi )
( matematika definicija)
2. Nepostojanje naredbi
-proceduralni stil je zasnovan na postojanju stanja programa na koje se u toku izvravanja
programa utie. Stanje je sadrano u tano odre|enim memorijskim lokacijama i na njega se utie
konstrukcijama programskog jezika, tj. naredbama dodeljivanja koje se izvravaju u tano odre|enom
redosledu.Nakon niza naredbi rezultat je u memorijskim lokacijama odakle se preuzima.
- funkcionalni stil - ne poznaje naredbe ve izraze. Izrazi su zapisi vrednosti tj. predstavljaju
vrednosti.
proceduralno
naredbe
uslovna naredba - odre|uje redosled
izvravanja
petlje
rezultat u memorijske lokacije
funkcionalno
izrazi
uslovni izraz - predstavlja vrednost
rekurzija
rezultat - vrednost nekog izraza
- ako je u programu potrebno definisati neko stanje i onda ga menjati u funkcionalnom stilu se
to postie prenoenjem stanja u sve izraze koji zavise od tog stanja (umesto da je stanje fiksirano na
odre|enim lokacijama).
Primer:
fakt(n) = f(n,1)
f(n,rez) = if n>0 then f(n-1,rez*n) else rez.
( eksplicitan prenos rezultata u naredni poziv funkcije )
3. Nepostojanje sporednih efekata
-isti izraz u istoj okolini uvek ima istu vrednost, tj. funkcija pozvana sa istim argumentima
uvek daje istu vrednost.
- osnovna osobina matematikog aspekta funkcije
- u programu se zbog sporednih efekata moe desiti da dva poziva iste funkcije daju razliit
rezultat f(x)f(x); najee zbog izmene vrednosti globalnih objekata programa ; uitavanja
vrednosti.
--VAR
a,x : INTEGER;
--PROCEDURE Isti(i:INTEGER):BOOLEAN;
BEGIN
a:=a+1;
RETURN i=a
END Isti;
--a:=0;x:=1;
IF Isti(x)=Isti(x) THEN
( nee biti jednako )
WriteString(jednako)
ELSE
WriteString(nije jednako )
END
--- ekvivalentnost spominjanja (referential transparency) - svi izrazi koji oznaavaju istu
vrednost se mogu zamenjivati jedni drugima.
2
Primer:
y=x^2+1 tada y+y <=> x^2+1+y <=> y+x^2+1 <=> x^2+1+x^2+1
Primer:
PROCEDURE Jedan(VAR x,y,z : INTEGER);
VAR
t: INTEGER;
BEGIN
t:=x; x:=y; y:=z; z:=t
END Jedan;
PROCEDURE Dva(VAR x,y,z : INTEGER);
VAR
t: INTEGER;
BEGIN
t:=y; y:=z; z:=x; x:=t
END Dva;
Moe se uiniti da ove procedure imaju isti efekat (pa da se mogu pozivati jedna umesto druge).
1) x=1, y=2, z=3
Jedan t=x=1
z=t=1
x=y=2
y=z=3
a
Dva
t=y=2
y=z=3
z=x=1
x=t=2
Dva(a,b,a)
x
t=x=1
x=y=2
y=z=1
z=t=1
t=y=2
y=z=1
z=x=1
x=t=2
f ( x) =
x3
x =
+ c = g( x)
3
2
je
funkcija.
5. Nesteriktna semantika
- semantika jezika je striktna, ako je svaki izraz tog jezika striktan.
- izraz je striktan ako nema vrednost kad bar jedan od njegovih operanada nema vrednost.
3
- izraz je nestriktan kad ima vrednost ak i ako neki od njegovih operanada nema vrednost.
Ovo vai samo u principu , a od konkretnog izraza zavisi dali e i na osnovu koliko poznatih
argumenata biti izraunata njegova vrednost.
Posmatrajmo funkciju oblika :
map_f S = < fS1,fS2,...,fSn >
tj.
map_f S =
NIL , null S
inae
Primer:
map_length<S1...Sn>=<lengthS1...lengthSn>
tj.
NIL , nullS
map_length S=
length(car S): map_length(cdr S) , inae
Da se svaki put ne bi ponavljala ista forma programa, moe se uvesti opti oblik koji bi mogao da
kreira sve sline funkcije.
Neka je opti oblik map funkcija koja za argumente ima eljenu funkciju koja se primenjuje na sve
argumente liste.
Da bi se realizovala funkcija length to se radi na sledei nain:
map(length) se primenjuje na S
(map(length))S
<=>
(map length)S
<=>
map length S .
D* R* ,
tj.
2) moe se koristiti Karijeva funkcija koja uzima prvi argument i vraa funkciju koja uzima
drugi argument itd.
Prvi nain nije dobar kad se programiraju funkcije prvog reda.
Ne Karijeva verzija map funkcije
map : (( D R ) x D* ) R*
funkcija
lista
rezultujua lista
(A B B) (B (A* B ))
(A B B) B A* B
1) fold ( f,b,l ) = fold ( f,b,[l1 ... ln]) = f (l1, f(l2 , ... f(ln , b) ... )
2) fold ( f,b,nil) = b
fold (f,b,x:l ) = f(x,fold (f,b,l))
Primer:
fold ( +,0,[1,3,5] ) = fold ( +,0,1:(3:(5: nil )))
+ ( 1, fold(+, 0 , 3 :(5: nil))) +(1,+(3,fold(+,0,5: nil)))
+ (1,+(3,+(5,fold(+,0, nil))))
+ (1,+(3,+(5,0))) 9
--------------------------------------------------------------------------------------------------------------------------Striktna semantika
-prvo se izraunaju vrednosti svih operanada , pa se onda izraunava vrednost izraza.Tehnika prenosa
parametara koja podrava ovu semantiku je poziv po vrednosti (call by value).
Nestriktna semantika
-izraunavanje operanada , tj. argumenata , se odlae sve dok te vrednosti ne budu potrebne. Ta
strategija je poznata kao zadrano izraunavanje (lazy evoluation ),a prenos parametara je po potrebi (
call by need).
Znaaj nestriktne semantike
1) Osloba|anje brige o redosledu izraunavanja
x=0 v 1/x=10
U nestriktnoj semantici za x=0 izraz=T .
f a x where a=ged(b,c)
-programer ne mora da vodi rauna da li je a komplikovano za raunanje
i da li treba uvek da se rauna (vredno raunanje) , ve e se a raunati ako treba.
U striktnoj semantici bi se izraunavao i izraz 1/x to bi dovelo do greke.
primer:
f(x,y,z)= if x then y else z
2) Omoguava kreiranje beskonanih struktura (konceptualno)
a=(1.a) -beskonana lista
car(a) - u nestriktnoj semantici daje prvi element 1
- u striktnoj semantici pokuava prvo da formira beskonanu listu to je nemogue
3) Potencijalno efikasnije ( raunanje po potrebi )
primer: Iranska bajka
6
6) Statiko vezivanje
Funkcionalni programi su statiki ; vrednosti se veliinama vezuju u trenutku njihovog definisanja (tj.
statiki), a ne u toku izvravanja programa ( tj. dinamiki ) kao u proceduralnim jezicima. Nekada se u
funkcionalnom programu neki izrazi zamenjuju imenima zbog vee preglednosti.
Primer:
neka_je n=1 i
neka_je f(z)=z+n i
neka je n=2 u_izrazu f(3)
f(3) ?
map F(x:S)=Fx:mapFS
( 2*)
Ovo nam pokazuje koliko su ovakve rekurzivne definicije mono oru|e u prog. jeziku. Me|utim, kako
vriti izraunavanja izraza u kojima figuriu ovakve strukture.
Pogledajmo jedan primer:
Dva naina izraunavanja jednog izraza koji sadri Prir.
1) Lenjo
car(cdr Prir)
tj. car(cdr (0: map [1+] Prir )) => car(map [1+] Prir )
( rauna car od izraza , taj izraz
rauna dok ne moe da uzme prvi i ostalo
zadrzava)
razvijajui to po (1*) i koristei (2*) =>
=> car( 1: map [1+] Prir)
7
ovo se zadrava
Primenjujui car dobijamo rezultat 1 . (To je lenjo izraunavanje, jer se izraz izraunava kada nema
drugog naina da se dobije njegova vrednost.)
2) Vredno
-zamenjujui Prir njihovom definicijom kad god je mogue, izraz e biti beskonaan.
car ( cdr Prir) = car ( cdr ( 0: map [1+] Prir))
= car ( cdr (0:1: map [1+] Prir))
-piemo ,
a stvarno se deava:
car ( cdr Prir) = cadr (0: map [1+] Prir)
Prir=0:map [1+] Prir
primeni se 1+ na prvi i na ostatak
po smislu map-a
.
.
.
--------------------------------------------------------------------------------------------------------------------------Lenjo izraunavanje izbegava beskonana izraunavanja.
Posmatrajmo drugi primer:
Po definiciji fac
if n=1 then 1 else n*fac (n-1)
fac (-1) -dovodi do beskonane petlje
Posmatrajmo:
cdr ( prefiks ( fac (-1), nil ))=
vredno: ako ponemo izraunavanje svih izraza , fac(-1) e otii u beskonanu petlju
lenjo: prefiksi cdr e se izraunavati pre fac , koji nije ni potreban
tj.
cdr( prefiks (fac(-1) , nil))=cdr < fac(-1) >=<>
Posmatrajmo trei primer:
(if y=0 ,1, x/y )
-moe se rei da se prvi argument rauna vredno , a druga dva argumenta lenjo
tj. raunaju se samo ako trebaju.
U ovom sluaju ako bi se sva 3 argumenta raunala vredno javilo bi se nemogue izraunavanje x/0.
Podela FP jezika sa stanovita lenjog izraunavanja
(daje prvih n
nthFirst(k,n)=toke(k,fr(1))
where
toke(k,x)=if k=0 then nil
else
car(x):toke(k1,force(cdr(x)))
end
8
*/
)
(fr lambda(n)
(cons n(delay(fr(add n(1))))) /* zadran rep */
)
)
fr(n)=n:delay(fr(n+1))
Izraunavanja sa nepoznatim (primer lenjog izraunavanja):
- rezultat funkcije zavisi od vrednosti koje nisu poznate sve dok se
izracunavanje ne
kompletira
ReplByMax zamenjuje sve el. liste pozitivnih brojeva
maksimalnim brojem
1) dva puta prolazei kroz listu (vredno izraunavanje)
- na|e max
- zameni svaki el. sa max
ReplByMax(L)=map(f,L)
,gde je f(x)=fold(max,0,L)
F+s
- striktni ^FPJ
F+s F-s=
- nestriktni ^FPJ
9
F-s
x - identifikator
x.e - apstrakcija
x1x2...xn.e
e1 e2 - aplikacija
(e)
10
x1.x2. ...
e3)
e1
, i<>j
, i=j
(e1
e2 e3
) ((e1
npr.
npr.
[y/x]x y
[y/x]z z
= ([e1/x]e2)([e1/x]e3)
,i=j
3) [e1/xi](xj.e2) = a) xj.e2
(xi nije slobodno)
,i<>j ,
b) xj.[e1/xi]e2
xjfV(e1)
,inae
c) xk.[e1/xi]([xk/xj]e2)
ki,kj,xkfV(e2) fv(e1)
(* mogui konflikt imena je izbegnut zamenom imena *)
Primer:
[y/x]((y.x)(x.x)x)
([y/x]x) (z.y)(x.x)y
e1
3a)
2
([y/x](y.x)) ([y/x](x.x))
e2
e3
3c)
1b)
z.[y/x]([z/y]x)
x.x
y
1a)
1b)
x
z.y
(* objanjenje:
3)
a) [y/x](x.x) = x.x
vezana
b) [z/y] x.xy
x.xz
(dovelo bi
do kolizije)
novo ime
z.y
*)
- -konverzije - pravilo za transformaciju izraza
1) -konverzija (preimenovanje)
xi.e xj.[xj/xi]e , xjfV(e)
2) -konverzija (primena)
(x.e1)e2 [e2/x]e1
11
3) -konverzija
(x.e)x
Primer:
, xfV(e)
z.+zy
- CHURCH-ROSSER-ove teoreme govore o redukovanju izraza,ali su - i
-konverzije mogue samo u stranu.
-redukcija
(x.e1)e2 [e2/x]e1
-redukcija
x.ex e
,xfV(e)
e1 * e2 oznaava da se e2 moe razviti iz e1 proizvoljnim
brojem(ukljuujui i 0) primena -redukcije,-redukcije i konverzije (* je refleksivno-tranzitivno zatvorenje ukljuujui i
-konverziju).
- -izraz je u normalnoj formi ako se ne moe dalje redukovati
korienjem - i -redukcija.
Neki -izrazi nemaju normalnu formu.
(x.(xx))(x.(xx)) (x.(xx))(x.(xx))
Primer:
e1
e2
e0
e1.
, a poto x ne
(x.y)((x.xx)(x.xx))
, krajnja
leva najunutranjija
(x.y)((x.xx)(x.xx))
Rekurzija
TEOREMA FIKSNE TA^KE:
Svaki -izraz e ima fiksnu taku e tako da (e e) * e.
Dokaz:
,gde je Y paradoxical combinator ( daje
Neka je e=(Ye)
zau|ujue jednostavan dokaz )
Y=f.(x.f(xx))(x.f(xx))
e=(Ye)=(x.e(xx))(x.e(xx)) = e((x.e(xx))(x.e(xx))) =
e(Ye) = e e
Posledica : Svaka rekurzivna funkcija moe biti napisana rekurzivno.
Kako?
f = ...f...
f je rekurzivna
funkcija.
Znamo da je e = e e ,pa moemo pisati
f (f. ...f... ) f
tj. f. je
fiksna taka izraza f. ...f... po definiciji FT
Kada iskoristimo Y kombinator , dobijemo nerekurzivnu definiciju za
f.
f Y (f. ...f...)
Primer:
1)))
nerekurzivno :
1)))
fac = n.
Uvodi se +,
xy.+xy
: +xy x+y
(* drugo + *)
- logike vrednosti T,F
- liste se predstavljaju kao specijalne strukture podataka
Logike konstante i operacije
Primer:
if P then Q else R
(COND PQR)
prevodi se u PQR sa pravilima TRUE xyx
FALSE xyy
u -raunu:
COND = p.q.r.pqr
13
TRUE = x.y.x
FALSE = x.y.y
Primer:
COND TRUE AB(p.q.r.pqr)(x.y.x)AB
(q.r.(x.y.x)qr)AB
(r.(x.y.x)Ar B
(x.y.x)AB
(y.A)B A
AND = x.y.x y FALSE
OR = x.y.(x TRUE)y
Liste u istom -raunu
-
NIL h t
CONS el slova
CONS = h.t.s.s ht
selektorske funkcije
h.t.h
h.t.t
(* definicijama TRUE i
FALSE *)
HD = L.L TRUE
TL = L.L FALSE
Tako primena HD i TL na CONS a b
daje odgovarajuu vrednost.
Primer:
HD(CONS a b ) = (c.c TRUE)((h.t.s.sht) a b)
((h.t.s.sht) a b) TRUE
(s.sab) TRUE
TRUE a b (h.t.h) a b (t.a) b a
isempty(IE) = TRUE , ako je lista NIL
IE(CONS a b) = IE((h.t.s.sht) a b) IE(s.sab)
poto ovo mora biti FALSE a,b ,jasno je da je IE oblika
GC(h.t.FALSE)
tj. NIL = x.TRUE
G uzima objekat (on je za 2 arg. uvek FALSE)
Redukovati:
IE =
IE ( TL ( CONS 1 NIL ) )
- Prirodni brojevi
Koristei liste definiemo prirodne brojeve:
- n kao lista od n el. proizvoljne vrednosti
- 0 praznoj listi
- EQ0 funkciji IE
- PRED funkciji TAIL
- SUCC =n.CONS any n
proizvoljni -izraz
Uvod u Miranda
1. Miranda - isto funkcionalni jezik
- program je skup jednaina (script)
- strogo je tipizirani jezik
- bazni tipovi :
brojevi,karakteri,istinitosne vrednosti
- bazne strukture - lista (el. istog
tipa)
14
- torka (tuple)
(el. razliitog tipa)
Primer: lista
1) radni_dani=[Pon,Ut,Sre,Cet,Pet]
dani=radni_dani ++ [Sub,Ned]
(append)
2) 0: [1,2,3] je [0,1,2,3] consiranje
#dani je 7 - duina liste
dani!0 je Pon - 0-ti el. liste
[1,2,3,4,5] [2,4] je [1,3,5]
3)biblioteke funkcije
product,sum
fac n = product[1..n]
res = sum [1,3..100]
Primer: torka
zaposleni=(Peric,True,False,39)
, a<b
a=b
Primer:
(* u desi je
,delta=0
= [b/(2*a)+radix/(2*a),-b/(2*a)radix/(2*a)]
,delta>0
where
delta = b*b-4*a*c
radix = sqrt delta
,a b
f x y = (f x) y
Primer:
foldr op k [] = k
foldr op k (a:x) = op a (foldr op k x)
poetna vrednost a op operacija
,gde je k
Primer:
sum = foldr (+) 0
,
product = foldr (*) 1
4. Lenjo izraunavanje - vrednost izraza se ne izraunava sve dok
nije potrebno
- mogunost definisanja
beskonanih struktura podataka
one s = 1 : ones
fib = f 0 1
not s = [0..]
where f a b = a : f b (a+b)
add s = [1,3,..]
5. ZF (Zermelo-Frankel) izrazi
- opti prikaz operacija nad listama
[n*n n[1..100]]
generator
- opti oblik
[telo kvalifikatori]
1) var izraz
2) filter - logiki izraz koji odre|uje rang
(vrednost) promenljive
3) vie kvalifikatora je razdvojeno sa ;
Primer:
1) perm [] = [[]]
perm x = [a : y ax ; yperms(x[a])]
2) faktori n = [i i[1.. n div 2]; n mod i = 0]
6. Tipiziranost
Miranda je strogo tipiziran jezik - svaki izraz i podizraz ima tip,
koji se proverava u vreme prevo|enja i ako ne do|e do podudaranja,
javlja se greka.
1) osnovni tipovi : num,bool,char
2) za tip T ; [T] je lista iji su el. tipa T
[[1,2][2,3,4]] je tipa [[num]]
3) za tipove T1,...,Tn ; (T1,...,Tn) je torka
4) T1 i T2 tipovi ; T1T2 je funkcija koja ima arg. tipa T1 a
rezultat je tipa T2
Primer:
sum je tipa [num] num
Program moe da ukljui deklaracije tipa korienjem :: .
Primer:
sq::numnum
sq n = n*n
Ne mora se definisati tip, ali je dobro da postoji zbog
dokumentacije.
7) Polimorfizam - jedna funkcija moe raditi sa argumentima
razliitog tipa.
16
id x = x
*,**,...
id :: **
Primer:
reverse :: [*][*]
fst(*,**)*
* - jedan proizvoljan
tip
snd(*,**)**
kao u
9.26
)
s-izraz (ime1 . . . imen)
4. SECD - maina
Prvi interpretator za izraunavanje vrednosti -izraza prvi je predloio Landin (1964). On se
sastojao od etiri steka S, E, C, D. Ovaj nain izraunavanja -izraza je opte prirode i omoguava
relativno jednostavan nain implementacije. Mada najstariji nain on se i danas koristi za
implementaciju funkcionalnih jezika, iako nije uvek i najefikasniji.
Javlja se u dva osnovna oblika:
19
E
C
()
((.x.(x)) succ 0)
()
0((.x.(x)) succ), @
()
((.x.(x))succ), @
()
succ, .x.(x),@,@
()
.x.(x),@,@
()
@@
( = succ)
x.(x)
( = succ)
()
()
@
( x=0, =succ)
((x))
( x=0, =succ)
x,,@
( x=0, =succ)
x,,@,,@
( x=0, =succ)
,@,,@
( x=0, =succ)
@,,@
( x=0, =succ)
,@
( x=0, =succ)
@
( x=0, =succ)
()
()
()
D
()
()
()
()
()
()
(0, ( ),@, ( ) )
(0, ( ),@, ( ) )
()
( ( ),( ),( ),( ) )
( ( ),( ),( ),( ) )
( ( ),( ),( ),( ) )
( ( ),( ),( ),( ) )
( ( ),( ),( ),( ) )
( ( ),( ),( ),( ) )
( ( ),( ),( ),( ) )
( ( ),( ),( ),( ) )
()
Tako|e:
fac(n) = if n = 0 then 1 else nfac(n-1),
else grana e se uvek izvravati na svaki rekurzivni poziv, uslovljavajui
beskonani niz poziva ( f(0) e prei u f(-1) . . .)
reenje1: transformisanje uslovnog izraza korienjem dummy funkcija. To je standardan
nain da se omogui normalan redosled izraunavanja. Ekvivalentan izraz je:
21
deley e dum.e
force e e any
P - predikat
E - else grana
T - then grana
Ovaj izraz cond T E P na vrhu C steka se zamenjuje sa P, cond T E, @ .
X = cond T E
( tl(S), E , T :: tl( tl(C) ) , D ) if hd (S) = true
( tl(S), E , E :: tl( tl(C) ) , D ) if hd (S) = false
-apstrakcija
L
22
Naredne pojave ovog imena na vrhu kontrolnog steka ( u toku primene njegove l apstrakcije) e
usloviti da se njegova l-apstrakcija postavi na stek uz dodatak u okruenje.
Dodatak u fju promene stanja
x=@
i S = :: a :: S
dajui :
1)
( d ) (iii) = apstrakcija, gura se u C stek tako da naredna promena formira
zatvorenje u S. Novo stanje je :
(a : S , E , :: C , D )
Traeno ztvorenje se formira u dva koraka.
1) Kada se na vrhu C na|e labela <ime,izraz> ona se ubaci u okruenje, i izraz se ostavi na vrh C-a. Od njega se na vrhu S-a formira zatvorenje. Kada
se na vrhu C-a na|e ime rekurzivne fje ond se iz okruenja vadi njegova def. i stavlja na vrh S-a. Otuda dodatak 1d, kada se na vrh S-a na|e apstrakcija, onda se ona postavlja na C da bi se izvrila.
fac = (.x. if x=0 then 1 else x.fac(x-1))
2
< fac , x.x = 0 1 x.fac(x-1))
1uuuuuuuuuu2uuuuuuuuuuu3
L
punjenje
punjenje konstante
punjenje fje
primena fje
povratak
kreira fiktivnu eliju tj. formalno okruenje
rekurzivna primena
selekcija podliste (za dalje izvravanje)
uspostavljanje glavnog upravljanja
prvi element od elemenata na vrhu steka
ostatak od elemenata na vrhu steka
formira listu od 2 elementa sa vrha steka
proverava jednakost 2 elementa sa vrha steka
aritmetike operacije koje primenjuje na 2 elementa
sa vrha steka
prvi(S) <= drugi(S)
zaustavljanje izvravanje SECD programa na maini
( a b . S ) e ( ADD . c ) d ( b + a . S ) e c d
( a b . S ) e ( SUB . c ) d ( b - a . S ) e c d
( a b . S ) e ( DIV . c ) d ( b DIV a . S ) e c d
( a b . S ) e ( REM . c ) d ( b MOD a . S ) e c d
( a b . S ) e ( EQ . c ) d ( b = a . S ) e c d
( a b . S ) e ( LEQ . c ) d ( b <= a . S ) e c d
Primer:
1-2*3=4
( EQ ( SUB (1 ) ( MUL (2 ) ( 3 ) ) ) ( 4 ) )
0
1
2 22
3 3 3 3 2 1 1 1 0
prevee se
( LDC 1 LDC 2 LDC 3 MUL SUB LDC 4 EQ )
Izvravanje:
(s)
e.
( 1 . S ) e ( LDC 2 LDC 3 MUL SUB LDC 4 EQ ) d
( 2 1 . S ) e ( LDC 3 MUL SUB LDC 4 EQ ) d
( 3 2 1 . S ) e ( MUL SUB LDC 4 EQ ) d
( 6 1 . S ) e ( SUB LDC 4 EQ ) d
( 1-6 . S ) e ( LDC 4 EQ ) d
( 4 -5 . S ) e ( EQ ) d
( F . S ) e NIL d
OPERACIJE SA LISTAMA:
( a b . S ) e ( CONS . c ) d ( ( a . b ) . S ) e c d
( a b . S ) e ( CAR . c ) d ( a . S ) e c d
( a b . S ) e ( CDR . c ) d ( b . S ) e c d
( a . S ) e ( ATOM . c ) d ( t . S ) e c d
t = T ako je a atom
t = F ako je a lista
POSTAVLJANJE VREDNOSTI:
Okruenje je lista listi u kojima se nalaze vrednosti koje figuriu u programu. Da bi se vrednost
iz okruenja prenela na vrh steka koristi se operacija maine LD. Ona ima argument koji je par (i,j)
indeksa: i odre|uje podlistu iz koje se uzima vrednost a j odre|uje koji element iz i-te podliste se uzima.
I podliste I elementi u njima se numeriu od 0,1,...
Primer:
0 1
0
( ( 3 17 ) ( ( AB ) ) )
0
1
(0.0)
(0.1)
(1.0)
3
17
(AB)
n = cdr( i )
IZVR[AVANJE OPERACIJE LD:
S e ( LD i . c ) d ( x . s ) e c d gde je x= locate ( i , e )
Primer:
s
NIL
( 7. )
(27)
(3)
e
((37)(20)
((37)(20)
((37)(20))
((37)(20))
c
( LD ( 0 . 1 ) LD( 1 . 0 ) ADD )
( LD ( 1 . 0 ) ADD)
(ADD)
NIL
d
d
d
d
d
USLOVNI IZRAZ:
Realizuje se pomou dve operacije:
SEL
JOIN
( ( ( LD ( 1 . 1 ) RTN ) . ( ( 3 7 ) ( A) ) ) 0 ) ( ( 3 7) ( A ) ) ( LD ( 0 . 1 ) ) NIL
25
- kada se zatvorenje poziva i pimenjuje ( APP komanda) ono se nalazi na vrhu steka S ispred
stvarnih parametara.
APP
( ( c . e ) v . S ) e ( APP . c) d NIL ( v . e ) c ( S e c d )
v je stvarni parametar koji se javlja u 0-toj podlisti. Svarni parametri se javljaju u nultoj podlisti a
u prvoj podlisti se javljaju slobodne promenljive. U steku d se uva stanje registara koje treba obnoviti
nakon zavretka izvravanja fje.
Primer:
( ( ( LD( 1.1 ) LD( 0.0 ) ADD RTN ) . ( (3 7) ( A) ) ) ( 6 ) 0 ) ( ( 2 B ) ) ( ADD STOP ) d
1uuuuuuuuuuu2uuuuuuuuuuuuuuu3 1uu2uuu3 2 2 123 1uu2uuu3
c
e
v S
e
c
( 130 ) ( ( 2 B ) ) ( STOP ) d
s e c|c d ! (x.s) e c d
c=(LDC1)
c=(RTN) => c|c=(LDC1 RTN) tj.
se (LDC1 RTN) d ! (1.s) e (RTN) d
Ako su c1 i c2 liste za pravilne L izraze i ako su vrednosti njihovih izraunavanja x1 i x2 tada vai :
se c1|c2|cd!(x2 x1.s) e c d.
x|y|z!x|y|z= x|y|z
tj. x|y<-> append(x,y)
Pri analizi L izraza formira se lista promenjivih koje se javaljaju u izrazima i blokovima unutar
njih. Ta lista ima istu formu kao liste tj. okruenje u kom se vri izraunavanje ( to je lista listi)
kada se pojavi novi blok ili funkcija, promenjive iz njega (nje) se dodaju kao nova prva podlista u
listi imena.
Primer:
(letrec
(append (x y)
(let
(REV )
(DUP ))
2.1
2.2
Da bi se pri prevo|enju odredili parovi indeksa za poziciju imena koja se javlja u programu koriste
se pomonje funkcije.
location (x,n) - x - promenjiva
n - lista imena
position (x,a) - u listi atoma a, daje indeks (poziciju) atoma x
position (x,a)= if eq(x,car(a)) then
else 1+(position(x, cdr(0))
location(x,n) = if member (x, car(n)) then cons (0,position (x,car(n)))
else cons(car(z)+1,cdr(z))
where z=location (x,cdr(n))
(lista, pozicija u listi)
6.1 Prevo|enje
(CAR e)*n=e*n|(CAR)
(CDR e)*n=e*n|(CDR)
(CONS e1 e2)*n=e2*n|e1*n|(CONS)
(ATOM e)*n=e*n|(ATOM)
Primer:
(ADD(CAR x)(1))*((xy))=(CAR x)*((xy))|(1)*((xy))|(ADD)=
x*((XY))|(CAR)|(LDC 1)|(ADD)
= (LD (0.0))|(CAR)|(LDC1)|(ADD)= (LD (0.0) CAR LDC 1 ADD)
uslovni izraz
Primer:
(IF e1 e2 e3)*n=e1*n|(SEL e2*n|(JOIN) e3*n | (JOIN))
argumenti od SLL
(ADD y(IF(EQ x y)x(i1)))*((xy))
=(LD(0.1)LD(0.0)LD(0.1)EQ SEL (LD(0.0) JOIN)
e1
(LDC 1 JOIN)ADD)
izraz
(LAMBDA (x1 xk)e)
(())
(())
(())
(())
(())
((1))
((1))
((1))
((1))
(())
d
d
d
d
d
(S (()) NIL.d)
(S (()) NIL.d)
(S (()) NIL.d)
(S (()) NIL.d)
d
LET blok
(LET e (x1.e1)(xk.ek))((LAMBDA (x1xk)e)e1ek)
(LET e (x1.e1)(xk.ek))*n(LDC NIL)| ek*n|(CONS)||e1*n|(CONS)|
(LDF e*m |(RTN) AP)
m=((x1xk).n)
za izraunavanje e1, , ek nisu potrebna imena x1,,xk, tako da pri izraunavanju e1, , ek pozicije
za x1,,xk jo nisu uspostavljene. One se ustanovljavaju komandom APP
LETREC blok
slino kao LET ali
1) izrazi koji odre|uju vrednosti lokalnih promenjivih izraunavaju se u odnosu na dopunjenu listu
imena.
2) program za te izraze izraunava se u formalnom okruenju koje se formira komandom DUM.
Umesto komande APP koristi se RAP.
(LETREC e(x1.e1)(xk.ek))*n=
(DUM LDC NIL)|ek*m|(CONS)||e1*m|(CONS)|(LDF e*m |(RTN) RAP)
m=((x1xk).n)
Primer:
(LETREC (FAK (6))
(FAK LAMBDA (x)))
x1
e1
m=(FAK.n)
kod za telo funkcije FAK
za FAK u odnosu na m
fiktivno
okruenje
29
Izvo|enje
NIL
NIL
(NIL)
((c. )NIL)
(((c. )))
(((LDC NILRTN))
((c. )))
zatvorenje za izraz
definisan blokom
NIL
(DUMRAP)
(LDC NILRAP)
(LDF CRAP)
(CONSRAP)
(LDF(LDC NILRTN)RAP)
(RAP)
NIL
NIL
NIL
NIL
NIL
NIL
=(NK)
Oba zatvorenja sadre fiktivno okruenje. Kada se izvri komanda RAP fiktivno okruenje se menja
tako da car te liste sadri listu definisanih vrednosti, pa se sledee stan
NIL (LDC NILRTN) (NIL NIL NIL.NIL)
koristi gde je zatvorenje = (((c. )).NIL) tj. je okruenje sa jedinstvenom pozicijom (0.0) gde se
uva vrednost (c. )
bilo -fiktivno okruenje
Stoga kada se u kontrolnoj listi javi komanda LD(0.0) za funkciju FAK e biti uvedeno
ispravno zatvorenje, a kada se izvrava rekurzivni poziv izRekurzivni
programapoziv
c, pomou
komande LD (1.0) to
je na vrh steka doveo
zatvorenje e se ponovo javiti, poto se (stvarno) javlja klistu
ao okruenje
tomzazatvorenju.
org., pa se ukod
FAC nalazi na
(1.0) poziciji.
Lenja
(DELAY e)*n=(LDE e*n|UPD)
FORCE e)*n=e*n|(APO)
recept (F(c.l)) - nije jo izraunat
(T x) - izraunat
L
([Tx.S)l(APO.c)d!(x.S) lcd
([F(c.l)].S)l(APO.c)d!NIL l c (([F(c.l)].S)lc.d
(x) l (UPD)(([F(c.l)].S)ec.d)!(x.S e c d
x [F(c.l)]![Tx]
30
Realizacija
S-izraz
cons
x
vred
x
x
atom
car
cdr
(A B C)
cons
cons
A
x
cons
B
x
NIL
x
x
C
x
(A.B)
cons
A
x
B
x
pr
(letrec l
(f -)
(g -))
komanda DUM 1)
NIL
s
NIL
NIL
cf
cg
s:(cfcg.s)
l
NIL
31
cf
cg
ce se izraunava u
okruenju
gde
su
fiktivno cf i cg koji se
raunaju u istom tom
okruenju.
Okruenje
sadri
zatvorenje koje u sebi
sadri to isto okruenje
- ciklina struktura.
FOLD / UNFOLD
sum (nil)=0
sum (x:l)=x+sum(l)
double (nil)=nil
double (x:l)=(2*x):double(l)
g(l)=sum(double(l))
g(nil) =sum(double(nil))
= sum (nil)
=
g(x:l) = sum (double (x:l))
= sum ((2*x):double(l))
= (2*x)+sum(double(l))
= (2*x)+g(l)
dalje po lanku!
(instantiation)
(unfolding)
(unfolding)
(instant)
(unfolding)
(unfolding)
(folding)
Funk. Program je izraz koji ima jedinsvenu vrednost i nije bitan redosled kojim emo do njega
doi.
Sva komunikacija je kroz graf
Stanje izraunavanja ! graf
Model:
Proc Proc Proc
komunikacije
graf
zadaci
+,AND,-, i kad je vrednost argument striktna. U kom sluaju obeleiti i vor primene i kombinator.
Zato? Ako obeleimo samo vorove
@
!
!
@
l
z
32
@
IF
y
x
Obrnuto:
@
@
@
!z
!y
!IF
!x
Znai oba moraju biti oznaena:
!@
!F
33
cons
34
symbol
istraivanje:
funkcionalnim
stilom reavanje
problema
("poznatih") i ta
nam donosi.
Funkcionalno
programiranje
Funkcionalni prog.
jezici
Konstrukcije jezika u
duhu funkcionalnog
programiranja (I/O)
Analize i optimizacije
sintaksna, semantika
zavisnost
striktnosti
"fold/unfold"
puteva
tipova
lambda raun
teorija
prevo|enje
optimizacije
teorijska podloga
(kombinatori, teorija
kategorija,...
Me|ujezik
SECD
Simulator
SK 6
spinless
tagless
stil, nain
programiranja koji
ima svoje principe i
zakonitosti
najpogodniji za
funkcionalno
programiranje
TIM
CAM
continuation
parallel
Prevodilac
Glasgow
London
Stirling
Birmingham
Chalmer (Se)
Yale
Wellington (NZ)
Parser 1
( f g) x = f(gx)
parse = syntax lex read
read - uitava iz fajla u listu znakova.
Leksika analiza treba da prepozna brojeve, identifikatore i pojedinane znakove.
lex c:cs = lex cs | is WhiteSpace
Parser 2
isIdChar c = letter c || digit c || (c = )
is WhiteSpace = member " \ t \ n " c
Gramatika
pozdrav = pz osoba !
pz = Zdravo | Dovidjenja
osoba = id znak
Parser uzima listu listi (tokena) i vraa listu uredjenih parova.Prvi elemenat je ono to
je isparsirao , a drugi je ostatak.(Lista treba ako je to mogue isparsirati na vie naina).
plit uzima string i kao rezultat vraa parser koji prepoznaje taj string :
plit s [] = []
plit s (tok:toks) = [(s,toks)] | s=tok
= []
| otherwise
Primer :
plit Zdravo [ Zdravo, Pero, ! ] [(Zdravo,[Pero , !] )]
Parser 3
Slino (za identifikatore)
36
pAlt uzima dva parsera i oba primenjuje na isti ulaz,a kao rezultat vraa sve mogue
rezultate (odgovara onome iz gramatike r = a | b)
pAlt p1 p2 toks = (p1 toks) ++ (p2 toks)
p ZiliD = (plit Zdravo ) pAlt (plit Dovidjenja )
pThen - sekvenca. Kombinuje dva parsera koji e dati trei koji radi sledee :
koristi prvo p1,pa p2 na ostatak ulazne liste. [ta je rezultat? Neka kombinacija
rezultata p1 i p2. Tu kombinaciju izraavamo funkcijom combine.
pThen combine p1 p2 toks =
= [(combine v1 v2,toks2) | (v1,toks1) p1 toks2,
(v2,toks2) p2 toks1]
Parser 4
pPozdrav = pThen mkPair pZiliD pVar
where
mkPair a b = (a,b)
Primer
pPozdrav [ Zdravo, Pero, !] [((Zdravo,Pero), [!] )]
Finalna varijanta:
p = pThen keep pPozdrav (plit !)
where
keep a b = a
keep - odbacuje znak uzvika
pZeroOrMore p = (p OneorMore p) pAlt (pEmpty [])
ZF izrazi
perms[] = [ [] ]
perms x = [a:y ax, yperms(x--[a])]
faktors n = [i i [1..n div2], n mod i = 0]
queens
[ [] ]
queens n
safe q b
checks q b i
37
1 2 3 4
[3,1]
Nema backtracking-a !!
lenjo - ni jedno reenje se ne izraunava dok se ne zatrai.
ZF lenjo
fib = 1:1: [a+b (a,b)zip fib (tail fib)]
zip (x :xs) (y:ys) = (x,y) : zip xs ys
zip xs ys = []
Vektor ( niz ) :
f : Index Value
Nula vektor f i =
Zbir dva vektora : vv Add f g = \ i ( f i ) + ( g i)
vvAdd f g i = ( f i ) + ( g i )
Negiranje :
v Neg f = \ i ( f i )
Primer f = \ i 1
g = \ i i+1
(vv Add f g 5) ili
(zbir = vv Add f g )
zbir 5
mm Add f g = \ i vv Add ( f i ) ( g i )
matrica : num num num
det matr n = matr 1 1
, n=1
altsum matr n 1
, otherwise
where
38
altsum matr
n k = 0, k>n
(matr 1 k ) ( minor matr n k ) (altsummatr n|k +1)
minor matr n j = det (det matr j )n1
det matr j = \ k l matr k+1 (if l> j then l else i+1 ))
Elementi rauna
Lambda raun (nadalje raun) je nastao tridesetih godina ovog veka kao (jo) jedan od pokuaja da
se prona|e formalizam koji bi uspeno predstavio osnovu itave matematike .Ubrzo je postalo jasno da
raun nee moi ispuniti taj zadatak (kao ni mnogi drugi formalizmi i teorije pre i posle
njega).Poetkom ezdesetih godina se me|utim pokazalo da je raun dobra teorijska osnova za itavu
jednu klasu programskih jezika funkcionalne programske jezike.
Krajem pedesetih godina su se u programskom jeziku LISP pojavili neki termini iz rauna : na
primer lambda izraz za definisanje funkcije.LISP je me|utim bio autohtoni proizvod, koji je od
rauna iskoristio samo tehnologiju [McCartny,1978].Prvi jezik koji je zaista bio zasnovan na raunu
je bio ISWIM [Landin,1966]. Po reima Landin-a, ISWIM je predstavljao sintaksni eer (engl.
syntactic sugar) za raun jer je bez malo sintaksnog eera raun teko progutati.
Od ISWIM-a do dananjih dana, raun je ostao osnova najpoznatijih funkcionalnih
programskih jezika, ali se sintaksni eer stalno unapre|uje1.
1.1 termi
Pod raunom (engl.calculus) se podrazumeva:
skup termova i
skup pravila za konverziju (transformaciju) termova iz jednog oblika u drugi.
Termovi se grade od simbola iz unapred odre|enog skupa simbola na osnovu (sintaksnih) pravila za
gra|enje termova.
Primer. Jedan mogui raun je i sledei. Neka je skup simbola rauna :{(,),S}i neka se termi (na
primer: S-Termi) grade na sledei nain:
a) S je S-term,
b) ako su A i B S-termi, tada je i (AB) S-term,
c) S-termi se dobijaju samo primenom gornja dva pravila konano mnogo puta.
Neka u raunu postoji samo jedno pravilo konverzije:svaki pod-term oblika (((SA)B)C) se
transformie u term ((AB)(AC)),pri emu su A,B,C S-termi2.
Nisu svi funkcionalni programski jezici direktno zasnovani na raunu, ali su oni koji jesu najpoznatiji i najuticajniji.
Stoga e se ovaj tekst odnositi samo na implementaciju onih jezika koji jesu zasnovani na raunu.
2
S-term i opisano pravilo transformacije su ustvari deo kombinatorskog rauna koji ima tako|e veliki znaaj u
implementaciji funkcionalnih programskih jezika i koji e biti opisan u etvrtom poglavlju.
39
Normalnom formom rauna se naziva term na koji se ne moe primeniti nijedno pravilo
konverzije.Intuitivno,normalna forma se moe smatrati i rezultatom raunanja,odnosno vrednou
terma.
Za razliku od gornjeg primera , termi i pravila konverzije rauna su vrlo intuitivni.Intuitivno
tumaenje osobina rauna e u daljem tekstu biti navo|ena uz formalne definicije.
Definicija.Termi rauna ( termi, ponekad i izrazi) se grade od simbola iz skupa {,(,), .} i
unapred zadatog skupa identifikatora Id. Neka je za nae potrebe skup identifikatora Id sledei skup:
{a, b, , z}.
termi se grade na sledei nain:
a) x je term, ako x Id,
b) e1e2 je term, ako su e1 i e2 termi,
c) x.e je term, ako x Id i ako je e term,
d) (e) je term, ako je e term i
e) termi se dobijaju primenom gornjih pravila konaan broj puta.
term naveden u pravilu c) se esto naziva () apstrakcijom, dok se term naveden u pravilu b) esto
naziva primenom (ili apstrakcijom).
Intuitivno (u ta emo se uveriti u kasnijim primerima) apstrakcija odgovara definisanju
funkcije (u matematici ili programiranju) od jednog argumenta (x) sa telom e. Primena odgovara
primeni terma (funkcije) e1 na term e2.
Zbog jednostavnijeg zapisivanja termova, uvodimo dve konvencije:
termi oblika x1. x2. . xn.e se mogu zapisivati i kao x1x2 xn.e,
termi oblika ((e1e2)e3) se mogu zapisivati i kao e1e2e3 (tj. nadalje pretpostavljamo da je primena
levo-asocijativna)
raun je u stvari jedan od dva najpoznatija formalizma za opis rada sa funkcijama (definisanja
funkcija i njihove primene): drugi je predstavljanje funkcija kao skupova ure|enih parova. raun je
me|utim optiji: dozvoljava primenu funkcije na drugu funkciju i rekurzivne primene funkcija. Ni
jedno ni drugo nije mogue predstaviti uobiajenom predstavom funkcija kao skupom ure|enih parova
(zbog takozvanog Russel-ovog paradoksa).
40
Intuitivna predstava slobodnih identifikatora je vrlo jednostavna: slobodni identifikatori su oni koji se
pojavljuju unutar tela apstrakcije, a ne pojavljuju se kao argumenti apstrakcije (tj. nisu
vezani lambdom). Pojam slobodnih identifikatora rauna je analogan pojmu globalnih
promenljivih funkcije nekog programskog jezika3.
Primer. U termu x.xz je identifikator z slobodan, dok identifikator x nije. U termu
xyz.abc identifikatori a, b i c su slobodni.
1.2.2 Pravila supstitucije
Supstitucija (zamena) svih slobodnih pojava identifikatora x termom e1 u izrazu e2 se oznaava
[e1/e2]e2 (ili: e1 stavljamo umesto svih slobodnih pojava identifikatora x u termu e2).
a)
[e / x i ]x j = {
e , ako i=j
xj , ako i j
Kao to je ve reeno, slobodne promenljive u rauna (odnosno funkcionalnih programskih jezika) mogu biti uzrok
neefikasnosti funkcionalnih programa.
41
1.2.3 Konverzije
Znajui pojmove slobodnih identifikatora i supstitucije , spremni smo da definiemo i pravila
transformacije termova, ime dovravamo definiciju rauna.
Definicija. Pravila za konverziju rauna su sledea :
- konverzija :
- konverzija :
- konverzija :
x.e
(x.e1 )e2
x.(ex)
42
Pri normalnoj redukciji se od svih najspoljanjijih reducibilnih podtermova za redukciju prvo bira
najlevlji. Pri aplikativnoj redukciji se od svih najunutranjijih reducibilnih podtermova za redukciju
prvo bira najlevlji.
Primer. U termu (x.y) (( x.x)z) je najunutranjiji podterm (x.x)z, dok je najspoljanjiji
reducibilni term itav polazni term. Normalnom redukcijom se term redukuje na sledei nain:
(x.y)(( x.x)z) y
(1)
43
- Curry-rana verzija
Primer: x.y.+x(*yy)
nije jo izraunato
Kako implementirati Normal Order Reduction ?
44
- Kopiranje
45
Koje izraunavanje :
- NOR
- Pointeri
- Zamena originalnog vora rezultatom
Problem : kopiranje je naporno, teko i sporo !
Konaan rezultat - NEEFIKASNOST
Od 1971-1976 (objavljeno 1979)
Kombinatori ( Schonfinjel, Carry & Fey's 1958 )
Kombinatori zatvornei lambda izrazi (bez slobodnoih promenljivih)
(x.x) = I identitet Ia a
(x.y.x) = K kancelerator Kab a
(x.y.z.xz(yz)) = S Sabc ac(bc)
Proizvoljan izraz se moe predstaviti odgovarajuom kombinacijom S i K kombinatora.
Ia = SKKa = Ka(Ka) = a
Kako transformisati izraz u SK i I kombinatore ?
C[x.x] I
C[x.c] c x Kc
C[x.AB] S(x.A)(x.B)
(x.AB)cA[xc]B[xc]
S(x.A)(x.B)c(x.A)c((x.B)c)
C[x]x , x je promenljiva ili konstanta
C[(x)] = (C[x]) C[x.y.E]=C[x.C[y.E]]
Prevodimo primer:
C[(x.+x1)]S[x.+x][x.1]S(S[x.+][x.x])[x.1] S(S(K+)I)(K1)
Nema lokalnih promenljivih!
Radi li ?
S(S(K+)I)(K1)5S(K+)I5((K1)5)K+5(I5)(K15) +(I5)(K15)+5(K15)+51
Optimizacija :
Zato. Iako nema parametara (pa ni potrebe za njihovim zamenjivanjem) SKI termovi su predugaki.
Uoavamo karakteristine pod termove :
(S(Kp)I)a (Kpa)(Ia)pa
1. (S(Kp)I) = p optimizacija
S(Kp)(Kq)a(Kpa)Kqa)pq
2. S(Kp)(Kq) = K(pq) optimizacija
C[x.y.+xy]=C[x.C[y.+xy]] = ....
S(S(KS)(S(S(KS)(S(KK)(K+)))(S(KK)I)))(KI)
46
47
Jo jedna optimizacija
Cpp, ako je p komutativni operator
Uvedimo jo neke optimizacije:
XnXn-1.... X2 X1.pq =
[Xn.[Xn-1....[X2.[X1.pq]....]]=
[Xn.[Xn-1....[X2.p1q1]....]]= (velicina 3)
S[X2.Sp1][x X2q1]
S(BS p2)q2
(velicina "duzina" 5)
2 2
[X3.S(BSp )q ]
S[X3.S(BSp2)]q3
S(BS[X3.BSp2] )q3
S(BS(B(BS)p3)q3
(duzina 8)
.......
S(BS(B(BS)(B(B(BS))p4))))q4(12)
[ta se deava u stvari i kako to moemo popraviti
[x.Epq] = S(BE p1)q1
Prave se dva kombinatora,od kojih je jedan ugnjeden.
Uvodimo optimizaciju (Turner)
S(Bxy)z S'xyz
Tada bi postojalo jednostavnije prevo|enje
[x.Epq]=S'E p1q1
Pravilo redukcije :
S'abcx = S(Bab)cx = (Babx)(cx)=a(bx)(cx)
S' je kao i S,sa "extra" prvim argumentom.
Kad se S' optimizacija primeni, tada se promenljive x1..xn redom iz izraza p i q apstrakuju kao
Spq
S'S p2q2
S'(S'S) p3q3
S'(S'(S'S)) p4q4
Broj kombinatora sada linearno raste sa brojem apstrakovanih promenljivih.
Broj S' je "produenje" kombinatora S, pravimo i odgovarajua produenja za B i C.
B'abcxab(cx)
C'abcxa(bx)c
Sa optimizacionim pravilima:
B(ab)c B'abc
C(Bab)cC'abc
(kako se pokazuje korektnost gornjih pravila)
48
S[x.Ex]
isto kao i:
SE[x.X]a = (Ea)[x.X]a
Moe i bez njih,ali se pravila za S,B* i C "gardiraju" uslovom x <> X ,pa se onda dobija isti
prevod,ali u dva cuga.Tu je kraj.Preveli smo.
Vraamo se na redukciju:
Podseamo: primena:
konstante:vorovi grafa
49
@$
x $
@
@ $
@ $
novi!
@
@
z
y
@
s
z
@ $
@ $
novi!
@
@
z
y
@
B
@
x
z
@ $
@
@
C
@
z
@
C
@
x
Slino za S',B*,C'.
50
@ $
z
y
ugra|ena funkcija:
@ $
zbir
$
Rekurzija:
Umesto realizacije Y kombinatora lambda izrazom,uvodimo ga kao ugra|eni kombinator.
(kao opti nain realizacije rekurzije)
@
y
@
x
ili
@
y
@
x
@
y
Redukcija:
@
@
@
.
.
.
.
.
.
k
.
.
.
51
-Poevi od vrha steka, sledimo levu granu sve dok ne nai|emo na vor koji nije vor primene
("unwinding the spine"). Usput u stek stavljamo adrese vorova...Stek je tu zbog efikasnosti. Ako je
kombinator, primenimo odgovarajuu
-Ako je ugra|ena funkcija, rekurzivno pozvati evaluator za one argumente koje je potrebno izraunati.
Ponavljati "razvijanje"sve dok ima ta da se redukuje, odnosno sve dok ne do|emo u tzv. WHNF.
Zasad kaemo da su WHNF: konstante
primene funkcija bez dovoljno argumenata
(posle emo proiriti spisak)
-Rekurzivni poziv moe koristiti isti stek
indirection nodes:
-problem sa selekcijom
-"indirection nodes"
-bolje prvo redukovati,pa kopirati
Pa tako umesto R[kxy] = x
R[kxy] = R[x]
Kraj lambda rauna:
Kako prevodimo ostalo iz naeg jezika?
Podsetimo se:(lambda(x1...xn)e) "apstrahovanjem" promenjivih x1,...,xn iz izraza e -primitivne funkcije
u odgovarajue kombinatore
(add x y) -> add x y
(koji e se opet redukovati po unapred utvr|enim pravilima)
-(let blok)
(let e (x1.e1)...(xn.en))
-dve mogunosti:zameniti unutar e sve x1,...,xn sa e1,...,en pa onda prevesti e
-ili
let x1 = e1,...,xn = en in e
(lx1. ...lxn.e)e1...en
-letrec blok
(letrec e (x1.e1)...(xn.en))
Ako (letrec e (x1.e1)) tada
let(rec) x1=e1 in e = [x1.e](Y[x1.e1])
Ostali sluajevi se rade svo|enjem na opisani sluaj, tako to smetamo identifikatore i izraze u listu:
letrec (x1,...xn) = (e1,...en) in e
[<x1,...,xn>.e] (Y[<x1,...,xn>]<e1,...,en>)
Jo samo odgovor na pitanje: Kako apstrahovati listu identifikatora iz izraza? Uvo|enjem kombinatora
U:
Ufx -> f(hd x) (tail x)
i pravila prevo|enja:
[<x1,...,xn>.e] = U[x1.[<x2,...,xn>.e]]
[<>e] = Ke
Primer:
[<x,y>.+ xy] =
U[x.[<y>.+xy]] =
U[x.U[y.[<>.+xy]]] =
U[x.U[y.K+xy]]] =...
(a.b) -> CONS a b
i dodajemo u spisak WHNF jo i term CONS a b
-To e nam omoguiti da "rukujemo" beskonanim strukturama podataka
52
f =xx.
case xx of
Nil ->Nil
CONS x' xs' ->case xs' of
Nil - > CONS x' Nil
CONS x xs ->...x',x,xs,xs'
-------------------------Funkcijom M (ali na primeru) za
f p11...p1n = e1
.
.
.
.
.
.
f pm1...pmn = em
[u1,...,un]
p11,...,p1n ; e1
pm1,...,pmn ; em
E
Poinjemo
[u1,u2,u3] Unutra bi trebalo da stoje
prevodi !
demo = u1.u2.u3
f [] ys
; A f ys
f (x:xs) []
; B f x xs
f (x:xs) (y:ys) ; C f x xs y ys
panic
1.Variable rule
[u2,u3]
M []
ys
(x:xs) []
(x:xs) (y:ys)
; A u1 ys
; B u1 x xs
; C u1 x xs y ys
panic!
Nije bitno kako se promenjive zovu, bitno da su promenjive!
2. Constructor rule
Prearaniramo da su svi konstruktori istog tipa jedan do drugog.To smemo! Potom uvodimo case
case u2 of
Nil ->
[u3]
M ys ; A u1 ys
panic!
[u4,u5,u3]
M x,xs,[]
; B u1 x xs ;
x,xs,(y:ys)
; C u1 x xs y ys
CONS u4 u5 ->
panic!
.
3. Empty rule:
[]
M
; A u1 u3
-> a u1 u3
panic!
________________
M [] [] e
-> e
4. Mixture rule:
demo []
ys
xs
[]
(x:xs) (y:ys)
[ u1,u2]
M
[]
ys ; ... )
M [u1,u2]
54
xs [] ; ...
M [u1,u2]
(x:xs) (y:ys) : ...
panic!
Neki specijalni sluajevi:
[]
(x:(y:z))
-> ...
-> ...
[u1]
M [] ; ...
(x:(y:z)) ; ...
panic!
case u1 of
NIL -> M ...
[u2, u3]
cons u2 u3 -> M
case u3 of
NIL -> M [] [] panic!
cons ... ->
Translacija ZF izraza
55
Prevodimo:
a) C[ [e | v <-l ; Q] ] = fMap (v. C[ [e|Q] ] ) C[L]
b) C[ [e | B ; Q] ] = IF C[ B ] C[ [e | Q] ] NIL
c) C[ [e | ] ] = CONS C[e] NIL
Pravilo a) realizuje 1 i 2 pravilo ponaanja ZF izraza, pravilo 6, 3 i 4 pravilo ponaanja, a c 5. pravilo
ponasanja.
Da bismo bolje shvatili pravilo a), treba da se podsetimo da se [e/x]a , moe se realizovati kao (x.a)e.
Primer:
C[ [x*x| x<-[1, 2, 3] ; add x] ]
fMap (x . C[ [x*x | add x] ]) [1, 2, 3]
(a)
fMap( x . IF (add x) C[ [x*x | ] ] NIL ) [1, 2, 3] (b)
fMap( x . IF (add x) (CONS (mul x x) NIL) NIL) [1, 2, 3] (c)
______________________________________________________________________
Kad bi ovo poelo da se izvrava, ta bi se desilo?
[1]++[]++[9]
Moe dalje, ali odustajemo. Ostatak spada u transformacije programa.
Wadler, 1987,
57