Uploaded by litig85506

FP izpiti kolokviji

advertisement
Funkcijsko programiranje: rešeni izpiti
(januar 2021)
2019/20 1. rok
1. naloga
a)
{a: 'a, c: 'b} -> 'c -> 'd
{a: 'a option, c: 'b list} -> 'c -> 'd
{a: bool option, c: bool list} -> bool -> -> bool
b)
fun find el sez =
#2 (List.foldl (fn (a, z) => if a = el then ((#1 z) + 1, (#2 z) @ [(#1
z)]) else ((#1 z) + 1, (#2 z))) (1, []) sez);
2. naloga
fun summarize sez =
let
fun pomozna sez {a=a, b=b} =
case sez of
SOME (A {a=a2})::t => pomozna t {a = a + a2, b = b}
| SOME (B (ref b2))::t => pomozna t {a = a, b = b + b2}
| NONE::t => pomozna t {a=a, b=b}
| [] => {a=a, b=b}
in
pomozna sez {a=0, b=0}
end;
-
A JE TUKI PROU NARJEN UN PRIMER PRI NAVODILIH? OD KJE 5 in 28?
A ne bi moglo bit 6 in 10, če js to prou razumem?
Ja, so narobe navodila.
Hvala :)
3. naloga
e1: 1,1, e2: 0,2, e3:1,2, e4: 0,0
(*Lokalno okolje, najslabša rešitev*)
(if e1
(letrec ([d2 (e2)]
[d3 (e3)])
(+ d2 d2 d3))
(letrec ([d3 (e3)])
(+ d3 d3)))
(*Najtežja rešitev z zakasnitvami in sprožitveni*)
(letrec ([ev3 e3]
[d2 (delay (lambda () e2))])
(if e1 (+ (force d2) (force d2) ev3) (+ ev3 ev3)))
(if e1 (+ (force d2) (forc
(letrec ([ev3 e3]
[ev2 e2])
(if e1 (+ ev2 ev2 ev3) (+ ev3 ev3)))
(if e1 (+ (force d2) (force d2) ev3) (+ ev3 ev3)))e d2) ev3) (+ ev3
ev3)))
(letrec ([ev3
[d2 (delay (lambda () e2))]
4. naloga
def arg_checker(f):
def wrapper( *args, **kwargs):
if len(args) != 2 and len(kwargs) != 2:
print('wrong number of parameters')
else if 'password' in kwargs.keys():
if kwargs['password'] == 'koala':
f()
else:
print('password incorrect')
else:
print('password not given')
2019/20 2. rok
1.naloga
datatype sadje =
Jabolko
| Hruska;
fun teza e =
case e of
Jabolko => 100
| Hruska => 150;
fun kalorije e =
case e of
Jabolko => 80
| Hruska => 120;
Lažje je v objektno-usmerjenim, ker vse spremembe naredimo le na enem mestu (naredimo nov
razred in implementiramo funkcije), medtem ko pri funkcijskem prog. moramo pri vsaki funkciji
dodati nov case.
2. naloga
fun repna_obdelava f1 f2 f3 n vhod =
let
fun pomozna (vhod, acc) =
if f1 (vhod)
then acc
else pomozna (f2(vhod), f3(vhod, acc))
in
pomozna (vhod, n)
end
val potenca_repna = repna_obdelava
(fn (x, y) => y=0)
(fn (x, y) => (x, y-1))
(fn ((x, y), acc) => acc*x)
1;
val vsota_repna = repna_obdelava
(fn sez => null sez)
(fn sez => tl sez)
(fn (sez, acc) => acc+(hd sez))
0;
(* f1 *)
(* f2 *)
(* f3 *)
(* zac. vr. *)
(* f1 *)
(* f2 *)
(* f3 *)
(* zac. vr. *)
3. naloga
(define preskocni_tok
(lambda (#:preskok [preskok 1] . sez)
(letrec ([f
(lambda (x)
(cons (list-ref sez x)
(lambda ()
(f (modulo (+ x preskok) (length sez))))))])
(f 0))))
4. naloga
1. 3+13+13 = 29
2. 3+13+4 = 20
3. 3+13+13 = 29
4. 3+13+4 = 20
a = 25
b = 23
5. 3+23+23=49
6. 3+23+4=30
7. 3+23+23=49
8. 3+23+4=30
2018/19 1. rok
1.naloga
Na kratko (največ dve povedi!) odgovori na naslednja vprašanja:
a.) (1t) Kaj je pomanjkljivosti sistema tipov (tipizator), ki je hkrati poln in trden?
Če je hkrati in poln, tipizator ne more ugotoviti, če je sistem ustavljiv. Izberemo namreč lahko le
2 od teh 3 lastnosti.
b.) (1t) Kombinacija dveh funkcionalnosti programskega jezika vodi do težav pri statičnem
sistemu tipov, ki se jih prevajalnik lahko ogne z omejitvijo vrednosti. Kateri dve funkcionalnosti
sta to?
Polimorfizem + mutacije??
c.) (1t) Kako lahko zmanjšamo odvečno število evalvacij, če namesto funkcije generiramo kodo
z makrom?
Lahko uporabimo lokalno okolje in v njem evalviramo izraz, lahko evalvacijo zakasnimo (tako
lahko tudi na primer preprečimo neskončno rekurzijo) ali pa uporabimo metodo “zakasnitev sprožitev”, kar je vedno najbolj učinkovito (ne pa najbolj enostavno).
d.) (2t) Kakšen je podatkovni tip funkcije f?
'a -> 'b -> 'c -> 'd
'a -> 'b -> 'c -> 'd -> 'e -> 'f
'a -> 'b -> 'c -> int option -> int list list -> int option
2.naloga
a)
datatype ('a, 'b) node = Node of (('b, 'a) node * ('a) * ('b, 'a) node) |
fin;
b)
; to mi ne dela ravno, ne vem zakaj
fun height drevo =
case drevo of
fin => 1
| Node (l, _, d) => 1 + Int.max (height l, height d);
Po mojem je “fin => 0”, ampak to seveda ni razlog zakaj ne dela...
3.naloga
(struct par (g r) #transparent)
(struct nic () #transparent)
???
4.naloga
fun poz flist arg limit =
List.foldl (fn (f, z) => if f (arg) >= limit then z + 1 else z) 0
flist;
Klic takšne funkcije:
poz [fn x => x - 100, fn x => x + 100] 0 ~101;
2018/19 2. rok
1.naloga
a.) (1t) Imejmo sistem tipov (tipizator), ki je poln in trden? Zakaj tak tipizator v praksi ni
uporaben?
Ker v tem primeru ne more biti ustavljiv, tj. tipizator se lahko ne bo nikoli ustavil.
b.) (1t) Minimalno katere lastnosti mora programski jezik oz. njegov sistem tipov (tipizator), da
lahko brez uvedbe posebnih novih podatkovnih tipov implementiramo sezname, ki hranijo
elemente različnih tipov (kot npr. v Pythonu ali Racketu)?
Tipizator mora uporabljati pretežno dinamično preverjanje (konkretno, da ne rabimo vnaprej
določiti podatkovnih tipov).
f1: int option option -> int
f2: int -> int
Če bi podali v f1 recimo string option option, bi še vedno šlo v naslednji korak - bi klicalo funkcijo
f2, kjer bi se zataknilo, ker stringa ne moremo množiti z int. Prevajalnik nam že po prevajanju
izpiše, kakšnega tipa morajo biti argumenti. Če podamo napačne, nam vrne napako.
2.naloga
F 4 5 = 5 + 5 + 5 + 5 + 0 = 20 (4 * 5)
G 2 10 = 2 ^ 10 = 1024
b) (1t) Opišite, kaj zares delata funkciji F in G.
F=a*b
G=a^b
c) (1t) Ali je katera od omenjenih funkcij vzajemno rekurzivna? Če da, opišite zakaj!
Ne, če bi hotela F uporabljati funkcijo G bi morala biti napisana kot vzajemna rekurzija (z and
vmes). Tukaj pa je G (ki uporablja F) definirana za F, zato po tem ni potrebe, saj jo že vidi
(prevajalnik gre po vrsti).
d) (1t) Ali je katera od omenjenih funkcij repno rekurzivna? Če da, jo navedite, če ne, pa opišite,
zakaj ne.
F ni repno rekurzivna, ker za vsakim rekurzivnim klicem še izvaja operacijo seštevanja. G pa je
repno rekurzivna. (Nisem siguren) ????
Če je funkcija repno rekurzivna bi moralo to veljati na vse veje. G kliče funkcijo F ki ni repno
rekurzivna in zato tudi G ni repno rekurzivna.????
e) (2t) Če lahko, funkciji F in G pretvorite v repno rekurzivno obliko. Če ne, argumentirajte, zakaj
ne.
fun F a b =
let
fun F 0 b acc =
acc
| F a b acc =
F (a-1) b (acc + b)
in
F a b 0
end
fun F2 a b =
let
fun pomozna(a, b, acc) =
if a = 0
then acc
else pomozna(a-1, b, acc+b)
in
pomozna(a, b, 0)
end;
fun G2 a b =
let
fun pomozna(a, b, acc) =
if b=0
then acc
else let val r = G2 a (b-1) in F a r end;
in
pomozna(a, b, 1)
end;
3.naloga
A) Nekaj v zvezi s tem, da so tokovi neskončni in zato moremo uporabiti različico folda, ki
ima ustavitveni pogoj
Dodaten argument v akumulatorju bi bilo število, kolikokrat naj se fold izvede nad tokom
(define (foldX/stream func acc stop stream)
(if (= stop 0)
acc
(foldX/stream func (func (car stream) acc) (- stop 1) ((cdr stream)))))
Primer uporabe:
(define naravna
(letrec ([get (lambda (x) (cons x (lambda () (get (+ x 1)))))])
(get 1)))
(define (foldX/stream func acc stop stream)
(if (= stop 0)
acc
(foldX/stream func (func (car stream) acc) (- stop 1) ((cdr stream)))))
(foldX/stream + 0 5 naravna)
Vrne 15.
4.naloga
def ​flatten​(fun): ​# ne dela
def ​flat_rek​():
print​(fun()) ​# tako dostopamo, nisem implementiral
return ​flat_rek
@flatten
def ​test​():
return ​[ ​1​, ​[​'b'​,​'c'​]​, ​[[​1​]​,​[​2​]] ]
2018/19 3. rok
1.naloga
a.) Kaj so to lažno pozitivni primeri?
Primeri, ki so negativni, ampak jih tipizator klasificira kot pozitivne. Torej programe brez napake,
zazna kot programe z napako.
b.) Ali so lažno pozitivni primeri zaželeni ali nezaželeni? Če so zaželeni, zakaj so koristni / če so
nezaželeni, zakaj se jim želimo izogniti?
So nezaželeni, ker tako nam lahko tipizator zavrne tudi programe, ki bi se pravilno izvedli.
c.) Podaj kratek primer lažno pozitivnega primera v poljubnem programskem jeziku in navedi
nek drugi programski jezik, v katerem je tvoj podani primer pravilno pozitivni primer.
sml: if true then 10 else 10 div “nekaj” (prepoznal bi ga kot pozitivnega)
V python-u bi tole delalo ( oz. v kakem drugem jeziku, ki je tudi pretežno dinamičen
(preverjanje)).
2.naloga
fun f1 (s1, s2) =
let
fun f1 sez acc =
case sez of
[] => acc
| {comment=_, data= Trip (_, n, _)}::t => f1 t (acc + n)
in
(f1 s1 0) + (f1 s2 0)
end;
3.naloga
4.naloga
14
10
9
19
15
9
b) Kakšen doseg vrednosti privzeto uporablja Python (od dveh, ki smo ju omenili na pred)?
dinamični
c) Katera vrsta dosega ima prednost pred drugo-slašbo? Naštej tri prednosti.
Vrsta dosega: leksikalni ima prednost
Prednosti:
slajdi
2017/18 1. rok
1.naloga
a) SML ima Lažno Pozitivne primere - primer programa je, ko definiramo case za sezname
in ne podpremo možnosti, da dobimo na vhod prazen seznam. Program se ne prevede
ker moramo definirati vzorec za vsako možnost, mi pa vemo, da ni možno da bo na vhod
prišel prazen seznam. Program je negativen a ga sml označi kot pozitivnega (lažno
pozitiven).
… a ni “match non exhaustive” samo warning?
primer iz slajdov je: if True then 10 else 10 div “niz”
b) RACKET ima Lažno Negativne primere - primer programa je, ko ne definiramo ustrezne
ustavitve na koncu seznama in poskuša preveriti element ki ne obstaja. ??? Racket je
tudi mocno tipiziran kar pomeni da ima lazno pozitivne primere???
c) JAIS je
i)
dinamično tipiziran (tipi izrazov se preverjajo med izvajanjem
ii)
Krepko/eksplicitno tipiziran (tekom programa se stalno preverja tip
iii)
Ima leksikalni doseg
2.naloga
(define (splosna f1 f2 zacetek konec)
(if (> zacetek konec)
null
(cons (f1 zacetek)
(splosna (f2 zacetek) konec))))
(define (stetje zacetek konec)
(splosna (lambda (a) a)
(lambda (a) (+ a 1) zacetek konec)))
(define (sinus zacetek konec)
(splosna (lambda (a) (sin a))
(lambda (a) (+ a (/ pi 8)) zacetek konec)))
3.naloga
4.naloga
2017/18 2. rok
1.naloga
2.naloga
3.naloga
4.naloga
2017/18 3. rok
1.naloga
2.naloga
3.naloga
4.naloga
Template
1.naloga
2.naloga
3.naloga
4.naloga
Download