Funkcje i zmienne.
Podstawową umiejętnością w programowaniu jest rozbijanie dużego algorytmu na mniejsze i prostsze zadania. Dla
tych zadań można przygotować porcje kodu - funkcje (a na wyższym
poziomie zaawansowania także klasy), które mogą być wielokrotnie używane
w programie i ułatwią zapisanie całego algorytmu.
W tym rozdziale pokażemy jak zaprogramować:
- Najprostsze funkcje
- Zmienne
-
Funkcje z argumentami
- Funkcje zwracające wynik
Najprostsze funkcje
Aby narysować kwadrat w poprzednim rozdziale użyliśmy pętli
powtarzającej krok w przód i obrót. Wiele kwadratów można narysować umieszczając tą pętlę wewnątrz jeszcze
jednej pętli repeat
:
repeat 9 [
repeat 4 [forward 100 right 90]
right 40
wait 100
]
lub napisać funkcję rysującą kwadrat i w pętli umieścić wywołanie funkcji:
to kwadrat
repeat 4 [forward 100 right 90]
end
repeat 9 [
kwadrat
right 40
wait 100
]
Obie wersje programu zadziałają identycznie, lecz kod pętli z funkcją jest bardziej klarowny - to bardzo ważne
w programowaniu. Funkcję kwadrat można też będzie wykorzystać w dowolnym innym miejscu programu, a jeśli trzeba
będzie kiedyś zmienić sposób rysowania wszystkich kwadratów w programie (np.: zmienić ich kolor) - wystarczy
to zrobić w jednym tylko miejscu: w treści funkcji kwadrat
.
Instrukcja wait
wstrzymuje program na zadaną liczbę milisekund (1 sekunda =
1000 milisekund). Pomoże to zaobserwować postępy rysowania kwadratów w pętli.
Zmienne
Do zapamiętania wartości (liczb, napisów, tablic...) w trakcie działania programu służą
zmienne. Zmienne w LOGO to bardzo obszerny temat, teraz
przedstawimy tylko podstawy niezbędne do dalszej pracy z funkcjami.
Zmienne w LOGO (a więc także w POOL) posiadają trzy ważne cechy:
- zmienne mogą zostać utworzone w dowolnym miejscu kodu programu;
-
jedna zmienna może przechowywać dane różnego rodzaju (jej typ jest dynamiczny), np. do
zmiennej przechowującej początkowo liczbę można później przypisać napis;
-
LOGO stara się dopasować typ zmiennej (oraz całych wyrażeń) do typu oczekiwanego w danym wyrażeniu, np.
dodawanie liczby 5 i napisu o treści "5" jest poprawne, a wynikiem jest liczba 10.
Do utworzenia zmiennej będziemy teraz używali instrukcję make
.
Jej argumentami są: nazwa zmiennej i jej początkowa wartość. Ta sama instrukcja służy do przypisania nowej
wartości do zmiennej, która już istnieje.
Ważne informacje:
-
nazwa zmiennej jest słowem, czyli ciągiem znaków; w LOGO ciąg
znaków rozpoczyna się od znaku cudzysłowu, np.:
"nazwa
-
aby odczytać wartość zmiennej należy użyć instrukcji
thing "nazwa
;
ponieważ odczytywanie zmiennych jest bardzo częstą operacją, instrukcja
thing "nazwa
ma skrócony
odpowiednik: :nazwa
(zauważ, że tu nazwa występuje bez
cudzysłowu);
-
w POOL możemy użyć bardziej naturalnego zapisu: odpowiednikiem
make "nazwa wartość
jest "nazwa := wartość
Oto kilka linijek programu, który ilustruje operacje na zmiennych:
make "x 1
print :x
make "y :x + 1
make "x 2 * :y
(print :x :y)
"z := :x + :y
print :z
make "x "10
(print "słowo :x)
print 2 * :x
Wynik działania programu (w oknie tekstowym):
1
4 2
6
słowo 10
20
W programie rysującym kwadraty możemy dodać zmienną :n
aby
ułatwić zmianę liczby kwadratów:
to kwadrat
repeat 4 [forward 50 right 90]
end
make "n 20
repeat round 360 / :n [
kwadrat
right :n
]
Funkcje z argumentami
Nasza funkcja zawsze rysuje kwadrat o długości boku 100, co ogranicza jej użyteczność. Można to usprawnić i
długość boku przekazywać jako argument funkcji - tak, jak do tej pory podawaliśmy np. długość kroku w
instrukcji forward 100
czy wartość kąta w obrocie
right 90
. Argument funkcji należy określić w jej definicji.
W treści funkcji odwołujemy się do argumentu tak jak do zmiennej:
to kwadrat :a
repeat 4 [forward :a right 90]
print :a
end
kwadrat 50
kwadrat 100
kwadrat 150
Każde wywołanie funkcji w powyższym programie rysuje kwadrat o zadanym boku. Funkcja wypisuje także wartość
argumentu w oknie tekstowym.
Zauważ: ostatnia, zakomentowana linia używa tej samej instrukcji co funkcja:
print :a
. Włączenie tej linii
(usunięcie pierwszego znaku ;
) spowoduje błąd w wykonaniu programu - spróbuj. Argument funkcji
jest zmienną lokalną - oznacza to, że jest dostępny
tylko wewnątrz funkcji, w której został zdefiniowany.
Poniższy program korzysta z funkcji kwadrat
o zmiennej długości boku. Zwróć uwagę, że argument
w wywołaniu funkcji jest wynikiem wyrażenia: 3 * repcount
. Instrukcja
repcount
jest często używana w
pętlach LOGO - jej wynikiem jest numer iteracji pętli.
to kwadrat :a
repeat 4 [forward :a right 90]
end
repeat 50 [
kwadrat 3 * repcount
right 1
]
Więcej argumentów
Funkcja może mieć wiele argumentów - to proste, w definicji funkcji wystarczy dodać kolejne argumenty. Co
więcej, funkcje i instrukcje mogą posiadać argumenty opcjonalne, np.: instrukcja print
,
która wypisuje wartości argumentów w oknie tekstowym, domyślnie używa jeden argument, np.:
print "ok
ale może też być użyta z wieloma argumentami, których wartości zostaną wypisane w jednej linii - w tym celu
instrukcję i jej argumenty należy umieścić w nawiasach, np.:
(print 1 "ok 2+3)
Podobnie do instrukcji także funkcje mogą posiadać argumenty opcjonalne. Jeśli w wywołaniu takiej funkcji
chcemy przekazać wartość argumentu opcjonalnego, całe wywołanie należy umieścić w nawiasach. Jeśli wartość
argumentu opcjonalnego nie zostanie podana w wywołaniu - funkcja nada mu wartość domyślną.
Argument opcjonalny umieszcza się w definicji funkcji razem z jego wartością domyślną w nawiasach kwadratowych:
to funkcja :arg_obowiązkowy [:arg_opcjonaly wartość]
.
Poniższy program definiuje funkcję kwadrat
, która ma dwa argumenty obowiązkowe :a
i
:kolor
oraz argument opcjonalny :p
o domyślnej wartości 100
.
to kwadrat :a :kolor [:p 100]
(setpc :kolor :p)
setps :a
forward :a
end
hideturtle
setpalette "hot
make "n 5
make "l 10
make "m 1 + round 360 / :n
repeat :m [
make "k 1000 * repcount / :m
(kwadrat :l :k 20)
pu bk :l - 4 pd
make "l :l + 1.7
right :n
]
Funkcje zwracające wynik
Funkcje zdefiniowane przez programistę mogą zwracać wynik, podobnie jak instrukcje LOGO takie jak licznik
iteracji pętli repcount
lub pierwiastek z liczby
sqrt x
. Oto przykład:
:pool_cfg,"scale_x := 30
:pool_cfg,"scale_y := 30
window
hideturtle
to pitagoras :a :b
let "p pos
left 90 forward :a
right 90 forward :b
setpos :p
output sqrt :a^2 + :b^2
end
print sqrt 3 * 3 + 4 * 4
print pitagoras 3 4
Program definiuje funkcję dwóch argumentów: :a
i :b
. Funkcja ta rysuje trójkąt
prostokątny, w którym długości przyprostokątnych odpowiadają wartościom argumentów. Wynikiem funkcji jest
liczba oznaczająca długość przeciwprostokątnej w tym trójkącie - instrukcja output
pozwala przekazać wartość wyniku do wyrażenia wywołującego funkcję. W tym przykładzie output
jest ostatnią instrukcją funkcji, ale można umieścić tą instrukcję także wewnątrz treści funkcji
- spowoduje wtedy przerwanie działania funkcji (podobnie jak instrukcja
stop
).
Zauważ, że funkcja zapamiętuje początkową pozycję żółwia w zmiennej :p
,
by po narysowaniu przyprostąkątnych wrócić do tej pozycji rysując przeciwprostokątną. Zmienna
:p
jest zmienną lokalną i podobnie jak argumenty :a
i :b
jest dostępna tylko wewnątrz funkcji. W POOL do utworzenia zmiennej lokalnej i nadania jej
wartości służy instrukcja let
. W
wielu dialektach LOGO instrukcja ta występuje pod nazwą localmake
-
POOL akceptuje także tą nazwę.
Fragment programu oznaczony jako "parametry rysowania" zawiera kod określający
rozmiar kroków żółwia w pikselach ekranu oraz sposób rysowania.
Zakończenie
Umiejętność programowania funkcji będzie bardzo przydatna w następnych rozdziałach. Pokażemy w nich jak
napisać funkcję rekurencyjną - czyli taką, która wywołuje
samą siebie. Pokażemy też jak napisać program, w którym jednocześnie działa wiele żółwi-obiektów i jak użyć
funkcji do opisu ich zachowania.