Paradygmaty programowania/Ćwiczenia 6: Programowanie funkcyjne — przegląd: Różnice pomiędzy wersjami

Z Studia Informatyczne
Przejdź do nawigacjiPrzejdź do wyszukiwania
Pitab (dyskusja | edycje)
Wkm (dyskusja | edycje)
 
(Nie pokazano 8 wersji utworzonych przez 2 użytkowników)
Linia 8: Linia 8:
Rozważmy następującą funkcję w ML-u:
Rozważmy następującą funkcję w ML-u:


       ''fun f(ys, 0)    = []
       fun f(ys, 0)    = []
         | f(x::ys, z) = if z < x
         | f(x::ys, z) = if z < x
             then f(ys, z)
             then f(ys, z)
             else (z mod x) :: f(x::ys, z mod x);''
             else (z mod x) :: f(x::ys, z mod x);


Jaki będzie wynik przy wywołaniu f ([9, 2, 1], 57)?
Jaki będzie wynik przy wywołaniu f ([9, 2, 1], 57)?
Linia 18: Linia 18:
Rozważmy następującą funkcję w Haskellu:
Rozważmy następującą funkcję w Haskellu:


       ''fx []      = 3
       fx []      = 3
       fx (x : y) = x + fx y''
       fx (x : y) = x + fx y


Jaki będzie wynik aplikacji fx do listy [1, 4..10]?
Jaki będzie wynik aplikacji fx do listy [1, 4..10]?


===Zadanie 5===
===Zadanie 5===
Napisać w dowolnym języku funkcyjnym funkcję obliczającą <math>x^{n}(a)</math> za pomocą algorytmu „naiwnego”, tzn. przez n – 1 mnożeń, (b) za pomocą algorytmu „bitowego”. Idea tego algorytmu jest następująca:
Napisać w dowolnym języku funkcyjnym funkcję obliczającą <math>x^{n}</math> (a) za pomocą algorytmu „naiwnego”, tzn. przez n – 1 mnożeń, (b) za pomocą algorytmu „bitowego”. Idea tego algorytmu jest następująca:


       // Algorytm oblicza <math>x^{n}</math>
       // Algorytm oblicza <math>x^{n}</math>
       // Niech <math>n_{k–1} \ldots n_{1}, n_{0}</math> oznacza reprezentację bitową liczby n
       // Niech <math>n_{k-1} \ldots n_{1} n_{0}</math> oznacza reprezentację bitową liczby n
       <math>w</math> := 1
       w := 1
       '''for''' <math>i</math> := 0 to <math>k</math> – 1 do {
       for i := 0 to k – 1 do {
         if <math>ni</math> = 1 then <math>w</math> := <math>wx</math>
         if <math>n_i</math> = 1 then w := w*x
         <math>x</math> := <math>x</math>2
         x := x*x
       }
       }
       '''return''' <math>w</math>
       return w


===Zadanie 6*===
===Zadanie 6*===
Przyjrzyj się poniższej funkcji w Haskellu, obliczającej <math>n</math>-ty wyraz ciągu Fibonacciego. Czy to jest rozsądnie napisana funkcja, czy też można to zrobić (znacznie) lepiej. Jeśli tak, zrób to. Czy odpowiedź na to pytanie zależy od tego, czy piszemy w języku funkcyjnym?
Przyjrzyj się poniższej funkcji w Haskellu, obliczającej ''n''-ty wyraz ciągu Fibonacciego. Czy to jest rozsądnie napisana funkcja, czy też można to zrobić (znacznie) lepiej. Jeśli tak, zrób to. Czy odpowiedź na to pytanie zależy od tego, czy piszemy w języku funkcyjnym?


       ''fib 0 = 0
       fib 0 = 0
       fib 1 = 1
       fib 1 = 1
       fib n = fib (n–1) + fib (n-2)''
       fib n = fib (n–1) + fib (n-2)


<div class="mw-collapsible mw-made=collapsible mw-collapsed">'''Wskazówka:''' <div class="mw-collapsible-content" style="display:none">Wyliczanie elementów ciągu Fibonacciego za pomocą takiej rekurencji to generalnie zły pomysł, prowadzący do fatalnej złożoności obliczeń — liczba operacji potrzebnych do wyliczenia n-tego wyrazu jest rzędu <math>2n</math>. Co prawda można sobie wyobrazić bardzo sprytny kompilator, który przearanżuje te obliczenia tak, by uzyskać mniejszą złożoność, ale w ogólności nie należy raczej na to liczyć... Choć trzeba przyznać, że w języku funkcyjnym kompilator jest w nieco lepszej sytuacji, gdyż nie musi się obawiać efektów ubocznych funkcji.
<div class="mw-collapsible mw-made=collapsible mw-collapsed">'''Wskazówka:''' <div class="mw-collapsible-content" style="display:none">Wyliczanie elementów ciągu Fibonacciego za pomocą takiej rekurencji to generalnie zły pomysł, prowadzący do fatalnej złożoności obliczeń — liczba operacji potrzebnych do wyliczenia n-tego wyrazu jest rzędu <math>2^n</math>. Co prawda można sobie wyobrazić bardzo sprytny kompilator, który przearanżuje te obliczenia tak, by uzyskać mniejszą złożoność, ale w ogólności nie należy raczej na to liczyć... Choć trzeba przyznać, że w języku funkcyjnym kompilator jest w nieco lepszej sytuacji, gdyż nie musi się obawiać efektów ubocznych funkcji.


W języku niefunkcyjnym lepiej zastosować prosty algorytm iteracyjny, który będzie wyliczał kolejne wyrazy ciągu korzystając z dwóch poprzednich zapisanych w zmiennych roboczych. W Haskellu trzeba zastosować strategię „łączenia w n-tki” — tutaj w pary — a z par brać pierwszy element. O łączeniu w n-tki będzie mowa w wykładzie poświęconym Haskellowi:
W języku niefunkcyjnym lepiej zastosować prosty algorytm iteracyjny, który będzie wyliczał kolejne wyrazy ciągu korzystając z dwóch poprzednich zapisanych w zmiennych roboczych. W Haskellu trzeba zastosować strategię „łączenia w ''n''-tki” — tutaj w pary — a z par brać pierwszy element. O łączeniu w ''n''-tki będzie mowa w wykładzie poświęconym Haskellowi:


       ''fibS 0    = (0, 1)
       fibS 0    = (0, 1)
       fibS (n+1) = (x, y), where (x, y) = fibS n
       fibS (n+1) = (y, x+y), where (x, y) = fibS n
       fib n      = fst (fibS n)''
       fib n      = fst (fibS n)
</div>
</div>
</div>
</div>


===Zadanie 7===
===Zadanie 7===
Napisz jak najprostszą funkcję w Haskellu odwracającą podaną listę. Ile operacji ona potrzebuje, by odwrócić listę o długości <math>n</math>?
Napisz jak najprostszą funkcję w Haskellu odwracającą podaną listę. Ile operacji ona potrzebuje, by odwrócić listę o długości ''n''?


<div class="mw-collapsible mw-made=collapsible mw-collapsed">'''Wskazówka:''' <div class="mw-collapsible-content" style="display:none"> Można tak...
<div class="mw-collapsible mw-made=collapsible mw-collapsed">'''Wskazówka:''' <div class="mw-collapsible-content" style="display:none"> Można tak...


       ''odwr []      = []
       odwr []      = []
       odwr (x : xs) = odwr xs ++ [x]''
       odwr (x : xs) = odwr xs ++ [x]
</div>
</div>
</div>
</div>


===Zadanie 8===
===Zadanie 8===
Funkcja z poprzedniego zadania zapewne potrzebuje O(<math>n^{2}</math>) operacji, by odwrócić n-elementową listę. Napisz funkcję, która potrzebuje tylko <math>O(n)</math> operacji.
Funkcja z poprzedniego zadania zapewne potrzebuje O(<math>n^{2}</math>) operacji, by odwrócić ''n''-elementową listę. Napisz funkcję, która potrzebuje tylko <math>O(n)</math> operacji.


<div class="mw-collapsible mw-made=collapsible mw-collapsed">'''Wskazówka:''' <div class="mw-collapsible-content" style="display:none"> Wskazówki szukaj w wykładzie poświęconym Haskellowi.
<div class="mw-collapsible mw-made=collapsible mw-collapsed">'''Wskazówka:''' <div class="mw-collapsible-content" style="display:none"> Wskazówki szukaj w wykładzie poświęconym Haskellowi.
</div>
</div>
</div>
</div>

Aktualna wersja na dzień 21:12, 22 wrz 2006

Zadanie 1

Napisać funkcję w Schemie, która zlicza zera w podanej liście liczb. Lista może zawierać zagnieżdżone podlisty itd. — zliczyć należy wszystkie zera.

Zadanie 2

Napisać funkcję w Schemie, która usuwa z podanej listy wszystkie niezagnieżdżone wystąpienia podanego atomu.

Zadanie 3

Rozważmy następującą funkcję w ML-u:

     fun f(ys, 0)    = []
       | f(x::ys, z) = if z < x
           then f(ys, z)
           else (z mod x) :: f(x::ys, z mod x);

Jaki będzie wynik przy wywołaniu f ([9, 2, 1], 57)?

Zadanie 4

Rozważmy następującą funkcję w Haskellu:

     fx []      = 3
     fx (x : y) = x + fx y

Jaki będzie wynik aplikacji fx do listy [1, 4..10]?

Zadanie 5

Napisać w dowolnym języku funkcyjnym funkcję obliczającą xn (a) za pomocą algorytmu „naiwnego”, tzn. przez n – 1 mnożeń, (b) za pomocą algorytmu „bitowego”. Idea tego algorytmu jest następująca:

     // Algorytm oblicza xn
     // Niech nk1n1n0 oznacza reprezentację bitową liczby n
     w := 1
     for i := 0 to k – 1 do {
       if ni = 1 then w := w*x
       x := x*x
     }
     return w

Zadanie 6*

Przyjrzyj się poniższej funkcji w Haskellu, obliczającej n-ty wyraz ciągu Fibonacciego. Czy to jest rozsądnie napisana funkcja, czy też można to zrobić (znacznie) lepiej. Jeśli tak, zrób to. Czy odpowiedź na to pytanie zależy od tego, czy piszemy w języku funkcyjnym?

     fib 0 = 0
     fib 1 = 1
     fib n = fib (n–1) + fib (n-2)
Wskazówka:

Zadanie 7

Napisz jak najprostszą funkcję w Haskellu odwracającą podaną listę. Ile operacji ona potrzebuje, by odwrócić listę o długości n?

Wskazówka:

Zadanie 8

Funkcja z poprzedniego zadania zapewne potrzebuje O(n2) operacji, by odwrócić n-elementową listę. Napisz funkcję, która potrzebuje tylko O(n) operacji.

Wskazówka: