Struktury danych i obliczenia

advertisement
Struktury danych i obliczenia
Przemysław Podkowiński, Michał Przybylski
Arytmetyka
Przykłady jak wygląda prosta arytmetyka w Prologu:
?- Y is 2+2.
Y=4
?- 5 is 3+3.
false
?- Z is 4.5 + (3.9 / 2.1).
Z = 6.3571428
Predykat „is” oblicza wyrażenie arytmetyczne z prawej strony i przypisuje je do
wyrażenia po lewej stronie.
Operatory
•
•
•
•
•
•
+
*
/
//
mod
dodawanie
odejmowanie
mnożenie
dzielenie zmiennoprzecinkowe
dzielenie całkowite
modulo
Funkcje
• abs() - wartość bezwzględna
• sqrt() – pierwiastek kwadratowy
• log() – logarytm, przy podstawie e
• exp()- funkcja wykładnicza, podstawa e
• floor() – największa wartość integer mniejsza lub równa argumentowi
• round()- zaokrąglenie do najbliższej liczby
Operatory
• R is wyrażenie – ocenia i przypisuje wartość
• wyrażenie1 =:= wyrażenie2 – jeżeli równe
• wyrażenie1 =\= wyrażenie2 – jeżeli różne
• wyrażenie1 > wyrażenie2 – jeżeli większe
• wyrażenie1 < wyrażenie2 – jeżeli mniejsze
• wyrażenie1 >= wyrażenie2 – jeżeli większe bądź równe
• wyrażenie1 =< wyrażenie2 – jeżeli mniejsze bądź równe
Konstruowanie wyrażeń
• ?- 4+1 =:= 2+3.
true.
• ?- 4 is sqrt(16).
false.
• ?- 4.0 is sqrt(16).
true.
• ?- What is 2 + 3*4 + 5.
What = 19.
Praktyczne przykłady
• Często zostajemy zmyleni przez błędne zaokrąglenie, dlatego zdefiniujmy
predykat close_enough który pozwoli nam porównać liczby zmiennoprzecinkowe.
close_enough(X,X) :- !.
close_enough(X,Y) :- X<Y,
Y-X<0.0001.
close_enough(X,Y) :- X>Y,
close_enough(Y,X).
close_enough(X,X) :- !. – jest to przypadek gdy dwa argumenty są równe.
close_enough(X,Y) :- X<Y, Y-X<0.0001. - porównuje X i Y, odejmuje mniejszą od
większej i sprawdza róznice, jeśli jest mniejsza od 0.0001.
close_enough(X,Y) :- X>Y, close_enough(Y,X). – porównuje X i Y, jeśli X jest większe
od Y to wywołuje sama siebie ponownie tylko z zamienionymi parametrami.
Praktyczne przykłady
• Obliczmy pierwiastek kwadratowy z danej liczby
real_square_root(X,nonexistent) :- X < 0.0.
real_square_root(X,Y) :- X >= 0.0,
Y is sqrt(X).
Przykład:
?- real_square_root(9.0,Root).
Root =3.0
?- real_square_root(-1.0,Root).
Root =nonexistent
Zapytanie real_square_root(121.0,11.0) daje true, ale real_square_root(121.0,11.0) już
daje false, ponieważ 11.0 nie równa się dokładnie zmienno-przecinkowem wynikowi sqrt
pomimo, że pierwiastek ze 121 wynosi dokładnie 11.
• Zmodyfikujmy naszą definicję tak by zwracała oba pierwiastki kwadratowe a nie jeden.
Do tego potrzebujemy jeszcze jednej alternatywy:
real_square_root(X,Y) :- X > 0.0,
R is -sqrt(X).
Co daję nam w sumie taki oto predykat:
real_square_root(X,nonexistent) :- X < 0.0.
real_square_root(X,Y) :- X >= 0.0,
Y is sqrt(X).
real_square_root(X,Y) :- X > 0.0,
Y is -sqrt(X).
Przykład:
?- real_square_root(9.0,Root).
Root =3.0
Root =-3.0
Ciągi znaków
Są trzy sposoby na zaprezentowanie ciągu znaków w Prologu:
• Jako atom.
• Jako lista kodów ASCII.
• Jako lista jedno znakowych atomów.
Jeśli wpiszemy („like this”) to komputer zinterpretuje to jako liste kodów ASCII.
A więc „abc” i [97,98,99] dla Prologa to dokładnie to samo. Lista kodów ASCII to
tradycyjnie nazywany string.
Wprowadzanie linii jako string albo atom
• Łatwo zrobić w Prologu czytanie całej linii do pojedynczego stringa, bez używania
read, a zamiast tego użycie get 0.
Oto sposób jak to zrobić:
% read_str(String)
% Accepts a whole line of input as a string (list of ASCII codes).
% Assumes that the keyboard is buffered.
read_str(String) :- get0(Char),
read_str_aux(Char,String).
read_str_aux(-1,[]) :- !. % end of file
read_str_aux(10,[]) :- !. % end of line (UNIX)
read_str_aux(13,[]) :- !. % end of line (DOS)
read_str_aux(Char,[Char|Rest]) :- read_str(Rest).
• Jeśli chcemy przeczytać linie nie jako string ale jako atom. Jest to proste,
ponieważ Prolog ma wbudowany predykat name/2:
?- name(abc,What).
What = [97,98,99] % equivalent to "abc"
?- name(What,"abc").
What = abc
?- name(What,"Hello there").
What = 'Hello there' yes
?- name(What,[97,98]).
What = ab
Struktury
• Wiele warunków w Prologu składa się z funktora wynikającego z zera albo
większej ilości warunków takich jak:
a(b,c)
alpha([beta,gamma],X)
'this and'(that)
f(g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v)
i_have_no_arguments
Warunki tej formy nazywane są Structures(Struktury). Funktor zawsze jest atomem,
ale argumenty mogą być warunkami każdego typu. Struktura bez argumentów jest
po prostu atomem.
• Przykład użycia struktur:
person(name('Michael Covington'),
gender(male),
birthplace(city('Valdosta'),
state('Georgia')))
sentence(noun_phrase(determiner(the),
noun(cat)),
verb_phrase(verb(chased),
noun_phrase(determiner(the) ),
noun(dog))))
• Struktury działają podobnie jak listy, ale inaczej są przechowywane w pamięci.
• Jedną z ważniejszych różnic to to, że lista jest podzielona na head i tail, a struktura
nie jest. Struktura zjednoczy się z inna kiedy ma taki sam funktor i taka samą ilość
argumentów.
Unify
With
Result
a(b,c)
X
X=a(b,c)
a(b,c)
a(X,Y)
X=b, Y=c
a(b,c)
a(X)
fails
a(b,c)
a(X,Y,Z)
fails
„Occurs check”
• Możemy stworzyć dziwaczna, zapętloną strukturę.
• Struktury te zawierają wskaźniki do siebie, a one doprowadzają do pętli bez
końca.
?- X = f(X). X = f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f...
?- X = [a,b,X] X = [a,b,[a,b,[a,b,[a,b,[a,b,[a,b,[a,b,[a,b[a,b,[a,b[a,b,[a,b...
?- f(X) = f(f(X)) X = f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(...
Standard ISO posiada funkcje unify_with_occurs_check która odpowiada za
kontrole przed próba wykonania:
?- unify_with_occurs_check(X,f(X)). no.
?- unify_with_occurs_check(X,f(a)).
X = f(a)
Konstruowanie celów na starcie
• Ponieważ zapytanie w Prologu jest strukturą, możesz je traktować jako dane i
konstruować je podczas uruchomienia programu. Call wykonuje argument jak
pytanie, więc call(write(`hello there`)) jest równoznaczne z write(`hello there`)
Cel może być stworzony przez obliczenie.
Dla przykładu:
answer_question :- write('Mother or father? '),
read_atom(X),
write('Of whom? '),
read_atom(Y),
Q =.. [X,Who,Y],
call(Q),
write(Who),
nl.
Jak wpiszemy mother i cathy wtedy Q będzie wyglądało tak:
mother(Who, cathy).
?- answer_question.
Mother or father? father
Of whom? michael
charles_gordon
yes
?- answer_question.
Mother or father? mother
Of whom? Melody
eleanor
yes
Strategie przechowywania danych
Są trzy sposoby na przechowywanie danych w programach w Prologu:
• W instancji zmiennej. Nie jest to trwały sposób przechowywania
danych, ponieważ działa tylko w zasięgu klauzuli która je definiuje.
• W argumentach. Lista argumentów jest sposobem by procedura
komunikowała się. Procedura może wykonać rekurencyjnie proces i
zapisywać informacje z jednej rekurencji do drugiej.
• W bazie wiedzy. Jest to najtrwalszy sposób przechowywania danych.
Przykłady:
count(X) :- retract(count_aux(N)),
X is N+1,
asserta(count_aux(X)).
:- dynamic(count_aux/1).
count_aux(0).
?- count(X).
X=1
yes
?- count(X).
X=2
Yes
Download