Paradygmaty programowania/Ćwiczenia 12: Programowanie funkcyjne w Haskellu III: Różnice pomiędzy wersjami

Z Studia Informatyczne
Przejdź do nawigacjiPrzejdź do wyszukiwania
Pitab (dyskusja | edycje)
Wkm (dyskusja | edycje)
 
(Nie pokazano 7 wersji utworzonych przez 2 użytkowników)
Linia 4: Linia 4:
<div class="mw-collapsible mw-made=collapsible mw-collapsed">'''Wskazówka:''' <div class="mw-collapsible-content" style="display:none"> Można użyć dopasowywania do wzorca lub odpowiedniej kaskady wyrażeń warunkowych.
<div class="mw-collapsible mw-made=collapsible mw-collapsed">'''Wskazówka:''' <div class="mw-collapsible-content" style="display:none"> Można użyć dopasowywania do wzorca lub odpowiedniej kaskady wyrażeń warunkowych.


   ''nibyalt :: Integer -> Integer -> Integer
   nibyalt :: Integer -> Integer -> Integer
   nibyalt 0 y = y
   nibyalt 0 y = y
   nibyalt x y = 1''
   nibyalt x y = 1


Zauważmy, że powyższa definicja jest prosta, ale ma dwa drobne mankamenty: wykorzystuje konkretną kolejność dopasowywania (od góry do dołu) oraz zwraca wartość różną od 1, jeśli x = 0 i y ≠ 1. Definicja z kaskadą wyrażeń warunkowych jest za to obszerniejsza:
Zauważmy, że powyższa definicja jest prosta, ale ma dwa drobne mankamenty: wykorzystuje konkretną kolejność dopasowywania (od góry do dołu) oraz zwraca wartość różną od 1, jeśli x = 0 i y ≠ 1. Definicja z kaskadą wyrażeń warunkowych jest za to obszerniejsza:


   ''nibyalt :: Integer -> Integer -> Integer
   nibyalt :: Integer -> Integer -> Integer
   nibyalt x y = if x /= 0 then 1 else if y /= 0 then 1 else 0''
   nibyalt x y = if x /= 0 then 1 else if y /= 0 then 1 else 0


</div></div>
</div></div>
===Zadanie 2===
===Zadanie 2===
Zapisać za pomocą wyrażeń z kwalifikatorem listę trójek pitagorejskich (czyli liczb naturalnych <math>x, y</math>, z takich, że <math>x^2 + y^2 = z^2</math>) z ustalonego zakresu. Chodzi zatem o funkcję o sygnaturze:
Zapisać za pomocą wyrażeń z kwalifikatorem listę trójek pitagorejskich (czyli liczb naturalnych <math>x, y, z</math> takich, że <math>x^2 + y^2 = z^2</math>) z ustalonego zakresu. Chodzi zatem o funkcję o sygnaturze:


   ''trójkipit :: Integer -> [(Integer, Integer, Integer)]''
   trójkipit :: Integer -> [(Integer, Integer, Integer)]


Dla danego <math>n </math> powinna ona stworzyć listę wszystkich trójek pitagorejskich, których elementy należą do przedziału <math>[1...n]</math>.
Dla danego ''n'' powinna ona stworzyć listę wszystkich trójek pitagorejskich, których elementy należą do przedziału [1...''n''].


<div class="mw-collapsible mw-made=collapsible mw-collapsed">'''Wskazówka:''' <div class="mw-collapsible-content" style="display:none"> Najprościej jest stworzyć najpierw funkcję, która wygeneruje listę trójek z podanego zakresu, a potem odfiltrować z nich tylko trójki pitagorejskie. A więc np.
<div class="mw-collapsible mw-made=collapsible mw-collapsed">'''Wskazówka:''' <div class="mw-collapsible-content" style="display:none"> Najprościej jest stworzyć najpierw funkcję, która wygeneruje listę trójek z podanego zakresu, a potem odfiltrować z nich tylko trójki pitagorejskie. A więc np.


   ''trójki :: Integer -> [(Integer, Integer, Integer)]
   trójki :: Integer -> [(Integer, Integer, Integer)]
   trójki n = [(x,y,z) | x<-[1..n], y<-[1..n], z<-[1..n]]
   trójki n = [(x,y,z) | x<-[1..n], y<-[1..n], z<-[1..n]]
 
 
   pit :: (Integer, Integer, Integer) -> Bool
   pit :: (Integer, Integer, Integer) -> Bool
   pit (x, y, z) = (x*x + y*y == z*z)
   pit (x, y, z) = (x*x + y*y == z*z)
 
 
   trójkipit :: Integer -> [(Integer, Integer, Integer)]
   trójkipit :: Integer -> [(Integer, Integer, Integer)]
   trójkipit = (filter pit) . trójki''
   trójkipit = (filter pit) . trójki


Oczywiście można zawrzeć cały program w jednej funkcji.
Oczywiście można zawrzeć cały program w jednej funkcji.
Linia 40: Linia 41:
<div class="mw-collapsible mw-made=collapsible mw-collapsed">'''Wskazówka:''' <div class="mw-collapsible-content" style="display:none"> Wystarczy zmienić definicję funkcji trójki tak, by generowała tylko trójki spełniające warunek x ≤ y ≤ z. Można to zrobić tak:
<div class="mw-collapsible mw-made=collapsible mw-collapsed">'''Wskazówka:''' <div class="mw-collapsible-content" style="display:none"> Wystarczy zmienić definicję funkcji trójki tak, by generowała tylko trójki spełniające warunek x ≤ y ≤ z. Można to zrobić tak:


   ''trójki :: Integer -> [(Integer, Integer, Integer)]
   trójki :: Integer -> [(Integer, Integer, Integer)]
   trójki n = [(x,y,z) | x<-[1..n], y<-[x..n], z<-[y..n]]''
   trójki n = [(x,y,z) | x<-[1..n], y<-[x..n], z<-[y..n]]


</div></div>
</div></div>
===Zadanie 4===
===Zadanie 4===
Napisać funkcję lsilnia, która dla danego <math>n \geq 1</math> wygeneruje listę silni liczb od 1 do <math>n</math>. Przykładowo, wywołanie lsilnia 4 ma dać listę [1, 2, 6, 24]. Jak zrobić to efektywnie?
Napisać funkcję lsilnia, która dla danego ''n'' ≥ 1 wygeneruje listę silni liczb od 1 do ''n''. Przykładowo, wywołanie lsilnia 4 ma dać listę [1, 2, 6, 24]. Jak zrobić to efektywnie?


<div class="mw-collapsible mw-made=collapsible mw-collapsed">'''Wskazówka:''' <div class="mw-collapsible-content" style="display:none"> Oczywiście należy unikać liczenia silnia dla każdej liczby od początku. Można więc tak jak poniżej, z tym że trzeba wówczas na końcu odwrócić wytworzoną listę.
<div class="mw-collapsible mw-made=collapsible mw-collapsed">'''Wskazówka:''' <div class="mw-collapsible-content" style="display:none"> Oczywiście należy unikać liczenia silnia dla każdej liczby od początku. Można więc tak jak poniżej, z tym że trzeba wówczas na końcu odwrócić wytworzoną listę.


   ''lsilnia :: Integer -> [Integer]
   lsilnia :: Integer -> [Integer]
   lsilnia 1 = [1]
   lsilnia 1 = [1]
   lsilnia (n+1) = ((n+1)*y) : y : ys where (y:ys) = lsilnia n''
   lsilnia (n+1) = ((n+1)*y) : y : ys where (y:ys) = lsilnia n


</div></div>
</div></div>
===Zadanie 5*===
===Zadanie 5*===
Zdefiniować operator >> za pomocą >>=.
Zdefiniować operator >> za pomocą >>=.
Linia 59: Linia 62:
<div class="mw-collapsible mw-made=collapsible mw-collapsed">'''Wskazówka:''' <div class="mw-collapsible-content" style="display:none"> Wywołania p >> q oraz p >>= q oznaczają, że wywołujemy p i q w takiej właśnie kolejności. Dla operatora >>= ta zależność czasowa bierze się stąd, że q wywoływane jest z wartością wyliczoną przez p. Chcąc zdefiniować >>, musimy oprzeć się na tej samej zależności, lecz zignorować wyliczoną przez p wartość.
<div class="mw-collapsible mw-made=collapsible mw-collapsed">'''Wskazówka:''' <div class="mw-collapsible-content" style="display:none"> Wywołania p >> q oraz p >>= q oznaczają, że wywołujemy p i q w takiej właśnie kolejności. Dla operatora >>= ta zależność czasowa bierze się stąd, że q wywoływane jest z wartością wyliczoną przez p. Chcąc zdefiniować >>, musimy oprzeć się na tej samej zależności, lecz zignorować wyliczoną przez p wartość.


   ''(>>) :: IO a -> IO b -> IO b
   (>>) :: IO a -> IO b -> IO b
   p >> q = p >>= f where f x = q''
   p >> q = p >>= f where f x = q


</div></div>
</div></div>
===Zadanie 6===
===Zadanie 6===
Co się stanie przy poniższych wywołaniach? Sprawdź...
Co się stanie przy poniższych wywołaniach? Sprawdź...


   ''getChar >>= return
   getChar >>= return
   return ’a’ >>= putChar''
   return ’a’ >>= putChar


<div class="mw-collapsible mw-made=collapsible mw-collapsed">'''Wskazówka:''' <div class="mw-collapsible-content" style="display:none"> Można powiedzieć, że return zamienia wartość typu a na IO a, zaś >>= — na odwrót.
<div class="mw-collapsible mw-made=collapsible mw-collapsed">'''Wskazówka:''' <div class="mw-collapsible-content" style="display:none"> Można powiedzieć, że return zamienia wartość typu a na IO a, zaś >>= — na odwrót.
</div></div>
</div></div>

Aktualna wersja na dzień 22:49, 23 wrz 2006

Zadanie 1

Napisać definicję leniwego operatora alternatywy na liczbach całkowitych, nie korzystając ze standardowego operatora ||.

Wskazówka:

Zadanie 2

Zapisać za pomocą wyrażeń z kwalifikatorem listę trójek pitagorejskich (czyli liczb naturalnych x,y,z takich, że x2+y2=z2) z ustalonego zakresu. Chodzi zatem o funkcję o sygnaturze:

 trójkipit :: Integer -> [(Integer, Integer, Integer)]

Dla danego n powinna ona stworzyć listę wszystkich trójek pitagorejskich, których elementy należą do przedziału [1...n].

Wskazówka:

Zadanie 3

Jak zmienić program z poprzedniego zadania, by nie wypisywał niepotrzebnie podobnych trójek, np. (3, 4, 5) i (4, 3, 5)?

Wskazówka:

Zadanie 4

Napisać funkcję lsilnia, która dla danego n ≥ 1 wygeneruje listę silni liczb od 1 do n. Przykładowo, wywołanie lsilnia 4 ma dać listę [1, 2, 6, 24]. Jak zrobić to efektywnie?

Wskazówka:

Zadanie 5*

Zdefiniować operator >> za pomocą >>=.

Wskazówka:

Zadanie 6

Co się stanie przy poniższych wywołaniach? Sprawdź...

 getChar >>= return
 return ’a’ >>= putChar
Wskazówka: