Koncepcje programowania/Funkcje

Jeśli tworzysz jakiś program, to od samego początku powinieneś zadbać o to, żeby był tworzony w sposób jak najbardziej efektywny. Przede wszystkim, aby kod źródłowy miał modułową strukturę, podzielony na proste, logiczne bloki. Dlaczego? Ponieważ taką strukturą kodu dużo łatwiej się zarządza a ponadto taki zbiór instrukcji włożonych do bloku, może być wykorzystywany wielokrotnie w trakcie działania programu z różnymi parametrami, dzięki czemu unikamy powtarzania się ciągle tych samych linijek kodu. Większość języków programowania ma taką możliwość, używa się tutaj różnych określeń, metody, subrutyny, funkcje, moduły czy bloki. W przypadku języków Python i JavaScript, nazywamy je funkcjami

Działa to trochę jak zestaw klocków, gdzie każdy klocek to jedna funkcja, a cały zestaw to cały program.

Zanim zaczniemy, powróćmy do modułowej struktury kodu. Każdy program dużo zyska, jeśli podzielisz go na logiczne funkcje, wyobraź sobie że piszesz serwis internetowy który ma główne bloki jak np. Artykuły. W tym bloku, można by odnaleźć pewne funkcje np. Dodaj artykuł, edytuj artykuł, usuń artykuł, które pozwalają na zhierarchizowanie która ułatwia pisanie i edytowanie programów. Przyjętą konwencją programistyczną jest nazywanie funkcji, które rozpoczynają się jakimś czasownikiem, ponieważ funkcje wykonują jakieś czynności, akcje, działanie. Innymi słowy, funkcja to zamknięty blok kodu, który wykonuje jedną konkretną rzecz. I taka funkcja może być zdefiniowana jeden raz, ale potem możesz, w różnych miejscach swojego programu, wiele razy używać.

Jak taka funkcja może wyglądać? Przykład w języku Python:

def myfunction():
	#Instrukcje wykonywane przez funkcje

Przykład w języku JavaScript:

function myFunction() {
	//Instrukcje wykonywane przez funkcje
}

Przykład w języku elisp:

(defun myFunction ()
	;Instrukcje wykonywane przez funkcje

Zaczynamy od słowa kluczowego, różnego w zależności od języka programowania, następnie nazywamy naszą funkcje dowolną nazwą, w tym wypadku myFunction. Po nazwie jest pusty nawias - to bardzo charakterystyczna cecha funkcji, pełni bardzo ważną rolę, co zostanie poruszone później. Następnie mamy blok funkcji (w zależności od języka, będą to klamerki albo białe znaki). W którym określamy co ta funkcja będzie dla nas robiła, np. Jeśli mamy zamiar utworzyć nowy artykuł, to w środku funkcji musimy wypisać wszystkie instrukcje których potrzebujemy po to, by móc go wytworzyć.

To co widzisz w ww. Kodzie źródłowym to tylko definicja naszej funkcji, ale ona sama z siebie się nie uruchomi. To my musimy jej powiedzieć, kiedy i w jakim miejscu ma się uruchomić. A jak wywołujemy funkcje? Bardzo prosto:

myfunction():

Przykład w języku JavaScript:

 myFunction()

Przykład w języku elisp:

(myFunction)

Podajesz nazwę funkcji którą przed chwilą stworzyłeś i po nazwie wpisujesz nawias (bądź dodatkowo średnik jak w JavaScript). Program, widząc nawiasy, będzie wiedział że ma odnaleźć funkcję która się w ten sposób nazywa i ją uruchomi i wykona wszystkie jej instrukcje.

I teraz najważniejsza koncepcja: funkcje określamy 1 raz i potem możemy jej używać wielokrotnie. Jeśli potrzebujesz by dana instrukcja wykonała się 50 razy, to raz ją zdefiniujesz w formie funkcji i potem 50 razy w dowolnym miejscu programu, będziesz mógł ją wywołać. To jest główna idea użycia funkcji w programowaniu.

Przykład w języku Python

def MyFunction():
	var x = 2;
	var y = 2;
	print( x * y );
MyFunction();
MyFunction();
MyFunction();

Przykład w języku JavaScript:

function myFunction() {
	var x = 2;
	var y = 2;
	alert( x * y );
}
MyFunction();
MyFunction();
MyFunction();

Przykład w języku elisp:

(defun my-function ()
  (let ((x 2)
        (y 2))
    (message "%d" (* x y))))

(my-function)
(my-function)
(my-function)

Prosty przykład który mnoży dwie wartości i są opakowane w funkcje. I to jest definicja funkcji, funkcja sama z siebie się nie uruchomi, dopiero gdy ją wywołamy, w tym wypadku nazwali naszą funkcję MyFunction więc wywołujemy ją poprzez odwołanie się do jej nazwy i dodając nawiasy (są charakterystycznym elementem funkcji w praktycznie dowolnym języku programowania) i to wystarczy, wywołanie sprawi że ww. Instrukcje zdefiniowane w funkcji uruchomią się. I najważniejsze, możemy utworzyć ile chcemy tych odwołań do tej funkcji i za każdym funkcja wykona to samo.

Parametry funkcji edytuj

Wspominałem często o nawiasach w funkcjach, nadszedł czas by ten temat rozwinąć. Parametry funkcji, sprawiają że dodatkowo zwiększa się ich przydatność, sprawia że funkcje stają się bardziej elastyczne. Ponieważ cała idea funkcji polega na tym żeby ich używać wielokrotnie, argumenty funkcji sprawią że funkcję możemy wywołać za każdym razem w inny sposób, z innymi wartościami.

Jaki jest problem z przykładowym kodem który był wyżej? Ona ma na sztywno zakodowane dwie wartości mnożenia. Skoro użyliśmy do tego celu funkcji, to przydałaby się możliwość podawania tych dwóch wartości za każdym razem innych, na przykład za pierwszym razem pomnożyć 7 * 4, w kolejnym wywołaniu 20 * 10 i tak dalej. I po to właśnie stosujemy parametry funkcji, które definiujemy właśnie w nawiasach.

Przykład w języku Python:

def myFunction(a, b):
	print( x * y)

MyFunction(2, 7)

Przykład w języku JavaScript:

function myFunction(a, b) {
	alert( x * y );
}
MyFunction(2, 7);
MyFunction(3, 6);
MyFunction(5, 4);

Przykład w języku elisp:

(defun myFunction (a, b)
	message( x * y );

MyFunction(2, 7);
MyFunction(3, 6);
MyFunction(5, 4);

Mamy funkcję o nazwie MyFunction, w której zostało zdefiniowane mnożenie. Czyli będziemy mnożyli dwie liczby, które podaliśmy w formie parametru funkcji (nawiasy) i później sobie wyprowadzimy na ekran A pomnożone przez B. I teraz najważniejsze: Skoro w nawiasie podaje dwa parametry, w definicji funkcji to teraz wartości tych dwóch parametrów obowiązkowo muszę podać w momencie, gdy tą funkcję wywołuje. I tak 2 i 7 zostanie przypisane odpowiednio A i B. Zamiast A będzie 2 i zamiast B będzie 7, funkcja zawiera mnożenie więc A * B i wynik pojawi się na ekranie.

Wartość zwracana przez funkcje edytuj

Funkcje zazwyczaj coś wykonują, na przykład tak jak powyższa funkcja, która przyjmowała dwie liczby, A oraz B a funkcja została zdefiniowana w ten sposób by te dwie wartości mnożyła czyli ona ten wynik dla nas zwraca, wynik tego mnożenia jest wartością zwracaną przez funkcję. Przykład:

Przykład w języku Python:

def myFunction(a, b):
	rezultat = a * b
	return rezultat

x = MyFunction(2, 7)
print(x)

Przykład w języku JavaScript:

function myFunction(a, b) {
	var rezultat = a * b;
	return rezultat;
}
var x = MyFunction(2, 7);
alert(x);

Przykład w języku elisp:

(defun my-function (a b)
  "Multiply two numbers and return the result."
  (let ((rezultat (* a b)))
    rezultat))

(setq x (my-function 2 7))
(message "%d" x)

Argument funkcji podaje A i B, wynik mnożenia A * B przypisujemy do zmiennej rezultat. I to właśnie zmienna rezultat będzie naszą wartością zwracaną przez funkcję. Aby określić że to jest wartość zwracana a nie tylko przypisana, w większości języków programowania użyjemy deklaracji RETURN. Czyli ZWRÓĆ. Niech funkcja zwróci do nas wynik. Uwaga na marginesie, funkcja return będzie ostatnią instrukcją w tej funkcji, tak jakbyśmy ją zakończyli. Funkcja wykonała swoje akcje i na końcu zwróciła dla nas rezultat.

Wartością zmiennej X może być to, co zwróciła funkcja czyli możemy funkcje wywołać, tak jakby była ona wartością dla zmiennej X. Czyli funkcja zwraca rezultat, w tym momencie gdy ją wywołujemy i ten rezultat zostanie przypisany do zmiennej X. A ponieważ mamy teraz zmienną poza funkcją, może użyć zmiennej X do wyprowadzenia tekstu na ekran.

Zakres zmiennych edytuj

Mamy dwa warianty zmiennych. Zauważ że w poniższym przykładzie mamy dwie deklaracje zmiennej X, dwa warianty. Pierwszy raz została zadeklarowana na samej górze, natomiast po raz drugi została zadeklarowana wraz z wartością 10 wewnątrz funkcji o nazwie myFunction.

Przykład w języku Python:

x = None

def my_function():
    global x
    x = 10

my_function()
print(x)

Przykład w języku JavaScript:

var x;
function myFuntion() {
	var x = 10;
}

Przykład w języku elisp:

(defvar x nil)

(defun my-function ()
  "Set the variable x to 10."
  (setq x 10))

(my-function)
(message "%s" x)

Pierwsza zmienna to tak zwana zmienna globalna, czyli taka którą możemy używać w dowolnym miejscu naszego kodu, natomiast druga wersja zmiennej, umieszczonej wewnątrz funkcji to tak zwana zmienna lokalna, czyli dostępna tylko dla niej. Jeśli została zadeklarowana wewnątrz funkcji to tylko przez tą funkcję może być użyta.

Dwie zmienne, które mają takie same nazwy, ale tak naprawdę to są dwie różne zmienne, to kolejna typowa pułapka dla początkującego programisty.

Przykład w Python:

x = 5

def my_function():
    global x
    x = 10
    print(x)

my_function()
print(x)

Przykład w JavaScript:

var x = 5;
function myFunction() {
 var = x 10;
	alert(x);
}
myFunction();
alert(x);


Przykład w elisp:

(defvar x 5)

(defun my-function ()
  "Set x to 10 and display it."
  (setq x 10)
  (message "%d" x))

(my-function)
(message "%d" x)

Spróbujmy to przeanalizować tak, jakby to zrobił komputer:

Przed funkcją przypisałem zmienną GLOBALNĄ x o wartości 5.

Mamy funkcje o nazwie myFunction, posiada LOKALNĄ zmienną x która ma wartość 10 i za pomocą słowa kluczowego (print/alert) wyprowadzam ją na ekran.

Na koniec, wywołuje funkcję o nazwie MyFunction co w rezultacie da wynik 10. Ponieważ jest to zmienna LOKALNA, wyprowadzenie na ekran wartości x nie spowoduje pojawienie się po raz drugi wartości 10, tylko 5. Nie odwołali się do tej zmiennej z funkcji tylko do GLOBALNEJ zmiennej x.

Zadania edytuj

  1. Zadanie - Napisz program, który definiuje prostą funkcję o nazwie wiadomosc() a następnie wywołuje tę funkcję w programie
  2. Zadanie - Napisz program, w którym zdefiniowano cztery funkcje: dodawanie, odejmowanie, mnożenie i dzielenie. Liczby a i b należy wprowadzić z klawiatury. Dodatkowo trzeba założyć, że b musi być różne od zera.