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 ;