From 27f28c93b0d0770e8a41e45b39879b0d55811845 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Sun, 11 Mar 2018 20:01:03 +0100 Subject: [PATCH 01/14] Init from MarekSuchanek/FPCourse --- tutorials/06_common-typeclasses-1.md | 195 +++++++++++++++++++++++++++ 1 file changed, 195 insertions(+) create mode 100644 tutorials/06_common-typeclasses-1.md diff --git a/tutorials/06_common-typeclasses-1.md b/tutorials/06_common-typeclasses-1.md new file mode 100644 index 0000000..7c152b4 --- /dev/null +++ b/tutorials/06_common-typeclasses-1.md @@ -0,0 +1,195 @@ +# Common typeclasses I + +Now we are going to spend some with predefined and important typeclasses which capture some important concepts in Haskell that are widely used in any types of projects. Typeclass always say something about the structure of type and what can you do with that. Also there are some laws and it is very tightly related to math and specifically with algebra and theory of categories. + +After learning common typeclasses it is not just easier to use them and understand code written by other developer but it also helps with designing own custom typeclasses. You can always find more about typeclass and instances with GHCi `:info` command. + +## Intro: Mathematical foundations + +// math, category theory + +## Monoid (and others from basic algebra) + +Monoid is the most simple typeclass we will learn. You can recall the [monoid](https://en.wikipedia.org/wiki/Monoid) them from algebra - it is algebraic structure with one binary operation which is associate and there is also one identity element. Same goes for Haskell - the operation is called `mappend` and identity is `mempty` (first letter `m` if for **m**onoid). + +```haskell +class Monoid m where + mempty :: m + mappend :: m -> m -> m + mconcat :: [m] -> m + mconcat = foldr mappend mempty +``` + +The law of monoid says that `mappend` must be associative and `mempty` is real identity when working with `mappend`: + +```haskell +mappend x (mappend y z) == mappend (mappend x y) z +-- the same in infix: +x `mappend` (y `mappend` z) == (x `mappend` y) `mappend` z + +mappend x mempty == x +mappend mempty x == x +``` + +If you take a look at the documentation of [Data.Monoid](https://hackage.haskell.org/package/base/docs/Data-Monoid.html), you might notice few more things: + +* synonym for `mappend` is `(<>)` so you can simply use it as operator `x <> b` (notice that it is not the same as not-equals in other languages), +* multiple newtypes for specifying monoid for basic type, like `Sum` and `Product` for numeric types, `All` and `Any` for booleans, `First` and `Last` for maybes and few more. + +```haskell +-- TODO: Sum & Product +-- TODO: First & Last +``` + +Of course there are not just `Monoid` from basic algebra. You might find interesting to learn more about: + +* [Data.Semigroup](https://hackage.haskell.org/package/base/docs/Data-Semigroup.html) (no identity as is in Monoid), +* [Data.Group, Data.Abelian](https://hackage.haskell.org/package/groups-0.4.0.0/docs/Data-Group.html) (inversions and commutative operation). + +It is possible to write own instances of `Monoid` or other typeclasses. Problem is that compiler won't check if laws are valid in your instance. For such checks you can use testing frameworks (esp. property testing) which will be covered later on. + +## Functor + +A functor is a way to apply a function on values inside some structure that we don’t want to change. For example if you want to change the values in the list, tree or in either without dealing with complexity and internal structure. + +```haskell +class Functor f where + fmap :: (a -> b) -> f a -> f b +``` + +The definition says that there is a function `fmap` which applies a function of type `a -> b` on elements in functor `f` with inner type `a` and result will be functor `f` with inner type `b`. Moreover there are two laws: + +```haskell +-- identity (fmap doesn't do nothing more than applying given function) +fmap id == id +-- composition +fmap (f . g) == fmap f . fmap g +``` + +Let's try it: + +``` +-- TODO play with functors +``` + +Just as with Monoid, you can take a look at the documentation of [Data.Functor](https://hackage.haskell.org/package/base/docs/Data-Functor.html). Again, there is operator alias, in this case `(<$>)` for `fmap`. There are two more similar - `<$` and `$>` (just flipped `<$`). + +``` +-- TODO play with functors and operators +``` + +*TODO*: IO Functor, lifting, forall + +## Applicative + +Next important typeclass is [Control.Applicate](https://hackage.haskell.org/package/base/docs/Control-Applicative.html). Notice that it is not "Data" anymore, but "Control" instead! It is intermediate structure between a `Functor` and a `Monad`. It is simpler than `Monad`, not so powerful, but sufficient in many use cases, and also easier to understand. + +```haskell +class Functor f => Applicative f where + pure :: a -> f a + (<*>) :: f (a -> b) -> f a -> f b +``` + +Function `pure` only lifts something into applicative structure `f`. The more interesting part is the "tie-fighter" operator `<*>` which applies lifted function over applicative. You can find out in the documentation following similar functions and partial functions as in [Data.Functor](https://hackage.haskell.org/package/base/docs/Data-Functor.html): + +```haskell +(<*) :: f a -> f b -> f a +(*>) :: f a -> f b -> f b + +liftA :: (a -> b) -> f a -> f b +liftA2 :: (a -> b -> c) -> f a -> f b -> f c +liftA3 :: (a -> b -> c -> d) -> f a -> f b -> f c -> f d +``` + +There are again some laws: + +```haskell +-- identity +pure id <*> v == v +-- composition +pure (.) <*> u <*> v <*> w == u <*> (v <*> w) +-- homomorphism +pure f <*> pure x = pure (f x) +-- interchange +u <*> pure y = pure ($ y) <*> u +``` + + +``` +-- TODO play with applicative and operators +``` + +## Monad + +The most famous and scary typeclass for Haskell students is [Control.Monad](https://hackage.haskell.org/package/base/docs/Control-Monad.html). It defines the basic operations over a monad, a concept from a branch of mathematics known as category theory. From the perspective of a Haskell programmer, however, it is best to think of a monad as an abstract datatype of actions. Haskell's do expressions provide a convenient syntax for writing monadic expressions. + +```haskell +class Applicative m => Monad m where + (>>=) :: m a -> (a -> m b) -> m b + (>>) :: m a -> m b -> m b + return :: a -> m a +``` + +Function `return` work just as `pure` in `Functor`. The `>>` is sequencing operator and `>>=` is bind. Also there are functions `liftM` and laws: + +```haskell +-- identity +return a >>= k == k a +m >>= return == m +-- associativity +(m >>= f) >>= g = m >>= (\x -> f x >>= g) +``` + +``` +-- TODO play with applicative and operators +``` + +### Do syntax + +Using `do` blocks as an alternative monad syntax was first introduced way back in the Simple input and output chapter. There, we used do to sequence input/output operations, but we hadn't introduced monads yet. Now, we can see that IO is yet another monad. + +Following are equivalent: + +```haskell +main = + putStr "Hello" >> + putStr " " >> + putStr "world!" >> + putStr "\n" +``` + +```haskell +main = do + { putStr "Hello" + ; putStr " " + ; putStr "world!" + ; putStr "\n" } +``` + +```haskell +main = do + putStr "Hello" + putStr " " + putStr "world!" + putStr "\n" +``` + +### IO Monad + +Haskell separates pure functions from computations where side effects must be considered by encoding those side effects as values of a particular type. Specifically, a value of type (IO a) is an action, which if executed would produce a value of type a. + +Some examples: + +```haskell +getLine :: IO String +putStrLn :: String -> IO () -- note that the result value is an empty tuple. +randomRIO :: (Random a) => (a,a) -> IO a +``` + +## Task assignment + +## Further reading + +* [Functors, Applicatives, And Monads In Pictures](http://adit.io/posts/2013-04-17-functors,_applicatives,_and_monads_in_pictures.html) +* [Monad](https://wiki.haskell.org/Monad) +* [IO Monad](https://wiki.haskell.org/Introduction_to_IO) From 5b6392f0b7f05d2a011909be544d5097ab3c14f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Wed, 14 Mar 2018 11:34:57 +0100 Subject: [PATCH 02/14] Improved outline, refs and hw info --- tutorials/06_common-typeclasses-1.md | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/tutorials/06_common-typeclasses-1.md b/tutorials/06_common-typeclasses-1.md index 7c152b4..0adf979 100644 --- a/tutorials/06_common-typeclasses-1.md +++ b/tutorials/06_common-typeclasses-1.md @@ -8,6 +8,12 @@ After learning common typeclasses it is not just easier to use them and understa // math, category theory +### Category theory + + +### The Hask category + + ## Monoid (and others from basic algebra) Monoid is the most simple typeclass we will learn. You can recall the [monoid](https://en.wikipedia.org/wiki/Monoid) them from algebra - it is algebraic structure with one binary operation which is associate and there is also one identity element. Same goes for Haskell - the operation is called `mappend` and identity is `mempty` (first letter `m` if for **m**onoid). @@ -78,7 +84,11 @@ Just as with Monoid, you can take a look at the documentation of [Data.Functor]( -- TODO play with functors and operators ``` -*TODO*: IO Functor, lifting, forall +### Lifting + +### Functors on Hask category + +### forall quantification ## Applicative @@ -119,6 +129,8 @@ u <*> pure y = pure ($ y) <*> u -- TODO play with applicative and operators ``` +### Lifting + ## Monad The most famous and scary typeclass for Haskell students is [Control.Monad](https://hackage.haskell.org/package/base/docs/Control-Monad.html). It defines the basic operations over a monad, a concept from a branch of mathematics known as category theory. From the perspective of a Haskell programmer, however, it is best to think of a monad as an abstract datatype of actions. Haskell's do expressions provide a convenient syntax for writing monadic expressions. @@ -174,6 +186,8 @@ main = do putStr "\n" ``` +### Monads in category theory + ### IO Monad Haskell separates pure functions from computations where side effects must be considered by encoding those side effects as values of a particular type. Specifically, a value of type (IO a) is an action, which if executed would produce a value of type a. @@ -188,8 +202,12 @@ randomRIO :: (Random a) => (a,a) -> IO a ## Task assignment +The homework to practice typeclasses from this tutorial [MI-AFP/hw06](https://github.com/MI-AFP/hw06). + ## Further reading * [Functors, Applicatives, And Monads In Pictures](http://adit.io/posts/2013-04-17-functors,_applicatives,_and_monads_in_pictures.html) -* [Monad](https://wiki.haskell.org/Monad) -* [IO Monad](https://wiki.haskell.org/Introduction_to_IO) +* [Haskell and Category Theory](https://en.wikibooks.org/wiki/Haskell/Category_theory) +* [Haskell - Typoclassopedia](https://wiki.haskell.org/Typeclassopedia) +* [Haskell - Monad](https://wiki.haskell.org/Monad) +* [Haskell - IO Monad](https://wiki.haskell.org/Introduction_to_IO) From db74e9998c2d217d3665d70e692ff57c59d6039d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Thu, 15 Mar 2018 15:46:29 +0100 Subject: [PATCH 03/14] Brief intro to category theory --- tutorials/06_common-typeclasses-1.md | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/tutorials/06_common-typeclasses-1.md b/tutorials/06_common-typeclasses-1.md index 0adf979..b7f5add 100644 --- a/tutorials/06_common-typeclasses-1.md +++ b/tutorials/06_common-typeclasses-1.md @@ -6,13 +6,33 @@ After learning common typeclasses it is not just easier to use them and understa ## Intro: Mathematical foundations -// math, category theory +Relation between math and Haskell is very strong. You can observe it everywhere. Functions are very similar to mathematical functions when you talk about their type, definitions with `let` and `where` keywords, guards with `otherwise`, function compositions, and so on. In this tutorial we are going to see this relation even more - with typeclasses that come from mathematical world. You should be already familiar with basic abstract algebra (esp. algebraic structures with a single binary operation). + +When getting into math, you should know that Haskell is based not just on the basic algebra, set theory, and logics, but also on the category theory. In order to sometimes mention the relation we will briefly explain what is it about. If you want to know more, please lookup some mathematical tutorials on your own. ### Category theory +Category theory is on higher abstract level than *Monoid*, *Semigroup*, and similar algebraic structures. A **category** is also a structure or collection *C* with three components: + +* a collection of **objects**, *ob(C)*, +* a collection of **morphisms**, *hom(C)*, that ties two objects together and sometimes they are called **arrows**, +* a **composition** of morphisms (similar to function composition). + +There are many categories, for example, **Set** category has all possible sets as objects, standard functions as morphisms, and classical function composition. There are also three laws: + +1. the composition of category must be associative (i.e., *f ∘ (g ∘ h) = (f ∘ g) ∘ h*), +2. the category needs to be closed under the composition operation (i.e., for all applies *h = f ∘ g ⇒ h ∈ C*), +3. for every object *A ∈ ob(C)* there is an identity function *idA: A → A*, *idA ∈ hom(C)*. ### The Hask category +In Haskell, we have the **Hask** category where: + +* *ob(Hask)* are **types** (`Char`, `Int`, `Double`, `[Integer]`, `Person`, `Int -> String`, etc.), +* *hom(C)* are **functions** (`show`, `id`, `length`, `words`, `flip`, `reverse`, etc.), +* composition is **function composition** `(.)`. + +The identity function is for every *o ∈ ob(Hask)* the polymorphic `id` function. The associativity of composition is assured and in *hom(C)* are all the functions, even those created by composition. That's it - now we will show some typeclasses, their laws and come back to **Hask** when necessary... ## Monoid (and others from basic algebra) From 24c8c3f278546c3b9cdcebdcd724e3f4936830dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Mon, 2 Apr 2018 15:49:23 +0200 Subject: [PATCH 04/14] Renumbering file and hw --- .../{06_common-typeclasses-1.md => 07_common-typeclasses-1.md} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename tutorials/{06_common-typeclasses-1.md => 07_common-typeclasses-1.md} (98%) diff --git a/tutorials/06_common-typeclasses-1.md b/tutorials/07_common-typeclasses-1.md similarity index 98% rename from tutorials/06_common-typeclasses-1.md rename to tutorials/07_common-typeclasses-1.md index b7f5add..814d7af 100644 --- a/tutorials/06_common-typeclasses-1.md +++ b/tutorials/07_common-typeclasses-1.md @@ -222,7 +222,7 @@ randomRIO :: (Random a) => (a,a) -> IO a ## Task assignment -The homework to practice typeclasses from this tutorial [MI-AFP/hw06](https://github.com/MI-AFP/hw06). +The homework to practice typeclasses from this tutorial is in repository [MI-AFP/hw07](https://github.com/MI-AFP/hw07). ## Further reading From d26199a13bfd24ac70323e25c433b425c25c5468 Mon Sep 17 00:00:00 2001 From: Robert Pergl Date: Thu, 5 Apr 2018 08:43:05 +0200 Subject: [PATCH 05/14] revisions --- tutorials/06_common-typeclasses-1.md | 95 +++++++++++++++++++++------- 1 file changed, 71 insertions(+), 24 deletions(-) diff --git a/tutorials/06_common-typeclasses-1.md b/tutorials/06_common-typeclasses-1.md index b7f5add..c9f82e1 100644 --- a/tutorials/06_common-typeclasses-1.md +++ b/tutorials/06_common-typeclasses-1.md @@ -1,28 +1,30 @@ # Common typeclasses I -Now we are going to spend some with predefined and important typeclasses which capture some important concepts in Haskell that are widely used in any types of projects. Typeclass always say something about the structure of type and what can you do with that. Also there are some laws and it is very tightly related to math and specifically with algebra and theory of categories. +Now we are going to spend some time with predefined and important typeclasses that capture important concepts in Haskell that are widely used in many projects. Typeclass always says something about the structure of type and what you can do with that. Also, there are some laws and it is very tightly related to math -- specifically the algebra and the category theory. -After learning common typeclasses it is not just easier to use them and understand code written by other developer but it also helps with designing own custom typeclasses. You can always find more about typeclass and instances with GHCi `:info` command. +After learning common typeclasses, it is not just easier to use them and understand a code written by other developer, but it also helps with designing own custom typeclasses. You can always find out more about typeclass and instances with GHCi `:info` command. ## Intro: Mathematical foundations -Relation between math and Haskell is very strong. You can observe it everywhere. Functions are very similar to mathematical functions when you talk about their type, definitions with `let` and `where` keywords, guards with `otherwise`, function compositions, and so on. In this tutorial we are going to see this relation even more - with typeclasses that come from mathematical world. You should be already familiar with basic abstract algebra (esp. algebraic structures with a single binary operation). +The relation between math and Haskell is very strong. You can observe it everywhere. Haskell functions are very similar to mathematical functions when you talk about their type, definitions with `let` and `where` keywords, guards with `otherwise`, function compositions, and so on. In this tutorial we are going to see this relation even more -- with typeclasses that come from mathematical world. You should be already familiar with [basic abstract algebra](https://en.wikipedia.org/wiki/Algebra#Abstract_algebra) (esp. algebraic structures with a single binary operation). -When getting into math, you should know that Haskell is based not just on the basic algebra, set theory, and logics, but also on the category theory. In order to sometimes mention the relation we will briefly explain what is it about. If you want to know more, please lookup some mathematical tutorials on your own. +When getting into math, you should know that Haskell is based not just on the basic algebra, set theory, and logic, but also on the category theory. In order to sometimes mention the relation, we will briefly explain what it is about. If you want to know more, please refer to some mathematical tutorials on your own. ### Category theory -Category theory is on higher abstract level than *Monoid*, *Semigroup*, and similar algebraic structures. A **category** is also a structure or collection *C* with three components: +Category theory is a higher abstraction level over *Monoid*, *Semigroup*, and similar algebraic structures. Actually, it is so abstract that it can describe so many things ... that it is very hard to comprehend. The "best practice" among programmers is to learn it bit by bit and return to it from time to time until things "click" together. This "click" means putting together the theory and its practical applications. + +A **category** is a structure or collection *C* with three components: * a collection of **objects**, *ob(C)*, -* a collection of **morphisms**, *hom(C)*, that ties two objects together and sometimes they are called **arrows**, +* a collection of **morphisms**, *hom(C)*, that ties two objects together; sometimes they are called **arrows**, * a **composition** of morphisms (similar to function composition). There are many categories, for example, **Set** category has all possible sets as objects, standard functions as morphisms, and classical function composition. There are also three laws: 1. the composition of category must be associative (i.e., *f ∘ (g ∘ h) = (f ∘ g) ∘ h*), 2. the category needs to be closed under the composition operation (i.e., for all applies *h = f ∘ g ⇒ h ∈ C*), -3. for every object *A ∈ ob(C)* there is an identity function *idA: A → A*, *idA ∈ hom(C)*. +3. for every object *A ∈ ob(C)* there is an identity function *idA: A → A*, *idA ∈ hom(C)*. ### The Hask category @@ -32,11 +34,11 @@ In Haskell, we have the **Hask** category where: * *hom(C)* are **functions** (`show`, `id`, `length`, `words`, `flip`, `reverse`, etc.), * composition is **function composition** `(.)`. -The identity function is for every *o ∈ ob(Hask)* the polymorphic `id` function. The associativity of composition is assured and in *hom(C)* are all the functions, even those created by composition. That's it - now we will show some typeclasses, their laws and come back to **Hask** when necessary... +The identity function is for every *o ∈ ob(Hask)* the polymorphic `id` function. The associativity of composition is assured and in *hom(C)* there are all the functions, even those created by composition. That's it for now -- now we will show some typeclasses, their laws and come back to **Hask** when necessary... ## Monoid (and others from basic algebra) -Monoid is the most simple typeclass we will learn. You can recall the [monoid](https://en.wikipedia.org/wiki/Monoid) them from algebra - it is algebraic structure with one binary operation which is associate and there is also one identity element. Same goes for Haskell - the operation is called `mappend` and identity is `mempty` (first letter `m` if for **m**onoid). +Monoid is the most simple typeclass we will learn. You can recall the [monoid](https://en.wikipedia.org/wiki/Monoid) from the algebra -- it is an algebraic structure with one binary operation that is associate and there is also one identity element. The same goes for Haskell -- the operation is called `mappend` and the identity is `mempty` (first letter `m` if for **m**onoid). ```haskell class Monoid m where @@ -46,7 +48,7 @@ class Monoid m where mconcat = foldr mappend mempty ``` -The law of monoid says that `mappend` must be associative and `mempty` is real identity when working with `mappend`: +The law of monoid says that `mappend` must be associative and `mempty` is a real identity when working with `mappend`: ```haskell mappend x (mappend y z) == mappend (mappend x y) z @@ -67,23 +69,45 @@ If you take a look at the documentation of [Data.Monoid](https://hackage.haskell -- TODO: First & Last ``` -Of course there are not just `Monoid` from basic algebra. You might find interesting to learn more about: +One of very practical usages of `mappend` is string concatenation, which is independent on its concrete implementation: + +```haskell +{-# LANGUAGE OverloadedStrings #-} +import Data.Text (Text) + +s1 :: String +s1 = "hello" +s2 :: String +s2 = "monoid" + +t1 :: Text +t1 = "hello" +t2 :: Text +t2 = "monoid" + +s1 <> ", " <> s2 -- instead of s1 ++ ", " ++ s2 +t1 <> ", " <> t2 -- works the same for text! +``` + +Here, obviously `mappend` is string concatenation and `mempty = ""`. + +Apart from basic `Monoid` from algebra, there are also other variants. You might find interesting to learn more about: * [Data.Semigroup](https://hackage.haskell.org/package/base/docs/Data-Semigroup.html) (no identity as is in Monoid), * [Data.Group, Data.Abelian](https://hackage.haskell.org/package/groups-0.4.0.0/docs/Data-Group.html) (inversions and commutative operation). -It is possible to write own instances of `Monoid` or other typeclasses. Problem is that compiler won't check if laws are valid in your instance. For such checks you can use testing frameworks (esp. property testing) which will be covered later on. +It is possible to write own instances of `Monoid` or other typeclasses. However, mind that compiler *won't* check if laws are valid in your instance. For such checks you can use testing frameworks (esp. property testing), which will be covered later on. ## Functor -A functor is a way to apply a function on values inside some structure that we don’t want to change. For example if you want to change the values in the list, tree or in either without dealing with complexity and internal structure. +A functor is a way to apply a function on values inside some structure, while the structure remains intact. For example, if you want to change values in a list, tree or in Either without dealing with complexity and internal structure. ```haskell class Functor f where fmap :: (a -> b) -> f a -> f b ``` -The definition says that there is a function `fmap` which applies a function of type `a -> b` on elements in functor `f` with inner type `a` and result will be functor `f` with inner type `b`. Moreover there are two laws: +The definition says that there is a function `fmap` which applies a function of type `a -> b` on elements in functor `f` with inner type `a` and the result will be functor `f` with inner type `b`. Moreover there are two laws: ```haskell -- identity (fmap doesn't do nothing more than applying given function) @@ -98,12 +122,16 @@ Let's try it: -- TODO play with functors ``` -Just as with Monoid, you can take a look at the documentation of [Data.Functor](https://hackage.haskell.org/package/base/docs/Data-Functor.html). Again, there is operator alias, in this case `(<$>)` for `fmap`. There are two more similar - `<$` and `$>` (just flipped `<$`). +Just as with Monoid, you can take a look at the documentation of [Data.Functor](https://hackage.haskell.org/package/base/docs/Data-Functor.html). Again, there is an operator alias, in this case `(<$>)` for `fmap` (denoting a sort of "wrapped" or "inside" apply). There are two more similar -- `<$` and `$>` (just flipped `<$`). ``` -- TODO play with functors and operators ``` +```diff ++klidne pouzij neco z LYAH nebo Haskell book +``` + ### Lifting ### Functors on Hask category @@ -112,7 +140,9 @@ Just as with Monoid, you can take a look at the documentation of [Data.Functor]( ## Applicative -Next important typeclass is [Control.Applicate](https://hackage.haskell.org/package/base/docs/Control-Applicative.html). Notice that it is not "Data" anymore, but "Control" instead! It is intermediate structure between a `Functor` and a `Monad`. It is simpler than `Monad`, not so powerful, but sufficient in many use cases, and also easier to understand. +Another important typeclass is [Control.Applicate](https://hackage.haskell.org/package/base/docs/Control-Applicative.html). Notice that it is not "Data" anymore, but "Control" instead! It is an intermediate structure between a `Functor` and a `Monad`. It is simpler than `Monad`, not so powerful, but sufficient in many use cases, and also easier to understand. + +In monoid, we applied a function over a "wrapped" value to get a resulting "wrapped" value. In applicative, we have the function wrapped, as well: ```haskell class Functor f => Applicative f where @@ -120,7 +150,7 @@ class Functor f => Applicative f where (<*>) :: f (a -> b) -> f a -> f b ``` -Function `pure` only lifts something into applicative structure `f`. The more interesting part is the "tie-fighter" operator `<*>` which applies lifted function over applicative. You can find out in the documentation following similar functions and partial functions as in [Data.Functor](https://hackage.haskell.org/package/base/docs/Data-Functor.html): +Function `pure` only lifts something into applicative structure `f`. The more interesting part is the ["tie-fighter"](http://starwars.wikia.com/wiki/TIE/LN_starfighter) operator `<*>` that applies a lifted function over an applicative. You can find out in the documentation following similar functions and partial functions as in [Data.Functor](https://hackage.haskell.org/package/base/docs/Data-Functor.html): ```haskell (<*) :: f a -> f b -> f a @@ -144,7 +174,6 @@ pure f <*> pure x = pure (f x) u <*> pure y = pure ($ y) <*> u ``` - ``` -- TODO play with applicative and operators ``` @@ -153,7 +182,7 @@ u <*> pure y = pure ($ y) <*> u ## Monad -The most famous and scary typeclass for Haskell students is [Control.Monad](https://hackage.haskell.org/package/base/docs/Control-Monad.html). It defines the basic operations over a monad, a concept from a branch of mathematics known as category theory. From the perspective of a Haskell programmer, however, it is best to think of a monad as an abstract datatype of actions. Haskell's do expressions provide a convenient syntax for writing monadic expressions. +The most famous (and scary :-) typeclass for Haskell students is [Control.Monad](https://hackage.haskell.org/package/base/docs/Control-Monad.html). It defines basic operations over a monad, a term from category theory. From the perspective of a Haskell programmer, however, it is best to think of a monad as an "abstract datatype of actions". Haskell's `do` expressions provide a convenient syntax for writing monadic expressions. ```haskell class Applicative m => Monad m where @@ -162,7 +191,13 @@ class Applicative m => Monad m where return :: a -> m a ``` -Function `return` work just as `pure` in `Functor`. The `>>` is sequencing operator and `>>=` is bind. Also there are functions `liftM` and laws: +Function `return` works just as `pure` in `Functor`. Why having two same functions? Historically; PureScript for instance has just `pure` both for the Functor and Monad. + +`>>=` is bind, which takes a monadic value (again, this is some "wrapped value") and a function, which takes an unwrapped value and transforms it into a monadic value. + +`>>` is a sequencing operator, which "passes" computation from monad to another. + +Again, there are functions `liftM` and laws: ```haskell -- identity @@ -178,18 +213,19 @@ m >>= return == m ### Do syntax -Using `do` blocks as an alternative monad syntax was first introduced way back in the Simple input and output chapter. There, we used do to sequence input/output operations, but we hadn't introduced monads yet. Now, we can see that IO is yet another monad. +Using `do` blocks as an alternative monad syntax was first introduced way back in the :"Simple input and output" chapter. There, we used do to sequence input/output operations, but we hadn't introduced monads yet. Now, we can see that IO is yet another monad. -Following are equivalent: +Imagine we have a sequence operation like this: ```haskell -main = putStr "Hello" >> putStr " " >> putStr "world!" >> putStr "\n" ``` +Now we can chain it using do: + ```haskell main = do { putStr "Hello" @@ -198,6 +234,8 @@ main = do ; putStr "\n" } ``` +or + ```haskell main = do putStr "Hello" @@ -206,11 +244,19 @@ main = do putStr "\n" ``` +This becomes translated to: + +```haskell +action1 >> +do { action2 + ; action3 } +``` + ### Monads in category theory ### IO Monad -Haskell separates pure functions from computations where side effects must be considered by encoding those side effects as values of a particular type. Specifically, a value of type (IO a) is an action, which if executed would produce a value of type a. +Haskell separates pure functions from computations where side effects must be considered by encoding those side effects as values of a particular type. Specifically, a value of type (IO a) is an action, which executed produces a value of type a. Some examples: @@ -228,6 +274,7 @@ The homework to practice typeclasses from this tutorial [MI-AFP/hw06](https://gi * [Functors, Applicatives, And Monads In Pictures](http://adit.io/posts/2013-04-17-functors,_applicatives,_and_monads_in_pictures.html) * [Haskell and Category Theory](https://en.wikibooks.org/wiki/Haskell/Category_theory) +* [Category Theory for Programmers by Bartosz Milewski](https://bartoszmilewski.com/2014/10/28/category-theory-for-programmers-the-preface) * [Haskell - Typoclassopedia](https://wiki.haskell.org/Typeclassopedia) * [Haskell - Monad](https://wiki.haskell.org/Monad) * [Haskell - IO Monad](https://wiki.haskell.org/Introduction_to_IO) From 94c4987c1b4858df494a4bf390a555e3c41f7cfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Sat, 7 Apr 2018 13:11:12 +0200 Subject: [PATCH 06/14] Monoid and Semigroup done --- tutorials/07_common-typeclasses-1.md | 68 ++++++++++++++++++++++++---- 1 file changed, 60 insertions(+), 8 deletions(-) diff --git a/tutorials/07_common-typeclasses-1.md b/tutorials/07_common-typeclasses-1.md index 4ee5967..1ced87b 100644 --- a/tutorials/07_common-typeclasses-1.md +++ b/tutorials/07_common-typeclasses-1.md @@ -36,16 +36,22 @@ In Haskell, we have the **Hask** category where: The identity function is for every *o ∈ ob(Hask)* the polymorphic `id` function. The associativity of composition is assured and in *hom(C)* there are all the functions, even those created by composition. That's it for now -- now we will show some typeclasses, their laws and come back to **Hask** when necessary... -## Monoid (and others from basic algebra) +## Semigroup, Monoid, ... Monoid is the most simple typeclass we will learn. You can recall the [monoid](https://en.wikipedia.org/wiki/Monoid) from the algebra -- it is an algebraic structure with one binary operation that is associate and there is also one identity element. The same goes for Haskell -- the operation is called `mappend` and the identity is `mempty` (first letter `m` if for **m**onoid). +Since `base-4.11.0.0`, the `Monoid` is subclass of `Semigroup` (just like in algebra). `Semigroup` defines just binary operation which is associative. In Haskell, the binary operation is `(<>)` (infixr 6) + ```haskell -class Monoid m where - mempty :: m +class Semigroup s where + (<>) :: s -> s -> s -- binary associative operation + +class Semigroup m => Monoid m where + mempty :: m -- identity of mappend mappend :: m -> m -> m + mappend = (<>) -- binary operation from Semigroup mconcat :: [m] -> m - mconcat = foldr mappend mempty + mconcat = foldr mappend mempty -- fold with mappend (catamorphism) ``` The law of monoid says that `mappend` must be associative and `mempty` is a real identity when working with `mappend`: @@ -64,11 +70,31 @@ If you take a look at the documentation of [Data.Monoid](https://hackage.haskell * synonym for `mappend` is `(<>)` so you can simply use it as operator `x <> b` (notice that it is not the same as not-equals in other languages), * multiple newtypes for specifying monoid for basic type, like `Sum` and `Product` for numeric types, `All` and `Any` for booleans, `First` and `Last` for maybes and few more. + ```haskell --- TODO: Sum & Product --- TODO: First & Last +Prelude> import Data.Monoid +Prelude Data.Monoid> :info Sum +newtype Sum a = Sum {getSum :: a} -- Defined in ‘Data.Monoid’ +... +Prelude Data.Monoid> :info Product +newtype Product a = Product {getProduct :: a} +... +Prelude Data.Monoid> (Product 5) <> (Product 2) +Product {getProduct = 10} +Prelude Data.Monoid> mempty :: Product Int +Product {getProduct = 1} +Prelude Data.Monoid> (Sum 5) <> (Sum 2) +Sum {getSum = 7} +Prelude Data.Monoid> mempty :: Sum Int +Sum {getSum = 0} +Prelude Data.Monoid> mconcat (map Sum [1..5]) +Sum {getSum = 15} +Prelude Data.Monoid> mconcat (map Product [1..5]) +Product {getProduct = 120} ``` +### Example: textual types + One of very practical usages of `mappend` is string concatenation, which is independent on its concrete implementation: ```haskell @@ -91,10 +117,36 @@ t1 <> ", " <> t2 -- works the same for text! Here, obviously `mappend` is string concatenation and `mempty = ""`. +### Example: Maybe + +From `:info Monoid`, we can see that `Maybe a` is instance of `Monoid` iff (=if and only if) `a` is instance of `Monoid`. Then, the `(<>)` is "propagated" inside and obviously the identity is `Nothing`. + +``` +Prelude Data.Maybe Data.Semigroup> (Just "a") <> (Just "b") +Just "ab" +Prelude Data.Maybe Data.Semigroup> (Just "a") <> Nothing +Just "a" +Prelude Data.Maybe Data.Semigroup> (Just "a") <> Nothing <> (Just "b") +Just "ab" +Prelude Data.Maybe Data.Semigroup> Nothing <> Nothing +Nothing +Prelude Data.Maybe Data.Semigroup> mconcat [Just "a", Nothing, Just "b"] +Just "ab" +Prelude Data.Maybe Data.Semigroup> mempty :: Maybe String +Nothing +``` + +### Verify the laws + +As said, there are some laws (identity and associativity in this case) that should be valid, but the compiler can not enforce it. Whenever you are introducing your own instance of `Monoid` or other structure with some laws that are expected to be valid, use tests to prove it. One way is to write the properties on your own. The second and better one is to use [checkers](https://hackage.haskell.org/package/checkers), where many standard properties are prepared for you... + +### Others from basic algebra + Apart from basic `Monoid` from algebra, there are also other variants. You might find interesting to learn more about: -* [Data.Semigroup](https://hackage.haskell.org/package/base/docs/Data-Semigroup.html) (no identity as is in Monoid), -* [Data.Group, Data.Abelian](https://hackage.haskell.org/package/groups-0.4.0.0/docs/Data-Group.html) (inversions and commutative operation). +* [semigrupoids](https://hackage.haskell.org/package/semigroupoids/docs/Data-Groupoid.html) (Semigrupoid, Grupoid), +* [groups](https://hackage.haskell.org/package/groups/docs/Data-Group.html) (Group, Abelian), +* etc. It is possible to write own instances of `Monoid` or other typeclasses. However, mind that compiler *won't* check if laws are valid in your instance. For such checks you can use testing frameworks (esp. property testing), which will be covered later on. From 2733406279105ec9a5679d4d23522dd62a8ab4e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Sat, 7 Apr 2018 14:26:21 +0200 Subject: [PATCH 07/14] Functor: Lifting and Math --- tutorials/07_common-typeclasses-1.md | 52 ++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/tutorials/07_common-typeclasses-1.md b/tutorials/07_common-typeclasses-1.md index 1ced87b..909d634 100644 --- a/tutorials/07_common-typeclasses-1.md +++ b/tutorials/07_common-typeclasses-1.md @@ -155,7 +155,7 @@ It is possible to write own instances of `Monoid` or other typeclasses. However, A functor is a way to apply a function on values inside some structure, while the structure remains intact. For example, if you want to change values in a list, tree or in Either without dealing with complexity and internal structure. ```haskell -class Functor f where +class Functor f where -- f is type constructor of kind * -> * fmap :: (a -> b) -> f a -> f b ``` @@ -186,9 +186,57 @@ Just as with Monoid, you can take a look at the documentation of [Data.Functor]( ### Lifting +[Lifting](https://wiki.haskell.org/Lifting) is a concept which allows you to transform a function into a corresponding function within another (usually more general) setting. Lifting is again concept taken from mathematics and category theory (see [wikipedia](https://en.wikipedia.org/wiki/Lift_(mathematics)). + +```haskell + +data Point2D a = Point2D a a + deriving Show + +instance Functor Point2D where + fmap f (Point2D x y) = Point2D (f x) (f y) + +liftF0 :: a -> Point2D a +liftF0 x = Point2D x x + +liftF1 :: (a -> b) -> Point2D a -> Point2D b +liftF1 = fmap + +liftF2 :: (a -> b -> r) -> Point2D a -> Point2D b -> Point2D r +liftF2 f (Point2D x1 x2) (Point2D y1 y2) = Point2D (f x1 y1) (f x2 y2) + +origin :: Point2D Int +origin = liftF0 0 + +doublePoint :: Point2D Int -> Point2D Int +doublePoint = liftF1 (*2) + +plusPoints :: Point2D Int -> Point2D Int -> Point2D Int +plusPoints = liftF2 (+) +``` + + ### Functors on Hask category -### forall quantification +In mathematics, a functor is a type of mapping between categories arising in category theory. Functors can be thought of as homomorphisms between categories. In the category of small categories, functors can be thought of more generally as morphisms. ([wikipedia](https://en.wikipedia.org/wiki/Functor)) + +We have some categories which have objects and morphisms that relate our objects together. Functor *F: C → D* relates categories *C* and *D* together - it is a transformation between categories: + +- maps every object *A* from category *C* to object *F(A)* in category *D* +- maps every morphism *f: A → B* from category *C* to morphism *F(f): F(A) → F(B)* in category *D* + +```haskell +class Functor (f :: * -> *) where + fmap :: (a -> b) -> f a -> f b -- maps A->B to F(A) -> F(B) as well as A to F(A) +``` + +There is also identity for functions and they must be homomorphic that, of course, apply for functors in Haskell: + +```haskell +fmap id == id + +fmap (f . g) = fmap f . fmap g +``` ## Applicative From 636fcfe95431778a38bc5c6d317eebd7842978be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Sat, 7 Apr 2018 15:09:27 +0200 Subject: [PATCH 08/14] Functors done --- tutorials/07_common-typeclasses-1.md | 40 +++++++++++++++++++++------- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/tutorials/07_common-typeclasses-1.md b/tutorials/07_common-typeclasses-1.md index 909d634..e836dab 100644 --- a/tutorials/07_common-typeclasses-1.md +++ b/tutorials/07_common-typeclasses-1.md @@ -168,21 +168,43 @@ fmap id == id fmap (f . g) == fmap f . fmap g ``` -Let's try it: +Let's try it with basic containers like list, `Maybe`, and `Either`: ``` --- TODO play with functors +Prelude> fmap (*2) [1..5] -- just like map! +[2,4,6,8,10] +Prelude> fmap (show . (*2)) [1..5] -- just like map! +["2","4","6","8","10"] +Prelude> fmap (*2) (Just 7) +Just 14 +Prelude> fmap (*2) Nothing +Nothing +Prelude> fmap (+10) (Left 5) +Left 5 -- no change! +Prelude> fmap (+10) (Right 5) +Right 10 -- changed, because "Either c" is functor for whatever "c" - it doesnt care ``` -Just as with Monoid, you can take a look at the documentation of [Data.Functor](https://hackage.haskell.org/package/base/docs/Data-Functor.html). Again, there is an operator alias, in this case `(<$>)` for `fmap` (denoting a sort of "wrapped" or "inside" apply). There are two more similar -- `<$` and `$>` (just flipped `<$`). +Just as with Monoid, you can take a look at the documentation of [Data.Functor](https://hackage.haskell.org/package/base/docs/Data-Functor.html). Again, there is an operator alias, in this case `(<$>)` for `fmap` (denoting a sort of "wrapped" or "inside" apply). There are two more -- `<$` and `$>` (just flipped `<$`). Flipped version of `(<$>)` is `(<&>)`. ``` --- TODO play with functors and operators +Prelude Data.Functor> (*2) <$> [1..5] +[2,4,6,8,10] +Prelude Data.Functor> [1..5] <&> (*2) +[2,4,6,8,10] +Prelude Data.Functor> 2 <$ [1..5] +[2,2,2,2,2] +Prelude Data.Functor> [1..5] $> 2 +[2,2,2,2,2] +Prelude> (*2) <$> (Just 7) +Just 14 +Prelude> 2 <$ (Just 7) +Just 2 +Prelude> (Just 7) $> 2 +Just 2 ``` -```diff -+klidne pouzij neco z LYAH nebo Haskell book -``` +These examples might seem bit too simple, but you can have any instance of `Functor` without knowing the structure and implementation of it and affect what is inside by these two (four if counting also flipped) simple operators. ### Lifting @@ -202,7 +224,7 @@ liftF0 x = Point2D x x liftF1 :: (a -> b) -> Point2D a -> Point2D b liftF1 = fmap -liftF2 :: (a -> b -> r) -> Point2D a -> Point2D b -> Point2D r +liftF2 :: (a -> b -> c) -> Point2D a -> Point2D b -> Point2D c liftF2 f (Point2D x1 x2) (Point2D y1 y2) = Point2D (f x1 y1) (f x2 y2) origin :: Point2D Int @@ -215,7 +237,6 @@ plusPoints :: Point2D Int -> Point2D Int -> Point2D Int plusPoints = liftF2 (+) ``` - ### Functors on Hask category In mathematics, a functor is a type of mapping between categories arising in category theory. Functors can be thought of as homomorphisms between categories. In the category of small categories, functors can be thought of more generally as morphisms. ([wikipedia](https://en.wikipedia.org/wiki/Functor)) @@ -280,6 +301,7 @@ u <*> pure y = pure ($ y) <*> u ### Lifting + ## Monad The most famous (and scary :-) typeclass for Haskell students is [Control.Monad](https://hackage.haskell.org/package/base/docs/Control-Monad.html). It defines basic operations over a monad, a term from category theory. From the perspective of a Haskell programmer, however, it is best to think of a monad as an "abstract datatype of actions". Haskell's `do` expressions provide a convenient syntax for writing monadic expressions. From 0c30118413d9c980d48f3bcfa84361567e52015a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Sat, 7 Apr 2018 16:52:02 +0200 Subject: [PATCH 09/14] Applicative done + start Monad --- tutorials/07_common-typeclasses-1.md | 82 +++++++++++++++++++++++----- 1 file changed, 69 insertions(+), 13 deletions(-) diff --git a/tutorials/07_common-typeclasses-1.md b/tutorials/07_common-typeclasses-1.md index e836dab..dbd38b8 100644 --- a/tutorials/07_common-typeclasses-1.md +++ b/tutorials/07_common-typeclasses-1.md @@ -71,7 +71,7 @@ If you take a look at the documentation of [Data.Monoid](https://hackage.haskell * multiple newtypes for specifying monoid for basic type, like `Sum` and `Product` for numeric types, `All` and `Any` for booleans, `First` and `Last` for maybes and few more. -```haskell +``` Prelude> import Data.Monoid Prelude Data.Monoid> :info Sum newtype Sum a = Sum {getSum :: a} -- Defined in ‘Data.Monoid’ @@ -261,14 +261,16 @@ fmap (f . g) = fmap f . fmap g ## Applicative -Another important typeclass is [Control.Applicate](https://hackage.haskell.org/package/base/docs/Control-Applicative.html). Notice that it is not "Data" anymore, but "Control" instead! It is an intermediate structure between a `Functor` and a `Monad`. It is simpler than `Monad`, not so powerful, but sufficient in many use cases, and also easier to understand. +Another important typeclass is [Control.Applicate](https://hackage.haskell.org/package/base/docs/Control-Applicative.html). Notice that it is not "Data" anymore, but "Control" instead! It is an intermediate structure between a `Functor` and a `Monad`. It is simpler than `Monad`, not so powerful, but sufficient in many use cases, and also easier to understand - it is **Applicative functor**. -In monoid, we applied a function over a "wrapped" value to get a resulting "wrapped" value. In applicative, we have the function wrapped, as well: +In fucntor, we applied a function over a "wrapped" value to get a resulting "wrapped" value. In applicative, we have the function wrapped, as well: ```haskell class Functor f => Applicative f where - pure :: a -> f a - (<*>) :: f (a -> b) -> f a -> f b + pure :: a -> f a -- lift a + (<*>) :: f (a -> b) -> f a -> f b -- sequential application + +--(<$>) :: (a -> b) -> f a -> f b -- this is from functor ``` Function `pure` only lifts something into applicative structure `f`. The more interesting part is the ["tie-fighter"](http://starwars.wikia.com/wiki/TIE/LN_starfighter) operator `<*>` that applies a lifted function over an applicative. You can find out in the documentation following similar functions and partial functions as in [Data.Functor](https://hackage.haskell.org/package/base/docs/Data-Functor.html): @@ -296,11 +298,47 @@ u <*> pure y = pure ($ y) <*> u ``` ``` --- TODO play with applicative and operators +Prelude> linfunc x = 2 * x + 10 +Prelude> (Just lin +lines linfunc +Prelude> (Just linfunc) <*> (Just 5) +Just 20 +Prelude> pure linfunc <*> (Just 5) +Just 20 +Prelude> pure linfunc <*> Nothing +Nothing +Prelude> Nothing <*> (Just 5) +Nothing +Prelude> (Just 5) <* (Just 10) +Just 5 +Prelude> (Just 5) *> (Just 10) +Just 10 + +Prelude> pure linfunc <*> (Left 7) +Left 7 +Prelude> pure linfunc <*> (Right 15) +Right 40 +Prelude> (Right 5) *> (Left 10) +Left 10 +Prelude> (Right 5) <* (Left 10) +Left 10 +Prelude Control.Applicative> (Right 15) <**> pure linfunc +Right 40 + +-- Lifts are already prepared in Control.Applicative +Prelude Control.Applicative> liftA2 (+) (Just 5) (Just 10) +Just 15 +Prelude Control.Applicative> liftA2 (+) (Just 5) Nothing +Nothing +Prelude Control.Applicative> liftA2 (+) (Left "error") (Right 7) +Left "error" +Prelude Control.Applicative> liftA2 (+) (Right 15) (Right 7) +Right 22 ``` -### Lifting +### Actions vs. functions +In Haskell terminology, we call `Functor f => f a` an **action**. Actions have the power to do some side effect but not necessarily (e.g., `Just "no effect"`). For example, `liftA2` is described as function that lifts a binary function to actions. Special sort of actions are I/O actions with do something with input and output, but there can be also other actions making side effects. ## Monad @@ -308,12 +346,16 @@ The most famous (and scary :-) typeclass for Haskell students is [Control.Monad] ```haskell class Applicative m => Monad m where - (>>=) :: m a -> (a -> m b) -> m b - (>>) :: m a -> m b -> m b - return :: a -> m a + (>>=) :: m a -> (a -> m b) -> m b -- compose two actions, passing the result + (>>) :: m a -> m b -> m b -- compose two actions, discarding the result + return :: a -> m a -- inject a value into the monadic type. + +-- (<**>):: f a -> f (a -> b) -> f b -- from Controll.Applicative +-- (*>) :: f a -> f b -> f b -- from Controll.Applicative +-- pure :: a -> f a -- from Controll.Applicative ``` -Function `return` works just as `pure` in `Functor`. Why having two same functions? Historically; PureScript for instance has just `pure` both for the Functor and Monad. +Function `return` works just as `pure` in `Applicative`. Why having two same functions? Historically; PureScript for instance has just `pure` both for the Applicative and Monad. `>>=` is bind, which takes a monadic value (again, this is some "wrapped value") and a function, which takes an unwrapped value and transforms it into a monadic value. @@ -330,7 +372,15 @@ m >>= return == m ``` ``` --- TODO play with applicative and operators +Prelude Control.Monad> (Just 5) >> (Just 10) +Just 10 +Prelude Control.Monad> (Just 5) >>= \x -> (Just (x+10)) +Just 15 +Prelude Control.Monad> return 5 >>= \x -> (Just (x+10)) +Just 15 + +Prelude Control.Monad> (Left "err") >>= (\x -> return (x+10)) +Left "err" ``` ### Do syntax @@ -376,7 +426,12 @@ do { action2 ### Monads in category theory -### IO Monad +Again, monad comes from math and more specifically from category theory. A monad is a special type of functor, from a category to that same category (i.e., it is *endofunctor*), that supports some additional structure. Monad is a functor *M: C → C* with two morphisms for every object *X* from *C*: + +1. *unit: X → M(X)* ~ `return :: Monad m => a -> m a` +2. *join: M(M(X)) → M(X)* ~ `(>>=) :: Monad m => m a -> (a -> m b) -> m b` + +## IO - What is it? Haskell separates pure functions from computations where side effects must be considered by encoding those side effects as values of a particular type. Specifically, a value of type (IO a) is an action, which executed produces a value of type a. @@ -397,6 +452,7 @@ The homework to practice typeclasses from this tutorial is in repository [MI-AFP * [Functors, Applicatives, And Monads In Pictures](http://adit.io/posts/2013-04-17-functors,_applicatives,_and_monads_in_pictures.html) * [Haskell and Category Theory](https://en.wikibooks.org/wiki/Haskell/Category_theory) * [Category Theory for Programmers by Bartosz Milewski](https://bartoszmilewski.com/2014/10/28/category-theory-for-programmers-the-preface) +* [LYAH - Functors, Applicative Functors and Monoids](http://learnyouahaskell.com/functors-applicative-functors-and-monoids) * [Haskell - Typoclassopedia](https://wiki.haskell.org/Typeclassopedia) * [Haskell - Monad](https://wiki.haskell.org/Monad) * [Haskell - IO Monad](https://wiki.haskell.org/Introduction_to_IO) From 3213d5eca58e696ef3be14c9037b56b41157926f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Sun, 8 Apr 2018 09:47:32 +0200 Subject: [PATCH 10/14] Monad and IO done --- tutorials/07_common-typeclasses-1.md | 98 +++++++++++++++++++++++++++- 1 file changed, 97 insertions(+), 1 deletion(-) diff --git a/tutorials/07_common-typeclasses-1.md b/tutorials/07_common-typeclasses-1.md index dbd38b8..7b0d555 100644 --- a/tutorials/07_common-typeclasses-1.md +++ b/tutorials/07_common-typeclasses-1.md @@ -342,7 +342,7 @@ In Haskell terminology, we call `Functor f => f a` an **action**. Actions have t ## Monad -The most famous (and scary :-) typeclass for Haskell students is [Control.Monad](https://hackage.haskell.org/package/base/docs/Control-Monad.html). It defines basic operations over a monad, a term from category theory. From the perspective of a Haskell programmer, however, it is best to think of a monad as an "abstract datatype of actions". Haskell's `do` expressions provide a convenient syntax for writing monadic expressions. +The most famous (and scary :-) typeclass for Haskell students is [Control.Monad](https://hackage.haskell.org/package/base/docs/Control-Monad.html). It defines basic operations over a monad, a term from category theory. From the perspective of a Haskell programmer, however, it is best to think of a monad as an "abstract datatype of actions". Haskell's `do` expressions provide a convenient syntax for writing monadic expressions. This time we will start Monads (operations, laws, basic behavior, etc.) and next time we will get deeper with some more practical use-cases. ```haskell class Applicative m => Monad m where @@ -424,6 +424,47 @@ do { action2 ; action3 } ``` +In `do`, you can also use `>>=` operator by binding `<-` and `let` instead of `let-in`: + +```haskell +main = do + putStrLn "Enter name:" + name <- getLine -- getLine >>= (\name -> ...) + putStrLn ("Hello, " ++ name ++ "!") + let answer = 42 -- let answer = 42 in (...) + putStrLn "The answer to life, the universe and everything is..." + print answer -- let and binding cannot be the last in do! +``` + +### Loops + +You might hear that "do" provides imperative-like way of programming... That's true but it is really just *imperative-like* from visual point of view, it is still purely functional! But even in math and functions you can introduce something like `for` or `while` loops. When you want to compute some result like factorial, sum, length of list it is natural to use recursion. With actions, it might give more sence to use loops (even when they are actually done by recursion): + +```haskell +import System.Random +import Control.Monad.Loops + +promptAnswer :: IO Int +promptAnswer = do + putStrLn "Guess the answer: " + x <- getLine + return (read x) + +guessAnswer :: Int -> IO Bool +guessAnswer x = do + guess <- promptAnswer + return (guess /= x) + +main = do + putStrLn "Welcome to GUESS 1 to 10 game" + answer <- randomRIO (1, 10) + whileM_ (guessAnswer answer) $ do -- whileM_ :: Monad m => m Bool -> m a -> m () + putStrLn "Incorrect!" + putStrLn "Good job!" +``` + +For other loops, visit [Control.Monad.Loops](https://hackage.haskell.org/package/monad-loops/docs/Control-Monad-Loops.html) and this [article](https://conscientiousprogrammer.com/blog/2015/12/11/24-days-of-hackage-2015-day-11-monad-loops-avoiding-writing-recursive-functions-by-refactoring/). + ### Monads in category theory Again, monad comes from math and more specifically from category theory. A monad is a special type of functor, from a category to that same category (i.e., it is *endofunctor*), that supports some additional structure. Monad is a functor *M: C → C* with two morphisms for every object *X* from *C*: @@ -443,6 +484,61 @@ putStrLn :: String -> IO () -- note that the result value is an empty tuple. randomRIO :: (Random a) => (a,a) -> IO a ``` +We tried to play with IO last time, but what is it? + +```haskell +Prelude> :info IO +newtype IO a + = GHC.Types.IO (GHC.Prim.State# GHC.Prim.RealWorld + -> (# GHC.Prim.State# GHC.Prim.RealWorld, a #)) + -- Defined in ‘GHC.Types’ +instance Monad IO -- Defined in ‘GHC.Base’ +instance Functor IO -- Defined in ‘GHC.Base’ +instance Applicative IO -- Defined in ‘GHC.Base’ +instance Monoid a => Monoid (IO a) -- Defined in ‘GHC.Base’ +``` + +It is instance of `Monad`, but also `Functor`, `Aplicative`, and `Monoid` (iff `a` is also `Monoid`): + +```haskell +import System.Random +import Control.Applicative + +main0 :: IO () +main0 = mempty + +main1 :: IO () +main1 = putStrLn "a" `mappend` putStrLn "b" + +main2 :: IO () +main2 = mconcat (map print [1..5]) + +main3 :: IO () +main3 = do + rname <- reverse <$> getLine -- fmap reverse getLine + print rname + +main4 :: IO () +main4 = print 1 *> print 2 *> print 3 + +main5 :: IO () +main5 = print 1 <* print 2 <* print 3 + +main6 :: IO () +main6 = do + res <- (+) <$> randomInt <*> randomInt + print res + where randomInt = randomRIO (1, 10) :: IO Integer + +main7 :: IO () +main7 = do + res <- liftA2 (\x y -> x + read y) randomInt getLine + print res + where randomInt = randomRIO (1, 10) :: IO Integer +``` + +A lot of confusion comes from ideas such as "Monad is IO", "To do something impure I need monad", "Monad bring imperative style to FP", or "Monad is something hard and weird". No, `Monad` is just a type class with defined operations and laws, just as `Monoid` (so pretty simple, right?!). What does something with input and output are IO actions = how is the type IO implemented, not that it is instance of `Monad`, `Applicative`, and `Functor`. Those just allows you to do some pure things with `IO` type and actions. Great and detailed explanation can be found on [HaskellWiki - IO inside](https://wiki.haskell.org/IO_inside). + ## Task assignment The homework to practice typeclasses from this tutorial is in repository [MI-AFP/hw07](https://github.com/MI-AFP/hw07). From 3f47d9146b9fe5200f9d783b0313dbd13f0f98db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Sun, 8 Apr 2018 11:20:57 +0200 Subject: [PATCH 11/14] Grammar check & fix --- tutorials/07_common-typeclasses-1.md | 52 ++++++++++++++-------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/tutorials/07_common-typeclasses-1.md b/tutorials/07_common-typeclasses-1.md index 7b0d555..e186dbe 100644 --- a/tutorials/07_common-typeclasses-1.md +++ b/tutorials/07_common-typeclasses-1.md @@ -1,14 +1,14 @@ # Common typeclasses I -Now we are going to spend some time with predefined and important typeclasses that capture important concepts in Haskell that are widely used in many projects. Typeclass always says something about the structure of type and what you can do with that. Also, there are some laws and it is very tightly related to math -- specifically the algebra and the category theory. +Now we are going to spend some time with predefined and important typeclasses that capture important concepts in Haskell that are widely used in many projects. Typeclass always says something about the structure of the type and what you can do with that. Also, there are some laws and it is very tightly related to math -- specifically the algebra and the category theory. -After learning common typeclasses, it is not just easier to use them and understand a code written by other developer, but it also helps with designing own custom typeclasses. You can always find out more about typeclass and instances with GHCi `:info` command. +After learning common typeclasses, it is not just easier to use them and understand a code written by other developers, but it also helps with designing own custom typeclasses. You can always find out more about a typeclass and instances with GHCi `:info` command. ## Intro: Mathematical foundations -The relation between math and Haskell is very strong. You can observe it everywhere. Haskell functions are very similar to mathematical functions when you talk about their type, definitions with `let` and `where` keywords, guards with `otherwise`, function compositions, and so on. In this tutorial we are going to see this relation even more -- with typeclasses that come from mathematical world. You should be already familiar with [basic abstract algebra](https://en.wikipedia.org/wiki/Algebra#Abstract_algebra) (esp. algebraic structures with a single binary operation). +The relation between math and Haskell is very strong. You can observe it everywhere. Haskell functions are very similar to mathematical functions when you talk about their type, definitions with `let` and `where` keywords, guards with `otherwise`, function compositions, and so on. In this tutorial, we are going to see this relation even more -- with typeclasses that come from the mathematical world. You should be already familiar with [basic abstract algebra](https://en.wikipedia.org/wiki/Algebra#Abstract_algebra) (esp. algebraic structures with a single binary operation). -When getting into math, you should know that Haskell is based not just on the basic algebra, set theory, and logic, but also on the category theory. In order to sometimes mention the relation, we will briefly explain what it is about. If you want to know more, please refer to some mathematical tutorials on your own. +When getting into the math, you should know that Haskell is based not just on the basic algebra, set theory, and logic, but also on the category theory. In order to sometimes mention the relation, we will briefly explain what it is about. If you want to know more, please refer to some mathematical tutorials on your own. ### Category theory @@ -34,13 +34,13 @@ In Haskell, we have the **Hask** category where: * *hom(C)* are **functions** (`show`, `id`, `length`, `words`, `flip`, `reverse`, etc.), * composition is **function composition** `(.)`. -The identity function is for every *o ∈ ob(Hask)* the polymorphic `id` function. The associativity of composition is assured and in *hom(C)* there are all the functions, even those created by composition. That's it for now -- now we will show some typeclasses, their laws and come back to **Hask** when necessary... +The identity function is for every *o ∈ ob(Hask)* the polymorphic `id` function. The associativity of the composition is assured and in *hom(C)* there are all the functions, even those created by composition. That's it for now -- now we will show some typeclasses, their laws and come back to **Hask** when necessary... ## Semigroup, Monoid, ... -Monoid is the most simple typeclass we will learn. You can recall the [monoid](https://en.wikipedia.org/wiki/Monoid) from the algebra -- it is an algebraic structure with one binary operation that is associate and there is also one identity element. The same goes for Haskell -- the operation is called `mappend` and the identity is `mempty` (first letter `m` if for **m**onoid). +`Monoid` is the most simple typeclass we will learn. You can recall the [monoid](https://en.wikipedia.org/wiki/Monoid) from the algebra -- it is an algebraic structure with one binary operation that is associative and there is also one identity element. The same goes for Haskell -- the operation is called `mappend` and the identity is `mempty` (the first letter `m` if for **m**onoid). -Since `base-4.11.0.0`, the `Monoid` is subclass of `Semigroup` (just like in algebra). `Semigroup` defines just binary operation which is associative. In Haskell, the binary operation is `(<>)` (infixr 6) +Since `base-4.11.0.0`, the `Monoid` is a subclass of `Semigroup` (just like in algebra). `Semigroup` defines just binary operation which is associative. In Haskell, the binary operation is `(<>)` (infixr 6) ```haskell class Semigroup s where @@ -67,8 +67,8 @@ mappend mempty x == x If you take a look at the documentation of [Data.Monoid](https://hackage.haskell.org/package/base/docs/Data-Monoid.html), you might notice few more things: -* synonym for `mappend` is `(<>)` so you can simply use it as operator `x <> b` (notice that it is not the same as not-equals in other languages), -* multiple newtypes for specifying monoid for basic type, like `Sum` and `Product` for numeric types, `All` and `Any` for booleans, `First` and `Last` for maybes and few more. +* by default, a synonym for `mappend` is `(<>)` so you can simply use it as operator `x <> b` (notice that it is not the same as not-equals in other languages), +* multiple newtypes for specifying monoid for basic types, like `Sum` and `Product` for numeric types, `All` and `Any` for booleans, `First` and `Last` for maybes and few more. ``` @@ -95,7 +95,7 @@ Product {getProduct = 120} ### Example: textual types -One of very practical usages of `mappend` is string concatenation, which is independent on its concrete implementation: +One of the very practical usages of `mappend` is string concatenation, which is independent of its concrete implementation: ```haskell {-# LANGUAGE OverloadedStrings #-} @@ -119,7 +119,7 @@ Here, obviously `mappend` is string concatenation and `mempty = ""`. ### Example: Maybe -From `:info Monoid`, we can see that `Maybe a` is instance of `Monoid` iff (=if and only if) `a` is instance of `Monoid`. Then, the `(<>)` is "propagated" inside and obviously the identity is `Nothing`. +From `:info Monoid`, we can see that `Maybe a` is an instance of `Monoid` iff (=if and only if) `a` is an instance of `Monoid`. Then, the `(<>)` is "propagated" inside and obviously the identity is `Nothing`. ``` Prelude Data.Maybe Data.Semigroup> (Just "a") <> (Just "b") @@ -138,31 +138,31 @@ Nothing ### Verify the laws -As said, there are some laws (identity and associativity in this case) that should be valid, but the compiler can not enforce it. Whenever you are introducing your own instance of `Monoid` or other structure with some laws that are expected to be valid, use tests to prove it. One way is to write the properties on your own. The second and better one is to use [checkers](https://hackage.haskell.org/package/checkers), where many standard properties are prepared for you... +As said, there are some laws (identity and associativity in this case) that should be valid, but the compiler cannot enforce it. Whenever you are introducing your own instance of `Monoid` or other structure with some laws that are expected to be valid, use tests to prove it. One way is to write the properties on your own. The second and better one is to use [checkers](https://hackage.haskell.org/package/checkers), where many standard properties are prepared for you... ### Others from basic algebra Apart from basic `Monoid` from algebra, there are also other variants. You might find interesting to learn more about: -* [semigrupoids](https://hackage.haskell.org/package/semigroupoids/docs/Data-Groupoid.html) (Semigrupoid, Grupoid), +* [semigroupoids](https://hackage.haskell.org/package/semigroupoids/docs/Data-Groupoid.html) (Semigroupoid, Grupoid), * [groups](https://hackage.haskell.org/package/groups/docs/Data-Group.html) (Group, Abelian), * etc. -It is possible to write own instances of `Monoid` or other typeclasses. However, mind that compiler *won't* check if laws are valid in your instance. For such checks you can use testing frameworks (esp. property testing), which will be covered later on. +It is possible to write own instances of `Monoid` or other typeclasses. However, mind that compiler *won't* check if laws are valid in your instance. For such checks, you can use testing frameworks (esp. property testing), which will be covered later on. ## Functor -A functor is a way to apply a function on values inside some structure, while the structure remains intact. For example, if you want to change values in a list, tree or in Either without dealing with complexity and internal structure. +A functor is a way to apply a function to values inside some structure, while the structure remains intact. For example, if you want to change values in a list, tree or in Either without dealing with complexity and internal structure. ```haskell class Functor f where -- f is type constructor of kind * -> * fmap :: (a -> b) -> f a -> f b ``` -The definition says that there is a function `fmap` which applies a function of type `a -> b` on elements in functor `f` with inner type `a` and the result will be functor `f` with inner type `b`. Moreover there are two laws: +The definition says that there is a function `fmap` which applies a function of type `a -> b` on elements in functor `f` with inner type `a` and the result will be functor `f` with inner type `b`. Moreover, there are two laws: ```haskell --- identity (fmap doesn't do nothing more than applying given function) +-- identity (fmap doesn't do anything more than applying given function) fmap id == id -- composition fmap (f . g) == fmap f . fmap g @@ -182,7 +182,7 @@ Nothing Prelude> fmap (+10) (Left 5) Left 5 -- no change! Prelude> fmap (+10) (Right 5) -Right 10 -- changed, because "Either c" is functor for whatever "c" - it doesnt care +Right 10 -- changed, because "Either c" is functor for whatever "c" - it doesn't care ``` Just as with Monoid, you can take a look at the documentation of [Data.Functor](https://hackage.haskell.org/package/base/docs/Data-Functor.html). Again, there is an operator alias, in this case `(<$>)` for `fmap` (denoting a sort of "wrapped" or "inside" apply). There are two more -- `<$` and `$>` (just flipped `<$`). Flipped version of `(<$>)` is `(<&>)`. @@ -204,7 +204,7 @@ Prelude> (Just 7) $> 2 Just 2 ``` -These examples might seem bit too simple, but you can have any instance of `Functor` without knowing the structure and implementation of it and affect what is inside by these two (four if counting also flipped) simple operators. +These examples might seem a bit too simple, but you can have any instance of `Functor` without knowing the structure and implementation of it and affect what is inside by these two (four if counting also flipped) simple operators. ### Lifting @@ -251,7 +251,7 @@ class Functor (f :: * -> *) where fmap :: (a -> b) -> f a -> f b -- maps A->B to F(A) -> F(B) as well as A to F(A) ``` -There is also identity for functions and they must be homomorphic that, of course, apply for functors in Haskell: +There is also the identity law for functions and they must be homomorphic that, of course, apply for functors in Haskell: ```haskell fmap id == id @@ -263,7 +263,7 @@ fmap (f . g) = fmap f . fmap g Another important typeclass is [Control.Applicate](https://hackage.haskell.org/package/base/docs/Control-Applicative.html). Notice that it is not "Data" anymore, but "Control" instead! It is an intermediate structure between a `Functor` and a `Monad`. It is simpler than `Monad`, not so powerful, but sufficient in many use cases, and also easier to understand - it is **Applicative functor**. -In fucntor, we applied a function over a "wrapped" value to get a resulting "wrapped" value. In applicative, we have the function wrapped, as well: +In functor, we applied a function over a "wrapped" value to get a resulting "wrapped" value. In applicative, we have the function wrapped, as well: ```haskell class Functor f => Applicative f where @@ -338,7 +338,7 @@ Right 22 ### Actions vs. functions -In Haskell terminology, we call `Functor f => f a` an **action**. Actions have the power to do some side effect but not necessarily (e.g., `Just "no effect"`). For example, `liftA2` is described as function that lifts a binary function to actions. Special sort of actions are I/O actions with do something with input and output, but there can be also other actions making side effects. +In Haskell terminology, we call `Functor f => f a` an **action**. Actions have the power to do some side effect but not necessarily (e.g., `Just "no effect"`). For example, `liftA2` is described as a function that lifts a binary function to actions. Special sort of actions are I/O actions that do something with input and output, but there can be also other actions making side effects. ## Monad @@ -355,7 +355,7 @@ class Applicative m => Monad m where -- pure :: a -> f a -- from Controll.Applicative ``` -Function `return` works just as `pure` in `Applicative`. Why having two same functions? Historically; PureScript for instance has just `pure` both for the Applicative and Monad. +Function `return` works just as `pure` in `Applicative`. Why having two same functions? Historically; PureScript, for instance, has just `pure` both for the Applicative and Monad. `>>=` is bind, which takes a monadic value (again, this is some "wrapped value") and a function, which takes an unwrapped value and transforms it into a monadic value. @@ -385,7 +385,7 @@ Left "err" ### Do syntax -Using `do` blocks as an alternative monad syntax was first introduced way back in the :"Simple input and output" chapter. There, we used do to sequence input/output operations, but we hadn't introduced monads yet. Now, we can see that IO is yet another monad. +Using `do` blocks as an alternative monad syntax was first introduced way back in the "Simple input and output" chapter. There, we used it to sequence input/output operations, but we hadn't introduced monads yet. Now, we can see that IO is yet another monad. Imagine we have a sequence operation like this: @@ -438,7 +438,7 @@ main = do ### Loops -You might hear that "do" provides imperative-like way of programming... That's true but it is really just *imperative-like* from visual point of view, it is still purely functional! But even in math and functions you can introduce something like `for` or `while` loops. When you want to compute some result like factorial, sum, length of list it is natural to use recursion. With actions, it might give more sence to use loops (even when they are actually done by recursion): +You might hear that "do" provides an imperative-like way of programming... That's true but it is really just *imperative-like* from a visual point of view, it is still purely functional! But even in math and functions, you can introduce something like `for` or `while` loops. When you want to compute some result like factorial, sum, length of a list it is natural to use recursion. With actions, it might give more sense to use loops (even when they are actually done by recursion): ```haskell import System.Random @@ -537,7 +537,7 @@ main7 = do where randomInt = randomRIO (1, 10) :: IO Integer ``` -A lot of confusion comes from ideas such as "Monad is IO", "To do something impure I need monad", "Monad bring imperative style to FP", or "Monad is something hard and weird". No, `Monad` is just a type class with defined operations and laws, just as `Monoid` (so pretty simple, right?!). What does something with input and output are IO actions = how is the type IO implemented, not that it is instance of `Monad`, `Applicative`, and `Functor`. Those just allows you to do some pure things with `IO` type and actions. Great and detailed explanation can be found on [HaskellWiki - IO inside](https://wiki.haskell.org/IO_inside). +A lot of confusion comes from ideas such as "Monad is IO", "To do something impure I need monad", "Monad bring imperative style to FP", or "Monad is something hard and weird". No, `Monad` is just a type class with defined operations and laws, just as `Monoid` (so pretty simple, right?!). What does something with input and output are IO actions = how is the type IO implemented, not that it is an instance of `Monad`, `Applicative`, and `Functor`. Those just allow you to do some pure things with `IO` type and actions. A great and detailed explanation can be found on [HaskellWiki - IO inside](https://wiki.haskell.org/IO_inside). ## Task assignment From d0b3f411858b0aa76cea071e7190233483f3b13e Mon Sep 17 00:00:00 2001 From: Robert Pergl Date: Tue, 10 Apr 2018 15:57:58 +0200 Subject: [PATCH 12/14] revisions --- tutorials/07_common-typeclasses-1.md | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/tutorials/07_common-typeclasses-1.md b/tutorials/07_common-typeclasses-1.md index e186dbe..50b3fef 100644 --- a/tutorials/07_common-typeclasses-1.md +++ b/tutorials/07_common-typeclasses-1.md @@ -74,7 +74,7 @@ If you take a look at the documentation of [Data.Monoid](https://hackage.haskell ``` Prelude> import Data.Monoid Prelude Data.Monoid> :info Sum -newtype Sum a = Sum {getSum :: a} -- Defined in ‘Data.Monoid’ +newtype Sum a = Sum {getSum :: a} -- Defined in ‘Data.Monoid’ ... Prelude Data.Monoid> :info Product newtype Product a = Product {getProduct :: a} @@ -138,7 +138,7 @@ Nothing ### Verify the laws -As said, there are some laws (identity and associativity in this case) that should be valid, but the compiler cannot enforce it. Whenever you are introducing your own instance of `Monoid` or other structure with some laws that are expected to be valid, use tests to prove it. One way is to write the properties on your own. The second and better one is to use [checkers](https://hackage.haskell.org/package/checkers), where many standard properties are prepared for you... +As said, there are some laws (identity and associativity in this case) that should be valid, but the compiler cannot enforce it. Whenever you introduce your own instance of `Monoid` or other structure with some laws that are expected to be valid, use tests to prove it. One way is to write the properties on your own. The second and better one is to use [checkers](https://hackage.haskell.org/package/checkers), where many standard properties are prepared for you... ### Others from basic algebra @@ -208,11 +208,11 @@ These examples might seem a bit too simple, but you can have any instance of `Fu ### Lifting -[Lifting](https://wiki.haskell.org/Lifting) is a concept which allows you to transform a function into a corresponding function within another (usually more general) setting. Lifting is again concept taken from mathematics and category theory (see [wikipedia](https://en.wikipedia.org/wiki/Lift_(mathematics)). +[Lifting](https://wiki.haskell.org/Lifting) is a concept that allows you to transform a function into a corresponding function within another (usually a more general) setting. Lifting is again a concept taken from mathematics and category theory (see [wikipedia](https://en.wikipedia.org/wiki/Lift_(mathematics)). ```haskell -data Point2D a = Point2D a a +data Point2D a = Point2D a a deriving Show instance Functor Point2D where @@ -223,7 +223,7 @@ liftF0 x = Point2D x x liftF1 :: (a -> b) -> Point2D a -> Point2D b liftF1 = fmap - + liftF2 :: (a -> b -> c) -> Point2D a -> Point2D b -> Point2D c liftF2 f (Point2D x1 x2) (Point2D y1 y2) = Point2D (f x1 y1) (f x2 y2) @@ -322,7 +322,7 @@ Prelude> (Right 5) *> (Left 10) Left 10 Prelude> (Right 5) <* (Left 10) Left 10 -Prelude Control.Applicative> (Right 15) <**> pure linfunc +Prelude Control.Applicative> (Right 15) <**> pure linfunc Right 40 -- Lifts are already prepared in Control.Applicative @@ -342,7 +342,7 @@ In Haskell terminology, we call `Functor f => f a` an **action**. Actions have t ## Monad -The most famous (and scary :-) typeclass for Haskell students is [Control.Monad](https://hackage.haskell.org/package/base/docs/Control-Monad.html). It defines basic operations over a monad, a term from category theory. From the perspective of a Haskell programmer, however, it is best to think of a monad as an "abstract datatype of actions". Haskell's `do` expressions provide a convenient syntax for writing monadic expressions. This time we will start Monads (operations, laws, basic behavior, etc.) and next time we will get deeper with some more practical use-cases. +The most famous (and [scary](https://camo.githubusercontent.com/f2c3667a2cdf19c0cf203fad44c81d197c4cd740/68747470733a2f2f692e696d67666c69702e636f6d2f317a6e707a622e6a7067) :-)) typeclass for Haskell students is [Control.Monad](https://hackage.haskell.org/package/base/docs/Control-Monad.html). It defines basic operations over a monad, a term from category theory. From the perspective of a Haskell programmer, however, it is best to think of a monad as an "abstract datatype of actions". Haskell's `do` expressions provide a convenient syntax for writing monadic expressions. This time we will start Monads (operations, laws, basic behavior, etc.) and next time we will get deeper with some more practical use-cases. ```haskell class Applicative m => Monad m where @@ -385,6 +385,11 @@ Left "err" ### Do syntax +```diff +-spis to vysvetlit jako v http://learnyouahaskell.com/a-fistful-of-monads#getting-our-feet-wet-with-maybe (sekce do notation). +-Klidne to vezmi copy-paste a ocituj ;-) +``` + Using `do` blocks as an alternative monad syntax was first introduced way back in the "Simple input and output" chapter. There, we used it to sequence input/output operations, but we hadn't introduced monads yet. Now, we can see that IO is yet another monad. Imagine we have a sequence operation like this: @@ -467,7 +472,7 @@ For other loops, visit [Control.Monad.Loops](https://hackage.haskell.org/package ### Monads in category theory -Again, monad comes from math and more specifically from category theory. A monad is a special type of functor, from a category to that same category (i.e., it is *endofunctor*), that supports some additional structure. Monad is a functor *M: C → C* with two morphisms for every object *X* from *C*: +Again, monad comes from math and more specifically from category theory. A monad is a special type of functor, from a category to that same category (i.e., it is *endofunctor*), that supports some additional structure. Monad is a functor *M: C → C* with two morphisms for every object *X* from *C*: 1. *unit: X → M(X)* ~ `return :: Monad m => a -> m a` 2. *join: M(M(X)) → M(X)* ~ `(>>=) :: Monad m => m a -> (a -> m b) -> m b` @@ -491,7 +496,7 @@ Prelude> :info IO newtype IO a = GHC.Types.IO (GHC.Prim.State# GHC.Prim.RealWorld -> (# GHC.Prim.State# GHC.Prim.RealWorld, a #)) - -- Defined in ‘GHC.Types’ + -- Defined in ‘GHC.Types’ instance Monad IO -- Defined in ‘GHC.Base’ instance Functor IO -- Defined in ‘GHC.Base’ instance Applicative IO -- Defined in ‘GHC.Base’ @@ -537,9 +542,9 @@ main7 = do where randomInt = randomRIO (1, 10) :: IO Integer ``` -A lot of confusion comes from ideas such as "Monad is IO", "To do something impure I need monad", "Monad bring imperative style to FP", or "Monad is something hard and weird". No, `Monad` is just a type class with defined operations and laws, just as `Monoid` (so pretty simple, right?!). What does something with input and output are IO actions = how is the type IO implemented, not that it is an instance of `Monad`, `Applicative`, and `Functor`. Those just allow you to do some pure things with `IO` type and actions. A great and detailed explanation can be found on [HaskellWiki - IO inside](https://wiki.haskell.org/IO_inside). +A lot of confusion comes from ideas such as "Monad is IO", "To do something impure I need a monad", "Monad brings imperative style to FP", or "Monad is something hard and weird". No, `Monad` is just a type class with defined operations and laws, just as `Monoid` (so pretty simple, right?!). IO actions manipulate and output, this is their essence. And BY THE WAY, they are (very conveniently) an instance of `Monad`, `Applicative`, and `Functor`. Those allow you to do some pure composition and other tricks with `IO` type and actions. A great and detailed explanation can be found on [HaskellWiki - IO inside](https://wiki.haskell.org/IO_inside). -## Task assignment +## The task assignment The homework to practice typeclasses from this tutorial is in repository [MI-AFP/hw07](https://github.com/MI-AFP/hw07). From 2a97b85f130a5877629e6596461b4af2c8264bdb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Wed, 11 Apr 2018 15:05:19 +0200 Subject: [PATCH 13/14] Changed do-notation a bit --- tutorials/07_common-typeclasses-1.md | 49 ++++++++++++---------------- 1 file changed, 20 insertions(+), 29 deletions(-) diff --git a/tutorials/07_common-typeclasses-1.md b/tutorials/07_common-typeclasses-1.md index 50b3fef..9e4a41b 100644 --- a/tutorials/07_common-typeclasses-1.md +++ b/tutorials/07_common-typeclasses-1.md @@ -385,51 +385,41 @@ Left "err" ### Do syntax -```diff --spis to vysvetlit jako v http://learnyouahaskell.com/a-fistful-of-monads#getting-our-feet-wet-with-maybe (sekce do notation). --Klidne to vezmi copy-paste a ocituj ;-) -``` - -Using `do` blocks as an alternative monad syntax was first introduced way back in the "Simple input and output" chapter. There, we used it to sequence input/output operations, but we hadn't introduced monads yet. Now, we can see that IO is yet another monad. +Monads in Haskell are so useful that they got their own special syntax called `do` notation. We first introduced it way back in the "Simple input and output" chapter. There, we used it to sequence input/output operations, but we hadn't introduced monads yet. Now, we can see that IO is yet another monad. Imagine we have a sequence operation like this: ```haskell - putStr "Hello" >> - putStr " " >> - putStr "world!" >> - putStr "\n" +Prelude> Just 7 >>= (\x -> Just (show x ++ "!")) +Just "7!" +Prelude> Just 7 >>= (\x -> Just "!" >>= (\y -> Just (show x ++ y))) +Just "7!" +Prelude> print 3 >> print 5 >> print 7 +3 +5 +7 ``` -Now we can chain it using do: +Haskell provides the `do` notation so we can avoid writing all the lambdas: ```haskell -main = do - { putStr "Hello" - ; putStr " " - ; putStr "world!" - ; putStr "\n" } +foo :: Maybe String +foo = do + x <- Just 7 + y <- Just "!" + Just (show x ++ y) ``` or ```haskell main = do - putStr "Hello" - putStr " " - putStr "world!" - putStr "\n" -``` - -This becomes translated to: - -```haskell -action1 >> -do { action2 - ; action3 } + print 3 + print 5 + print 7 ``` -In `do`, you can also use `>>=` operator by binding `<-` and `let` instead of `let-in`: +In `do`, you can use basic sequencing `>>`, `>>=` operator by binding `<-` and `let` instead of `let-in`: ```haskell main = do @@ -554,6 +544,7 @@ The homework to practice typeclasses from this tutorial is in repository [MI-AFP * [Haskell and Category Theory](https://en.wikibooks.org/wiki/Haskell/Category_theory) * [Category Theory for Programmers by Bartosz Milewski](https://bartoszmilewski.com/2014/10/28/category-theory-for-programmers-the-preface) * [LYAH - Functors, Applicative Functors and Monoids](http://learnyouahaskell.com/functors-applicative-functors-and-monoids) +* [LYAH - A Fistful of Monads](http://learnyouahaskell.com/a-fistful-of-monads) * [Haskell - Typoclassopedia](https://wiki.haskell.org/Typeclassopedia) * [Haskell - Monad](https://wiki.haskell.org/Monad) * [Haskell - IO Monad](https://wiki.haskell.org/Introduction_to_IO) From 0b0126e90713faf3e8e5c9af6e55aadee0cc4765 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Fri, 13 Apr 2018 08:04:06 +0200 Subject: [PATCH 14/14] Improved fmap comment for CT functor --- tutorials/07_common-typeclasses-1.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tutorials/07_common-typeclasses-1.md b/tutorials/07_common-typeclasses-1.md index 9e4a41b..1adf385 100644 --- a/tutorials/07_common-typeclasses-1.md +++ b/tutorials/07_common-typeclasses-1.md @@ -248,7 +248,8 @@ We have some categories which have objects and morphisms that relate our objects ```haskell class Functor (f :: * -> *) where - fmap :: (a -> b) -> f a -> f b -- maps A->B to F(A) -> F(B) as well as A to F(A) + fmap :: (a -> b) -> f a -> f b +-- fmap :: (a -> b) -> (f a -> f b) ``` There is also the identity law for functions and they must be homomorphic that, of course, apply for functors in Haskell: