Podstawy programowania funkcjonalnego

Transkrypt

Podstawy programowania funkcjonalnego
Podstawy programowania funkcjonalnego
haskell.mariuszrozycki.pl
Mariusz Różycki
Churchill College, University of Cambridge
rev. 2014.03.27.1
Wprowadzenie
Materiały
I
haskell.mariuszrozycki.pl
Slajdy (w tym opisana wersja z zajęć), kody źródłowe,
dodatkowe zadania i materiały, filmy (niedługo)
I
github.com/mrozycki/haskell-course-pl
To, co wyżej, w formie surowej (tj. pliki TEXowe itp.)
I
learnyouahaskell.com (ang.)
Anglojęzyczna strona z kursem programowania w Haskellu
Narzędzia
I
WinGHCi. Kompilator i interpreter języka Haskell dla
systemu Windows.
Wchodzi w skład pakietu Haskell Platform.
I
Notepad++. Edytor tekstu.
Każdy inny edytor tekstu (vim, emacs, notatnik) też się
sprawdzi.
Programowanie funkcjonalne (1)
Paradygmat (trudne słowo) programowania, odmienny od
programowania imperatywnego (kolejne trudne słowo), w którym
zamiast mówić komputerowi jak ma wykonywać obliczenia,
mówimy mu co ma policzyć.
Poza tym, tak jak nazwa wskazuje, opiera się na funkcjach.
Programowanie funkcjonalne (2)
Na przykład w C++ (programowanie imperatywne) napisalibyśmy:
int n ; cin >> n ;
int wynik = 1;
for ( int i = 0; i < n ; i ++) {
wynik = wynik * i ;
}
cout << wynik ;
Aby policzyć silnię.
Programowanie funkcjonalne (3)
Natomiast w Haskellu (programowanie funkcjonalne) napiszemy:
silnia 0 = 1
silnia n = n * silnia (n -1)
A w ML (również programowanie funkcjonalne) napisalibyśmy:
fun silnia 0 = 1;
| silnia n = n *( silnia (n -1));
W tym kursie skupimy się jednak na Haskellu.
Podstawy Haskella
Zapytania
GHCi jest interpreterem, zatem musimy wydawać mu zapytania,
aby otrzymać interesujący nas wynik.
Prelude> 2+2*2
6
it :: Integer
Ile wynosi 2 + 222 ?
Definiowanie funkcji
Możemy w zewnętrznym pliku zdefiniować własne funkcje, które
potem będziemy wykorzystywać w zapytaniach.
Stwórzmy plik funkcje.hs, w którym napiszemy:
kwadrat x = x*x
Po wczytaniu go do GHCi możemy wykonać zapytanie:
Main> kwadrat 23
Jaki otrzymamy wynik?
Zadania
Zadanie 1
Napisz funkcję potega 2 n, która policzy wartość n-tej potęgi 2.
Na przykład potega 2 16 zwróci 65 536.
Rozwiązanie
potega_2 n = 2^ n
Zadanie 2
Napisz funkcję suma n, która policzy wartość sumy liczb od 1 do n.
Rozwiązanie
suma n = n *( n +1)/2
Funkcje wielu argumentów
Funkcje w Haskellu mogą przyjmować więcej niż jedną wartość.
suma_kwadratow x y = x ^2 + y ^2
Jaki wynik zwróci zapytanie suma kwadratow 3 4?
Jaki wynik zwróci zapytanie suma kwadratow 1.2 0.5?
Zadania
Zadanie 3
Napisz funkcję srednia a b, która policzy średnią arytmetyczną
liczb a i b.
Rozwiązanie
srednia a b = ( a + b )/2
Zadania
Zadanie 4
Napisz funkcję jednomian a x n, która policzy wartość
jednomianu ax n .
Rozwiązanie
jednomian a x n = a * x ^ n
Podstawy rekurencji
Funkcja rekurencyjna
Funkcja rekurencyjna to taka, która w swojej definicji odwołuje się
do siebie samej.
Przykład
Silnia zdefiniowana jest jako:
0! = 1
n! = n · (n − 1)!, dla n 6= 0
Co w Haskellu można zapisać jako
silnia 0 = 1
silnia n = n * silnia (n -1)
Potęgowanie rekurencyjne
Potęgę o wykładniku naturalnym również można zdefiniować
rekurencyjnie:
a0 = 1
an = a · an−1 , dla n 6= 0
W jaki sposób zapisać to w Haskellu?
potega a 0 = 1
potega a n = a * potega a (n -1)
Zadania
Zadanie 5
Napisz funkcję suma kwadratow n, która policzy sumę kwadratów
liczb od 1 do n włącznie.
Rozwiązanie
suma_kwadratow 1 = 1
suma_kwadratow n = n ^2 + suma_kwadratow (n -1)
Kontrola przebiegu programu
Kontrola przebiegu programu
Mechanizmy służące kontroli przebiegu programu, to wszystkie te
elementy języka, które umożliwiają „podejmowanie decyzji”.
We współczesnych językach imperatywnych możemy spotkać się z
instrukcjami warunkowymi if oraz switch, a także pętlami for,
foreach, while itp.
W językach funkcjonalnych spotkać możemy się, oprócz instrukcji
warunkowych, z dopasowaniem do wzorca czy pętlami.
Dopasowanie do wzorca
W dopasowaniu do wzorca podajemy kilka definicji funkcji, z
których każda posiada inny wzór argumentów wejściowych (patrz
rekurencja).
Wzorce są sprawdzane w kolejności pojawienia się w programie na
podstawie przekazanych argumentów i wybierana jest pierwsza
pasująca definicja.
Przykład
silnia 0 = 1
silnia n = n * silnia (n -1)
if...then...else...
Podstawowym sposobem kontroli przebiegu programu we
wszystkich współczesnych językach programowania jest wyrażenie
warunkowe if.
W Haskellu przyjmuje ono postać if <warunek> then
<wartosc prawda> else <wartosc falsz>.
Przykład – wartość bezwzględna
w art osc_bezwzgl e d na n = if n > 0 then n else -n
Zadania
Zadanie 6
Ciąg Collatza dla danego a zdefiniowany jest następująco:
c0 = a
(
cn+1 =
1
2 cn
3cn +
dla cn parzystego
1 dla cn nieparzystego
Napisz funkcję collatz cn, która dla danego cn obliczy i zwróci
wartość cn+1 .
Rozwiązanie
collatz n = if mod n 2 == 0
then div n 2
else n *3+1
Warunki w definicji
Gdybyśmy chcieli sprawdzić wiele różnych warunków przy użyciu
wyrażeń if, wynik byłby dość trudny do zrozumienia.
Haskell daje nam możliwość podania warunków w definicji funkcji,
na przykład:
w ar t o sc_bezwzgl e d na n
| n >= 0 = n
| otherwise = -n
Zadania
Zadanie 7
Funkcja signum zdefiniowana jest następująco
sgn(n) =


 1
dla n > 0
0
dla n = 0

 −1 dla n < 0
Napisz funkcję signum n, która dla danego n obliczy i zwróci
wartość sgn(n).
Rozwiązanie
signum n
| n > 0 = 1
| n == 0 = 0
| otherwise = -1
Listy
Podstawowa notacja list
Co zwróci zapytanie [1..10]?
Listę elementów od 1 do 10:
[1,2,3,4,5,6,7,8,9,10]
Możemy też napisać [1,3..10]. Co otrzymamy?
[1,3,5,7,9]
Możemy również po prostu zapisać listę jako oddzielone
przecinkami pojedyncze elementy, tak jak widoczne jest to w
wynikach poprzednich dwóch zapytań.
Operacje na listach
Konkatenacja (łączenie) list
[2,4,6] ++ [5,3,1]
Dołączenie nowego elementu z przodu listy
2:[4,3]
Znajdowanie długości listy
length [5,6,8,4,2,5,1,7,9]
Sumowanie listy
sum [1..10]
Znajdowanie maksimum listy (minimum analogicznie)
minimum [5,6,8,4,2,5,1,7,9]
Listy w funkcjach
Funkcje mogą zwracać listy jako wynik:
przedzial a b = [a..b]
Ale mogą być także przekazywane jako argumenty:
srednia listy l = (sum l)/(length l)
Zadania
Zadanie 5
Napisz funkcję suma przedzialu a b, która zwróci sumę liczb
naturalnych od a do b włącznie.
Rozwiązanie
suma_przedzialu a b = sum [ a .. b ]
Zadania
Zadanie 6
Napisz funkcję suma list l1 l2, która zwróci sumaryczną
długość list l1 i l2.
Rozwiązanie
suma_list l1 l2 = sum ( l1 ++ l2 );
Albo:
suma_list l1 l2 = sum l1 + sum l2 ;