- 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

Podobne dokumenty