Tematyka:
sum2c :: Int -> Int -> Int sum2c m n = m + n
to co się tutaj tak naprawdę dzieje to:
sum2c :: Int -> (Int -> Int)
czyli funkcja sum2c
przyjmuje argument typu Int
i zwraca funkcję, której typem jest Int -> Int
dodaj1 :: Int -> Int dodaj1 = sum2c 1
dodaj1 jest funkcją zwróconą przez sum2c 1
, czyli funkcją dodającą 1 do swojego argumentu
Takie częściowe określenie argumentów funkcji nazywa się Partial_application
map
, którą implementowaliśmy na pierwszych zajęciach? Jaki jest jej typ? ghci> :t map map :: (a -> b) -> [a] -> [b]
dodajmy do tego brakujący nawias, aby nie było wątpliwości co tutaj się dzieje:
map :: (a -> b) -> ([a] -> [b])
czyli: map przyjmuje jako swój argument funkcję o typie a -> b
i zwraca funkcję o typie [a] -> [b]
, czyli jak najbardziej możemy wywołać:
map dodaj1 [1..10]
nie musisz nawet tworzyć osobnej funkcji dodaj1
! map może przyjąć to co jest zwrócone przez sum2c 1
:
map (sum2c 1) [1..10]
możesz nawet pójść o krok dalej i stworzyć funkcję, która dodaje 1 do wszystkich elementów listy!
dodaj1doListy :: [Int] -> [Int] dodaj1doListy = map dodaj1
.
(kropka). Poniższy kod robi dokładnie to samo (ale w jednej iteracji po liście):map ((* 2) . dodaj1) [1..10]
.
za pomocą: :t (.)
czy rozumiesz ten typ?
map
– wywołuje funkcję podaną jako argument na każdym z elementów; tę funkcję już znaszfilter
– sprawdza czy każdy z elementów spełnia zadany warunek (czy funkcja podana jako argument zwróciła True), np. możemy wybrać z listy wszystkie elementy mniejsze od 5:filter (<5) [1..10]
fold
– przechodzi po wszystkich elementach, wykonując zadaną operację, a wynik zapisując do akumulatora; tak naprawdę jest to cała rodzina funkcji różniących się sposobem przechodzenia po liście – dwie podstawowe to foldl i foldr, przechodzące po liście odpowiednio od lewej i od prawej strony, np. możemy zsumować wszystkie elementy listy: foldl (+) 0 [1..10]
gdzie (+) jest funkcją, a 0 jest akumulatorem, do którego będą dodawane kolejne elementy listy → ładne wyjaśnienie graficzne działania fold można znaleźć na stronie
\
oraz wykorzystujemy operator ->
-- nazwana funkcja: f x = x + 1 -- dokładnie ta sama funkcjonalność zapisana jako funkcja anonimowa: f = \x -> x+1
sum2lambda = \x y -> x + y
$
, który ma bardzo niski priorytet + co najważniejsze: jest łączony z prawej strony, a nie z lewej jak spacja. Co nam to daje? Porównaj dwa wywołania:[f x | x <- lista, p x]
Zdefiniuj własną funkcję wykorzystującą wybrane z funkcji: map, fold, filter, aby otrzymać dokładnie taki sam efekt. Aby to przetestować możesz skorzystać z poniższego kodu – funkcje mojeLiczby
i mojeLiczby'
powinny zwracać w efekcie dokładnie tę samą listę!
mojeLiczby = [f x | x <- lista, p x] where f = \a -> 2 * a -- f mnoży liczbę razy 2 lista = [1..10] -- lista początkowa p = \b -> b `mod` 2 == 0 -- p wybiera liczby parzyste mojeLiczby' = -- TUTAJ WPISZ SWOJĄ FUNKCJĘ! where f = \a -> 2 * a lista = [1..10] p = \b -> b `mod` 2 == 0
generatorOperator
.generatorOperator :: (lewa -> prawa -> wynik) -> lewa -> (prawa -> wynik) -- funkcja przyjmuje operator, który jest typu (lewa -> prawa -> wynik) -- oraz lewą część operatora i zwraca funkcję, która przyjmuje prawą część operatora i zwraca wynik
ghci> dodaj3 = generatorOperator (+) 3 ghci> dodaj3 2 5 ghci> podziel100 = generatorOperator (/) 100 ghci> podziel100 8 12.5
fold
zdefiniuj funkcję odwracającą String.ghci> myReverse "Kocham Haskella" "alleksaH mahcoK" ghci> myReverse "kobyla ma maly bok" "kob ylam am alybok"
policzISumuj
, która przyjmuje trzy argumenty: funkcję, którą ma zaaplikować do każdego z elementów listy oraz pierwszy i ostatni element zakresu dla którego ma zostać zastosowana. W wyniku funkcja zwraca sumę wyników zaaplikowania funkcji do każdego z elementów.ghci>policzISumuj (^2) 1 10 385 ghci> policzISumuj (\x -> 42) 123 127 210
filter
oraz lambdy, stwórz funkcję wybierającą z zadanej listy liczby pierwsze.ghci> pierwsze [100..110] [101,103,107,109] ghci> take 15 $ pierwsze [1..] [2,3,5,7,11,13,17,19,23,29,31,37,41,43]
conajmniejn
z poprzedniego laboratorium, ale tym razem jako jedną funkcję bez wykorzystania funkcji pomocniczych (dodatkowe utrudnienie dla zainteresowanych: zrób to bez korzystania z funkcji nub
). Dla przypomnienia:ghci> conajmniejn2 [4,5,2,5,4,3,1,3,4] 2 [5,3,4] ghci> conajmniejn2 [4,5,2,5,4,3,1,3,4] 4 []