Podstawy programowania funkcjonalnego haskell.mariuszrozycki.pl Mariusz Różycki Churchill College, University of Cambridge rev. 2014.03.27.1
Wprowadzenie
Materiały haskell.mariuszrozycki.pl Slajdy (w tym opisana wersja z zajęć), kody źródłowe, dodatkowe zadania i materiały, filmy (niedługo) github.com/mrozycki/haskell-course-pl To, co wyżej, w formie surowej (tj. pliki TEXowe itp.) learnyouahaskell.com (ang.) Anglojęzyczna strona z kursem programowania w Haskellu
Narzędzia WinGHCi. Kompilator i interpreter języka Haskell dla systemu Windows. Wchodzi w skład pakietu Haskell Platform. 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 + 2 22?
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 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: a 0 = 1 a n = a a n 1, dla n 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 wartosc_bezwzgledna n = if n > 0 then n else -n
Zadania Zadanie 6 Ciąg Collatza dla danego a zdefiniowany jest następująco: c 0 = a { 1 c n+1 = 2 c n dla c n parzystego 3c n + 1 dla c n nieparzystego Napisz funkcję collatz cn, która dla danego c n obliczy i zwróci wartość c n+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: wartosc_bezwzgledna n >= 0 = n otherwise = - n n
Zadania Zadanie 7 Funkcja signum zdefiniowana jest następująco 1 dla n > 0 sgn(n) = 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;