Intro

12
Szybkie wprowadzenie do Prologu Roman Huk 31 października 2007 Streszczenie Celem tego artykulu jest przedstawienie w skrótowej formie (przy- znaję — nie zawsze wyczerpującej — ale od czego są podręczniki?) podstawowych zasad pisania programów w języku Prolog. W zamie- rzeniu jest to pierwszy z serii artykulów na ten temat. W tym „od- cinku” zostaly zaprezentowane podstawowe informacje, pozwalające na opanowanie Prologu na tyle, żeby móc samodzielnie eksperymentować z programowaniem w logice. Spis treści 1 Wprowadzenie 1 1.1 Notacja .............................. 2 1.2 Dopasowywanie .......................... 2 2 Pierwsze przyklady 4 2.1 Co kto lubi? ............................ 4 2.2 Struktury danych ......................... 5 2.3 Arytmetyka ............................ 7 3 Listy 7 3.1 Lista i jej elementy ........................ 7 3.2 Operacje na listach ........................ 8 3.3 Jeszcze o listach ......................... 10 4 Grafy 11 4.1 Ścieżki w grafie nieskierowanym ................. 11 4.2 Graf skierowany .......................... 12 4.3 Drzewo (genealogiczne) ..................... 12 5 Prosty system ekspertowy 12 1

Transcript of Intro

Page 1: Intro

Szybkie wprowadzenie do Prologu

Roman Huk

31 października 2007

Streszczenie

Celem tego artykułu jest przedstawienie w skrótowej formie (przy-znaję — nie zawsze wyczerpującej — ale od czego są podręczniki?)podstawowych zasad pisania programów w języku Prolog. W zamie-rzeniu jest to pierwszy z serii artykułów na ten temat. W tym „od-cinku” zostały zaprezentowane podstawowe informacje, pozwalające naopanowanie Prologu na tyle, żeby móc samodzielnie eksperymentowaćz programowaniem w logice.

Spis treści

1 Wprowadzenie 11.1 Notacja . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21.2 Dopasowywanie . . . . . . . . . . . . . . . . . . . . . . . . . . 2

2 Pierwsze przykłady 42.1 Co kto lubi? . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42.2 Struktury danych . . . . . . . . . . . . . . . . . . . . . . . . . 52.3 Arytmetyka . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7

3 Listy 73.1 Lista i jej elementy . . . . . . . . . . . . . . . . . . . . . . . . 73.2 Operacje na listach . . . . . . . . . . . . . . . . . . . . . . . . 83.3 Jeszcze o listach . . . . . . . . . . . . . . . . . . . . . . . . . 10

4 Grafy 114.1 Ścieżki w grafie nieskierowanym . . . . . . . . . . . . . . . . . 114.2 Graf skierowany . . . . . . . . . . . . . . . . . . . . . . . . . . 124.3 Drzewo (genealogiczne) . . . . . . . . . . . . . . . . . . . . . 12

5 Prosty system ekspertowy 12

1

Page 2: Intro

1 Wprowadzenie

Czy naukę języka programowania należy prowadzić w sposób bardzo usys-tematyzowany? Zapewne w wielu przypadkach jest to wskazane — a nastudiach technicznych wręcz pożądane. Mógłbym również tak zrobić w przy-padku Prologu i zacząć zajęcia od słów „Podstawowymi elementami językasą termy, zmienne i predykaty. Termem nazywamy itd.”. Jednak czy w tymprzypadku jest to konieczne? Po pierwsze, jest to kolejny język programo-wania, który poznają słuchacze — to prawda, że inny od języków impera-tywnych, ale każdy we własnym zakresie będzie mógł stwierdzić, że „Pod-stawowymi elementami języka...itd.”; po drugie, w tym przypadku naukajęzyka nie jest celem samym w sobie — Prolog ma być jedynie narzędziempomocnym w realizacji ćwiczeń z przedmiotu „Sztuczna Inteligencja”. Nieo samo opanowanie języka zatem chodzi, lecz bardziej o to, jak (przy jegopomocy) rozwiązać niektóre problemy, trudno rozwiązywalne „klasycznymi”metodami.

Takie podejście doskonale koresponduje z filozofią Prologu, która mówi,że program ma określać „co trzeba zrobić” a nie „jak trzeba zrobić”. Dlategowybrałem formę prezentacji konstrukcji języka by-example. Zatem do dzieła!

1.1 Notacja

Najważniejszym źródłem informacji o Prologu jest system pomocy, dostar-czany z każdym interpreterem/kompilatorem Prologu. Oto fragment infor-macji, pochodzący z mojego środowiska (GNU Prolog):

|7.20.2 member/2,membercheck/2|Templates| member(?term,?list)| membercheck(?term,?list)|Description| member(Element, List) succeds if Element belongs to list.| This predicate is| . . .

Co oznaczają te dziwne zapisy? Otóż w punkcie 7.20.7 systemu pomocyopisane jest działanie predykatów member i membercheck, które wymagajądwóch argumentów. Pierwszym z nich jest term, drugim lista. znak ’?’poprzedzający argumenty mówi o tym, że argument może być ukonkretnioną(instantiated) wartością lub nieukonkretnioną zmienną. Czasami pojawiająsię inne znaki: znak ’+’ oznacza, że argument musi mieć ukonkretnionąwartość, zaś znak ’–’ oznacza, że argument musi być zmienną (która zostanieukonkretniona jakąś wartością jeżeli predykat powiedzie się).

2

Page 3: Intro

1.2 Dopasowywanie

Prolog wykorzystuje dopasowywanie do wzorców, zwane unifikacją. Jestto niezwykle elastyczne dopasowywanie. Do tego celu używa się predykatu=/2. Najprostsze zapytania to zapytania o termy:

| ?- a=a.

yes| ?- a=b.

no

Termy mogą być bardziej złożone, przetwarzanie również powiedzie się, gdytermy są identyczne lub zawiedzie:

| ?- f(a(b))=f(a(b)).

yes| ?- f(a(b))=f(b(a)).

no

Można wprowadzić zmienną — zarówno z lewej jak i z prawej strony znakurówności:

| ?- X=a.

X = a

yes| ?- b=Y.

Y = b

yes

Unifikacja zapewnia, że zmienna zostanie zwrócona ”wypełniona treścią”,ukonkretniona, jeżeli przetwarzanie powiedzie się. Popatrzmy na bardziejskomplikowane struktury:

| ?- f(a)=X.

X = f(a)

yes| ?- f(a,B,c,D)=f(A,b,C,d).

3

Page 4: Intro

A = aB = bC = cD = d

yes

2 Pierwsze przykłady

2.1 Co kto lubi?

Stwórzmy pierwszy miniprogram:

| ?- consult(user).compiling user for byte code...lubi(jan,herbata).lubi(jan,piwo).lubi(tomasz,piwo).lubi(tomasz,kawa).lubi(adam,kawa).

user compiled, 6 lines read - 606 bytes written, 65902 ms

(12 ms) yes| ?-

Oto kilka prostych pytań:

| ?- lubi(jan,piwo).

yes| ?- lubi(jan,X).

X = herbata ? ;

X = piwo

yes| ?- lubi(X,piwo).

X = jan ? ;

X = tomasz ? ;

no

4

Page 5: Intro

Sspróbujmy znaleźć dwóch piwoszy w jednym zapytaniu:

| ?- lubi(X,piwo),lubi(Y,piwo).

X = janY = jan ? ;

X = janY = tomasz ? ;

X = tomaszY = jan ? ;

X = tomaszY = tomasz ? ;

no

Czy nie przypomina to iloczynu kartezjańskiego? zatem trzeba nałożyć do-datkowe warunki:

| ?- lubi(X,piwo),lubi(Y,piwo),X \= Y.

X = janY = tomasz ? ;

X = tomaszY = jan ? ;

no

Już lepiej, ale to w dalszym ciągu nadmiar informacji. Na razie jednak nieprzejmujmy się tym.

2.2 Struktury danych

Spróbujmy lepiej zorganizować bazę danych i dodać kilka reguł. Niech osobybędą opisywane predykatem osoba/2, której argumentami są imię oraz ilośćposiadanej gotówki, zaś napoj/3 będzie zawierał informacje o nazwie napoju,jego charakterze (zimny, gorący) i cenie.

| ?- [user].compiling user for byte code...osoba(jan,20).osoba(tomasz,5).osoba(adam,3).

5

Page 6: Intro

lubi(jan, herbata).lubi(jan, piwo).lubi(tomasz, piwo).lubi(tomasz, kawa).lubi(adam, kawa).

napoj(piwo,zimny,6).napoj(herbata,goracy,2).napoj(kawa,goracy,4).

moze_kupic(X,Y) :-osoba(X,Kwota),napoj(Y,_,Cena),Cena =< Kwota .

user compiled, 19 lines read - 1701 bytes written, 107623 ms

(4 ms) yes| ?-

Przyjrzyjmy się regułom. Każda reguła składa się z dwóch części: głowyi ciała, deklaracji i definicji, oddzielonych od siebie symbolem ’:-’, którypełni rolę operatora relacji implikacji, tyle, że zapisanej odwrotnie. Regułęmoze kupic/2 należy interpretować następująco:

JEŻELI (osoba X dysponuje kwotą Kwota) ∧ (napoj Y kosztuje Cena)∧ ( Kwota ≥ Cena ) TO (osoba X moze kupic napój Y ).

Należy zwrócić uwagę na symbol ’ ’ w predykacie napoj/3 użytym wewnątrzreguły. Oznacza on, że ukonkretniona wartość zmiennej, która powinnaznaleźć się w tym miejscu, nie jest dla nas interesująca. Poeksperymentujmy:

| ?- napoj(X,_,Y), Y=<3.

X = herbataY = 2 ? ;

no| ?- moze_kupic(X,piwo).

X = jan ? ;

no| ?- moze_kupic(jan,X).

6

Page 7: Intro

X = piwo ? ;

X = herbata ? ;

X = kawa

yes

2.3 Arytmetyka

Jako operator przypisania, uzywany jest predykat is/2:

| ?- X is 2.

X = 2

yes| ?- X is 7+8.

X = 15

yes| ?- X = 7+8.

X = 7+8

yes| ?- X=3, Y=4, Z is sqrt(Y*Y + X*X).

X = 3Y = 4Z = 5.0

yes

3 Listy

Listy stanowią podstawową złożoną strukturę danych. Dostęp do elementówlisty nie jest jednak taki prosty. Bezpośredni dostęp jest w zasadzie tylko dopierwszego elementu (głowy). Żeby dostać się do dalszego elementu trzebalistę przetwarzać rekurencyjnie. Operator ’|’ dzieli listę na głowę i ogon.

7

Page 8: Intro

3.1 Lista i jej elementy

Przyjrzyjmy się przykładom, które mówią same za siebie:

| ?- [H|T] = [a,b,c,d,e].

H = aT = [b,c,d,e]

yes| ?- [H|T] = [[a,b,c],d,e,f,g,[h,i]].

H = [a,b,c]T = [d,e,f,g,[h,i]]

yes| ?- [H|T] = a.

no| ?- [H|T] = [a].

H = aT = []

yes| ?- [A|[B|C]] = [a,b].

A = aB = bC = []

yes| ?- [_|[_|[_|[X|_]]]] = [1,2,3,4,5,6,7,8].

X = 4

yes

3.2 Operacje na listach

Podstawowe operacje na listach dostępne są w każdej implementacji Prologu.Jeżeli nawet nie — łatwo można je zdefiniować. Oto potęga rekurencji:

length([],0).length([_|T], X) :- length(T, Y), X is Y+1.

8

Page 9: Intro

append([],X,X).append([H|T],L1,[H|L2] :- append(T,L1,L2).

last([X|[]],X).last([_|T], X) :- last(T, X).

Jak zachowują się te predykaty?

| ?- last([a,b,c,d,e],X).

X = e

yes| ?- last([H|T], Y).

T = []Y = H ? ;

T = [Y] ? ;

T = [_,Y] ? ;

T = [_,_,Y] ? ;

T = [_,_,_,Y] ? ;

T = [_,_,_,_,Y] ? <RETURN>yes| ?- append([1,2,3],[a,b,c],Y).

Y = [1,2,3,a,b,c]

yes| ?- append(X,[a,b,c],[o,a,b,c]).

X = [o] ? ;

no| ?- append(X,Y,[a,b,c]).

X = []Y = [a,b,c] ? ;

X = [a]

9

Page 10: Intro

Y = [b,c] ? ;

X = [a,b]Y = [c] ? ;

X = [a,b,c]Y = [] ? ;

no| ?- append([a,b],[a,b],Y).

Y = [a,b,a,b]

yes| ?- length([a,b,c], 3).| ?- length([a,b,c],3).

yes| ?- length([a,b,c],4).

no| ?- length([a,b,c],X).

X = 3

yes| ?- length(X,3).

X = [_,_,_] ? ;

OOPS! Przestało działać. Dlaczego Prolog poszukiwał kolejnego rozwiąza-nia? Jakiego rozwiązania? Wyjaśnię to w jednym z kolejnych rozdziałów.

3.3 Jeszcze o listach

Oto klasyczny przykład, jak obliczyć sumę elementów listy:

| ?- [user].compiling user for byte code...sum([],X,X).sum([H|T],X,Y) :- Z is H + X, sum(T,Z,Y).sum(List, X) :- sum(List, 0, X).

user compiled, 4 lines read - 826 bytes written, 167521 ms

10

Page 11: Intro

(4 ms) yes| ?- sum([1,2,3,4,5],X).

X = 15

yes

Czy można to zrobić inaczej? Zapewne tak! Byłbym zdziwiony, gdyby niebyło innej metody. Zatem warto spróbować znaleźć lepsze rozwiązanie.

4 Grafy

Chyba już wystarczy prostych, w sumie banalnych przykładów. Czas zająćsię czymś pożytecznym. Wiele sytuacji, zjawisk czy zdarzeń, z którymi mado czynienia programista da się zamodelować w postaci grafu: siatka połą-czeń drogowych, drzewo rozbioru gramatycznego, przebieg procesu techno-logicznego itp. Spróbujmy zatem na prostym przykładzie zaprzęgnąć Prologdo „inteligentnej” pracy.

4.1 Ścieżki w grafie nieskierowanym

Oto fragment sieci dróg krajowych (mam nadzieję, że w niedalekiej przy-szłości Droga Krajowa będzie oznaczała drogę szybkiego ruchu) lekko do-stosowany do potrzeb dydaktycznych.

11

Page 12: Intro

Przecież to jest graf (nieskierowany). Model systemu drogowego w Pro-logu może wyglądać następująco: predykat droga/4 będzie opisany następu-jącymi argumentami: skąd (nazwa miasta), dokąd (nazwa miasta), odległośći numer drogi (na rysunku w nawiasie).

4.2 Graf skierowany

4.3 Drzewo (genealogiczne)

5 Prosty system ekspertowy

12