Rekurencja - Haskell Bartosz Pawlak Sebastian Żółtowski Adam Stegenda Krystian Sobótka Tomasz Gołębiewski.

Slides:



Advertisements
Podobne prezentacje
Tablice 1. Deklaracja tablicy
Advertisements

Programowanie w PMC.
Sortowanie przez scalanie
Algorytmy sortowania i przeszukiwania
Instrukcje - wprowadzenie
Język C/C++ Funkcje.
Rekurencja 1 Podprogram lub strukturę danych nazywamy rekurencyjną, (recursive subprogram, recursive data structure) jeżeli częściowo składa się z samej.
Schemat blokowy M START KONIEC
Wzorce.
Programowanie I Rekurencja.
Języki programowania C++
PROGRAMOWANIE STRUKTURALNE
formatowanie kodu źródłowego
Liczby Pierwsze - algorytmy
Turbo pascal – instrukcje warunkowe, iteracyjne,…
Materiały do zajęć z przedmiotu: Narzędzia i języki programowania Programowanie w języku PASCAL Część 7: Procedury i funkcje © Jan Kaczmarek.
Materiały do zajęć z przedmiotu: Narzędzia i języki programowania Programowanie w języku PASCAL Część 8: Wykorzystanie procedur i funkcji © Jan Kaczmarek.
Programowanie imperatywne i język C Copyright, 2004 © Jerzy R. Nawrocki Wprowadzenie.
1 Dygresja: cztery płyty główne…. 2 Dygresja: osobliwości C /* cos o nieistniejacym typie Boolean */ /* oraz o operatorze przecinkowym */ #include int.
Materiały pomocnicze do wykładu
Dr Anna Kwiatkowska Instytut Informatyki
Ułamki zwykłe i liczby mieszane.
Podstawy programowania
Algorytmy i struktury danych
Ciąg liczbowy Ciąg arytmetyczny Ciąg geometryczny
Rekurencja.
Programowanie strukturalne i obiektowe
Instrukcje sterujące część 2
© A. Jędryczkowski – 2006 r. © A. Jędryczkowski – 2006 r.
Algorytmy i struktury danych
Algorytmy i struktury danych
Złożone typy danych Listy Tworzenie elastycznych baz danych
Zastosowania ciągów.
Programowanie strukturalne i obiektowe
Łódź, 3 października 2013 r. Katedra Analizy Nieliniowej, WMiI UŁ Podstawy Programowania Programy różne w C++
Instrukcje iteracyjne
Wykład 10 typ zbiorowy rekurencja.
Algorytmika Iteracje autor: Tadeusz Lachawiec.
Programowanie strukturalne i obiektowe C++
Metody numeryczne szukanie pierwiastka metodą bisekcji
Derekursywacja i optymalizacja kodu
Temat 8: Pętle.
Rekurencja.
Krakowski Piotr, Woliński Radosław, Kowalski Piotr, Machowski Michał.
Haskell. Dopasowanie do wzorca Jest to operacja, gdzie pewnie wyrażenie sprawdza się ze wzorcem, w którym może znajdować się jedno lub więcej "wolnych.
Wybrane aspekty programowania w C++ (i nie tylko)
Rodzaje Liczb JESZCZE SA TAKIE
METODY REPREZENTOWANIA IFORMACJI
Listy Listy w Prologu mogą przechowywać dane dowolnego typu [alpha,beta,gamma,delta] [1,2,3] Sama lista również może zawierać listę: [[a,list,within],a,list]
Rozdział IV Wyrażenia proceduralne algorytmów Grzegorz Gacek Patryk Gajewski.
Pętle – instrukcje powtórzeń
Instrukcje warunkowe w php. Pętla FOR Czasem zachodzi potrzeba wykonania jakiejś czynności określoną ilość razy. Z pomocą przychodzi jedna z najczęściej.
Wstęp do programowania Wykład 1
PHP jest językiem skryptowym służącym do rozszerzania możliwości stron internetowych. Jego składnia jest bardzo podobna do popularnych języków programowania.
Programowanie I Rekurencja.
Liczby 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, …(i tak dalej) nazywamy liczbami naturalnymi. Tak jak z liter tworzy się słowa, tak z cyfr tworzymy liczby. Dowolną.
Algorytmy. Co to jest algorytm? Przepis prowadzący do rozwiązania zadania.
Algorytmy, sposoby ich zapisu.1 Algorytm to uporządkowany opis postępowania przy rozwiązywaniu problemu z uwzględnieniem opisu danych oraz opisu kolejnych.
Liczby naturalne i całkowite Spis treści Definicje Działania na liczbach Wielokrotności liczb naturalnych Cechy podzielności Przykłady potęg,potęgi o.
Liczbami naturalnymi nazywamy liczby 0,1,2,3,..., 127,... Liczby naturalne poznaliśmy już wcześniej; służą one do liczenia przedmiotów. Zbiór liczb.
C++ mgr inż. Tomasz Turba Politechnika Opolska 2016.
Sposoby zapisu algorytmu
Rozdział 5 REKURENCJA.
Listy.
DEFINICJA I ZASTOSOWANIE W JĘZYKU HASKELL
Liczby pierwsze: szukanie, rozmieszczenie, zastosowanie, ciekawostki. Liczby pierwsze: szukanie, rozmieszczenie, zastosowanie, ciekawostki. Kinga Cichoń.
Programowanie I Rekurencja.
Rekurencja Ponieważ w Haskellu nie mamy klasycznych pętli for czy while dlatego w wielu algorytmach musimy używać rekurencji.
Implementacja rekurencji w języku Haskell
Haskell Składnia funkcji.
Zapis prezentacji:

Rekurencja - Haskell Bartosz Pawlak Sebastian Żółtowski Adam Stegenda Krystian Sobótka Tomasz Gołębiewski

Haskell – czysto funkcyjny język programowania Języki czysto funkcyjne: Wynik działania funkcji jest uzależniony od przekazywanych jej argumentów i tylko od nich Nie ma efektów ubocznych1 Programy funkcyjne nie zawierają przypisań, więc wartości zmiennych raz ustalone, nigdy nie mogą zostać zmienione. 1.Efekt Uboczny -  dowolny efekt wyrażenia, lub wywołania funkcji, który wykracza poza zwrócenie wartości np. wyrażenie 2 + 3 nie ma skutków ubocznych, wyrażenie a = 2 + 3 ma oczywisty skutek uboczny na zmiennej a.

Haskell – czysto funkcyjny język programowania

Co to jest rekurencja? Rekurencja zwana również rekursją, polega na wywołaniu przez funkcję samej siebie. Algorytmy rekurencyjne zastępują w pewnym sensie iteracje. Zazwyczaj zadania rozwiązywane tą techniką są wolniejsze od iteracyjnego odpowiednika, natomiast rozwiązanie niektórych problemów jest znacznie wygodniejsze. Najpopularniejsze przykłady zastosowania: ciąg Fibonacciego silnia NWD za pomocą algorytmu Euklidesa

Rekurencja - Haskell Chyba każdy program (poza "Hello world") napisany w języku imperatywnym wykorzystuje jakiegoś rodzaju pętle. Działanie pętli kończy się, gdy zostanie spełniony (lub nie spełniony) pewien warunek. Wiąże się to ze zmianą wartości zmiennej będącej licznikiem pętli. Jak wiadomo, zmiana wartości zmiennej w Haskellu nie jest możliwa, a więc zastosowanie pętli staje się również niemożliwe. Wszystkie zadania, które w językach imperatywnych są wykonywane w pętli, w Haskellu można zrealizować wykorzystując rekurencję. W językach imperatywnych rekurencja jest stosowana rzadko, między innymi ze względu na słabą wydajność. Kompilatory języków funkcyjnych posiadają bardzo dobre mechanizmy optymalizacji dla rekurencji Język imperatywny - język w którym program jest pojmowany jako ciąg wykonywanych po sobie instrukcji. Przykładami języków imperatywnych są Pascal i C.

Rekurencja - Haskell W Haskellu rekurencja odgrywa bardzo ważną rolę, gdyż w przeciwieństwie do języków imperatywnych (np. Java czy Python) w Haskellu wykonujemy obliczenia deklarując co chcemy uzyskać a nie jak to chcemy uzyskać. Z tego powodu język ten nie posiada pętli for i while a żeby otrzymać wynik często musimy użyć właśnie rekursji.

Silnia Jak wiemy silnią liczby naturalnej n nazywamy iloczyn wszystkich dodatnich liczb naturalnych nie większych niż n. Symbolicznie oznaczamy za pomocą wykrzyknika n! i czytamy n silnia. Na przykład silnia z liczby 5 to 5 * 4 * 3 * 2 * 1 = 120. Składnia silni w Haskellu: silnia 0 = 1 silnia n = n * silnia (n-1)

Silnia Bez warunku końca (silnia 0 = 1) otrzymamy błąd (Exception: stack overflow) co oznacza przepełnienie stosu. Jest to spowodowane tym, że program nie wie kiedy ma skończyć funkcję i bierze pod uwagę także liczby ujemne.

Silnia Silnia z użyciem Guards

Rekurencyjne mnożenie dwóch liczb Z pewnością każdy programista, zarówno piszący w językach imperatywnych jak i funkcyjnych, aby pomnożyć dwie liczby a i b napisze po prostu a * b. Mnożenie można jednak zapisać w sposób rekurencyjny. Wykorzystamy do tego definicję podawaną dzieciom w szkole podstawowej. Aby pomnożyć liczbę a razy liczbę b, weź liczbę a i dodaj do siebie b razy. Na przykład 6*4 = 6+6+6+6. Podobnie jak w poprzednim przykładzie, zapiszmy dwa przykłady mnożenia.

Rekurencyjne mnożenie dwóch liczb Tak samo jak w przypadku silni zapis ten możemy uogólnić: a * b = a + a * (b-1) Pozostaje jeszcze zdefiniowanie przypadku bazowego. Będzie to mnożenie przez liczbę 0. Dowolna liczba pomnożona przez 0 daje 0. a * 0 = 0 Funkcja pomnoz zapisana w Haskellu będzie więc wyglądać następująco:

Ciąg Fibonacciego Jest to ciąg liczb naturalnych określony rekurencyjnie w sposób następujący: Pierwszy wyraz jest równy 0, drugi jest równy 1, każdy następny jest sumą dwóch poprzednich. Ciąg Fibonacciego w Haskellu: fib :: Integer -> Integer fib 0 = 1 fib 1 = 1 fib n = fib (n-1) + fib (n-2)

Ciąg Fibonacciego Podany algorytm dla większych liczb liczy bardzo długo, poniższy algorytm rozwiązuje ten problem. fibs:: [Integer] fibs= 0 : 1 : zipWith (+) fibs(tail fibs) fib :: Int -> Integer fib n = fibs!! (n+1)

Potęgowanie rekurencyjnie Potęgę o wykładniku naturalnym również można zdefiniować rekurencyjnie: a0 = 1 an = a * an−1 , dla n ≠ 0 W jaki sposób zapisać to w Haskellu?

Maximum Funkcja maximum zwraca największy element z zadanego zbioru, dlatego też musi być zabezpieczona na wypadek gdyby zbiór był pusty, lub zawierał tylko jeden element.

Maximum Pierwszy warunek końcowy zwraca błąd jeśli nasza lista jest pusta. Maximum [] = error „Lista jest pusta” W wypadku jeśli jest to lista jednoelementowa - wynikiem będzie ten jeden element. Maximum [x] = x W trzecim warunku końcowym rozłączamy naszą listę na głowę i ogon. Używamy funkcji where w celu zdefiniowania funkcji maxTail, jako maximum reszty listy, a następnie sprawdzamy warunek (if) czy głowa jest większa od reszty listy. Jeśli tak- zwracamy głowę jako wynik. W innym wypadku zwracamy maximum reszty listy. Maximum (x: xs) | x> maxTail = x | otherwise = maxTail where maxTail = maximum xs

Maximum

Maximum Łatwiejszy zapis z użyciem funkcji max

Funkcja elem - rekurencyjnie Funkcja elem sprawdza, czy x jest elementem listy Funkcja elem rekurencyjnie

Funkcja replicate - rekurencyjnie Funkcja replicate pobiera dwa argumenty z czego pierwszy to int który mówi o tym ile razy ma zostać powtórzony drugi argument funkcji. Wynikiem działania tej funkcji jest lista powtarzających się elementów. Funkcja replicate rekurencyjnie

Funkcja take - rekurencyjnie Funkcja take jest to funkcja, która pobiera zadaną liczbę elementów z listy. Funkcja take rekurencyjnie

Funkcja reverse - rekurencyjnie Funkcja reverse jest to funkcja, która odwraca listę. Warunkiem końca jest uzyskanie pustej listy. Jeżeli podzielimy listę na head i tail, to odwrócona lista jest odpowiednikiem odwróconego tail (ogona) i head (głowy) na samym końcu.

Funkcja repeat - rekurencyjnie Funkcja repeat jest to funkcja, która zwraca nieskończoną listę, której elementem jest podany argument. W funkcji tej brakuje warunku końca, gdyż ma ona nam uświadomić, że Haskel umożliwia nam tworzenie nieskończonych struktur danych w tym przypadku nieskończonych list.

Funkcja repeat - rekurencyjnie Jednakże zastosowanie funkcji repeat dobrze sprawdza się w zestawieniu z innymi funkcjami np. w przypadku gdy chcemy stworzyć listę x-elementową która wypełniona będzie takimi samymi wartościami. (Skorzystamy wtedy z funkcji take)

Sortowanie (Quick Sort) Załóżmy, że mamy listę elementów typu Ord do posortowania. Najefektywniej można to osiągnąć za pomocą popularnego algorytmu QuickSort. O ile jednak w językach imperatywnych taki algorytm zajmować może nawet kilkanaście linijek kodu, to jego implementacja w Haskellu jest dużo krótsza i bardziej przejrzysta.

Sortowanie (Quick Sort) Zasada działania szybkiego sortowania w Haskellu: Pierwsza linijka pokazuje, że będziemy korzystać z typu Ord, który działa dla uporządkowanych danych. quicksort :: (Ord a) => [a] -> [a] W drugiej linijce mamy warunek dla pustej listy quicksort [] = [] Działanie głównej funkcji można opisać tak: Bierzemy pierwszą liczbę z listy a potem tworzymy listę liczb mniejszych bądź równych tej liczbie oraz listę liczb większych. Oczywiście obie te listy są zdefiniowane rekurencyjnie, więc wewnątrz tych list dzieje się to samo co w liście głównej. Po policzeniu obu list pozostaje nam tylko skleić obie listy oraz wstawić pomiędzy nie pierwszą liczbę głównej listy, którą pobraliśmy na początku quicksort (x:xs) = let smallerSorted = quicksort [a | a <- xs , a <= x] biggerSorted = quicksort [a | a <- xs, a > x] in smallerSorted ++ [x] ++ biggerSorted

Sortowanie (Quick Sort) Algorytm sortowania szybkiego jest uważany za najszybszy algorytm dla danych losowych. Zasada jego działania opiera się o metodę dziel i zwyciężaj. Zbiór danych zostaje podzielony na dwa podzbiory i każdy z nich jest sortowany niezależnie od drugiego.

Dziękujemy za uwagę