% === 11.1 === % ukazkove implementacie v Haskelli: % last [] = error "prazdny zoznam" -- toto je volitelne % last [x] = x % last (_:s) = last s % init [] = error "prazdny zoznam" -- toto je volitelne % init [_] = [] % init (x:s) = x : init s % zip (x:s) (y:t) = (x,y) : zip s t % zip _ _ = [] % predikat nazveme lastel; mohlo by to byt aj last, ale taky uz existuje a hoci % by jeho prekrytie nerobilo problem lastel([A], A). lastel([_|T], X) :- lastel(T, X). % lastel([_,H2|T], X) :- lastel([H2|T], X). -- alternativa k predchadzajucemu riadku init([_], []). init([H|T], [H|X]) :- init(T, X). % init([H1,H2|T], [H1|X]) :- init([H2|T], X). -- alternativa k predchadzajucemu riadku zip([H1|T1], [H2|T2], [(H1,H2)|T12]) :- zip(T1, T2, T12). zip([], [_ |_ ], []). zip(_, [], []). % zip(_, _, []). -- alternativa k poslednym dvom riadkom; to by sme ale dostali cez ; % viacero nespravnych rieseni, kedze tento fakt sa da pouzit aj pre neprazdne pravidla. % === 11.2 === % toto sa pouzit neda, treba pouzit predikat call/[2..] % ... :- MF(In, Out), ... . % mapf(:Fun, +List, -Result) % : oznacuje predikat, + plne instanciovany term, - neinstanciovanu premennu mapf(_, [], []). mapf(Fun, [H|T], Out) :- call(Fun, H, HOut), mapf(Fun, T, TOut), Out = .(HOut, TOut). % alternativne mozeme namiesto posledneho pravidla pouzit jedno z tychto % map(Fun, [H|T], [H1|T1]) :- call(Fun, H, H1), map(Fun, T, T1). % map(Fun, [H|T], Out) :- call(Fun, H, H1), map(Fun, T, T1), Out = [H1|T1]. % UKAZKA A POKEC K CHVOSTOVEJ REKURZII V C % % int fun(int x) { % if (x == 1) return 0; % x--; % return fun(x); % } % % za normalnych okolnosti sa pri rekurzivnom volani funkcie plni zasobnik - kazde volanie % funkcie vytvori zaznam na zasobniku s informaciami o lokalnych premennych, navratovej % adrese (to plati snad v kazdom jazyku); ak je vsak rekurzia hlboka, moze dojst % k zaplneniu pamate pre zasobnik % tomu sa da vyhnut v pripade pouzitia chvostovej rekurzie - funkcia je chvostovo rekurzivna, % ak vola sama seba iba raz a toto volanie je uplne poslednou cinnostou, ktora sa % vo funkcii vykona % tuto vlastnost vedia vyuzit kompilatory na optimalizaciu kodu, ktory generuju tak, % ze vzdy pri rekurzivnom zavolani funkcie nie je potrebne zachovat aktualny usek % zasobnika vyuzivany sucasnym volanim funkcie, kedze sa k nemu uz nevratime - pri zavolani % funkcie teda blablabla navratovu adresu zachovame (stale sa chceme vratit za miesto, kde % bola prvykrat zavolana funkcia) a stary usek zasobnika prepiseme hodnotami pre zasobnik % noveho volania funkcie % to nam teda vo vysledku umozni obmedzit velkost zasobnika z linearnej na konstantnu % (vzhladom na hlbku rekurzie) a takisto z posledneho rekurzivneho volania sa vieme vratit % na miesto prveho volania namiesto linearneho v konstantnom case % proddot(+Vect1, +Vect2, ?Prod). proddot([], [], 0). proddot([H1|T1], [H2|T2], Out) :- proddot(T1, T2, Out1), Out is Out1 + H1 * H2. % ukazky nespravnych rieseni: % proddot([H1|T1], [H2|T2]) :- H1 * H2 + proddot(T1, T2, Out1). % predikaty nie su funkcie - nic nevracaju; snazime sa ich dokazat a pripadny vysledok % ziskame ako Prologom vypocitanu instanciaciu niektorej premennej (tu to ma byt spravne Out) % proddot([H1|T1], [H2|T2], out) :- out = H1 * H2 + proddot(T1, T2, Out1). % premenne musia zacinat malym pismenom % proddot([H1|T1], [H2|T2], Out) :- Out = H1 * H2 + proddot(T1, T2, Out1). % neda sa pouzit =; to unifikuje termy, ale nevynuti vyhodnotenie aritmetickeho vyrazu! skuste si % uz vobec by neslo ==; to robi syntakticku rovnost termov % =:= by tiez neslo; to robi rovnost po vyhodnoteni aritmetickych vyrazov na oboch stranach, pritom % na lavej strane by sme mali v momente dokazovania predikatu vzdy neinstanciovanu premennu % tu len staci vediet (vygooglit), ako pocitat vektorovy sucin prodcross([A1,A2,A3],[B1,B2,B3],[C1,C2,C3]) :- C1 is A2 * B3 - A3 * B2, C2 is A3 * B1 - A1 * B3, C3 is A1 * B2 - A2 * B1. % opat je potrebne pouzit is, kedze chceme aritmeticke hodnotenie; u = by sme dostali % ?- prodcross([1,2,3], [4,5,6], [C1,C2,C3]). % C1 = 2 * 6 - 3 * 5, % C2 = 3 * 4 - 1 * 6, % C3 = 1 * 5 - 2 * 4