- Republika WWW
Transkrypt
- Republika WWW
Ćwiczenie nr 5 ZMIENNE GLOBALNE, INSTRUKCJE PĘTLOWE 1. Zmienne globalne Zmienne globalne definiujemy w następujący sposób: (defglobal ?*<zmienna1>* = <wartosc1> . . . ?*<zmiennaN>* = <wartoscN>) Zmienna zdefiniowana za pomocą konstrukcji (defglobal ...) jest rozpoznawana globalnie, przez wszystkie reguły. Różnice między zmiennymi globalnymi a lokalnymi: a) Zmienne globalne nie mogą być użyte tak samo jak zmienne lokalne po lewej stronie reguły, czyli niedopuszczalne jest użycie zmiennej globalnej w taki sposób jak w poniższej regule: (defrule regula-niedopuszczalna (x ?*x*) => ...) b) Zmienna globalna może być natomiast użyta po lewej stronie reguły jako część funkcji (test ...), np.: (defrule regula-dopuszczalna (y ?y) (test (> ?y ?*x*)) => ...) Tak więc, jeśli ?*x* = 5 oraz mamy fakt (y 6), to reguła zostanie uaktywniona. c) Jeżeli wartość zmiennej globalnej zostanie zmieniona podczas wykonywania programu, to reguły, w których jest ona użyta po lewej stronie, „dostosują się” do zmian. Np. jeśli zmienimy wartość ?*x* na 10, powyższa reguła zostanie uaktywniona przez fakt (y 6), choć poprzednio byłaby przez taki fakt uaktywniona. Zmienne globalne mogą być wstawiane przy pomocy komendy (bind ...) po prawej stronie reguły, lub bezpośrednio z poziomu CLIPS’a. Zmienne globalne mogą być usunięte za pomocą komendy (clear). Po podaniu polecenia (clear) należy w programie zmodyfikować wyrażenie (defglobal ...) tak, aby nie zawierało niepożądanych zmiennych i tak zmieniony program załadować do CLIPS’a. Inny sposób usunięcia zmiennej globalnej to polecenie: (undefglobal <nazwa-zmiennej-globalnej>) Jeżeli podczas wykonywania programu zmienimy wartość zmiennej globalnej, to po podaniu komendy (reset) zostanie przywrócona jej pierwotna wartość (zdefiniowana w programie). 1 Przykład: (defglobal ?*gx* = 5 ?*gy* = 10 ?*gz* = 50) (defrule start (initial-fact) => (printout t "Podaj wartosc x = ") (bind ?x (read)) (printout t "Podaj wartosc y = ") (bind ?y (read)) (printout t "Podaj wartosc z = ") (bind ?z (read)) (assert (x ?x)(y ?y)(z ?z))) (defrule regula1 (x ?x)(y ?y)(z ?z) (test (> ?x ?*gx*)) => (printout t "Zmienna lokalna x = " ?x " jest wieksza od zmiennej globalnej gx = " ?*gx* crlf)) (defrule regula2 (x ?x)(y ?y)(z ?z) (test (= ?*gy* 10)) => (printout t "Zmienna globalna gy jest rowna 10" crlf) (printout t "Zmieniamy wartosc zmiennej globalnej gy oraz gz = " ?*gz* crlf) (bind ?*gy* 100) (printout t "Podaj nowa wartosc zmiennej globalnej gz = ") (bind ?*gz* (read)) (bind ?tmp 1) (assert (tmp ?tmp))) (defrule regula3 (x ?x)(y ?y)(z ?z)(tmp ?tmp) => (printout t "Nowa wartosc gy wynosi = " ?*gy* crlf) (printout t "Nowa wartosc gz wynosi = " ?*gz* crlf)) 2. Funkcja while Składnia pętli while jest nastepująca: (while (<warunek>) (<akcja1>) ... (<akcjaN>)) 2 Przykład: (defrule start (initial-fact) => (printout t "Program oblicza wartosc silni z n" crlf) (printout t "Podaj n = ") (bind ?n (read)) (assert (n ?n))) (defrule licz (n ?n) => (bind ?silnia 1) (bind ?licznik 1) (while (<= ?licznik ?n) (bind ?silnia (* ?silnia ?licznik)) (bind ?licznik (+ ?licznik 1))) (assert (silnia ?silnia))) (defrule wypisz (silnia ?silnia) => (printout t "Silnia = " ?silnia crlf)) 3. Instrukcja (loop-for-count ...) Funkcja (loop-for-count) w języku CLIPS pozwala na proste iteracje. Jej składnia jest następująca: (loop-for-count <zakres-iteracji> (<akcje>)) przy czym <zakres-iteracji> może przyjmować dwie postacie: <zakres-iteracji> := <indeks-koncowy> lub: <zakres-iteracji> := (?zmienna <indeks-poczatkowy> <indeks-koncowy>) przy czym <indeks-poczatkowy> i <indeks-koncowy> muszą być liczbami całkowitymi. W przypadku pierwszym przykładowe użycie funkcji (loop-for-count) może być następujące: a) (loop-for-count 2 (printout t “Podwójna iteracja” crlf)) Efekt działania: Podwójna iteracja Podwójna iteracja 3 b) (bind ?x 2) (loop-for-count ?x (printout t „OK” crlf)) Efekt działania: OK OK c) (defglobal ?*x* = 2) (loop-for-count ?*x* (printout t “OK” crlf)) Efekt działania: OK OK d) (loop-for-count (?a ?*x* 4) (printout t ?a crlf)) ; ?*x* = 2 Efekt działania: 2 3 4 Funkcje (loop-for-count ...) mogą być zagnieżdżone. Druga z możliwości tj. rozszerzona deklaracja <zakresu-iteracji>, wraz z zagnieżdżeniem iteracji może być zilustrowana następująco: (loop-for-count (?a ?*x* 4) ;?*x* = 2 (loop-for-count (?b 1 3) (printout t ?a “ “ ?b crlf))) Efekt działania: 2 1 2 2 2 3 3 1 3 2 3 3 4 1 4 2 4 3 4. Zadania do wykonania 1. Napisać program wypisujący kolejno liczby od 1 do zadanej wartości n. Np. po podaniu wartości n=7, program powinien wypisać: 1 2 3 4 5 6 7 4 2. Napisać program wyznaczający n-ty wyraz ciągu Fibonacciego przy użyciu instrukcji (loop-forcount) oraz korzystając z iteracyjnego wzoru na ten ciąg postaci: F0=1; F1=1; F2=2; F3=3; F4=5; F5=8 Fn=Fn-1+Fn-2 Program powinien posiadać funkcję (fibo ?n), w której n-ty wyraz ciągu był by obliczany przy użyciu instrukcji (loop-for-count). Struktura programu: Funkcja o nazwie (fibo ?n) R1: Reguła uruchamia się na (initial-fact), wprowadzana jest liczba mówiąca o tym, który wyraz ciągu Fibonacciego chcemy policzyć. Tworzony jest fakt (n ?n) R2: Reguła uruchamia się, gdy zaistnieje fakt (n ?n) i gdy ?n będzie większe równe zero. Wówczas przy użyciu zdeklarowanej funkcji (fibo ?n) wyznaczany jest n-ty wyraz ciągu Fibonacciego i tworzony jest fakt (wynik ?wynik) R3: Reguła uruchamia się gdy zaistnieje fakt (wynik ?wynik) i wypisuje komentarz na ekran np. „5-ty wyraz ciagu = 8” 3. Program z punktu 1 zabezpieczyć z wykorzystaniem instrukcji while, aby nie było możliwe podanie nieprawidłowych wartości zmiennej ?n (np. o ujemnych wartościach) 5