Programowanie funkcyjne (Haskell Wprowadzenie) Kowalik Adrian

Podobne dokumenty
- nawiasy kwadratowe oznaczają, że to lista

Programowanie funkcyjne wprowadzenie Specyfikacje formalne i programy funkcyjne

Typy, klasy typów, składnie w funkcji

Podstawy programowania funkcjonalnego

Nazwa pochodzi od imienia znanego logika Haskell a Brooks a Curry ego ( )

Języki programowania Haskell

Elementy języka Haskell

Języki i Paradygmaty Programowania

Wprowadzenie do języka Java

1 Podstawy c++ w pigułce.

Paradygmaty programowania

1 Podstawy c++ w pigułce.

Prezentacja o Haskell u(rozdział 3 i 4)

4. Funkcje. Przykłady

PARADYGMATY I JĘZYKI PROGRAMOWANIA. Haskell. (w11)

Programowanie obiektowe

Pascal - wprowadzenie

METODY I JĘZYKI PROGRAMOWANIA PROGRAMOWANIE STRUKTURALNE. Wykład 02

Programowanie C++ Wykład 2 - podstawy języka C++ dr inż. Jakub Możaryn. Warszawa, Instytut Automatyki i Robotyki

Programowanie strukturalne. Opis ogólny programu w Turbo Pascalu

λ parametry. wartość funkcji suma = λ x y. x + y kwadrat = λ x. x * x K.M. Ocetkiewicz, 2008 WETI, PG 2 K.M. Ocetkiewicz, 2008 WETI, PG 3

Wstęp do Programowania potok funkcyjny

WEJŚCIE/WYJŚCIE HASKELL ŁUKASZ PAWLAK DARIUSZ KRYSIAK

Cw.12 JAVAScript w dokumentach HTML

Wstęp do programowania

LibreOffice Calc VBA

Programowanie Funkcyjne. Marcin Kubica Świder,

Instytut Mechaniki i Inżynierii Obliczeniowej Wydział Mechaniczny Technologiczny Politechnika Śląska

Naukę zaczynamy od poznania interpretera. Interpreter uruchamiamy z konsoli poleceniem

Swift (pol. jerzyk) nowy język programowania zaprezentowany latem 2014 r. (prace od 2010 r.)

Język skryptowy: Laboratorium 1. Wprowadzenie do języka Python

Wstęp do programowania

Jak napisać program obliczający pola powierzchni różnych figur płaskich?

Paradygmaty programowania

Swift (pol. jerzyk) nowy język programowania zaprezentowany latem 2014 r. (prace od 2010 r.)

Informatyka I. Klasy i obiekty. Podstawy programowania obiektowego. dr inż. Andrzej Czerepicki. Politechnika Warszawska Wydział Transportu 2018

Laboratorium 03: Podstawowe konstrukcje w języku Java [2h]

Podstawy języka C++ Maciej Trzebiński. Instytut Fizyki Jądrowej Polskiej Akademii Nauk. Praktyki studenckie na LHC IVedycja,2016r.

Bash - wprowadzenie. Bash - wprowadzenie 1/39

Po uruchomieniu programu nasza litera zostanie wyświetlona na ekranie

Programowanie. Lista zadań nr 15. Na ćwiczenia 11, 19 i 23 czerwca 2008

Przyszłość programowania Języki funkcyjne na przykładzie Clojure

Podstawy Programowania ELEMENTY PROGRAMU i TYPY DANYCH

Wydział Zarządzania AGH. Katedra Informatyki Stosowanej. Podstawy VBA cz. 2. Programowanie komputerowe

Wstęp do Programowania potok funkcyjny

Programowanie Komputerów

JAVAScript w dokumentach HTML (1)

Algorytmika i Programowanie VBA 1 - podstawy

MATERIAŁY DO ZAJĘĆ II

Programowanie. programowania. Klasa 3 Lekcja 9 PASCAL & C++

Podstawy Programowania Podstawowa składnia języka C++

Podstawy programowania skrót z wykładów:

Podstawy programowania. Wykład Funkcje. Krzysztof Banaś Podstawy programowania 1

KLASA UCZEN Uczen imię, nazwisko, średnia konstruktor konstruktor Ustaw Wyswietl Lepszy Promowany

Język ludzki kod maszynowy

Podstawy języka C++ Maciej Trzebiński. Praktyki studenckie na LHC IFJ PAN. Instytut Fizyki Jądrowej Polskiej Akademii Nauk. M. Trzebiński C++ 1/16

KLASA UCZEN Uczen imię, nazwisko, średnia konstruktor konstruktor Ustaw Wyswietl Lepszy Promowany

Programowanie w języku Python. Grażyna Koba

Tablice (jedno i wielowymiarowe), łańcuchy znaków

Wiadomości wstępne Środowisko programistyczne Najważniejsze różnice C/C++ vs Java

Informacja o języku. Osadzanie skryptów. Instrukcje, komentarze, zmienne, typy, stałe. Operatory. Struktury kontrolne. Tablice.

Java Podstawy. Michał Bereta

Język programowania zbiór reguł określających, które ciągi symboli tworzą program komputerowy oraz jakie obliczenia opisuje ten program.

Microsoft IT Academy kurs programowania

Haskell Moduły Ładowanie

#include <stdio.h> int main( ) { int x = 10; long y = 20; double s; s = x + y; printf ( %s obliczen %d + %ld = %f, Wynik, x, y, s ); }

Informatyka I. Typy danych. Operacje arytmetyczne. Konwersje typów. Zmienne. Wczytywanie danych z klawiatury. dr hab. inż. Andrzej Czerepicki

Część 4 życie programu

2 Przygotował: mgr inż. Maciej Lasota

Składnia funkcji i Rekurencja w języku Haskell

Semantyka i Weryfikacja Programów - Laboratorium 3

Zatem w jaki sposób nasze programy mają komunikować się ze światem zewnętrznym?

Informatyka- wykład. Podstawy programowania w Pythonie. dr Marcin Ziółkowski

Podstawy algorytmiki i programowania - wykład 4 C-struktury

SWIFT. Zaawansowane Programowanie Obiektowe

Podstawy programowania

Wstęp do programowania

Haskell. Rozdział Ogólne informacje o języku

Pascal typy danych. Typy pascalowe. Zmienna i typ. Podział typów danych:

Wstęp do programowania

Wstęp do programowania

Interpreter - EasyCompile

Wstęp do Programowania, laboratorium 02

Dr Michał Tanaś(

3. Instrukcje warunkowe

Powtórka algorytmów. Wprowadzenie do języka Java.

Typ użyty w deklaracji zmiennej decyduje o rodzaju informacji, a nazwa zmiennej symbolicznie opisuje wartość.

Obiektowy Caml. Paweł Boguszewski

Języki formalne i automaty Ćwiczenia 6

Temat 1: Podstawowe pojęcia: program, kompilacja, kod

Języki i metodyka programowania. Typy, operatory, wyrażenia. Wejście i wyjście.

Podstawy i języki programowania

Imię i Nazwisko Data Ocena. Laboratorium 7

Swift (pol. jerzyk) nowy język programowania zaprezentowany latem 2014 r. (prace od 2010 r.)

Wykład 2 Składnia języka C# (cz. 1)

JAVAScript w dokumentach HTML (1) JavaScript jest to interpretowany, zorientowany obiektowo, skryptowy język programowania.

dr inż. Jarosław Forenc

Wykład 11a. Składnia języka Klasycznego Rachunku Predykatów. Języki pierwszego rzędu.

Wstęp do programowania. Różne różności

Transkrypt:

Programowanie funkcyjne (Haskell Wprowadzenie) Kowalik Adrian

Programowanie funkcyjne Krótka geneza języka Haskell Polecenia i składnia języka Funkcje i wyrażenia Typy i typy klasowe Listy i krotki

Programowanie Funkcyjne Odmiana programowania deklaratywnego, Program tworzy prosta bądź złożona funkcja (w sensie matematycznym), Wykonanie programu polega na obliczaniu wartości funkcji matematycznych, W czystym programowaniu funkcyjnym, raz zdefiniowana funkcja dla tych samych danych wejściowych zawsze zwróci ten sam wynik, Przykład: Fun_kolo r = 2*3.14*r

Podstawą do programowania funkcyjnego był opracowany przez Alonzo Church a Rachunek Lambda z Typami (lata 30-te XX wieku), Pierwszy język funkcyjny: Information Processing Language (IPL) (połowa lat 50-tych), Lisp (1958), Scheme (połowa lat 70-tych) ML (1973), Miranda (początek lat 80-tych), Haskell (początek lat 90-tych). F # (Microsoft) jeden z najnowszych języków funkcyjnych.

Mieszany język funkcyjny, Lisp Jako pierwszy przypominał dzisiejsze języki programowania, Najpopularniejsze dialekty : Common Lisp, Scheme i Clojure. (print "Hello world") (defun factorial (n) (if (<= n 1) 1 (* n (factorial (- n 1)))))

Scheme Powstał z Lisp u miał za zadanie go uprościć Minimalistyczny język (define hello-world (lambda () (begin (write Hello-World) (newline) (hello-world)))) (define fib (lambda (n) (cond ((= n 0) 0) ((= n 1) 1) (else (+ (fib (- n 1)) (fib (- n 2)))))))

ML (Meta Language) Rodzina języków o silnym statycznym typowaniu Jako jeden z pierwszych udostępniał typy polimorficzne print "Hello world!\n"; fun ins (n, [ ]) = [n] ins (n, ns as h::t) = if (n<h) then n::ns else h::(ins (n, t)) val insertionsort = List.foldr ins [ ]

Ocaml Wielo-paradagmatowy język programowania Wspiera dobrze programowanie funkcyjne obiektowe jak i programowanie imperatywne. print_string "Hello, world!\n";; (* komentarz *) let rec fib n = if n < 2 then n else fib (n-1) + fib (n-2) ;;

Miranda Pierwszy czysto funkcyjny język programowania Podobny do Haskella fib 0 = 1 fib 1 = 1 fib (n+2) = flist!(n+1) + flist!n where flist = map fib [ 0.. ] 7 Porównanie wielu języków http://hyperpolyglot.org/

Lambda Expressions Nawet języki obiektowe takie jak C# czy Java wykorzystują wstawki programowania funkcyjnego tzw. wyrażenia lambda których celem jest wsparcie programowania wielordzeniowego oraz domknięć.

Haskell Język nazwany na cześć Haskella Curry ego Początkowo intensywnie rozwijany wokół ośrodka University of Glasgow (1998r). Najbardziej popularna dystrybucja : GHC (Glasgow Haskell Compiler). GHC (kompilator) + GHCi (interpreter) Haskell Platform - http://hackage.haskell.org/platform/

Haskell cd. nowoczesny język czysto funkcyjny ogólnego przeznaczenia stworzony po to, aby połączyć wszystkie atuty programowania funkcyjnego w jednym eleganckim, silnym i ogólnie dostępnym języku programowania. Czysto funkcyjny nie występują zmienne ani efekty uboczne: Zmiana zmiennej Wyświetlanie na ekranie Zapis do pliku.

Leniwe wartościowanie wyznacza wartości argumentów funkcji co najwyżej raz i tylko wtedy, kiedy są potrzebne brak wykonywania niepotrzebnych obliczeń wydajność większa

przykład ax 2 + bx + c = 0 pierw(a, b, c) = if d<0 then putstrln pierwiastki urojone else (r1,r2) where r1 = e - sqrt d/ (2 * a) r2 = e + sqrt d/ (2 * a) d = b * b 4 * a * c e = - b / (2 * a)

przykład 2 Funkcje : cycle, repeat, listy nieskończone. Funkcja take wykorzystuje leniwe wartościowanie

Silne typowanie Niemożliwa niejawna konwersja brak błędów automatyczne rozpoznawanie typów

Sesja Haskell pozwala nam na interaktywną prace z poziomu linii poleceń interpretera. Język nie ogranicza nam wielkości liczb jedynie może być ograniczenie sprzętowe.

Plik zapisany w odpowiedniej składni zrozumiałej dla Haskella, zwany jest skryptem. Typowy skrypt zapisuje się w pliku z rozszerzeniem.hs. Przykład: fun1 :: Integer -> Integer fun1 x = x * (x 1) fun2 :: Integer -> Bool fun2 y = if (x>0) Then True else False Definicja składa się z dwóch części: Opisu typu funkcji - funkcja bierze jako argument liczbę całkowitą i zwraca również liczbę całkowitą (opis typu można pominąć, jeśli nie prowadzi to do niejednoznaczności). Sposobu wyliczenia wartości funkcji W wielu sytuacjach składnia Haskella pozwala obejść się bez znaków takich jak średniki czy przecinki - ich rolę spełnia odpowiedni układ tekstu.

Operatory Operatory działające na liczbach oraz operatory listowe

Kolejność wykonania operatorów jest określona przez priorytet operatora Dodatkowa właściwość "fixity" decyduje czy operator wiąże w lewo ("left-associative"), w prawo ("right-associative") czy równorzędnie w obu kierunkach ("non-associative"). Użycie Funkcji ma najwyższy priorytet.

Priorytety operatorów Left-associative Non-associative Right-associative 9!!. 8 ^, ^^, ** 7 *, /, `div`,`mod`, `rem`, `quot` 6 +, - 5 :, ++ 4 ==, /=, <, <=, >, >=, `elem`, `notelem` 3 && 2 1 >>, >>= 0 $, $!, `seq`

Definiowanie operatorów Haskell umożliwia tworzenie własnych operatorów oraz określanie sposobu w jaki mają się zachowywać. Sposób definiowania i używania operatorów dwuargumentowych opiera się na sygnaturze: a -> a -> a gdzie a jest pewnym typem, polimorficznym lub zwykłym. Przykład: Integer -> Integer -> Integer Num a => a -> a -> a

Obowiązuje następująca konwencja notacyjna: Jeśli nazwa funkcji jest zwykła (tzn. składa się z liter, cyfr i ewentualnie znaków podkreślenia), to funkcji tej można używać w zwykły sposób, np. div 7 4 a po ujęciu jej nazwy w odwrócone apostrofy - w notacji infiksowej, np. 7 `div` 4 Jeśli nazwa funkcji składa się z symboli, to w definicji należy ująć ją w nawiasy okrągłe np. (+). Wówczas funkcji (+) używa się w notacji infiksowej, np. 7 + 4 a po ujęciu w nawiasy - w zwykłej, np. (+)7 4

Podobnie jak z operatorami od zastosowanej notacji zależy tez wynik, np.: Prelude> 3 `add` 4 * 2 11 Zastosowanie add jako funkcji da jednak inny wynik: Prelude> add 3 4 * 2 14! Użycie funkcji zawsze ma najwyższy priorytet.

Funkcje wyższego rzędu Funkcje to podstawa Haskella. Funkcje wyższego rzędu przyjmują jako argumenty inne funkcje bądź zwracają inną funkcje. np. map funkcja [lista]

Składanie Funkcji Typy składanych funkcji muszą się odpowiednio zgadzać, tzn. żeby można było złożyć g.f, wynik f musi być zgodny z typem argumentu funkcji g. Złożenia funkcji możemy dokonać za pomocą operatora kropki (. ) W wielu przypadkach nie ma potrzeby jawnego zapisywania składania funkcji, mimo że w języku funkcyjnym to przecież fundamentalna operacja

Składanie Funkcji iter :: (Integer, Integer -> Integer) -> (Integer -> Integer) iter (0, f) x = x iter (n, f) x = f (iter (n - 1, f) x) iter :: (Integer, Integer -> Integer) -> (Integer -> Integer) iter (0, f) = id iter (n, f) = f. iter (n - 1, f)

Where ObliczBmi :: (RealFloat a) => a -> a -> String ObliczBmi wzrost waga wzrost / waga ^ 2 <= 18.5 = " niedowaga!" wzrost / waga ^ 2 <= 25.0 = " OK!" wzrost / waga ^ 2 <= 30.0 = " nadwaga!" otherwise = brak skali!"

ObliczBmi :: (RealFloat a) => a -> a -> String ObliczBmi wzrost waga bmi <= 18.5 = " niedowaga!" bmi <= 25.0 = " OK!" bmi <= 30.0 = " nadwaga!" otherwise = "brak skali! " where bmi = wzrost / waga ^ 2

Guard - strażnicy Odpowiednik instrukcji if else liczba a a>0 = "dodatnia" a==0 = "zero" a<0 = "ujemna duzaczymala c c >= 'a' && c <= 'z' = "Mała" c >= 'A' && c <= 'Z' = "Duża" otherwise = "to nie litera!"

Typy danych Haskell jest językiem silnie typowanym. Podstawowe typy języka Haskell, to: Int - liczby całkowite z ograniczonego zakresu [-2^29.. 2^29-1], Integer - liczby całkowite o dowolnej precyzji, Float - liczby zmiennoprzecinkowe o pojedynczej precyzji, Double - liczby zmiennoprzecinkowe o podwójnej precyzji, Char - typ znakowy (Unicode), Bool - zmienne logiczne.!! Typ każdego wyrażenia w języku Haskell możemy sprawdzić używając komendy :t lub :type.

Typy polimorficzne Sztywne przyporządkowanie typów funkcjom jest często nadmiernym ograniczeniem. Rozważmy przykład funkcji podnoszącej liczbę x do kwadratu: kw :: Integer -> Integer kw x = x * x Jest oczywiste, że chcielibyśmy od tej funkcji aby była polimorficzna (tj. dla każdego typu liczbowego wyglądała tak samo). Można to zrobić używając następującej definicji. kw :: Num a => a -> a kw x = x * x Polimorficzna może być nawet stała: sto :: Num a => a sto = 100 Są funkcje, gdzie ograniczanie zakresu zmiennej typowej w ogóle nie jest potrzebne, gdyż mogą działać dla dowolnego typu. Taka jest np. z funkcją iter zdefiniowaną już wcześniej: iter :: (Integer, a -> a) -> (a -> a) iter (0, f) = id iter (n, f) = f. iter (n - 1, f)

Klasy typów Operując typami polimorficznymi, często potrzebujemy zawęzić klasę typów, które dopuszczamy w danym kontekście. Przy definicji funkcji np. kw, podnoszącą liczbę do kwadratu, korzystaliśmy z definicji polimorficznej, w której typ argumentu i wyniku musiał pochodzić z klasy Num. Sygnatura: kw :: Num a => a -> a dopuszcza w miejscu a dowolny typ liczbowy (tzn. z klasy Num), ale musi to być ten sam typ po obydwu stronach - nie może być np. sytuacji: Float -> Integer Predefiniowane klasy typów do wykorzystania, to: Num - klasa typów liczbowych, Eq - klasa typów, dla których zdefiniowane jest porównywanie (operatory == i /=), Show - klasa typów, których wartości można wypisywać na ekranie, Enum - klasa typów wyliczeniowych (dla których muszą istnieć m.in. operacje brania poprzednika i następnika).

Klasa Num zdefiniowana w standardowej bibliotece Prelude ma postać: class (Eq a, Show a) => Num a where (+), (-), (*) :: a -> a -> a negate :: a -> a abs, signum :: a -> a frominteger :: Integer -> a Definicja ta mówi, że typy z klasy Num muszą spełniać założenia klas Eq i Show (w świetle języka programowania obiektowego powiedzielibyśmy, że Num jest podklasą klas Eq i Show) oraz muszą posiadać wymienione tu operacje. Konkretne instancje typów wprowadza się teraz za pomocą słowa kluczowego instance. Przykład poniżej pokazuje deklarację, która zgłasza typ Int jako instancję klasy Eq, w której do porównania służy wbudowana funkcja primeqint: instance Eq Int where (==) = primeqint

Klasy typów oraz ich wybrane operatory i funkcje

Listy Homogeniczne struktury danych. Lista pozwala na przechowywanie dowolnej liczby elementów tego samego typu. Listy są otoczone nawiasami kwadratowymi, a ich elementy oddzielone przecinkami. Przykład: Prelude> let imiona = [ Zosia, Kasia, Małgosia ] Prelude> let liczby = [3,4,5] Prelude> 2 : liczby [2,3,4,5] Prelude> 0 : 1 : 2 : liczby [0,1,2,3,4,5]

Język Haskell oferuje wiele funkcji operujących na listach. Dwie chyba najważniejsze z nich to head i tail, zwracające odpowiednio głowę (pierwszy element) i ogon listy (to co zostanie po usunięciu głowy). Prelude> head [1,2,3,4] 1 Prelude> tail [1,2,3,4] [2,3,4]

Łączenie i odwracanie list Do łączenia (konkatenacji) list służy operator ++, np. [0, 1] ++ [2, 3, 4] daje [0, 1, 2, 3, 4], [ a, b ] ++ [] ++ [ c ] daje [ a, b, c ] - co interpreter zapewne wyświetli jako abc, ab ++ ++ c Łączone listy muszą być oczywiście tego samego typu. Z kolei definicja prostej funkcji służącej do odwracania dowolnej listy mogłaby mieć postać: odwroc :: [a] -> [a] odwroc [] = [] odwroc (x:xs) = odwroc xs ++ [x]

Aplikacja zbiorowa do list Bardzo przydatną rzeczą jest operator map, który otrzymawszy funkcję i listę argumentów, aplikuje tą funkcję do poszczególnych elementów listy. Jest on zdefiniowany w następujący sposób: map :: (a -> b) -> [a] -> [b] map f [] = [] map f (x:xs) = f x : map f xs Przykładowo, możemy napisać: map (+1) [0, 1, 2] - w wyniku otrzymujemy listę: [1, 2, 3]

Filtrowanie Wybranie z listy tylko tych elementów, które spełniają podane kryterium, i zwrócenie ich jako nowej listy. Do filtrowania służy standardowa funkcja filter i jest ona zdefiniowana w następujący sposób: filter :: (a -> Bool) -> [a] -> [a] filter p [ ] = [ ] filter p (x:xs) = if p x then x : filter p xs else filter p xs Przykładowo: filter (>0) [ 1, 0, 1, 2] - w wyniku otrzymujemy listę: [1, 2] filter even [3, 4, 1, 6, 7, 9, 0] - w wyniku otrzymujemy listę: [4, 6, 0

Tworzenie list z użyciem kwantyfikatorów [ wyrażenie kwalifikator ] Kwalifikator może być generatorem lub strażnikiem (czyli warunkiem). Całość opisuje listę w podobny sposób, jak często opisuje się zbiory w matematyce, np. {x^2 x in {0, 1,, 99}, x-parzyste} w Haskellu zapisać możemy: [x*x x <- [0..99], even x] Generator ma postać x <- y, gdzie x jest zmienną lub n-tką zmiennych, a y jest wyrażeniem listowym. Dozór to po prostu wyrażenie logiczne. Przykłady kilku wyrażeń z kwalifikatorami: [(x, y) x <- [1..4], y <- [1..5]] [(x, y) x <- [1..4], y <- [1..5 x]] Zauważmy, że operację filtrowania moglibyśmy teraz zdefiniować również w następujący sposób: filter p l = [ x x <- l, p x ]

Listy nieskończone Jeżeli ostatni element listy nie zostanie podany, Haskell utworzy listę o "nieskończonej" długości. Jest to możliwe dzięki leniwemu wartościowaniu. Wyznaczony zostanie tylko ten element listy, który będzie w danej chwili potrzebny. Prelude>[1,2..]

Krotki (Tuples) Krotki to heterogeniczne struktury danych. Są wykorzystywane wtedy, kiedy wiadomo dokładnie ile elementów i jakiego typu chcemy przechować. Zmienne wewnątrz jednej krotki nie muszą (w przeciwieństwie do list) być tego samego typu. Krotkę zapisujemy podobnie jak listę, jednak zamiast nawiasów kwadratowych używamy nawiasów okrągłych. Prelude> ( Michał,17) Prelude> ( Jan, Kowalski,1980, Częstochowa, False) Krotki mają ściśle określoną liczbę elementów. Nie możliwe jest więc dołączenie czegokolwiek do krotki. Krotki zawierające dwa elementy są nazywane parami.

Podobnie jak listy, krotki można łączyć w struktury wielowymiarowe. Prelude> (("Jan","Kowalski",35),("Opel","Tigra",1999), 10, 1, 2008) Jest możliwość również takiego połączenia: Prelude> ( "Jaś","Kowalski",[4,4,5],[],[3,2,4],[5,5,5,4],[3,3,2],[2])

Dziękuje za uwagę.