Zasady zaliczania kursu
Zaliczenie tego kursu polega na otrzymaniu zaliczenia z laboratorium. Nie ma egzaminu końcowego.
Laboratoria
Odbędzie się jedno końcowe kolokwium. Składać się będzie z dwóch części: praktycznej i teoretycznej. Część praktyczna odbędzie się na ostatnich laboratoriach. Część teoretyczna odbędzie się na ostatnim wykładzie. Wyniki obu części testów (ocenianych w skali [0,1]) uwzględnione zostaną w ocenie końcowej - wpływać będą tylko pozytywnie na ocenę końcową. Aby otrzymać 5.5 będzie trzeba zrealizować pewien projekt w Haskall'u.
Przykładowe zadania na kolokwium praktyczne
- Napisz funkcję, która dla danych liczb naturalnych $n\geq 1$ i $k$ generuje listę wszystkich $k$ elementówych rosnących podciągów $[1,\ldots,n]$.
- Liczba $\omega(n)$ oznacza liczbę różnych dzielników pierwszych liczby $n \geq 2$. Napisz funkcję, która dla danej liczby m wyznacza średnią wartość liczb $[\omega(2), \ldots , \omega(m)]$. Funkcja ta powinna w rozsądnym czasie (kilka sekund) zwracać wartości dla każdego $m$ z zakresu od $2$ do $10000$.
- Skorzystaj z monady
Writer [String] Int
do oprogramowania funkcjimyGCD
, która oprócz obliczenia GCD zwróci ślad obliczeń.
Przykładowe zadania na kolokwium teoretyczne
- Załóżmy, że $(M,e,\star)$ jest monoidem. Niech $M^* = \{x\in M : (\exists y) (x * y = e)\}$. Pokaż, że $(M^*,e,\star)$ jest grupą. Wyznacz $(Z,1,\cdot)^*$ (to jest monoid liczb całkowitych z mnożeniem).
- Niech $R$ będzie ustalonym zbiorem. Rozszerz przyporządkowanie $C(X) = R^{R^X}$ do funktora, pokaż poprawność tej definicji oraz oprogramuj to w języku Haskell.
- Niech $V_2(X) = X\times X$ będzie funktorem pary. Niech $\eta: I \to V_2$ będzie naturalną transformacją określoną wzorem $\eta(x) = (x,x)$. Niech $\pi:V_2 \to I$ będzie naturalną transformację okresloną wzorem $\pi(x,y) = x$. Wyznacz horyzontalne złożenie $\pi\star \eta$.
Zadania z kolokwium teoretycznego
Zadanie 1
Niech $(M,e,\star)$ będzie monoidem oraz niech $X$ będzie zbiorem. Określ na zbiorze $M^X$ strukturę monoidu oraz wyznacz $(M^X)^*$ (zbiór elementów odwracalnych).
Rozwiązanie. Dla $f,g\in M^X$ określamy $(f \oplus g)(x) = f(x)\star g(x)$.
Ponadto, niech $\vec{e}:X\to M$ będzie funkcją o stałą o dziedzinie $X$ przyjmującą wartość $e$.
Dla dowolnej funkcji $f\in M^X$ oraz dowolnego $x\in X$ mamy
$$(\vec{e}\oplus f)(x) = \vec{e}(x) \star f(x) = e \star f(x) = f(x)~,$$ więc $\vec{e}\oplus f = f$.
Podobnie pokazujemy $f\oplus \vec{e} = f$. Zatem $\vec{e}$ jest elementem neutralnym w $M^X$.
Niech $f,g,h\in M^X$ oraz $x\in X$. Wtedy, korzystając z łączności $\star$ mamy
$$
((f\oplus g)\oplus h)(x) = (f\oplus g)(x) \star h(x) = (f(x)\star g(x)) \star h(x) =
$$
$$
f(x) \star (g(x) \star h(x)) = f(x)\star (g\oplus h)(x) = (f\oplus (g\oplus h))(x)~,
$$
zatem $(f\oplus g)\oplus h = f \oplus (g \oplus h)$, więc działanie $\oplus$ jest łączne.
Zadanie 2
Częściowy porządek $(\{1,2,3,\ldots\},|)$ traktujemy jako kategorię. Wyznacz produkt i ko-produkt w tej kategorii.
Rozwiązanie. Ustalmy dodatnie liczby naturalne $a$ i $b$. Niech $c = \gcd(a,b)$.
Wtedy $c|a$, więc istnieje dokładnie jedna strzałka z $c$ do $a$; oznaczmy ją przez $\pi_a$.
Podobnie mamy dokładnie jedną strzałkę $\pi_b: c\to b$.
Rozważmy teraz dowolny obiekt $x$ oraz morfizmy $f:x\to a$ i $g:x\to b$. Lecz morfizm w tej kategorii oznacza podzielność,
zatem $x|a$ i $x|b$. Lecz $c$ jest nawiększym wspolnym dzielnikiem liczb $a$ i $b$. Zatem $x|c$. Oznaczmy ten morfizm prze $\rho$.
Oczywiście $\pi_a \circ \rho = f$ i $\pi_b\circ \rho = g$. Zatem produktem jest $\gcd$.
Podobnie pokazujemy, że ko-produktem jest najmniejsza wspólna wielokrotność.
Zadanie 3
Niech $M$ będzie monadą. Pokaż, że liftM2 f (return x) (return y) = return( f x y)
Rozwiązanie. Korzystamy z następującej własności: ((return x) >>= f) = f(x)
:
liftM2 f (return x) (return y) = do{a <- return x; b <- return y; return( f a b)} = (return x) >>= (\a -> (return y)>>=(\b->(return(f a b)))) = (return x) >>= (\a -> (return(f a y))) = return (f x y)
Projekty
Niech S będzie sumą cyfr Twojego numeru indeksu. Wyznacz liczbę X = S mod 4. Jeśli chcesz otrzymać ocenę 5.5 musisz uzyskać zaliczenie na ocenę 4.0, 4.5 lub 5.0 i zrealizować projekt o numerze X.Termin oddawania projektów: 03.07.2019 (wysyłacie je do mnie)
Postarajcie się realizować projekty w stylu haskelowskim: projektów napisanych w stylu przypominającym język imperatywny nie będę czytał. Przed wysłaniem mi projektu przepuście go przez hlint'a. To jest pierwszy test który będę wykonywał. Macie tak napisać kod aby hlint nie zwracał żadnych uwag.
Zwracajcie też uwagę na to czy nie "wyłamujecie otwartych drzwi": np. gdy samemu piszecie coś w rodzaju iteratora po liście, to pewnie powinniście użyć jakiejś wersji fmap lub folda a może zipWith. Pamiętajcie o takich funkcjach jak words, unwords, elem, nub, sortBy (itd.).
Przyślijcie mi również swoje pliki testowe i plik info.txt z imieniem, nazwiskiem, swoim emeilem, numerem zadania, opisem sposobu uruchomiena (jak będę musiał myśleć więcej niż minutę nad tym jak Wasz program uruchomić, to nie będę go analizował).
- Projekt 0. Na stronie Proca.html znajduje się aplikacja ilustrująca działanie procy grawitacyjnej. Napisz w Haskellu, korzystając z bibliteki Gloss (lub podobnej), jej trochę bardziej rozbudowaną wersję: na scenie powinna by planeta, jej księżyc oraz mały obiekt (pojazd kosmiczny); obiekt ten powinien wykorzystać zjawisko procy grawitacyjnej do zwiększenia oraz do zmniejszenia swojej prędkości wykorzystując do tego celu księżyc. Wszystko ma się rozgrywać na scenie 2D.
Jako wstępny materiał do korzystania z biblioteki Gloss polecam stronę haskell-gloss. - Projekt 1. W pewnym katalogu znajduje się kilkanaście plików tekstowych oraz jeden plik z tzw. stop-words. Program ma przeanalizować te pliki.
- ma oczyścić pliki (usunąć znali przystankowe; artefakty); przekształcić w "lower-case"; usunąć wszystkie stop-words
- wyznaczyć częstotliwość wszystkich słów; posortować słowa wegług częstotliwości
- Wyznaczyć N (np. N=200; to ma być jeden z parametrów działania programu) najczęstszych słów w każdym dokumencie
- Następnie, dla każdej pary dokumentów należy wyznaczyć podobieństwo Jaccarda pomiędzy listami N najczęściej występujących słów.
- Nazwy wszystkich przeanalizowanych plików
- Liczby słów w tych plikach
- Zestawienie 50 najczęściej wystepujących słów zapisanych w formacie, który będzie akceptowanych przez wybraną przez Ciebie aplikację typu "Cloud of Words"
- Tablicę z podobieństwami Jaccarda zapisaną w formacie akceptowanych przez wybrany przez Ciebie pakiet do automatycznej klasyfikacji.
[17.06.2019] PUNKT 4. MOŻECIE SOBIE ODPUŚCIĆ !
-
Projekt 2. W pewnym pliku znajduje się opis grafu skierowanego zapisanego w postaci par (Int,Int) (para (x,y) oznacza strzałkę między x i y).
- Wyznacz wszystkie silne składowe spójne tego grafu
- Wyznacz graf zredukowany i zapisz go do jakiegoś innego pliku
- Za pomocą biblioteki Diagrams (patrz https://wiki.haskell.org/Diagrams) wygeneruj plik z graficzną reprezentacją grafu zredukowanego.
Projekt 3. W pewnym pliku tekstowym podany jest opis skończonego niedeterministycznego automatu. Opis funkcji przejścia składa z wierszy postaci (Int Char Int). Oprócz tego znajduje się w nim stan początkowy i stany akceptujące. Stany są indeksowane liczbami całkowitymi, zaś alfabet za pomocą typu Char. Aplikacja ma przekształcić ten automat w skończony automat deterministyczny. Automat ten ma być zoptymalizowany: nie powinno w nim być stanów nieosiągalnych ze stanu początkowego. Wynikem działania aplikacji ma być kod w języku C++ z funkcją symulującą działanie tego automatu.Literatura
- Podstawowa
- Bryan O’Sullivan, John Goerzen, and Don Stewart, Real World Haskell, O’Reilly,
- Will Kurt, Get Programming with Haskell, Manning,
- Benjamin C. Pierce, Basic Category Theory for Computer Scientists, The MIT Press,
- Pomocnicza:
- S. Tompson, Haskell. The craft for functional Programming, Addison Wesley,
- B. Milewski, Category Theory for Programmers, Creative Licence,
- Miran Lipovaca, Learn You a Haskell for Great Good! A Beginner's Guide, No Starch Press,
- learnyouahaskell.com/chapters
- Haskell Cheat Sheet: CheatSheet.pdf
- Haskell 2010 Language Report
- Podstawowe "containery" Haskella
- Lista zadań: Functional_2019.pdf
- Pytania do mnie związane z kursem: Q&A
Zagadnienia omówione na wykładzie
26.02.2019: Wprowadzenie
Wprowadzenie do Haskella
- Haskell Brooks Curry
- Pojęcie czystej funkcji
Funkcja która nie jest czysta
int x = 2; ... int myAdd (int y) { return x + y; } ... print myAdd (3);
Czysta funkcja
int myAdd (int y) { return 2 + y; } ... print myAdd (3)
- Przykład: sumowanie listy
sumuj [] = 0 sumuj (x:xs) = x + sumuj xs
- Implementacja funkcji silnia (niezbyt dobra)
silnia :: Integer -> Integer silnia n = if n <= 1 then 1 else n * silnia (n-1)
Inny wariant (również kiepski)fact n | n <= 1 = 1 | otherwise = n * fact (n-1)
jeszcze inny wariant (też kiepski)fact' 0 = 1 fact' n = n * fact' (n-1)
- Podstawowe typy: Int, Integer, Float, Double, Char, Bool, ()
- Funkcja
myAdd x y = x + 2 * y
ma typmyAdd :: Num a => a -> a -> a
Usiłujemy zrozumieć ten fragment a -> a -> a; to jest fragment języka opisu typów; jest równoważmy a -> (a -> a). - Currying:
Odwzorowanie $$ \Phi : A^{B\times C} \to (A^B)^C $$ określone wzorem $(\Phi(f)(c))(b) = f((b,c))$ jest bijekcją.PRZEMYŚLCIE To SOBIE DOBRZE !!!
Wprowadzenie do Teorii Kategorii
- Pojęcie kategorii
- Przykłady kategorii
- Set: obiekty - zbiory; morfizmy - funkcje
- Grp: obiekty - grupy; morfizmy - homorfizmy grup
- Ustalamy częściowy porządek $(X,\leq)$: obiekty - elementy $X$; strzałki - pary $(x,y)$ takie, że $x\leq y$.
- Obiekt końcowy w kategorii $\mathcal{C}$: taki obiekt $T$, że dla każdego obiektu $X$ istnieje dokładnie jeden morfizm $f:X\to T$.
- Obiekt początkowy w kategorii $\mathcal{C}$: taki obiekt $P$, że dla każdego obiektu $X$ istnieje dokładnie jeden morfizm $f:P\to X$.
- Def. Obiekty $X$ i $Y$ są izomorficzne jeśli istnieją morfizmy $f:X\to Y$ oraz $g:Y\to X$ takie, że $g\circ f = Id_X$ i $f\circ g = Id_Y$
- Tw. Dowolne dwa obiekty końcowe są izomorficzne. (bez dowodu)
- Przykład in Set: obiekt końcowy $\{1\}$; obiekt początkowy $\emptyset$.
- Uwaga: typ $()$ języka Haskell jest odpowiednikiem obiektu końcowego w kategorii typów Haskella (Hask)
- Uwaga: niektóre kategorie nie mają obiektów końcowych an początkowych
Miejsce na twoje notatki
05.03.2019: Listy
Monoidy elementy Teorii Kategorii
- Pojęcie monoidu
- Def.MON = kategoria monoidów; morfizmy = homomorfizmy monoidów
- Listy:
List(X) = (X*,[],++)
- Tw. Dowolne dwa elementy końcowe są izomorficzne
- [Kategoria dualna]. Mamy kategorię $\mathcal{C}$. Budujemy kategorię $\mathcal{C}^{op}$. Obiekty $\mathcal{C}^{op}$ są obiektami kategorii $\mathcal{C}$. $f:X\to Y$ jest morfizmem w $\mathcal{C}^{op}$ wtedy i tylko wtedy, gdy $f:Y\to X$ jest morfizmem w $\mathcal{C}$. Złożenie morfizmów w $\mathcal{C}^{op}$ definiujemy $f\bullet g = g\circ f$ (gdzie $\circ$ jest złożeniem morfizmów w kategorii $\mathcal{C}$).
- Obserwacja: obiekty końcowe w $\mathcal{C}$ są obiektami początkowymi w $\mathcal{C}^{op}$; obiekty początkowe w $\mathcal{C}$ są obiektami końcowymi w $\mathcal{C}^{op}$
- [Metoda dualności] Wniosek. Dowolne dwa elementy początkowe są izomorficzne
Generatory list
- Podstawowe metody:
- Prosta metoda:
t = [1,2,3,4]
,t=[2..20]
- Prosta metoda przyrostowa:
t = [1,5..20]
- Generator
t = [f t| t <- xs]
- Generator ze strażnikiem:
t = [f t| t <- xs, p t]
- Prosta metoda:
- Trójki pitegorejskie
pyth n = [(a,b,c)| a <- [1..n], b <- [1..a], c <- [1..b], a^2 == b^2 + c^2]
- Quick Sort
qs [] = [] qs (x:xs) = qs [t| t <- xs, t <= x] ++ [x] ++ qs [t| t <- xs, t > x]
Ten kod łatwo można ulepszyć - to będzie na liście zadań. - Kod Cezara i narzędzie do łamania tego kodu oparte na teście statystycznym chi-kwadrat Pearsona :
Cesar.hs. Przykład użycia:
- Kodowanie:
t = encode 3 "Haskell is cool"
- Dekodowanie:
encode (-3) t
- Łamanie kodu: crack t
- Kodowanie:
- Jak można oprogramować silnię: The Evolution of a Haskell Programmer :--)
Miejsce na twoje notatki
12.03.2019: Funktory i lazy evaluation
- Pojęcie produktu (w języku kategorii)
- Produkt w kategorii Set: $A\times B = \{(x,y) : x\in A \land y \in B\}$
- Pojęcie coproduktu (w języku kategorii)
- Co-produkt w kategorii Set $$ A \oplus B = (A\times\{0\}) \cup (B\times\{1\}) $$
- Pojęcie funktora między kategoriami. WIKI: Functor
Operator tworzenia list
- $L(X) = X^*$; $L(f) [x_1,\ldots,x_n] = [f(x_1),\ldots,f(x_n)]$
- Uwaga (haskell): $L(f) x$ odpowiada
map f x
(link do kodu z pakietu Prelude:map; przyzwyczajcie się do korzystania z tej strony) - Definiujemy $\eta_X (x) = [x]$; mamy: $\eta_X: X \to L(X)$
- Definiujemy $\mu_X: L(L(X)) \to L(X)$ wzorem $$\mu_X ([L_1,\ldots,L_n]) = L_1++\ldots++L_n$$.
- Własność 1: $\mu_X \circ \eta_{L(X)} = \mu_X \circ L(\eta_X) = id_{L(X)}$
- Własność 2: $\mu_X \circ \mu_{L(X)} = \mu_X \circ L(\mu_X)$
Lazy evaluation
- Przykład:
Prelude>z = [1..100] :: Int Prelude>:sprint z z = _ Prelude>take 5 z [1,2,3,4,5] Prelude>:sprint z z = 1 : 2 : 3 : 4 : 5 : _
Uwaga: tutaj był błąd: było
Prelude>z = [1..100] i nie działało tak jak chciałem. - Strumienie (nieskończone listy)
Prelude>x=[0..] Prelude>:take 5 x [0,1,2,3,4] Prelude>y = map (\n -> n^2) x Prelude>:take 5 y [0,1,4,9,16]
- Ciąg Fibbonaciego
f = 0 : 1 : zipWith (+) f (tail f)
Miejsce na twoje notatki
19.03.2019: Funktory i lambda wyrażenia
- Przykłady funktorów:
- Identyczność $I:\mathcal{C}\to \mathcal{C}$: $I(X)=X$; $I(f)=f$
- Funktor stały: $C(X) = A$; $C(f) = id_A$
- Kwadrat : $S(X) = X\times X$; $S(f:X\to Y)(x,y) = (f(x),f(y))$
- Reader: $R_A(X) = X^A$; $R_A(f:X\to Y)(\phi) = f\circ \phi$
- State: $S_A(X) = (A\times X)^A$; $S_A(f:X\to Y)(\phi)(a) = \text{let }(b,x)=\phi(a)\text{ in } (b, f(x))$
- Writer: Jeśli $\mathcal{M}=(M,e,\star)$ jest monoidem, to $W_{\mathcal{M}}(X) = M\times X$; $W_{\mathcal{M}}(f:X\to Y) (m,x) = (m, f(x))$ (uwaga: wykorzytujemy tutaj monoidy, aby móc sensownie zdefiniować odwzorowania $\eta$ i $\mu$)
- Maybe: $M(X) = X\cup\{\uparrow_X\}$; $M(f:X\to Y) = f\cup \{(\uparrow_X,\uparrow_Y)\}$
- Lambda wyrażenia
- $(\lambda x\to x+1)$ jest równoważne funkcji
f x = x+1
- $(\lambda x\to x)$ oznacza (polimorficzną) identyczność
- Wyrażenia: $(\lambda x \to (\lambda y \to w))$ i $(\lambda x\; y \to w)$ są równoważne
- const: $(\lambda x \;y \to x)$
- Zastosowanie:
map (\x->x+10)[1,2,3]
$\Rightarrow$[11,12,13]
- Zastosowanie:
map (+ 10)[1,2,3]
$\Rightarrow$[11,12,13]
- Wyrażenie let: wyrażenie
let x1 = w1; x2 = w2; ... xn = wn in v
jest równoważne $$(\lambda x_1\to (\lambda x_2 \to \ldots (\lambda x_n \to v)...) w_1\; w_2 \ldots w_n$$ czyli $$ (\lambda x_1 \; \lambda x_2 \ldots \lambda x_n \to v) w_1\; w_2 \ldots w_n $$
- $(\lambda x\to x+1)$ jest równoważne funkcji
- Kostrukcja where: przykład: wyrażenie
f x y | u < v = ... | u == v = ... | otherwise = ... where u = (x+y)^2 v = (x-y)^2
jest równoważnef x y = (\u -> (\v -> | u < v = ... | u == v = ... | otherwise = ... ) ) ((x+y)^2) ((x-y)^2)
Miejsce na twoje notatki
26.03.2019: Foldy
- LEWY FOLD:
foldl _ z [] = z foldl f z (x:xs) = foldl f (f z x) xs
- PRAWY FOLD:
foldr _ z [] = z foldr f z (x:xs) = f x (foldl f z xs)
- Tw. Jeśli `f` jest łączne zaś e jest elementem nautralnym `f` to foldl
f e x = foldr f e x
- Przykład:
sum x = foldr (+) 0 x
- Przykład:
product x = foldr (*) 1 x
factorial n = product [1..n]
- Tw. Jeśli g x y = f x y, to
foldl g [] x = foldr f [] (reverse x)
reverse x = foldl (flip (:)) [ ] x
- Obowiązkowa lektura każdego haskelowca: Graham Hutton: A tutorial on the universality and expressiveness of fold
- Różne warianty foldów: foldl1, foldr1, foldl', foldr'
- Definicje wewnętrzne operatorów
&&
i||
(patrz GHC-Classes.html)-- | Boolean "and" (&&) :: Bool -> Bool -> Bool True && x = x False && _ = False -- | Boolean "or" (||) :: Bool -> Bool -> Bool True || _ = True False || x = x
- Przykład:
any p x = foldr (\x y -> (p x) || y) False x
- Przykład:
all p x = foldr (\x y -> (p x) && y) True x
- Pojęcie naturalnej transformacji funktorów: WIKI
- Przykład: jeśli $I(X)=X$ oraz $I(f)=f$ (czyli: jeśli $I$ jest funktorem identycznościowym), to jedyną naturalną transformacją $\eta: I \stackrel{\cdot}{\rightarrow} I$ jest $\eta_X = id_X$; czyli $Nat(I,I) = \{ID\}$
- Przykład: jeśli $S(X)=X\times X$ oraz $S(f)=f\times f$, to jedyną naturalną transformacją $\eta: I \stackrel{\cdot}{\rightarrow} S$ jest $\Delta_X (x) = (x,x)$; czyli $Nat(I,S) = \{\Delta\}$
Miejsce na twoje notatki
02.04.2019: User defined types
- Typy wyliczeniowe:
data Color = Green | Yellow | Red deriving (Show, Eq) nextC :: Color -> Color nextC Green = Yellow nextC Yellow = Red nextC Red = Green
- Record-like types
data Pracownik1 = Pracownik1 String String Int data Pracownik = Pracownik { pracImie :: String , pracNazwisko :: String , pracPensja :: Int } deriving Show
- Typy rekurencyjne i parametryczne
data Tree a = L a | N (Tree a) a (Tree a) deriving Show tree = N (L 12) 3 (N (L 1) 5 (L 3))
Robimy z tego funktor:instance Functor Tree where fmap f (L x) = L (f x) fmap f (N left x right) = N (fmap f left) (f x) (fmap f right) fmap (\x -> x+100) tree
Oprogramowujemy własne show:instance (Show a) => Show (Tree a) where show (L x) = "<" ++ show x ++ ">" show (N l x r) = "[" ++ show l ++ ", " ++ show x ++ ", " ++ show r ++ "]"
Robimy z tego foldableinstance Foldable Tree where foldr f z (L x) = f x z foldr f z (N left x right) = foldr f (f x (foldr f z right)) left
- Zrobiliśmy własną klasę i zrobilśmy z Int i list dowolnego typu instancje klasy YesNo
class YesNo a where yesno :: a -> Bool instance YesNo Int where yesno 0 = False yesno _ = True instance YesNo [a] where yesno [] = False yesno _ = True
- Funktor Maybe - podstawowe użycie
safeHead :: [a] -> Maybe a safeHead [] = Nothing safeHead (x:_) = Just x
- Instalacja modułu QuickCheck
cabal update cabal install QuickCheck
i przykłady użyciaimport Test.QuickCheck quickCheck (\x -> length (take 3 x) == 3) quickCheck (\x -> length (take 3 x) <= 3)
Miejsce na twoje notatki
09.04.2019: Składanie
- Własności funktorów: $F(id_X) = id_{F(X)}$ oraz $F(g\circ f) = F(g)\circ F(f)$.
Te własności musimy samemu sprawdzić, gdy definiujemu własny funktor w Haskellu.
Pierwsza własność odpowiada prawu
fmap id = id
Druga własność odpowiada prawufmap (g.f) = (fmap g) . (fmap f)
- Zadanie: pokaż, że definicja fmap dla typu Tree z poprzedniego wykładu jest poprawna. Wskazówka: można to zrobić "strukturalną indukcją", czyli zaczynamy od pokazania poprawności dla (L x), a potem, zakładając, że jest OK dla leftT i rightT pokazujemt, że jest OK dla (N leftT x rightT).
- Dla funktora Mayby definiujemy:
mSqrt x = if x<0 then Nothing else Just (sqrt x) mInv x = if x==0 then Nothing else Just (1/x)
- Dla funktora [ ] definiujemy:
lSqrt x | x<0 = [] | x==0 = [0] | otherwise = [sqrt x, -(sqrt x)] lS2 a b d = if a==0 then [] else [((-b)+d)/(2*a)]
- Odwzorowania $\eta_X: X\to F(X)$ (return) i $\mu_X:F(F(X))\to F(X)$ (join) dla Maybe i [ ]:
$$
\eta_X(x) = x; \quad \mu_X = id_X \cup \{(\uparrow_X, \uparrow_X),(\uparrow_{M(X)}, \uparrow_X)\}
$$
oraz
$$
\eta_X(x) = [x]; \quad \mu_X([L_1,\ldots,L_n]) = L_1++\ldots++L_n
$$
czyli (Haskell)
return x = Just x; join Just (Just x) = Just x join otherwise = Nothing
orazreturn x = []; join = concat
- Operator >>= (bind): dla $fx \in F(X)$ oraz $f:X\to F(Y)$ definiujemy $$ fx >>= f = \mu_Y (F(f) (fx)) $$
- Przykład obliczeń w Mayby
f x = ((Just x) >>= mSqrt) >>= mInv
- Przykład obliczeń w [ ] (rozwiązanie równania kwadratowego):
lSolve2 a b c = (lSqrt (b*b-4*a*c)) >>= lS2 a b
- Teraz bierzemy się za uporządowanie tego co do tej pory na tym wykładzie zrobiliśmy. To nam zajmie trochę czasu.
- Naturalna transformacja - przypomnienie
- Oba rozważane na tym wykładzie odwzorowania $\eta$ (dla list i MayBe) są naturalnymi transformacjami $\eta : I \overset{\bullet}{\rightarrow} F$
- Złożenie (pionowe) naturalnych transformacji: jeśli $\alpha:F \overset{\bullet}{\rightarrow} G$ oraz $\beta:G \overset{\bullet}{\rightarrow} H$ to $\beta\circ\alpha$ zdefiniowane wzorem $$ (\beta\circ\alpha)_X = \beta_X \circ \alpha_X $$ jest naturalną transformacją z $F$ to $H$.
- Definicja: $Funct(\mathcal{C},\mathcal{D})$ oznacza kategorię w której obiektami są funktory z $\mathcal{C}$ w $\mathcal{D}$ zaś morfizmami są naturalne tansformacje między nimi. Morfizm identycznościowy na functorze $F$: $$ \iota_X = id_{F{X}} $$ Inne oznaczenia na kategorię funktorów: $[\mathcal{C},\mathcal{D}]$, $\mathcal{D}^\mathcal{C}$
Miejsce na twoje notatki
30.04.2019: Lemat Yonedy i wstęp do monad
- Przykłady naturalnych transformacji funktorów.
- Pojęcie kategorii lokalnie małej.
- Hom funktor: $\mathcal{Y}_A(X) = Hom(A,X)$; $\mathcal{Y}_A(f) = (\lambda g\to f\circ g)$
- Lemat Yonedy: Jeśli $\mathcal{C}$ jest lokanie mała, $A$ jest obiektem $\mathcal{C}$ oraz $F: \mathcal{C} \to Set$ jest funktorem, to istnieje bijekcja między $$ Nat(\mathcal{Y}_A, F) $$ oraz $F(A)$. Co więcej, $Nat(\mathcal{Y}_A, F) = \{\eta^{\alpha}: \alpha\in F(A)\}$, gdzie $\eta^{\alpha}(f) = F(f)(\alpha)$.
- Wniosek. $Nat(X\times\cdots\times X, F) \sim F(\{1,\ldots,n\})$ (po lewej stronie mamy produkt $n$ kopii $X$)
- Przykład: $Nat(X\times X,X\times X) \sim \{1,2\}\times\{1,2\}$
- MONADA: Trójka $(L,\eta,\mu)$ taka, że $L$ jest funktorem, $\eta: I \overset{\bullet}{\rightarrow} L$ oraz $\mu : L\circ L \overset{\bullet}{\rightarrow} L$ są naturalnymi transformacjami takimi, że następujące diagramu komutują:
- Przykład (Lista):
-
L(X) = [X]
, L(f) = map f
;- $\eta_X$
(x) = [x]
; - $\mu_X$
([X1, ... , Xn]) = X1 ++ ... ++ Xn (= concat [X1, ... , Xn])
-
- Pomysł na rozwiązanie problemu sekwencyjnego czytania
let (x,a) = readInt (0) in let (y,b) = readInt (a) in f(x,y)
(przekazywanie żetonów). - Program "Hello World" w Haskellu przed wprowadzeniem monad do języka:
- A tak to się robi teraz:
main = do putStrLn "Hello World"
- Czytanie i wyświetlanie wyniku:
main = do putStr "Podaj liczbę calkowitą : " str <- getLine let n = read str :: Int putStrLn ("Jej szescian to " ++ show(n * n * n))
Szczegóły: na najbliższych wykładach.
Miejsce na twoje notatki
07.05.2019: Monady - I
- Przykład zanurzenia w struktury o większej liczbie wymiarów: odwzorowania afinicze płaszczyzny są zdefinione wzorem $$ F\left(\begin{bmatrix} x\\y\end{bmatrix}\right) = \begin{bmatrix} a_{11}&a_{12}\\a_{21}&a_{22}\end{bmatrix} \cdot \begin{bmatrix} x\\y\end{bmatrix} + \begin{bmatrix} b_1\\b_2\end{bmatrix} $$ Implementowane są one (z reguły) w taki sposób $$ \begin{bmatrix} a_{11}&a_{12}&b_1\\a_{21}&a_{22}&b_2\\ 0 & 0 & 1\end{bmatrix} \cdot \begin{bmatrix} x\\y\\1\end{bmatrix} $$
- Def. Dla monady $(T,\eta,\mu)$ i $f:X\to T(Y)$ definiujemy
$$f^* = \mu \circ T(f)$$Mamy: $f^*: T(X) \to T(Y)$.
-
- W1: Jeśli $f:X\to T(Y)$ i $g:Y\to T(Z)$ to $(g^*\circ f^* = (g^*\circ f)^*$
- W2: Jeśli $f:X\to T(Y)$ to $f^*\circ \eta_X = f$
- W3. $(\eta_X)^* = id_{T(X)}$
- Operacja BIND: (>>=):: T a -> (a -> T b) -> T b
$$(tx >\!>= f) = f^*(tx)$$
- Monada Writer - pierwsze podejście
- $W(X) = X \times String$
- $W(f)(x,s) = (f(x),s)$
- $\eta(x) = (x,"")$
- $\mu (((x,s),t)) = (x, t +\!\!+ s)$
Przerabiamy to na kod Haskella:data Writer a = Writer (a,String) deriving Show instance Functor Writer where fmap f (Writer (x,s)) = Writer (f x, s) instance Monad Writer where return x = Writer (x, "") (Writer (x,s)) >>= f = let Writer (y,t) = f x in Writer (y, s++t) instance Applicative Writer where pure = return fw <*> xw = do f<- fw; x<- xw; return( f x)
Przykład użyciahalf::Int -> Writer Int half x = Writer (x `div` 2, "Polowie " ++ show x ++ "; ")
*Main> half 120 Writer (60,"Polowie 120; ") *Main> half 120 >>= half Writer (30,"Polowie 120; Polowie 60; ") *Main> half 120 >>= half >>= half Writer (15,"Polowie 120; Polowie 60; Polowie 30; ")
jestPodejrzany :: Int -> Bool jestPodejrzany n = (50<=n) && (n<= 55) dane = [55,11,45,51,22,50,23,1,11,2,3,4,5,6,7,8,55,1,2,3,4,5,6,7,8] :: [Int] zsumuj :: [Int] -> Writer Int zsumuj [] = Writer (0,"") zsumuj (x:xs) = zsumuj xs >>= (\y -> if jestPodejrzany x then Writer (x+y,"+") else Writer (x+y, "-"))
*Main> zsumuj dane Writer (395,"--------+----------+-+--+")
- Implementacja Monoidu w Haskellu: wiki.haskell.org/Monoid
- Monada Writer - drugie podejście (uogólniamy String na dowolny monoid)
- Implementacja
import Data.Semigroup newtype Writer w a = Writer (a,w) deriving Show instance Functor (Writer w) where fmap f (Writer (x,s)) = Writer (f x, s) instance (Monoid w) => Monad (Writer w) where return x = Writer (x, mempty) (Writer (x,w)) >>= f = let Writer (y,t) = f x in Writer (y, w `mappend` t) instance (Monoid w) => Applicative (Writer w) where pure = return -- fw <*> xw = do f<- fw; x<- xw; return( f x) Writer (f, m) <*> Writer (x, n) = Writer (f x, m `mappend` n)
- Przykład użycia:
jestPodejrzany :: Int -> Bool jestPodejrzany n = (50 <= n) && (n <= 55) dane = [55,11,45,51,22,50,23,1,11,2,3,4,5,6,7,8,55,1,2,3,4,5,6,7,8] :: [Int] zsumuj :: [Int] -> Writer (Sum Int) Int zsumuj [] = Writer (0,0) zsumuj (x:xs) = do zsumuj xs >>= (\y -> if jestPodejrzany x then Writer (x+y,1) else Writer (x+y, 0) )
- Inny przykład użycia:
zsumujPlus :: [Int] -> Writer (Sum Int, Sum Int, String) Int zsumujPlus [] = Writer (0,(0,0,"")) zsumujPlus (x:xs) = do zsumujPlus xs >>= (\y -> if jestPodejrzany x then Writer (x+y,(1,0,"+")) else Writer (x+y,(0,1,"-")) )
- W ostatnim przykładzie skorzystaliśmy z następującego faktu: jeśli $(M,e,\cdot)$ i $(N,f,\star)$ są monoidami, to struktura $(M\times N,(e,f),\oplus)$, gdzie $(x,y)\oplus(a,b) = (x\cdot a,y\star b)$ jest monoidem.
- Implementacja
- A w ostanich minutach wykładu zabawiliśmy się takim kodem:
zsumujPlus :: [Int] -> Writer (Sum Int, Sum Int, Dual String) Int zsumujPlus [] = writer (0,(0,0,Dual "")) zsumujPlus (x:xs) = do zsumujPlus xs >>= (\y -> if jestPodejrzany x then writer (x+y,(1,0,Dual "+")) else writer (x+y,(0,1,Dual "-")) )
Dual M
jest monoidem dualnym do monoidu M.
Miejsce na twoje notatki
14.05.2019: Monady - II (notacja do)
- Własności operacji
>>=
(bind):((tx >>= f) >>= g) = (tx >>= (\x -> f(x) >>= g))
[łączność](return x >>= f) = f x
[lewa identyczność](mx >>= return) = mx
[prawa identyczność]
- Operacja Kleisli'ego (fish):
(f >=> g)(x) = f(x) >>= g
- Tw.
((f >=> g) >=> h) = (f >=> (g >=> h))
czyli: operacja>=>
jest łączna. - Tw.
(join ttx) = (ttx >>= fmap id)
czyli odwzorowanie naturalne $\mu$ (join) może być zdefiniowane za pomocą>>=
- Def.
(tx >> ty) = (tx >>= (\_ -> ty))
- Przykład (listy):
([x1,...,xn] >> a) = a ++ ... ++ a
(konkatenacja n kopii listya = [a1,...,am]
) - Przykład (Maybe):
(Nothing >> x) = Nothing
,((Just _) >> x) = x
- Notacja do
do {x <- tx; expr}
==(tx >>= (\x -> do {expr}))
do {let x = w; expr}
==(let x = w in do {expr})
do {w; expr}
==(w >> do {expr})
do {w} = w
- Przykład:
safeInv, safeSqrt :: Float -> Maybe Float safeInv x = if x /= 0 then Just (1/x) else Nothing safeSqrt x = if x>=0 then Just (sqrt x) else Nothing f:: Float -> Maybe Float f x = do y <- Just x z <- safeInv x safeSqrt z
f x = Just x >>= safeInv >>= safeSqrt
- Trochę bardziej rozbudowany przykład (evaluator prostego języka):
import qualified Data.Map as M data Term = N Float | A Term Term | S Term Term | M Term Term | D Term Term deriving Show termA = D (A (N 1)(N 2) ) (M (N 2) (N 3)) termB = D (A (N 1)(N 2) ) (M (N 2) (N 0)) eval:: Term -> Maybe Float eval (N x) = Just x eval (A t1 t2) = do x<- eval t1; y<- eval t2; return (x+y) eval (S t1 t2) = do x<- eval t1; y<- eval t2; return (x-y) eval (M t1 t2) = do x<- eval t1; y<- eval t2; return (x*y) eval (D t1 t2) = do x<- eval t1; y<- eval t2; if y==0 then Nothing else return (x/y)
- Jeszcze bardziej rozbudowany przykład (evaluator prostego języka ze zmiennymi):
data Term = X String -- zmienna | N Float -- stała | A Term Term -- add | S Term Term -- substract | M Term Term -- multiply | D Term Term -- divide termA = D (A (X "x")(X "y") ) (M (X "v") (X "z")) termB = D (A (X "x")(N 10 ) ) (M (X "v") (X "w")) zmienne :: M.Map String Float zmienne = M.fromList [("x",12.0),("y",2.1),("z",3.1),("v",2.0)] eval:: M.Map String Float -> Term -> Maybe Float eval z (X x) = M.lookup x z eval z (N x) = Just x eval z (A t1 t2) = do x<- eval z t1; y<- eval z t2; return (x+y) eval z (S t1 t2) = do x<- eval z t1; y<- eval z t2; return (x-y) eval z (M t1 t2) = do x<- eval z t1; y<- eval z t2; return (x*y) eval z (D t1 t2) = do x <- eval z t1; y <- eval z t2; if y==0 then Nothing else return (x/y)
Miejsce na twoje notatki
21.05.2019: Monady - III (Writer/Reader)
- Obliczenia dla $W_M(X) = X\times M$; $W_M(f) (x,m) = (f x, m)$:
(f,m) <*> (x,y) = (f x, m `mappend` n)
- Przerabiamy to na kod Haskella:
Uwaga: zastosowaliśmy konstrukcję
import Data.Semigroup newtype Writer w a = Writer {runWriter :: (a,w)} instance Functor (Writer w) where fmap f (Writer (x,s)) = Writer (f x, s) instance (Monoid w) => Applicative (Writer w) where pure x = Writer (x, mempty) Writer (f, m) <*> Writer (x, n) = Writer (f x, m `mappend` n) instance (Monoid w) => Monad (Writer w) where return = pure (Writer (x,w)) >>= f = let (y,t) = runWriter(f x) in Writer (y, w `mappend` t)
newtype
zamiastdata
. - Dodajemy dodatkowe funkcjonalności do monady Writer. Wprowadzamy nową klase
MonadWriter:
class (Monoid w, Monad m) => MonadWriter w m | m -> w where pass :: m ( a, w->w) -> m a listen :: m a -> m (a,w) tell :: w -> m () writer :: (a,w) -> m a
(m->w oznacza, że z monady m wynika jednoznacznie typ monoidu w) i tak oprogramowujemy instancję Writera:instance (Monoid w) => MonadWriter w (Writer w) where pass (Writer ((a,f),w)) = Writer (a, f w) listen (Writer (a, w)) = Writer ((a,w),w) tell w = Writer ((),w) writer (a,w) = Writer (a,w)
Aby do zrobić, w nagłowku pliu z kodem musimy dodać następujące polecenia dla kompilatora:{-# LANGUAGE FunctionalDependencies #-} {-# LANGUAGE FlexibleInstances #-}
- Przykładowy kod
i przykłady użycia:
import Control.Monad.Writer half :: Int -> Writer String Int half x = do tell ("Przepolowilem " ++ show x ++ "! ") return (x `div` 2)
*Main> runWriter $ half 120 *Main> runWriter $ half 120 >>= half *Main> runWriter $ half 120 >>= half >>= half
- Własności monady Writer: definiujemy funkcję $\pi:X\times M \to X: (x,m)\to x$ (projekcja na pierwszą oś). Jeśli $f:X \to W_M(Y)$, $g:Y \to W_M(Z)$, $h:Z \to W_M(U)$ to $$ \pi\large( (x,m) \gt\!\gt= f \gt\!\gt\!= g \gt\gt= h\large) = \large((\pi\circ h) \circ (\pi\circ g) \circ (\pi \circ f)\large)(x) $$ Uwaga: Writer jest wyjątkową monadą; mamy naturalną transformację $\pi: W_M \Rightarrow I$ taką, że $\pi\circ \eta = \text{id}$.
- Monada Reader:
- $R_A(X) = X^A$;
- $R_A (f:X\to Y) = (\phi \to f\circ\phi)$
- $\eta(x) = (\lambda a \to x)$;
- $\mu(\Phi) = (\lambda a \to (\Phi(a))(a))$
- Po prostych obliczeniach otrzymujemy: $$(\phi \gt\!\!\gt\!= f) = (\lambda a \to f (\phi(a))(a))$$
- Szczegóły implementacji
instance MonadReader p (Reader p) where ask = Reader id reader = Reader ....
- Przykład użycia:
import Control.Monad.Reader import Data.Char (toLower) cleanStr :: String -> String; cleanStr x = map toLower ( unwords . words x ) cleanFirstStr :: Reader (String,String) String cleanFirstStr = do (x, _) <- ask return ( cleanStr x ) cleanSecondStr :: Reader (String,String) String cleanSecondStr = do (_,y) <- ask return ( cleanStr y ) compStr :: Reader (String,String) Bool compStr = do a <- cleanFirstStr b <- cleanSecondStr return (a==b) -- użycie: (runReader compStr) ("Ala ma kota", "Ala ma KOta")
Miejsce na twoje notatki
28.05.2019: Monady - IV
- Złożenie horyzontalne naturalnych transformacji: jeśli $\alpha:F \Rightarrow G$ oraz $\beta:K \Rightarrow L$ to $$ (\beta\star\alpha)_X = \beta_{G(X)} \circ K (\alpha_X) $$
- Zrobiliśmy (było trochę roboty) de-sugaryzację kodu z poprzedniego wykładu.
Pokazaliśmy, że cały kod jest równoważny następującemu kodowi
cleanStr :: String -> String; cleanStr x = map toLower ( unwords . words x ) compStr:: String -> String -> Bool compStr a b = cleanStr a == cleanStr b
- Zaczęliśmy dobierać się do monady State. Ustalamy zbiór S.
- Rozważać będziemy przyporządkowanie $S(X) = (X\times S)^S$ (jak zrobić z tego funktor - później)
- Dla $f:X\times S \to Y\times S$ definiujemy $f^c: X \to (Y\times S)^S$ wzorem $f^c(x) = \lambda s \to f((x,s))$
- Dla $f:X \to (Y\times S)^S$ definiujemy $f^u: X \times S \to (Y\times S)$ wzorem $f^u((x,s)) = (f(x))(s)$
- Mamy $(f^c)^u = f$ oraz $(g^u)^c = g$
- Dla $\alpha \in (X\times S)^S$ i $f:X\to (Y\times S)^S$ definiujemy $$ (\alpha \BIND f) = f^u \circ \alpha $$
- Definiujemy $\eta_X = (id_{X\times S})^c$; czyli $\eta_X(x) = (\lambda s\to(x,s))$
- Fakt 1: $(\alpha \BIND \eta) = \alpha$
- Fakt 2: $(\eta(x) \BIND f) = f(x)$
- Fakt 3: $((\alpha \BIND f) \BIND g) = (\alpha \BIND (\lambda x \to f(x) \BIND g))$
- ZATEM zanurzenie $\eta$ i operacja $\BIND$ spełniają prawa monady. Na następnym wykładzie będziemy te rozważania kontynuować i zrobimy z przyporządkowania $S$ monadę.
Miejsce na twoje notatki
04.06.2019: Monady - IV
- Zakładamy, że mamy przyporządkowanie $M:\mathcal{C}\to\mathcal{C}$, naturalne przyporządkowanie $\eta:I \to F$ oraz $\BIND$
spełniające prawa monadyczne.
- Definiujemy $M(f:X\to Y) (mx)= (do \{x \leftarrow mx; return (f x)\}) = mx \BIND (\lambda x \to \eta(f(x)))$. Pokazaliśmy, że w ten sposób zrobiliśmy z przyporządkowania $M$ funktor.
- Definiujemy $\mu(mmx) = (do\{mx\leftarrow mmx; mx\}) = mmx \BIND id$.
- Pokazaliśmy, że trójka $(M,\eta,\mu)$ jest monadą.
- Pokazaliśmy, że jeśli za pomocą trójki $(M,\eta,\mu)$ zdefiniujemy operację BIND, to otrzymamy tę samą operację od której zaczęliśmy.
- State monad: obliczamy S(f:X\to Y). Otrzymaliśmy $$ S(f:X\to Y) (\alpha) = (\lambda s \to \text{ let } (x,t) = \alpha(s) \text{ in } (f(x) ,t)) $$
- Implementacja monady state w Haskellu
{-# LANGUAGE FunctionalDependencies #-} {-# LANGUAGE FlexibleInstances #-} newtype State s a = State {runState::s -> (a,s)} instance Functor (State s) where fmap f st = State (\s -> let (x,t) = runState st s in (f x,t)) instance Monad (State s) where return x = State (\s -> (x, s)) sx >>= f = State $ \s -> let (x, t) = runState sx s in runState (f x) t instance Applicative (State s) where pure = return fS <*> xS = do f<- fS; x<- xS; return (f x) class Monad m => MonadState s m | m -> s where get :: m s -- | Replace the state inside the monad. put :: s -> m () -- | Embed a simple state action into the monad. state :: (s -> (a, s)) -> m a instance MonadState s (State s) where get = state (\s -> (s, s)) put s = state (\_ -> ((), s)) state f = State f
- Przykład: myślimy o funkcji f: (Float,Int) -> (Float,Int) określonej wzorem
$$
f(x,s) = \begin{cases} (\sqrt{|x|},s+1) &: s \lt 5 \\ (x+1,s+1) &: x\geq 5\end{cases}
$$
Robimu currying tej funkcji i zamieniamy to w kod
Przykład użycia
fnc :: Float -> State Int Float fnc x = state ( \s -> if s < 5 then (sqrt (abs x), s+1) else (x+1, s+1) )
(runState ((return 10.0)>>= fnc >>= fnc)) 0
- Bawimy się z funkcją Collatza. Zaczynamy od wersji licznikowej:
Uwaga: to mogliśmy zrobić za pomocą monady Writer. Ale teraz modyfikujemy: pozwalamy iterować tylko ograniczoną liczbę razy:
import Control.Monad.State oneStepCollatz :: Int -> Int oneStepCollatz n = if mod n 2 == 0 then div n 2 else 3*n + 1 collatz :: Int -> State Int Int collatz n = if n <= 1 then return 1 else do k <- collatz (oneStepCollatz n) state (\s -> (k,s+1))
Teraz mamylazyCollatz :: Int -> State Int Int lazyCollatz n = if n <= 1 then return 1 else do let stan = lazyCollatz (oneStepCollatz n) state (\s -> let (y,t)= (runState stan) s in if t>0 then ( y, t-1) else (-1, t) )
*Main> runState (lazyCollatz 96) 100 (1,88)
ale dla liczby 97 odmawia obliczeń; mamy bowiem*Main> runState (lazyCollatz 97) 100 (-1,0)
- Monoid w języku teorii kategorii: gdzie $(M,e,\star)$ jest monoidem, $I$ = końcowy obiekt w kategorii Set, $\eta:I \to M$ jest dana wzorem $\eta () = \text{const}_e$ oraz $\mu(x,y)= x\star y$.
Miejsce na twoje notatki
11.06.2019: Monady - V
- Przekształciliśmy równania algebraiczne monad w diagramy definiujące monoidy. Stwierdziliśmy, że monada jest monoidem w klasie Endo(Set) (endofunktorów klasy Set), gdzie iloczynem tensorowym jest złożenie, identycznością transformacja naturalna $\eta$ zaś działaniem binarnym jest transformacja $\mu$ (tu będzie obrazek)
- Porównanie monad - I
- Listy: $\eta(x) = [x]$
- Reader: $\eta(x) = (\lambda a \to x)$
- Writer: $\eta(x) = (x,e)$
- State: $\eta(x) = (\lambda s \to (x,s))$
- Porównanie monad - II
- Listy: $([x_1,\ldots,x_n] \BIND f) = (f x_1) ++ \ldots ++ (f x_n)$
- Reader: $(rx \BIND f) = (\lambda a \to (f (rx(a))) a)$
- Writer: $((x,m)\BIND (f_1,f_2)) = (f(x_1), m\star f_2(x))$
- State: $(sx \BIND f) = (\lambda s \to \text{ let } (x,t) = sx(s) \text{ in } (f(x))(t))$
- STRESZCZENIE: średnik w
do{x<-mx; f x}
jest (w odróżnienu od klasycznych języków programowania) średnikiem programowalnym - Lifting and friends:
- LiftM
Proste obliczenia pokazują, że
liftM :: (Monad m) => (a -> b) -> (m a -> m b) liftM f mx = do {x<- mx; return (f x)}
liftM = fmap
. To jest efekt pewnych błędów historycznych. - LiftM
Przykłady:
liftM2 :: (Monad m) => (a -> b -> c) -> (m a -> m b -> m c) liftM2 f mx my = do {x<- mx; y <- my; return (f x y)}
liftM2 (+) [1,2] [10,20] => [11,21,12,22]
,liftM2 (+) (Just 3) (Just 2) => Just 5
Twierdzenie.liftM2 f (return x) (return y) = return (f x y)
- filterM
Przykład:
filterM :: (Monad m) => (a -> m Bool) -> [a] -> m [a] filterM _ [] = return [] filterM p (x:xs) = do test <- p x ys <- filterM p xs return (if test then x:ys else ys)
(filterM (\_ -> [True,False]) [1,2,3])
=> wszystkie "podzbiory" [1,2,3]
- LiftM
IO (X) = State OuterWorld X
jest to wariant monady typu State z brakiem bezpośredniego dostępu do zbioru stanów OuterWorld. Tu będzie obrazek.- Przykład:
main :: IO () main = do putStr "Podaj imie " -- :: IO () s <- getLine -- :: IO String putStrLn ( "Witaj " ++ s ) -- :: IO ()
Miejsce na twoje notatki