Programowanie funkcyjne - wprowadzenie

Transkrypt

Programowanie funkcyjne - wprowadzenie
Programowanie funkcyjne – wprowadzenie
Specyfikacje formalne i programy funkcyjne
dr inż. Marcin Szlenk
Politechnika Warszawska
Wydział Elektroniki i Technik Informacyjnych
[email protected]
Paradygmaty programowania
Programowanie imperatywne
Program jest sekwencją instrukcji do wykonania
Wykonywanie instrukcji polega na zmianie stanu
programu
C, C++, Java, …
Programowanie funkcyjne
Wykonanie programu polega na obliczaniu wartości
funkcji matematycznych
Definicja funkcji przedstawia zależność pomiędzy
danymi wejściowymi i wyjściowymi
Lisp, ML, Haskell, …
2
Przykład – Algorytm Quicksort
5
3
2
1
1
2
1
2
3
2
4
2
6
1
3
4
3
4
4
5
5
1
7
6
7
6
7
6
7
3
Implementacja w C/C++
void quicksort (int beg, int end)
{
int i = beg, j = end, v;
int x = A[beg];
do
{
while (A[ i ] < x) i++;
while (A[ j ] > x) j--;
if (i <= j )
{
v = A[ i ]; A[ i ] = A[ j ];
A[ j ] = v; i++; j--;
}
} while (i <= j);
if (beg < j) quicksort(beg, j);
if (i < end) quicksort(i, end);
}
4
Implementacja w Haskellu
Wynikiem sortowania ciągu
pustego jest ciąg pusty
quicksort [ ]
= []
Wybierz elementy < x
z ciągu xs
quicksort (x : xs) = quicksort (filter (< x) xs) ++
[ x ] ++
quicksort (filter (>= x) xs)
Ciąg niepusty składa się
z pierwszego elementu x
i reszty xs
Połącz ciągi
Wybierz elementy ≥ x
z ciągu xs
Nie ma przypisywania wartości do zmiennych
Kolejność obliczeń nie jest explicite określona
5
Historia języków funkcyjnych
1930
Rachunek Lambda
(1936)
1940
Języki
mieszane
Języki czysto
funkcyjne
1950
LISP
1960
(1958)
1970
ML
(1973)
1980
Miranda
(1985)
Erlang
Haskell
1990
(1986)
Clean
(1987)
(1990)
OCaml
2000
(1996)
Scala
(2003)
F#
(2002)
Clojure
2010
(2007)
6
Podstawowe koncepcje
Funkcje czyste
Ścisłe, nieścisłe i leniwe wartościowanie
Rekurencja
Funkcje wyższego rzędu
Polimorfizm
7
Funkcje czyste
Efekt uboczny (side effect) to zmiana stanu
spowodowana przez funkcję lub wyrażenie:
modyfikacja zmiennej
wyświetlenie na ekranie
zapis do pliku
Funkcja jest czysta (pure) jeżeli nie ma efektów
ubocznych
8
Własności funkcji czystych
Mogą być wykonywane w dowolnej kolejności
y = f(a) * g(a)
Wartości f(a) i g(a) mogą być
obliczone równolegle
Łatwość analizy
a=…
f(x) = …
…
y = f(a)
…
W każdym miejscu programu
wartość f(a) będzie taka sama
9
Własności funkcji czystych
Jeżeli zdefiniowano równość dwóch wyrażeń, to mogą
być używane zamiennie (referential transparency)
z = f(a) * g(b) * c
y = f(a) * f(a)
z = f(a)
y=z*z
Wyrażenia z i f(a) * g(b) * c są
całkowicie zamienne
Można zoptymalizować…
Równoważne powyższemu, ale
f(a) liczymy tylko raz
10
Własności funkcji czystych
y = random() * random()
z = random()
y=z*z
Nie jest równoważne
powyższemu
y = printf(”x”) * printf (”x”)
z = printf(”x”)
y=z*z
Nie jest równoważne
powyższemu
11
Ścisłe, nieścisłe i leniwe wartościowanie
f(x) = x2 + x
g(x, y) = x + y
Ścisłe wartościowanie (strict evaluation)
f(g(1, 4)) → f(1+4) → f(5) → 52 + 5 → 30
Nieścisłe wartościowanie (non-strict evaluation)
f(g(1,4)) → g(1,4)2 + g(1,4) → (1+4)2 + (1+4) → 52 + 5 → 30
Leniwe wartościowanie (lazy evaluation)
Argument funkcji zostanie policzony co najwyżej raz, wtedy gdy
będzie potrzebny
12
Leniwe wartościowanie
ax2 + bx + c = 0
Trzeba obliczyć d …
roots (a, b, c) = if d < 0 then error "pierwiastki urojone"
else (r1, r2) where
r1 = e + sqrt d / (2 * a)
r2 = e - sqrt d / (2 * a)
d =b*b-4*a*c
r1, r2 zostaną
e = -b / (2 * a)
obliczone, gdy d ≥ 0
e zostanie obliczone, gdy
będą obliczane r1 lub r2
(tylko raz)
13
Leniwe wartościowanie
1/0
OK. Definicja, a nie przypisanie
a = 1/0
a + 1 → Błąd
const x = 1
const a → 1
Definicja funkcji stałej
OK. Argument nie jest obliczany, bo
nie jest potrzebny
Nieskończone struktury danych
[1.. ] → [1, 2, 3, 4, 5, 6, 7, 8, …
take 3 [1.. ] → [1, 2, 3]
Lista nieskończona
OK. Weź 3 pierwsze elementy
14
Rekurencja
Nie ma zmiennych – nie ma pętli
int length = 0;
node_ptr = head_ptr;
while (node_ptr != NULL) {
length++;
node_ptr = node_ptr->next;
}
… i w Haskellu
length [ ]
= 0
length (x : xs) = 1 + length xs
Obliczenie długości
listy w C/C++
Lista pusta ma
długość zero
Lista niepusta ma długość
1+ długość ogona
15
Funkcje wyższego rzędu
Funkcja wyższego rzędu (higher order) przyjmuje jako
argumenty lub zwraca w wyniku inne funkcje
f x = 2*x
Definicja funkcji f
map f [1, 2, 3] → [2, 4, 6]
Zastosuj funkcję f do każdego
elementu listy
16
Polimorfizm
quicksort [ ]
= []
quicksort (x : xs) = quicksort (filter (< x) xs) ++
[ x ] ++
quicksort (filter (>= x) xs)
Sortuje elementy dowolnego typu, dla
którego zdefiniowano operatory <, >=
quicksort
quicksort
quicksort
quicksort
[ 2, 1, 3 ]
[ ’b’, ’a’, ’c’ ]
[ ”ala”, ”ma”, ”kota” ]
[ (2, ’a’), (1,’b’) ]
→
→
→
→
[ 1, 2, 3 ]
[ ’a’, ’b’, ’c’ ]
[ ”ala”, ”kota”, ”ma” ]
[ (1, ’b’), (2, ’a’) ]
17
Myślenie imperatywne a funkcyjne
 a1   b1 
a  b  n
 2    2    a b
 .   .  i 1 i i
   
an  bn 
Imperatywne:
c := 0
for i = 1 to n do
c := c + a [ i ]  b [ i ]
Podatne na błędy
Funkcyjne:
sum ( zipWith () a b )
[a1, a2, ..., an]
zipWith () → [a1  b1, a2  b2, …, an  bn]
[b1, b2, …, bn]
Funkcja wyższego rzędu
18
Zastosowania komercyjne
Ericsson – oprogramowanie urządzeń sieciowych i
telekomunikacyjnych (Erlang)
www.erlang.se
Bluespec – narzędzia do projektowania układów ASIC i
FPGA (Haskell)
www.bluespec.com
Jane Street Capital – analiza statystyczna danych
finansowych (OCaml)
www.janestcapital.com
…
Commercial Users of Functional Programming,
www.cufp.org
19
Zalety i wady
Deklaratywność
Kolejność wykonania nie określana przez programistę
Funkcje definiowane jako zależności pomiędzy
wartościami
Duża ekspresyjność
Funkcje wyższego rzędu
Polimorfizm
Łatwiejsza weryfikacja (przez indukcję matematyczną)
Spadek wydajności
Problemy z wnioskowaniem nt. wydajności
Wciąż eksperymentalne (brak narzędzi i programistów)
20

Podobne dokumenty