Prezentace se nahrává, počkejte prosím

Prezentace se nahrává, počkejte prosím

Vestavěné predikáty a jejich použití Jan Hric, KTI MFF UK 1997-2010c (oprava 4.5.)

Podobné prezentace


Prezentace na téma: "Vestavěné predikáty a jejich použití Jan Hric, KTI MFF UK 1997-2010c (oprava 4.5.)"— Transkript prezentace:

1 Vestavěné predikáty a jejich použití Jan Hric, KTI MFF UK c (oprava 4.5.)

2 Vestavěné predikáty  aritmetika  výpočty, porovnávání  vstup/výstup  spracování termů a atomů  testy druhu, porovnávání, vytváření a dekompozice  řízení spracování  + práce s databází  práce s množinami řešení

3 Aritmetika  “speciální” predikáty, které vyhod. výrazy  důsledek neexistence typů  operátorová syntax  is/2  vyhodnotí výraz napravo a unifikuje s levou stranou  ?- is(X,1+3), X is 2+2.  is je operátor, oba zápisy jsou možné a rovnocenné  >/2, =/2, =

4 Aritmetické funkce  které se vyhodnocují: (viz help a manuál, impl.)  + - * / // mod ^  max min rand/1 ip fp  ln log sin cos asin atan...  bitové: /\ \/ > \  ! Nevyhodnocuje se při předávání parametrů  Chybně 1: faktorial(N,...):-  faktorial(N-1,...),...  Přesněji: synt. OK, sem. chybně: ((2-1)-1)-1  Chybně 2: faktorial(N,...):- N is N-1,...  Dtto; proměnnou nelze měnit „na místě“, správně:...N1 is N-1,…

5 Délka seznamu  aritmetika je jednosměrná (a nedeklarativní) length([],0). % mod (+,?) length([_|L],N):- length(L,N1), N is N1+1.  seznam dané délky (z anonymních prom.) length1(0,[]). % mod (+,?) length1(N,[_|L]):- % impl. N>0,N1 is N-1,length1(N1,L).  test N>0: pro deklarativní správnost, brání cyklu  rozdíl: (+,+) neúspěch: l. po návratě z rek., l1. v hloubce

6 Unární aritmetika  V Prologu: číselné hodn. lze repr. pomocí termů  Dat. typ: 0 pro 0, s(N) pro n+1 (tj. následníka) ?- plus(s(s(0)),s(s(s(0))), X). % 2+3 je ? X=s(s(s(s(s(0)))))  I jiné reprezentace čísel: délkou seznamu ?- komb(3,[a,b,c,d,e],K). vs ?- komb(s(s(s(0))),[a,b,c,d,e],K). vs ?- K=[_,_,_],komb([a,b,c,d,e],K). %|K| = 3 DC: prostřední prvek, první (a druhá) polovina s.

7 Insertsort % insert(+X,+L,-V):- zatřídí X do uspořádaného L a výsledek je V ; L je seznam čísel (protože používáme <...) insert(X,[],[X]). insert(X,[Y|L],[X,Y|L]):- X=Y, insert(X,L,V). % isort(+L,-V) :- utřídí L do V isort([],[]). isort([X|L],V):- isort(L,V1), insert(X,V1,V).  zobecnění: porovnávací procedura jako parametr

8 Mergesort % msort(+I::[Int],-O::[Int]) :- utřídí I do O msort([],[]). msort([X],[X]). %nutné obě koncové podm. msort(I,O):- I=[_,_|_], /*% I má aspoň dva prvky */ mergesplit(I,I1,I2), msort(I1,O1), msort(I2,O2), merge(O1,O2,O).  metoda: rozděl a panuj  jinak: mergesplit/3 obsahuje stráž-podmínku  ale pak není univerzální

9 Slití seznamů: merge/3  Slije uspořádané (číselné) seznamy, vyloučí vícenásobné % merge(+L1,+L2,-L) merge([],L,L). merge(L,[],L):- L\=[]. % bez opakovaných řešení merge([X1|L1],[X2|L2],[X1|L]):- X1X2, merge([X1|L1],L2,L). merge([X1|L1],[X2|L2],[X1|L]):- % bez opak. prvků X1=X2, merge(L1,L2,L). % test nutný pro dekl. spr.

10 Rozdělení: mergesplit/3 /* mergesplit(+L,-L1,-L2):- * rozdělí L na sudé (L1) a liché (L2) */ mergesplit([],[],[]). mergesplit([X],[X],[]). mergesplit([X,Y|L],[X|L1],[Y|L2]):- mergesplit(L,L1,L2).  viz autotest z minulé přednášky

11 Stavba Haldy  Stavba min-haldy přeuspořádáním ze stromu  Použitelné taky pro heapsort heapify(v,v). heapify(t(L,X,R),H):- heapify(L,HL), heapify(R,HR), adjust(X,HL,HR,H). adjust(X,HL,HR,t(HL,X,HR)):- tree_gt(X,HL),tree_gt(X,HR). adjust(X,t(L,X1,R),HR,t(HL,X1,HR)):- X>X1, tree_gt(X1,HR),adjust(X,L,R,HL). adjust(X,HL,t(L,X1,R),t(HL,X1,HR)):- X>X1, tree_gt(X1,HL),adjust(X,L,R,HR). tree_gt(X,v).% progr. technika: lifting, „zvednutí“ =< tree_gt(X,t(_L,X1,_R)) :- X=

12 Symbolické derivace  der(výraz, X, derivovaný_výraz), bez zjednodušování der(N,X,0) :- number(N). % test čísla der(X,X,1). % bez symb. parametrů, jiných proměnných a parciálních derivací  der(Y,X,0) :- atom(Y), X\=Y.% derivace podle jiné prom.anebo symb. konstanty der(X^N,X,N*X^N1):- N > 0, N1 is N-1. der(sin(X),X,cos(X)).% pro každou funkci 1 fakt (A) der(cos(X),X,-sin(X)).% anebo: …, (-1)*sin(X) ), když nemáte unární mínus. der(e^X,X,e^X). der(log(X),X,1/X). der(F+G,X,DF+DG):- % pro každý způsob skládání fcí (tj. operátor) 1 pravidlo der(F,X,DF),der(G,X,DG). der(F-G,X,DF-DG):-der(F,X,DF),der(G,X,DG). der(F*G,X, F*DG+DF*G):-der(F,X,DF),der(G,X,DG). der(1/F,X,-DF/(F*F)):-der(F,X,DF). % spec. případ další klauzule der(F/G,X,(G*DF-F*DG)/(G*G)):-der(F,X,DF),der(G,X,DG).  Bez zjednodušování: ?- der(3*x+2,x,D). –> D=(3*1+0*x)+0  Druhá derivace  : nepřehledná  Proměnné: doménové vs. Prologovské  Zde bez složených funkcí, lze implementovat rozepsáním podle vnější fce : der(sin(U),X,cos(U)*DU):-der(U,X,DU). % nahradí fakt (A)  Anebo změnou reprezentace termů: př.: t(sin,[t(^(2),[x])])  der(t(F,[G]),X,t(DF,[G])*DG):- der(G,X,DG), derF(F,DF).  derF(sin,cos). derF(exp,exp). % atd., nedokonalé: log potřebuje jiné (samostatné) pravidlo

13 N-arní stromy  struktura: t(sezn. podstromů f(klic,hodn,podstrom))% hranově ohodnocené stromy  Místo seznamů i jiné struktury: BVS  ! Vzájemně rekurzivní dat. strukturu ( t/1 a seznamy) zpracujeme vzájemně rek. Predikáty  Varianta: vrcholově ohodncené stromy: t(HodnotaVrch, [podstromy] ) t([f(k1,h1,v),f(k2,h2,t([f(k21,h21,v),f(k22,h22,v)])),f(k3,h3,v)])  Vyhledání složeného klíče s proměnou délkou (podle cesty), tj. vyhledávaní řetězců find([K],t(Ts),H):- member(f(K,H,_),Ts). find([K|Ks],t(Ts),H):- member(f(K,_,Ps),Ts), % jednoprvkový seznam … find(Ks,Ps,H). % … uspěje, ale pak v rekurzi neuspěje prázdný ?- find([k2,k21], T, H). H =h21; no  Datová struktura TRIE: vyhl. podle řetězců  Použitelné pro implemenataci vnořených záznamů s pojmenovanými položkami  Seznamy atribut-hodnota, zde jsou hodnoty strukturovány  Vlastně dopředný vyhledávací strom v alg. Aho-Corasicková  Ale nelze jednoduše odkázat a dostat se na daný podstrom  Aplikace: reprezentace XML, HTML … a jejich zpracování

14 Logické formule  struktura: true/0, false/0,  p/1…proměnné, explicitní funkční symbol  Nevhodné je negativní vymezení: atomy různé od true a false jsou proměnné  and/2, or/2, non/1, imp/2, ekv/2, (xor/2, nand/2…)  je_lf(LF).. LF je správně utvořená log. formule je_lf(true). je_lf(false). je_lf(p(_)). % elementární f. je_lf(and(A,B)):- je_lf(A), je_lf(B). % kontroluje funkční s. a #arg. je_lf(or(A,B)):- je_lf(A), je_lf(B). je_lf(non(A)):- je_lf(A). je_lf(imp(A,B)):- je_lf(A), je_lf(B). je_lf(ekv(A,B)):- je_lf(A), je_lf(B). % a další spojky… %nelze: je_lf(F(A,B)):- (F=and ; F=or ; F=imp ; F=ekv),…  Pro „dávkové“ ověření korektnosti vstupu z neověřeného zdroje do nekontrolujícího programu (prog. bez kontrol jsou přehlednější / kratší / lepší)  Dvě vrstvy interface: vnitřní nekontrolujíci, vnější kontrolující

15 Zjednodušování LF  zjedn(F,V) … zjednoduší f. odstraněním konstant zjedn(true,true). zjedn(false,false). zjedn(p(X),p(X)). zjedn(and(F,G),V):- zjedn(F,VF), zjedn(G,VG), zjedn_and(VF,VG,V). % další log. spojky analogicky zjedn(non(F),V):- zjedn(F,VF), zjedn_non(VF,V). zjedn_and(true,F,F). zjedn(F,true,F). zjedn_and(false,F,false). zjedn_and(F,false,false). zjedn_and(F,G,and(F,G)):- F\=true, F\=false, G\=true, G\=false. zjedn_non(true,false). zjedn_non(false,true). zjedn_non(F,non(F)) :- F\=true, F\=false.  Podobně zjednodušování aritmetických výrazů, např. pro derivace

16 Vyhodnocení LF 1/2  eval(LF,Ps,V).. Vyhodnotí LF s prom. Ps do V eval(true,_Ps,true). eval(false,_Ps,false). eval(p(X),Ps,V):-lookup(X,Ps,V). % vyhledání proměnné eval(and(F,G),Ps,V):-eval(F,Ps,VF), eval(G,Ps,VG), eval_and(VF,VG,V). % analogicky or, non eval(imp(F,G),Ps,V) :- eval(or(non(F),G),Ps,V). %převedení %eval(ekv(F,G),Ps,V) :- % nevhodné, exp. složitost % eval(or(and(F,G),and(non(F),non(G))),Ps,V). eval(ekv(F,G),Ps,V) :- eval(F,Ps,VF), eval(G,Ps,VG), eval(or(and(VF,VG),and(non(VF),non(VG))),Ps,V).

17 Vyhodnocení LF 2/2  Vlastní sprac. spojek eval_and(false,_VG,false). eval_and(VF,false,false):-VF\=false. %bez opak. řeš. eval_and(VF,VG,true):-VF\=false,VG\=false.  DC: rozšířit LF o sprac. konstanty unk/0 ve významu hodnota není známá, výsledek může být unk  opatrně: eval_ekv(X,X,true). % zdá se OK, ale platí pouze pro X=true a X=false -> přidat podmínky  ?- eval_ekv(unk,unk, true). ?? %rozšíření programu není OK

18 Typy: btree a log. fle  neformálně: typy pomocí BNF (Backus-Naurova forma)  bude (více) formálně: typy v Haskellu ::= v | t(,, )  dtto bin. strom, s “typem” parametrů ::= v | t(,, )  Typ l.f. ::= true | false | p( ) | and(, ) | or(, ) | non( ) | imp(, ) | ekv(, ) ad p/1: doménová jména proměnných jsou vnořeny v p/1 mají „samostatný namespace“: p(x), p(1), p(true), p(and)

19 Autotest  převést stručné seznamy čísel na úplné: rozvin/2 ../2 je aritm. posl., krok je daný rozdílem prvních dvou členů  když nejsou, tak default kroku je 1 .. považujme za operátor  jinak je nutné psát: [..(1,10),9,..(8,1)]  [1..6] ==> [1,2,3,4,5,6]  [1,3..6] ==> [1,3,5]  [5,4.. -1] ==> [5,4,3,2,1,0,-1]  jiná konvence: neuvedený krok je +1 nebo -1 podle pořadí mezí: [5.. -1]

20 Práce s programem  consult(Soubor)  anebo v menu  compile(Soubor)  listing(Co)  Co je Predikat, Predikat/Arita, seznam předcházejících ?- listing([append/3, member]). ?- listing. seznam všech nakonzultovaných predikátů

21 I/O  Termový  write(X) výpis termu  display(X) výpis bez operátorů, vše v prefixním tvaru  writeq(X) výpis v zpětně čitatelném tvaru, speciálně apostrofy  print(X)  používá portray/1 pro uživatelský výpis (idea: late binding – TVM) Bin. strom: |3|v>, nebo |3| |5|v>>  zkracuje (dlouhé) výpisy: vypíše „horní“ část termu, pak „…“  read(X) čtení jednoho termu s tečkou (a bílým znakem)  term(s(teckou),[na,konci]).  pokud může následovat operátor, musím mít konvenci, jak term ukončit  ! Syntaktická analýza zdarma (pokud reprezentujete vstup termem)  Používá se při čtení klauzulí programu: za tečkou nesmí být EOF  znakový nl, get(X),get0(X), put(X)  X je Ascii kód jednoho přečteného/vypsaného znaku (tj. číslo)  ovládání proudů (vstupního a výstupního)  formátovaný I/O, spolupráce s OS - viz manuál Backtracking nevrací přečtené/vypsané data

22 Ovládání proudů  vstupní a výstupní proud (stream)  aktuálními proudy jsou použity write, nl, read  vstupní proud  see(+Soubor) přesměruje vstup na Soubor  jméno je atom, často v apostrofech ’c:/home/m.pl’  seeing(?S) vrátí jméno akt. vstup. proudu  seen/0 přesměruje na stand. vstup, zvaný user klávesnice  výstupní proud - analogicky  tell/1, telling/1, told/0  ?-tell(’m.pl’),write(hello),told.  výpis (generovaného) programu „zdarma“  user je obrazovka

23 Řetězce a ascii kódy  řetězce jsou seznamy ascii kódů znaků  následující zápisy jsou totožné:  ”abc”  [97,98,99] % výpis  [0’a,0’b,0’c]  Ř. využijeme, pokud potřebujeme přístup na znaky, často stačí (a jsou správnou d.s.) atomy  Použitelné pro vstup, čitatelný výst. nutno naprogramovat  ascii kódy znaků:  0’a = 97  ! zápis ’a’ je atom a

24 Autotest  třídění  výběrem: vybere se minimum jako hlava výsledku a dále rekurze  quicksort  průnik, sjednocení: pro uspořádané seznamy (čísel)  napište predikát, který interní formu řetězců vypíše jako posloupnost znaků v uvozovkách (včetně okrajových uvozovek)  [97,99,98] ~> “acb”

25

26 Převod do DNF  dnf(F,V).. V je ekv. formule k F v DNF

27 Zavěsné mobily (rybičky)  Vyváženost, bezpečnost mobilu: vracíme seznam “chybných” mobilů  (pod)mobily nejsou pojmenované, vracíme celou strukturu mobilu  jiné možnosti: (jednoznačné ) jméno ve struktuře, polohu chyby vůči kořeni  D.s.: m(DelkaL-MobilL, DelkaR-MobilR) nebo z(Hmotnost ) jeVyv(z(H), H, V, V). %mod(+,-,+,-) jeVyv(m(DL-ML,DR-MR),H,V1,V0):- % do V0 se vloží výstupní hodn., podle větve jeVyv(ML,HL,V1,V2), jeVyv(MR,HR,V2,V3), % „stav“ V - tok dat: V1->V2->V3->V0 H is HL+HR, % celková hmotnost (jeVyvKoren(DL,HL,DR,HR) -> V0 = V3% „přiřazení“ výstupu V0 ; V0 = [m(DL-ML,DR-MR)|V3] ).% dtto, se změnou jeVyvKoren(DL,HL, DR,HR):- DL*HL=:=DR*HR. % sémantiku dodá doménový expert jeBezp(z(_H),0,V,V). jeBezp(m(DL-ML,DR-MR), D,V1,V0):- jeBezp(ML,D1,V1,V2), jeBezp(MR,D2,V2,V3), D is max(DL+D1,DR+D2), % delší rameno (jeBezpKoren(DL,D1, DR,D2) -> V0=V3 ; V0 = [m(DL-ML,DR-MR)|V3] ). jeBezpKoren(DL,D1, DR,D2) :- DL+DR > D1+D2.  Programátorský idiom: tok dat předáváním stavu, tj. akumulátor  Při předávání do/z/mezi voláním procedur se stav může změnit – zde: V3 na V0  Programy jsou strukturou podobné, liší se výkonnou částí : chtěli bychom abstrakci

28 if - then - else  v těle můžeme používat kromě čárky a středníku:  If -> Then ; Else  podmínka se vyhodnocuje 1x, uvnitř částí se může backtrackovat  nebacktrackuje se mezi Then a podmínkou, mezi Then a Else if1->(then % ”->“ a “;” jsou binární operátory stejné ;(if2->(then2 % priority asociované doprava ;(if3->(then3 ;else3 )) )) )

29 Slití seznamů: merge/3  Slije uspořádané (číselné) seznamy, vyloučí vícenásobné % merge(+L1,+L2,-L) merge([],L,L). merge(L,[],L). merge([X1|L1],[X2|L2],[X|L]):- X1 X=X1,merge(L1,[X2|L2],L) ; X1>X2 -> X=X2,merge([X1|L1],L2,L) ; /*X1=X2*/ X=X1,merge(L1,L2,L).  varianta: každá větev samostatně merge([X1|L1],[X2|L2],[X1|L]):- % X1 ve výst. X1


Stáhnout ppt "Vestavěné predikáty a jejich použití Jan Hric, KTI MFF UK 1997-2010c (oprava 4.5.)"

Podobné prezentace


Reklamy Google