• Nie Znaleziono Wyników

Języki i paradygmaty programowania Wykład 7 dr Dariusz Wardowski, Katedra Analizy Nieliniowej Łódź, 22 maja 2010 r. 1/18

N/A
N/A
Protected

Academic year: 2021

Share "Języki i paradygmaty programowania Wykład 7 dr Dariusz Wardowski, Katedra Analizy Nieliniowej Łódź, 22 maja 2010 r. 1/18"

Copied!
18
0
0

Pełen tekst

(1)
(2)

Prolog - ”prawie” jak język naturalny

Prolog powstał na początku lat siedemdziesiątych XX wieku, jako odpowiedź na problem automatycznego dowodzenia twierdzeo.

Powstanie Prologu wiązało się także ze szczególnym rozwojem w tym okresie metod

badania języków naturalnych - wydawało się, że Prolog będzie doskonałą odpowiedzią na te badania.

Przypomnijmy w tym miejscu o znanym podziale języków programowania ze względu na stopieo zaawansowania. I tak:

języki pierwszej generacji: języki maszynowe (kod binarny),

języki drugiej generacji: języki symboliczne (asemblery), np. Asembler,

języki trzeciej generacji: języki wysokiego poziomu, proceduralne (imperatywne), np. C++, języki czwartej generacji: języki bardzo wysokiego poziomu, deklaratywne, np. SQL,

języki piątej generacji: języki sztucznej inteligencji, języki systemów ekspertowych, najbardziej zbliżone do języka naturalnego, np. Prolog.

Prolog nie stał się językiem programowania o możliwościach języka naturalnego, jednak jego wkład w informatykę, a szczególnie w zagadnienia sztucznej inteligencji są duże i warto go w pewnym chociaż minimalnym stopniu poznad.

(3)

Program w języku Prolog

Oto jeden z prostych przykładów „programów” w Prologu:

lubi(jan, tatry).

lubi(jan, beskidy).

lubi(jerzy, beskidy).

lubi(jerzy, bieszczady).

lubiToSamo(X, Y) :- lubi(X, S), lubi(Y, S), X \= Y.

Program ten (jak każdy w języku Prolog) składa się z faktów:

lubi(jan, tatry).

lubi(jan, beskidy).

lubi(jerzy, beskidy).

lubi(jerzy, bieszczady).

oraz reguł:

lubiToSamo(X, Y) :- lubi(X, S), lubi(Y, S), X \= Y.

Ten program jest zupełnie ”samowystarczalny” - nie potrzebujemy nigdzie dodatkowo deklarowad, co to znaczy lubi bądź lubiToSamo. Wszystko, co potrzeba do wykorzystania tego programu, już tu jest.

Samo uruchomienie polega teraz na wpisaniu celu i przejrzeniu wszystkich odpowiedzi udzielonych przez Prolog.

(4)

Program w języku Prolog

Oto kilka przykładów zapytao (do programu z poprzedniego slajdu), wraz z odpowiedziami języka. Znaki ?- są wypisywane przez interpreter:

?- lubi(jan, beskidy).

true

?- lubi(jan, sudety).

false

?- lubi(jan, X).

X = tatry;

X = beskidy;

false

?- lubi(X, beskidy) X = jan;

X = jerzy;

false

?- lubi(filip, tatry).

false

?- lubi(filip, X).

false

(5)

Program w języku Prolog Cel może byd:

• konkretny (fakt),

•może zawierad zmienne (reguła).

W pierwszym przypadku interpreter odpowiada true lub false, w zależności od tego, czy udało mu się znaleźd potwierdzenie wpisanego celu.

W drugim przypadku interpreter znajduje wszystkie możliwości spełnienia wpisanej relacji (po czym odpowiada false - co oznacza, że nie ma już więcej rozwiązao). Zauważmy, że

odpowiedź przecząca oznacza, że interpreter nic nie wie na żądany temat - a nie że potrafi udowodnid fałszywośd wpisanego celu.

Innymi słowy, Prolog działa przy założeniu, że mamy ”zamknięty świat faktów”, o którym wiemy wszystko; to, czego nie wiemy, nie istnieje...

Zauważmy, że:

• Możemy pytad również o byty, o których wcześniej nie wspomnieliśmy ani słowem. Tak jest np. w pytaniu

lubi(filip, tatry).

Wbrew pozorom, nie zawsze uzyskamy wtedy odpowiedź false. Możemy otrzymad odpowiedź twierdzącą, jeśli wynika to z mniej szczegółowych stwierdzeo programu.

• Nazwy zmiennych we wpisanym celu nie mają nic wspólnego z ewentualnymi nazwami zmiennych w programie.

(6)

Program w języku Prolog

Powyższe przykłady celów i odpowiedzi pokazują, że można zapytad o dowolny fragment relacji, a interpreter spróbuje dopasowad (ściślej mówimy uzgodnid lub zunifikowad;

dopasowanie to właściwie techniczny sposób dokonania uzgodnienia) wartości zmiennych tak, by uzyskad stwierdzenia zgodne z posiadanym stanem wiedzy (czyli stwierdzeniami w programie). Wszystkie powyższe przykłady były jednak ograniczone do pytao, które dało się rozstrzygnąd przez pojedyncze dopasowanie celu do stwierdzeo w programie. Prolog jest oczywiście znacznie bardziej zręczny i potrafi udowodnid stwierdzenia, które wymagają uzgodnieo w wielu etapach.

Np:

?- lubiToSamo(jan, jerzy).

true

?- lubiToSamo(X, Y).

X = jan, Y = jerzy;

X = jerzy, Y = jan;

No

Zauważmy, że stwierdzenia w których występują zmienne:

lubiToSamo(X, Y) :- lubi(X, S), lubi(Y, S), X \= Y.

traktujemy tak jakby stał przed nimi kwantyfikator uniwersalny wiążący wszystkie owe

zmienne. Dzięki temu stwierdzenie to staje się regułą na podstawie której interpreter może wnioskowad o ”osobach lubiących to samo”.

(7)

Jak rozumied klauzule?

Klauzula złożona z pojedynczej struktury prologowej, to stwierdzenie, które przyjmujemy za fakt, np.

lubi(jan, tatry).

Występujące w tej klauzuli atomy: lubi, jani tatry - nie mają tu żadnego innego znaczenia niż powiązanie ich w taką właśnie klauzulę, która następnie może byd wykorzystana przy poszukiwaniu odpowiedzi przez interpreter. Innymi słowy, atomy oznaczają po prostu siebie i dopóki nie użyjemy ich w jakimś konkretnym kontekście (np. w operacji arytmetycznej), nie wymagamy od nich żadnych własności. Oczywiście intuicyjne rozumienie takiej klauzuli-faktu to stwierdzenie:

Jan lubi Tatry

czyli że podane w nawiasach obiekty spełniają relację podaną na początku. A zatem funktor lubi spełnia rolę nazwy relacji, zaś atomy (w tym przypadku parametry): jan, tatry - rolę elementów tę relację spełniających. Zamiast atomów mogą również pojawiad się stałe liczbowe lub napisowe oraz całe struktury.

Drugi typ klauzul to klauzule postaci:

B :- A1, A2,..., Am

takie jak podana chwilę wcześniej reguła ”lubid to samo”. Klauzule tego rodzaju prawie zawsze zawierają zmienne. W praktyce klauzulę rozumiemy jako definicję nowej relacji - nie poprzez wyliczenie obiektów ją spełniających, lecz poprzez określenie reguły wiążącej ją z innymi relacjami. W trakcie poszukiwania odpowiedzi interpreter może wykorzystad taką klauzulę, uzgadniając odpowiednio zmienne.

(8)

Rola struktur

Struktura to twór postaci: funktor(listaParametrów)

gdzie parametry są atomami, zmiennymi lub innymi strukturami, rozdzielonymi przecinkami.

Termto stała, zmienna lub struktura.

Stałamoże byd atomem (składnia - jak typowy identyfikator zaczynający się od małej litery lub napis ujęty w apostrofy) lub liczbą. System typów Prologu jest niezbyt rozbudowany i zazwyczaj obejmuje liczby całkowite, zmiennopozycyjne oraz napisy, przy czym napisy w podwójnych cudzysłowach utożsamiane są z listą kodów znaków, zaś napisy w apostrofach - z atomami.

Zmiennezaczynają się z dużej litery.

Struktury mogą występowad zarówno w roli danych, jak i w roli zbliżonej do funkcji w klasycznych językach programowania.

W rozważanym dotychczas przykładzie struktury z funktorem lubi uznalibyśmy zapewne za dane,

natomiast strukturę z funktorem lubiToSamoza coś w rodzaju funkcji. Podział ten jest jednak sztuczny i bierze się po prostu z naszych przyzwyczajeo. Prolog traktuje wszystkie struktury tak samo,

wykorzystując je w uzgodnieniach. Zauważmy, że do naszego programu moglibyśmy dodad klauzulę:

lubi(_, pieniny).

Można ją interpretowad jako stwierdzenie: ”każdy lubi pieniny. W tej sytuacji funktor lubi przestaje oznaczad tylko dane. Zauważmy, że taka klauzula pozwala interpreterowi odpowiedzied twierdząco np.

na poniższe pytania:

lubi(X, pieniny).

lubi(filip, pieniny).

lubi(filip, _).

lubi(filip, X).

(9)

Rola struktur

Warto zauważyd, że jeśli jakaś zmienna występuje w klauzuli tylko raz, to należy ją zapisad jako zmienną anonimową, czyli za pomocą znaku podkreślenia: _. Taka sytuacja oznacza, że wartośd tej zmiennej nie będzie potrzebna w żadnym innym miejscu.

W szczególności dwa wystąpienia znaku podkreślenia oznaczają dwie zupełnie nie związane ze sobą zmienne anonimowe. Tak więc np. klauzula:

zna(X, X).

oznacza ”każdy zna samego siebie”, natomiast klauzula:

zna(_, _).

oznacza ”każdy zna każdego”. Zmienna anonimowa użyta we wpisanym celu oznacza, że nie chcemy znad wartości, jakie interpreter nada tej zmiennej, próbując osiągnąd cel.

(10)

Rola struktur

Przykład struktur z funktoremlubi kojarzyd się byd może nie tyle z reprezentacją ”obiektów pierwotnych”

bazy danych (czyli, powiedzmy, rekordów w tabeli w relacyjnej bazie danych), co raczej z reprezentacją zależności między takimi obiektami. Popatrzmy więc na taki przykład:

pracownik(imię(jan),

nazwisko(kowalski),

adres(ulica(długa),nr(2),miasto(kraków)), telefon(’0123456789’)).

Użyliśmy tu zagnieżdżonych struktur do reprezentacji danych pracowników. W potocznym rozumieniu owi pracownicy są ”obiektami pierwotnymi”. Zauważmy jednak, że w Prologu sposób reprezentowania jest w obydwu przypadkach w istocie taki sam.

Reprezentacja taka jak powyżej daje nam możliwości podobne do rekordów przy znacznie większej elastyczności. Przyjrzyjmy się ponownie pracownikom:

• Funktor pracownik użyty jest w roli podobnej do nazwy typu.

• Funktory imię,nazwisko itp. spełniają rolę analogiczną do pól rekordu.

• Atomyiliczby zachowują się jak wartości pól.

Mamy tu obiekty (pracowników) opisane w sposób samoistny - bez odwoływania się do zewnętrznych definicji typów. Mechanizm ten, chociaż nie pozwala np. na statyczne sprawdzenie zgodności typu, ma cechy przyzwoitego typowania. Otóż wszelkie wykorzystanie takich obiektów musi następowad przez uzgodnienie, a żeby ono się powiodło, konieczna jest pełna zgodnośd struktur (nazwy, ilości argumentów i podstruktury). Dodajmy, że atomy można traktowad jako funktory zeroargumentowe.

(11)

Zmienne i ich ukonkretnianie

Zmienne w Prologu są zupełnie odmienne od zmiennych w językach imperatywnych i tylko trochę podobne do zmiennych w językach funkcyjnych. Owo podobieostwo polega na tym, że zmienna prologowa nie może dowolnie zmieniad wartości tak, jak się to dzieje przy

podstawieniach - tych zresztą w ogóle w Prologu nie ma. W Prologu nadawanie wartości zmiennym następuje w wyniku uzgodnieo - powiemy o nich dokładniej w dalszej części wykładu.

(12)

Ukonkretnianie zmiennych

Zmiennaw programie Prologowym reprezentuje zupełnie nieokreślony byt, bez typu. W trakcie obliczeo, w rezultacie uzgodnieo następuje ukonkretnianie zmiennej, czyli bliższe określenie bytu

reprezentowanego przez zmienną. Ów byt będziemy nazywali konkretyzacją zmiennej.

Ukonkretnienie może byd:

• całkowite,

• częściowe.

W przypadku ukonkretniania całkowitego zmienna utożsamia się z termem niezawierającym zmiennych i nie podlega dalszemu ukonkretnianiu. W tym momencie można ją postrzegad jak zainstancjonowaną zmienną w programie funkcyjnym.

W przypadku ukonkretniania częściowego zmienna reprezentuje term, który wciąż zawiera inne zmienne, i może byd ukonkretniana dalej.

Ciekawym przypadkiem jest ukonkretnienie, które następuje przy uzgadnianiu dwóch dotychczas nieukonkretnionych zmiennych. Nie pojawia się wtedy żaden bardziej szczegółowy opis struktury reprezentowanej przez zmienną, gdyż obydwie zmienne na razie reprezentują byty nieokreślone.

Dwie zmienne zostają natomiast utożsamione, czyli odtąd każde wystąpienie i ukonkretnienie jednej z nich odnosi się tak samo do drugiej.

Ukonkretnienie zmiennej nie może zostad zmienione na inne, może natomiast zostad anulowane w wyniku nawrotu. Generalnie odnosi się to do ostatniego etapu ukonkretnienia - zmienna wraca do poprzedniej konkretyzacji, a nie do stanu całkowicie nie ukonkretnionego.

(13)

Przykłady ukonkretniania Przykład 1

Do programu:

lubi(jan, tatry).

lubi(jan, beskidy).

lubi(jerzy, beskidy).

lubi(jerzy, bieszczady).

lubiToSamo(X, Y) :- lubi(X, S), lubi(Y, S), X \= Y.

zadajemy zapytanie:

lubiToSamo(jan,X).

W pierwszym etapie następuje dopasowanie owego celu do definicji

lubiToSamo(X, Y)

co skutkuje dwoma uzgodnieniami:

•Atom janzostaje dopasowany do zmiennej X z definicji. W rezultacie zmienna X zostaje ukonkretniona do wartości jan.

•Zmienna X z celu zostaje uzgodniona ze zmienną Y z definicji. W rezultacie powstaje jedna zmienna.

Oczywiście zmienna X, której konkretyzacją jest atom jan, nie ma nic wspólnego z tą drugą.

(14)

Przykłady ukonkretniania Przykład 2

Do programu:

pracownik(imię(jan),

nazwisko(kowalski),

adres(ulica(długa),nr(2),miasto(kraków)), telefon(’0123456789’)).

zadajemy zapytanie:

pracownik(X, Y, Z, telefon(’0123456789’)).

Cel pasuje do definicji jednego, konkretnego pracownika, a zatem mamy trzy uzgodnienia z następującymi skutkami:

• Zmienna X zostaje ukonkretniona do imię(jan).

• Zmienna Y zostaje ukonkretniona do nazwisko(kowalski).

• Zmienna Zzostaje ukonkretniona do adres(ulica(długa), nr(2), miasto(kraków)).

Zauważmy, że wartościami zmiennych stają się tu całe struktury, a nie pojedyncze atomy.

Druga obserwacja to to, że interpretera Prologu można użyd wprost jako mechanizmu wyszukiwania w bazie danych - podajemy znane elementy (tu: telefon), a interpreter znajduje wszystkie pasujące ”rekordy”.

(15)

Przykłady ukonkretniania Przykład 3

Do programu:

pracownik(imię(jan),

nazwisko(kowalski),

adres(ulica(długa),nr(2),miasto(kraków)), telefon(’0123456789’)).

pracownik(imię(stefan), nazwisko(nowak),

adres(ulica(jodlowa),nr(2),miasto(warszawa)), telefon(’0123499999’)).

zadajemy zapytanie:

pracownik(imię(X), nazwisko(Y), adres(A1, A2, A3), telefon(Z)).

Tym razem cel pasuje do obydwu pracowników, więc mamy jeden zestaw ukonkretnieo, nawrót (a więc anulowanie ukonkretnieo) i drugi zestaw. Konkretyzacje zmiennych X, Y, A1, A2, A3 i Z w poszczególnych zestawach to oczywiście dane dwóch pracowników:

X = jan, Y = kowalski, A1 = ulica(długa), A2 = nr(2), A3 = miasto(kraków), Z = ’0123456789’

oraz

X = jerzy, Y = nowak, A1 = ulica(krótka), A2 = nr(123), A3 = miasto(kraków), Z = ’0987654321’.

(16)

Przykłady ukonkretniania

W ostatnim przykładzie w przypadku zmiennych X, Y i Z dotarliśmy tu już do atomów, natomiast w przypadku A1, A2 i A3 otrzymujemy struktury, gdyż na tym poziomie zagnieżdżenia odbyło się uzgodnienie.

Dwa ostatnie przykłady pokazują, że uzgodnienia mogą byd na różnych poziomach zagnieżdżenia. Pozwala to zadawad pytania o różnym stopniu szczegółowości. Trzeba natomiast pamiętad, że zawsze należy przestrzegad arności (argumentowości) funktora. A zatem niepoprawne, właśnie ze względu na niewłaściwą arnośd, są cele:

pracownik(imię(X), nazwisko(Y), adres(A), telefon(Z)).

pracownik(imię(X), nazwisko(Y), adres(A1, A2), telefon(Z)).

(17)

Przykłady ukonkretniania zmiennych

(18)

KONIEC

Dziękuję za uwagę 

Cytaty

Powiązane dokumenty

Innymi słowy, funkcja (w sensie matematycznym) definiuje wartośd, ale nie określa ciągu działao na wartościach w pamięci, które mogłyby ją wytworzyd... dr Dariusz Wardowski,

Filtrowanie listy polega na wybraniu z listy tylko tych elementów, które spełniają podane kryterium, i zwróceniu ich jako nowej (zwykle krótszej) listy.. dr Dariusz Wardowski,

•Jeżeli obiekt utworzono w sposób dynamiczny (tzn. za pomocą operatora new), wówczas destruktor tego obiektu jest wywoływany automatycznie, gdy użyjemy delete do

Konstruktory, które posiadają jeden argument mogą pełnić rolę funkcji konwersji, czyli mechanizmu, który przekształca wartość argumentu na typ

Jeżeli wskaźnik (referencja) wskazuje na obiekt typu B, wówczas nastąpi wywołanie destruktora ~B() klasy potomnej, a następnie ~A() klasy macierzystej... Wiązanie statyczne

Jeżeli klasa dziedziczy z klas, które dziedziczą po wirtualnej klasie macierzystej, wówczas konstruktor tej pierwszej klasy musi jawnie wywoływad konstruktor tej drugiej klasy.

Dobrym rozwiązaniem jest zamiana powyższych klas na jedną definicję szablonu, posługując się tzw..

Definiując szablon klasy możemy korzystać zarówno z wartości domyślnych dla parametrów typu jaki i wartości domyślnych dla argumentów wyrażeń (nie-typów).. Definiując szablon