From 9579f7304641ce016fd93cb1e90f5329c5c4bdb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Sun, 3 Mar 2019 09:43:02 +0100 Subject: [PATCH 01/26] Move textual types from 04 to 03 --- tutorials/03_branching.md | 198 ++++++++++++++++++++++++++++++++++ tutorials/04_types-errors.md | 202 ----------------------------------- 2 files changed, 198 insertions(+), 202 deletions(-) diff --git a/tutorials/03_branching.md b/tutorials/03_branching.md index c4ba660..1e86ac7 100644 --- a/tutorials/03_branching.md +++ b/tutorials/03_branching.md @@ -417,6 +417,80 @@ show $ getSiblingsOf $ getParentOf $ head people -- A bit nicer show . getSiblingsOf . getParentOf . head $ people -- Haskell way (will be covered later on) ``` +### List comprehensions + +Creation of lists using a constructor (or its syntactic sugar) is pretty straightforward, but there are two more interesting ways for that. First is used basically for basic ranges and it is called "dot dot notation". You have seen it already. It works with types that are instances of type class `Enum` (you can check within GHCi by `:info Enum`. You can specify start, step and end of the range (inclusive), but you need to be careful with floats and doubles because of their precision - the error cumulatively grows. + +``` +Prelude> [1..10] +[1,2,3,4,5,6,7,8,9,10] +Prelude> [0,5..20] +[0,5,10,15,20] +Prelude> ['a' .. 'z'] +"abcdefghijklmnopqrstuvwxyz" +Prelude> [1.0,1.05 .. 1.2] +[1.0,1.05,1.1,1.1500000000000001,1.2000000000000002] +``` + +A more flexible way is offered by [list comprehensions](https://wiki.haskell.org/List_comprehension). This concept/construct is nowadays used in many other programming languages, as well, such as Python. In "list" you first specify an expression with variables and then after pipe `|`, there are specifications of bindings and restrictions. It is also possible to define local names with `let`. + +``` +Prelude> [n*2+1 | n <- [1..5]] +[3,5,7,9,11] +Prelude> [(i, j) | i <- [1..5], j <- [0,1]] +[(1,0),(1,1),(2,0),(2,1),(3,0),(3,1),(4,0),(4,1),(5,0),(5,1)] +Prelude> [x | x <- [0..10], x `mod` 3 == 1, x /= 7] +[1,4,10] +Prelude> take 10 [(i, j) | i <- [1..5], let k=i-5, j <- [k..6]] +[(1,-4),(1,-3),(1,-2),(1,-1),(1,0),(1,1),(1,2),(1,3),(1,4),(1,5)] +``` + +### Lazy Haskell + +As we've already seen, Haskell has lazy non-strict evaluation strategy. It means that no expression is evaluated, unless the value is needed. One of the possibilities is creating infinite lists. You may use `undefined` for testing when the expression is evaluated. + +``` +Prelude> let x = 1:x +Prelude> take 10 x +[1,1,1,1,1,1,1,1,1,1] +Prelude> take 20 x +[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1] +Prelude> x +[1,1,1,1,1,1,1,1,1,1,1,1,1,1,...^C Interrupted. +Prelude> [1,2..] +[1,2,3,4,5,6,7,8,9,10,11,12,13,14,...^C Interrupted. +Prelude> let x = undefined +Prelude> let y = 1 + x +Prelude> let z = y * 2 + 15 +Prelude> :type y +y :: Num a => a +Prelude> :type x +x :: a +Prelude> z +*** Exception: Prelude.undefined +CallStack (from HasCallStack): + error, called at libraries/base/GHC/Err.hs:79:14 in base:GHC.Err + undefined, called at :37:5 in interactive:Ghci23 +``` + +(For stopping output press CTRL+C in GHCi) + +### Strictness with types + +In the previous lesson, we touched the topic of enforcing strictness with `!` in patterns ([bang patterns](https://ocharles.org.uk/blog/posts/2014-12-05-bang-patterns.html)) and in function application with `$!` operator. Similarly, we can use `!` with type fields like this: + +```haskell +data MyType = MyConstr Int !Int + +data MyRec = MyRecConstr { xA :: Int + , xB :: !Int + } +``` + +For both cases it means that when data constructor is evaluated, it must fully evaluate ([weak head normal form](https://wiki.haskell.org/Weak_head_normal_form)) the second parameter, but the first one will stay unevaluated in a lazy way. All depends on language implementation in the used compiler. + +In order to achieve laziness, Haskell wraps all types with some additional information = *boxed types*. If you don't need laziness and other related properties, it is more efficient to use raw *unboxed types*. We will talk about that as a bonus or at the end of course in the *Performance* section. Now you just need to know roughly what is it about, because it is used in some textual types... + ## Modules and imports A Haskell program consists of a collection of modules (similar to other programming languages). In the top level, you can declare and define data types, function, typeclasses and their instances, pattern bindings and so on. @@ -523,6 +597,130 @@ x = myFunc1 10 -- a function from TestModule y = FPTM.myFunc1 25 ``` +## Textual types + +Textual types [(strings)](https://wiki.haskell.org/Strings) are kind of pain in Haskell. This is mostly because of its long legacy and also laziness/strictness trade-offs. However, as everything, they are not really insidious, just not convenient as they could be (and actually are in newer "Haskells", such as PureScript). + +### String + +[String](https://hackage.haskell.org/package/base/docs/Data-String.html) is the string type in the `base` package. It is just a type synonym for `[Char]`, so it comes with all properties of a [list](https://hackage.haskell.org/package/base/docs/Data-List.html), and as such, it is the most common one, especially for non-performance-sensitive applications. But when it comes to performance (and sometimes even Unicode behavior), then problems arise - `String` has big overhead in time and space. + +### Text + +[Data.Text](https://hackage.haskell.org/package/text/docs/Data-Text.html) from [text](https://hackage.haskell.org/package/text) package is a time and space-efficient implementation of Unicode text. You can convert between `Text` and `String` with functions `pack` and `unpack`. The `Data.Text` package exports functions with same names as there are for `String` (`head`, `length`, `map`, `replace`, etc.), so the advised import style is `import qualified Data.Text as T`. + +``` +Prelude> import qualified Data.Text as T +Prelude T> txt = T.pack "my effective text" +Prelude T> :type txt +txt :: T.Text +Prelude T> T.index txt 1 +'y' +Prelude T> T.replace "my" "your" txt + +:13:11: error: + • Couldn't match expected type ‘T.Text’ with actual type ‘[Char]’ + • In the first argument of ‘T.replace’, namely ‘"my"’ + In the expression: T.replace "my" "your" txt + In an equation for ‘it’: it = T.replace "my" "your" txt + +:13:16: error: + • Couldn't match expected type ‘T.Text’ with actual type ‘[Char]’ + • In the second argument of ‘T.replace’, namely ‘"your"’ + In the expression: T.replace "my" "your" txt + In an equation for ‘it’: it = T.replace "my" "your" txt +Prelude T> T.replace (T.pack "my") (T.pack "your") txt +"your effective text" +Prelude T> length txt + +:11:8: error: + • Couldn't match expected type ‘[a0]’ with actual type ‘T.Text’ + • In the first argument of ‘length’, namely ‘txt’ + In the expression: length txt + In an equation for ‘it’: it = length txt +Prelude T> T.length txt +17 +``` + +There is another variant of the Text package, which is [Data.Text.Lazy](https://hackage.haskell.org/package/text/docs/Data-Text-Lazy.html), which exports same operations and thanks to laziness, it can work with huge texts and it may provide better performance under the right circumstances. [Data.Text.Encoding](https://hackage.haskell.org/package/text/docs/Data-Text-Encoding.html) (and its lazy alternative) may be also useful. + +### ByteString + +Last of the types mentioned here is [Data.ByteString](https://hackage.haskell.org/package/bytestring/docs/Data-ByteString.html) from [bytestring](https://hackage.haskell.org/package/bytestring) package. Byte vectors are encoded as strict Word8 arrays of bytes and they are used for interoperability between Haskell and C or other lower-level situations. In many ways, the usage is similar to [text](https://hackage.haskell.org/package/text) package (again `pack` and `unpack`, same basic functions, `Lazy` alternative, and so on). Next, there is an option to use vectors with `Char8` instead of `Word8`, which works as Unicode subset (0-255) strings and it is used when working with pure ASCII string representations. + +``` +Prelude T> import Data.ByteString as B +Prelude T B> bstr = B.pack [97, 98, 99] +Prelude T B> bstr +"abc" +Prelude T B> index bstr 2 +99 +Prelude T B> B.map (+1) bstr +"bcd" + +Prelude T B> import qualified Data.ByteString.Char8 as C +Prelude T B C> C.pack "abc" +"abc" +Prelude T B C> B.pack "abc" + +:28:8: error: + • Couldn't match type ‘Char’ with ‘GHC.Word.Word8’ + Expected type: [GHC.Word.Word8] + Actual type: [Char] + • In the first argument of ‘pack’, namely ‘"abc"’ + In the expression: pack "abc" + In an equation for ‘it’: it = pack "abc" +Prelude T B C> cstr = C.pack "abc" +Prelude T B C> C.index cstr 2 +'c' +``` + +In other cases you need to use encoding to encode/decode bytes to/from text: + +``` +Prelude T B> import qualified Data.Text.Encoding as E +Prelude T B C E> E.encodeUtf8 (T.pack "život, жизнь, lífið, ਜੀਵਨ, ,حياة") +"\197\190ivot, \208\182\208\184\208\183\208\189\209\140, l\195\173fi\195\176, \224\168\156\224\169\128\224\168\181\224\168\168, ,\216\173\217\138\216\167\216\169" +Prelude T B C E> x = E.encodeUtf8 (T.pack "život, жизнь, lífið, ਜੀਵਨ, ,حياة") +Prelude T B C E> x +"\197\190ivot, \208\182\208\184\208\183\208\189\209\140, l\195\173fi\195\176, \224\168\156\224\169\128\224\168\181\224\168\168, ,\216\173\217\138\216\167\216\169" +Prelude T B C E> index x 0 +197 +Prelude T B C E> index x 2 +105 +``` + +### OverloadedStrings + +As needing to pack all string literals when using non-base string representations is cumbersome, there is a handy [GHC] language extension [OverloadedStrings](https://ocharles.org.uk/blog/posts/2014-12-17-overloaded-strings.html). + +Generally, [GHC] language extensions can be enabled in the source file using pragma `LANGUAGE` as the first line in the file: + +```haskell +{-# LANGUAGE OverloadedStrings #-} + +module XY ... +``` + +In GHCi, the extension can be enabled using the `:set` directive: + +``` +Prelude> :set -XOverloadedStrings +``` + +After that, a string literal type can be inferred by its usage in the source code: + +``` +Prelude> import qualified Data.Text as T +Prelude T> :type "abc" +"abc" :: [Char] +Prelude T> :set -XOverloadedStrings +Prelude> :type "abc" +"abc" :: Data.String.IsString p => p +Prelude T> T.length "abc" -- no need to pack the literal any more! +3 +``` + ## Task assignment The homework to practice branching and slightly working with modules is in repository [MI-AFP/hw03](https://github.com/MI-AFP/hw03). diff --git a/tutorials/04_types-errors.md b/tutorials/04_types-errors.md index 97aa0eb..a9a960c 100644 --- a/tutorials/04_types-errors.md +++ b/tutorials/04_types-errors.md @@ -1,207 +1,5 @@ # Types, containers, and errors -## Evaluation - -First, we briefly get back to laziness in Haskell as mentioned in the previous lesson, because it is also related to lazy/strict types which will be discussed in this lesson. - -### List comprehensions - -Creation of lists using a constructor (or its syntactic sugar) is pretty straightforward, but there are two more interesting ways for that. First is used basically for basic ranges and it is called "dot dot notation". You have seen it already. It works with types that are instances of type class `Enum` (you can check within GHCi by `:info Enum`. You can specify start, step and end of the range (inclusive), but you need to be careful with floats and doubles because of their precision - the error cumulatively grows. - -``` -Prelude> [1..10] -[1,2,3,4,5,6,7,8,9,10] -Prelude> [0,5..20] -[0,5,10,15,20] -Prelude> ['a' .. 'z'] -"abcdefghijklmnopqrstuvwxyz" -Prelude> [1.0,1.05 .. 1.2] -[1.0,1.05,1.1,1.1500000000000001,1.2000000000000002] -``` - -A more flexible way is offered by [list comprehensions](https://wiki.haskell.org/List_comprehension). This concept/construct is nowadays used in many other programming languages, as well, such as Python. In "list" you first specify an expression with variables and then after pipe `|`, there are specifications of bindings and restrictions. It is also possible to define local names with `let`. - -``` -Prelude> [n*2+1 | n <- [1..5]] -[3,5,7,9,11] -Prelude> [(i, j) | i <- [1..5], j <- [0,1]] -[(1,0),(1,1),(2,0),(2,1),(3,0),(3,1),(4,0),(4,1),(5,0),(5,1)] -Prelude> [x | x <- [0..10], x `mod` 3 == 1, x /= 7] -[1,4,10] -Prelude> take 10 [(i, j) | i <- [1..5], let k=i-5, j <- [k..6]] -[(1,-4),(1,-3),(1,-2),(1,-1),(1,0),(1,1),(1,2),(1,3),(1,4),(1,5)] -``` - -### Lazy Haskell - -As we've already seen, Haskell has lazy non-strict evaluation strategy. It means that no expression is evaluated, unless the value is needed. One of the possibilities is creating infinite lists. You may use `undefined` for testing when the expression is evaluated. - -``` -Prelude> let x = 1:x -Prelude> take 10 x -[1,1,1,1,1,1,1,1,1,1] -Prelude> take 20 x -[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1] -Prelude> x -[1,1,1,1,1,1,1,1,1,1,1,1,1,1,...^C Interrupted. -Prelude> [1,2..] -[1,2,3,4,5,6,7,8,9,10,11,12,13,14,...^C Interrupted. -Prelude> let x = undefined -Prelude> let y = 1 + x -Prelude> let z = y * 2 + 15 -Prelude> :type y -y :: Num a => a -Prelude> :type x -x :: a -Prelude> z -*** Exception: Prelude.undefined -CallStack (from HasCallStack): - error, called at libraries/base/GHC/Err.hs:79:14 in base:GHC.Err - undefined, called at :37:5 in interactive:Ghci23 -``` - -(For stopping output press CTRL+C in GHCi) - -### Strictness with types - -In the previous lesson, we touched the topic of enforcing strictness with `!` in patterns ([bang patterns](https://ocharles.org.uk/blog/posts/2014-12-05-bang-patterns.html)) and in function application with `$!` operator. Similarly, we can use `!` with type fields like this: - -```haskell -data MyType = MyConstr Int !Int - -data MyRec = MyRecConstr { xA :: Int - , xB :: !Int - } -``` - -For both cases it means that when data constructor is evaluated, it must fully evaluate ([weak head normal form](https://wiki.haskell.org/Weak_head_normal_form)) the second parameter, but the first one will stay unevaluated in a lazy way. All depends on language implementation in the used compiler. - -In order to achieve laziness, Haskell wraps all types with some additional information = *boxed types*. If you don't need laziness and other related properties, it is more efficient to use raw *unboxed types*. We will talk about that as a bonus or at the end of course in the *Performance* section. Now you just need to know roughly what is it about, because it is used in some textual types... - -## Textual types - -Textual types [(strings)](https://wiki.haskell.org/Strings) are kind of pain in Haskell. This is mostly because of its long legacy and also laziness/strictness trade-offs. However, as everything, they are not really insidious, just not convenient as they could be (and actually are in newer "Haskells", such as PureScript). - -### String - -[String](https://hackage.haskell.org/package/base/docs/Data-String.html) is the string type in the `base` package. It is just a type synonym for `[Char]`, so it comes with all properties of a [list](https://hackage.haskell.org/package/base/docs/Data-List.html), and as such, it is the most common one, especially for non-performance-sensitive applications. But when it comes to performance (and sometimes even Unicode behavior), then problems arise - `String` has big overhead in time and space. - -### Text - -[Data.Text](https://hackage.haskell.org/package/text/docs/Data-Text.html) from [text](https://hackage.haskell.org/package/text) package is a time and space-efficient implementation of Unicode text. You can convert between `Text` and `String` with functions `pack` and `unpack`. The `Data.Text` package exports functions with same names as there are for `String` (`head`, `length`, `map`, `replace`, etc.), so the advised import style is `import qualified Data.Text as T`. - -``` -Prelude> import qualified Data.Text as T -Prelude T> txt = T.pack "my effective text" -Prelude T> :type txt -txt :: T.Text -Prelude T> T.index txt 1 -'y' -Prelude T> T.replace "my" "your" txt - -:13:11: error: - • Couldn't match expected type ‘T.Text’ with actual type ‘[Char]’ - • In the first argument of ‘T.replace’, namely ‘"my"’ - In the expression: T.replace "my" "your" txt - In an equation for ‘it’: it = T.replace "my" "your" txt - -:13:16: error: - • Couldn't match expected type ‘T.Text’ with actual type ‘[Char]’ - • In the second argument of ‘T.replace’, namely ‘"your"’ - In the expression: T.replace "my" "your" txt - In an equation for ‘it’: it = T.replace "my" "your" txt -Prelude T> T.replace (T.pack "my") (T.pack "your") txt -"your effective text" -Prelude T> length txt - -:11:8: error: - • Couldn't match expected type ‘[a0]’ with actual type ‘T.Text’ - • In the first argument of ‘length’, namely ‘txt’ - In the expression: length txt - In an equation for ‘it’: it = length txt -Prelude T> T.length txt -17 -``` - -There is another variant of the Text package, which is [Data.Text.Lazy](https://hackage.haskell.org/package/text/docs/Data-Text-Lazy.html), which exports same operations and thanks to laziness, it can work with huge texts and it may provide better performance under the right circumstances. [Data.Text.Encoding](https://hackage.haskell.org/package/text/docs/Data-Text-Encoding.html) (and its lazy alternative) may be also useful. - -### ByteString - -Last of the types mentioned here is [Data.ByteString](https://hackage.haskell.org/package/bytestring/docs/Data-ByteString.html) from [bytestring](https://hackage.haskell.org/package/bytestring) package. Byte vectors are encoded as strict Word8 arrays of bytes and they are used for interoperability between Haskell and C or other lower-level situations. In many ways, the usage is similar to [text](https://hackage.haskell.org/package/text) package (again `pack` and `unpack`, same basic functions, `Lazy` alternative, and so on). Next, there is an option to use vectors with `Char8` instead of `Word8`, which works as Unicode subset (0-255) strings and it is used when working with pure ASCII string representations. - -``` -Prelude T> import Data.ByteString as B -Prelude T B> bstr = B.pack [97, 98, 99] -Prelude T B> bstr -"abc" -Prelude T B> index bstr 2 -99 -Prelude T B> B.map (+1) bstr -"bcd" - -Prelude T B> import qualified Data.ByteString.Char8 as C -Prelude T B C> C.pack "abc" -"abc" -Prelude T B C> B.pack "abc" - -:28:8: error: - • Couldn't match type ‘Char’ with ‘GHC.Word.Word8’ - Expected type: [GHC.Word.Word8] - Actual type: [Char] - • In the first argument of ‘pack’, namely ‘"abc"’ - In the expression: pack "abc" - In an equation for ‘it’: it = pack "abc" -Prelude T B C> cstr = C.pack "abc" -Prelude T B C> C.index cstr 2 -'c' -``` - -In other cases you need to use encoding to encode/decode bytes to/from text: - -``` -Prelude T B> import qualified Data.Text.Encoding as E -Prelude T B C E> E.encodeUtf8 (T.pack "život, жизнь, lífið, ਜੀਵਨ, ,حياة") -"\197\190ivot, \208\182\208\184\208\183\208\189\209\140, l\195\173fi\195\176, \224\168\156\224\169\128\224\168\181\224\168\168, ,\216\173\217\138\216\167\216\169" -Prelude T B C E> x = E.encodeUtf8 (T.pack "život, жизнь, lífið, ਜੀਵਨ, ,حياة") -Prelude T B C E> x -"\197\190ivot, \208\182\208\184\208\183\208\189\209\140, l\195\173fi\195\176, \224\168\156\224\169\128\224\168\181\224\168\168, ,\216\173\217\138\216\167\216\169" -Prelude T B C E> index x 0 -197 -Prelude T B C E> index x 2 -105 -``` - -### OverloadedStrings - -As needing to pack all string literals when using non-base string representations is cumbersome, there is a handy [GHC] language extension [OverloadedStrings](https://ocharles.org.uk/blog/posts/2014-12-17-overloaded-strings.html). - -Generally, [GHC] language extensions can be enabled in the source file using pragma `LANGUAGE` as the first line in the file: - -```haskell -{-# LANGUAGE OverloadedStrings #-} - -module XY ... -``` - -In GHCi, the extension can be enabled using the `:set` directive: - -``` -Prelude> :set -XOverloadedStrings -``` - -After that, a string literal type can be inferred by its usage in the source code: - -``` -Prelude> import qualified Data.Text as T -Prelude T> :type "abc" -"abc" :: [Char] -Prelude T> :set -XOverloadedStrings -Prelude> :type "abc" -"abc" :: Data.String.IsString p => p -Prelude T> T.length "abc" -- no need to pack the literal any more! -3 -``` - ## Important "base" types We already know basic data types (from `base` package) such as [Data.Char](https://hackage.haskell.org/package/base/docs/Data-Char.html), [Bool](https://hackage.haskell.org/package/base/docs/Data-Bool.html), or [Data.Int](https://hackage.haskell.org/package/base/docs/Data-Int.html) and structures like [Data.List](https://hackage.haskell.org/package/base/docs/Data-List.html) and [Data.Tuple](https://hackage.haskell.org/package/base/docs/Data-Tuple.html) pretty well. But of course, there are more widely used types and we are going to know some more now. From 7ca3813360f3626f5c3cbf2be8e1f7cf9f75e55e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Sun, 3 Mar 2019 19:21:48 +0100 Subject: [PATCH 02/26] Improve title and move references --- tutorials/03_branching.md | 7 ++++++- tutorials/04_types-errors.md | 5 ----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tutorials/03_branching.md b/tutorials/03_branching.md index 1e86ac7..ed2b3f3 100644 --- a/tutorials/03_branching.md +++ b/tutorials/03_branching.md @@ -1,4 +1,4 @@ -# Structuration and branching +# Structuration, branching, and evaluation ## If and case @@ -730,8 +730,13 @@ The homework to practice branching and slightly working with modules is in repos * [Learn You a Haskell for Great Good](http://learnyouahaskell.com) (chapters 4, 7) * [Haskell: Pattern matching](https://en.wikibooks.org/wiki/Haskell/Pattern_matching) * [Haskell: Control structures](https://en.wikibooks.org/wiki/Haskell/Control_structures) +* [Haskell: List comprehension](https://wiki.haskell.org/List_comprehension) +* [Haskell: Lazy evaluation](https://wiki.haskell.org/Lazy_evaluation) * [Haskell: Laziness](https://en.wikibooks.org/wiki/Haskell/Lazines) * [Haskell: Modules](https://en.wikibooks.org/wiki/Haskell/Modules) * [Haskell: Import](https://wiki.haskell.org/Import) * [Haskell: Import modules properly](https://wiki.haskell.org/Import_modules_properly). * [24 Days of GHC Extensions: Bang Patterns](https://ocharles.org.uk/blog/posts/2014-12-05-bang-patterns.html) +* [Oh my laziness](http://alpmestan.com/posts/2013-10-02-oh-my-laziness.html) +* [Haskell String Types](http://www.alexeyshmalko.com/2015/haskell-string-types/) +* [Untangling Haskells strings](https://mmhaskell.com/blog/2017/5/15/untangling-haskells-strings) diff --git a/tutorials/04_types-errors.md b/tutorials/04_types-errors.md index a9a960c..0b0cd9b 100644 --- a/tutorials/04_types-errors.md +++ b/tutorials/04_types-errors.md @@ -284,11 +284,6 @@ The homework to practice working with new types, list comprehensions, containers ## Further reading -* [Oh my laziness](http://alpmestan.com/posts/2013-10-02-oh-my-laziness.html) -* [Haskell - list comprehension](https://wiki.haskell.org/List_comprehension) -* [Haskell - Lazy evaluation](https://wiki.haskell.org/Lazy_evaluation) -* [Haskell String Types](http://www.alexeyshmalko.com/2015/haskell-string-types/) -* [Untangling Haskells strings](https://mmhaskell.com/blog/2017/5/15/untangling-haskells-strings) * [Haskell containers](https://haskell-containers.readthedocs.io/en/latest/) * [Haskell - Handling errors in Haskell](https://wiki.haskell.org/Handling_errors_in_Haskell) * [Haskell - error](https://wiki.haskell.org/Error) From 3313571a8c164d320071611a11fe518837f22a14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Sun, 10 Mar 2019 07:46:25 +0100 Subject: [PATCH 03/26] Moving stuff between 4,5,6 --- tutorials/04_types-errors.md | 577 +++++++++++++++++-- tutorials/05_functions-typeclasses.md | 768 +++++++------------------- tutorials/06_io-test-doc.md | 179 ------ 3 files changed, 761 insertions(+), 763 deletions(-) diff --git a/tutorials/04_types-errors.md b/tutorials/04_types-errors.md index 0b0cd9b..f0e75af 100644 --- a/tutorials/04_types-errors.md +++ b/tutorials/04_types-errors.md @@ -1,4 +1,4 @@ -# Types, containers, and errors +# Types, containers, and advanced functions ## Important "base" types @@ -224,59 +224,574 @@ Again, there is an efficient implementation of maps, where the keys are of `Int` Finally, [containers] specify also [Data.Tree](https://hackage.haskell.org/package/containers/docs/Data-Tree.html) and [Data.Graph](https://hackage.haskell.org/package/containers/docs/Data-Graph.html), both in a very generic manner. If you ever need to work with trees or graphs, it is convenient to use those instead of reinventing the wheel yourself. -## Handling errors +## More about functions -As we saw, a very elegant way way how to handle errors is using `Maybe` or `Either` types. This is a preferred way with obvious advantages, however, in practice, it may still come to a more explosive situation. +Creating new own functions or using the predefined ones from libraries is common in most programming languages. However, in a pure functional language, first-class functions enable to do much more. Generally, we architecture the programme by *composing functions* and other "tricks". -### error +### Currying -`error` is a special function which stops execution with given message: +When we talk about "currying", in Haskell it has (almost) nothing to do with dishes or spices. A famous mathematician and logician [Haskell Curry](https://en.wikipedia.org/wiki/Haskell_Curry) (the language is named after him) developed with others technique called currying: *translating the evaluation of a function that takes multiple arguments (or a tuple of arguments) into evaluating a sequence of functions, each with a single argument*. Technically, the original author of this is [Moses Schönfinkel](https://en.wikipedia.org/wiki/Moses_Sch%C3%B6nfinkel), so sometimes you may even come across a very nice name ["Schönfinkelization"](http://www.natansh.in/2012/07/27/schonfinkelization/). +Currying can be achieved in all functional programming languages, but Haskell is special in that *all functions are curried by default*, similarly to pure lambda calculus. Let's se how we parenthesize function types: + +```haskell +myFunc1 :: a -> b -> c +myFunc1 :: a -> (b -> c) ``` -Prelude> error "Stop now" -*** Exception: Stop now -CallStack (from HasCallStack): - error, called at :1:1 in interactive:Ghci1 + +This means that the type annotation is right-associative. We can read that `myFunc1` takes value of `a` and returns a function that takes value of `b` and result is a value of `c`. It is possible to apply value of `a` and "store" the function `b -> c` for later application or reuse: + +``` +Prelude> let myFunc x y z = x * y + z +Prelude> :type myFunc +myFunc :: Num a => a -> a -> a -> a +Prelude> :type (myFunc 8) +(myFunc 8) :: Num a => a -> a -> a +Prelude> :type (myFunc 8 7) +(myFunc 8 7) :: Num a => a -> a +Prelude> :type (myFunc 8 7 1) +(myFunc 8 7 1) :: Num a => a +Prelude> myFunc 8 7 1 +57 +Prelude> myFunc2 = myFunc 8 7 +Prelude> myFunc2 1 +57 +Prelude> myFunc2 2 +58 +``` + +So what is currying useful for? It enables a very powerful abstraction technique called **[partial application](https://en.wikipedia.org/wiki/Partial_application)**. Without going into a detail, partial application is currying + taking care of the context (closure) enabling us to achieve *reification* (a more concrete behaviour). + +Imagine this situation of a polygon library: + +```haskell +type PSize = Int +type NoVertices = Int +data Polygon = -- some representation + +mkPolygon :: NoVertices -> PSize -> Polygon +mkPolygon = -- some code to make a polygon + +mkHexagon :: PSize -> Polygon +mkHexagon = mkPolygon 6 + +mkRectangle :: PSize -> Polygon +mkRectangle = mkPolygon 4 + +--etc. ``` +Here we create *specialized* versions of polygon constructor functions by providing the `PSize` parameter. As functions can be parameters, as well, we can reify the behaviour, as well: + +```haskell +generalSort :: Ord a => (a -> a -> Ordering) -> [a] -> [a] +generalSort orderingFn numbers = -- use the orderingFn to sort the numbers + +fastOrderingFn :: Ord a => a -> a -> Ordering +fastOrderingFn = -- a fast, but not too reliable ordering algorithm -There is another quite similar one - `errorWithoutStackTrace`: +slowOrderingFn :: Ord a => a -> a -> Ordering +slowOrderingFn = -- a slow, but precise ordering algorithm +fastSort :: Ord a => [a] -> [a] +fastSort = generalSort fastOrderingFn + +goodSort :: Ord a => [a] -> [a] +goodSort = generalSort slowOrderingFn ``` -Prelude> errorWithoutStackTrace "Stop now without stack trace" -*** Exception: Stop now without stack trace + +This technique is very elegant, DRY and it is a basis of a good purely functional style. Its object-oriented relatives are the [Template Method design pattern](https://en.wikipedia.org/wiki/Template_method_pattern) brother married with the [Factory Method design pattern](https://en.wikipedia.org/wiki/Factory_method_pattern) – quite some fat, bloated relatives, aren't they? + +As you can see, the "parametrising" parameters must come first, so we can make a curried version of the constructor function. At the same time, the order of parameters can be switched using the `flip` function that takes its (first) two arguments in the reverse order of `f`: + +```haskell +flip :: (a -> b -> c) -> b -> a -> c ``` +Then we can have: -It is obviously even worse than just `error` because you somewhere deep in your code say something about rendering the error... +```haskell +generalSort :: [Something] -> (Something -> Something -> Ordering) -> [Int] +generalSort numbers orderingFn = -- use the orderingFn to sort the numbers -### undefined +fastOrderingFn :: Something -> Something -> Ordering +fastOrderingFn = -- a fast, but not too reliable ordering algorithm -Special case of error is that something is `undefined` and it does not accept any message: +slowOrderingFn :: Something -> Something -> Ordering +slowOrderingFn = -- a slow, but precise ordering algorithm +fastSort :: [Something] -> [Something] +fastSort = (flip generalSort) fastOrderingFn + +goodSort :: [Something] -> [Something] +goodSort = (flip generalSort) slowOrderingFn ``` -Prelude> undefined -*** Exception: Prelude.undefined -CallStack (from HasCallStack): - error, called at libraries/base/GHC/Err.hs:79:14 in base:GHC.Err - undefined, called at :5:1 in interactive:Ghci1 + +which is of course equivalent (but bloated and not idiomatic!) to: + +```haskell +fastSort :: [Something] -> [Something] +fastSort numbers = generalSort numbers fastOrderingFn +``` + +As we said, all functions in Haskell are curried. In case you want to make them not curried, you can use tuples to "glue" parameters together: + +```haskell +notCurried :: (a, b) -> (c, d) -> e +``` + +However, we do this *just* in case they are inherently bound together like key-value pairs. + +There are also `curry` and `uncurry` functions available to do such transformations: + +``` +Prelude> :type curry +curry :: ((a, b) -> c) -> a -> b -> c +Prelude> let myFunc (x, y) = x + y +Prelude> :type myFunc +myFunc :: Num a => (a, a) -> a +Prelude> myFunc (1, 5) +6 +Prelude> (curry myFunc) 1 5 +6 +Prelude> :type (curry myFunc) +(curry myFunc) :: Num c => c -> c -> c +Prelude> :type uncurry +uncurry :: (a -> b -> c) -> (a, b) -> c +Prelude> let myFunc x y = x + y +Prelude> :type (uncurry myFunc) +(uncurry myFunc) :: Num c => (c, c) -> c +``` + +If you like math, then it is the same difference as between *f*: ℝ → ℝ → ℝ and *g*: ℝ × ℝ → ℝ. + +In most other functional languages, like Lisp (Clojure) and Javascript, the situation is the opposite to Haskell: the functions are by default not curried and there are functions (usually called `curry`), which enable partial function application – see e.g. [this post](https://blog.benestudio.co/currying-in-javascript-es6-540d2ad09400). + +### Function composition + +As stated in the beginning, function composition is the main means of devising an **architecture** of a functional programme. It works similarly to function composition in math: Having two functions, one with type `a -> b` and second with type `b -> c` you can create a composed one with type `a -> c`. In Haskell, a composition is done using the dot `(.)` operator: + +```haskell +Prelude> :type (5+) +(5+) :: Num a => a -> a +Prelude> :type (5*) +(5*) :: Num a => a -> a +Prelude> :type show +show :: Show a => a -> String +Prelude> show ( (5+) ( (5*) 5 ) ) +"30" +Prelude> (show . (5+) . (5*)) 5 +"30" +``` + +Or using the earlier introduced `($)` application: + +``` +Prelude> show . (5+) . (5*) $ 5 +"30" +``` + +Again, like in math, *f*: A → B and *g*: B → C, then (*f* ∘ *g*): A → C. + +### The "pointfree" style + +It is very common in FP to write functions as a composition of other functions without mentioning the actual arguments they will be applied to. Consider the following two examples and notice that although the result is the same, the first one is a way more declarative, concise and readable. + +```haskell +sumA = foldr (+) 0 +sumB xs = foldr (+) 0 xs +``` + +Those are very simple examples but you can build more complex ones with function composition `(.)` and partially applied or plain functions. + +```haskell +myFunc :: Int -> String +myFunc = show . (5+) . (5*) +``` + +Now you might ask why we call this a "pointfree" style, when there are actually more points. The confusion comes from the origin of the term, which is (again) math: it is a function that does not explicitly mention the points (values) of the space on which the function acts. + +### Fixity and precedence + +You might wonder how it works in Haskell that the following expression is evaluated in the correct order you would expect without using brackets: + +``` +Prelude> 5 + 2^3 - 4 + 2 * 2 +13 +Prelude> 5 * sin pi - 3 * cos pi + 2 +5.0 +``` + +The first basic rule is that a function application binds the most. For example, in `foo 5 + 4` it will first evaluate `foo 5` and then add `4` (`foo 5 + 4` is the same as `(+) (foo 5) 4`. If you want to avoid that, you need to use brackets `foo (5 + 4)` or a function application operator `foo $ 5 + 4` (or strict `$!`). + +For infix operators (`+`, `**`, `/`, `==`, etc.) and functions (with backticks: `div`, `rem`, `quot`, `mod`, etc.), there is a special infix specification with one of three keywords: + +- `infix` = Non-associative operator (for example, comparison operators) +- `infixl` = Left associative operator (for example, `+`, `-`, or `!!`) +- `infixr` = Right associative operator (for example, `^`, `**`, `.`, or `&&`) + +Each of them should be followed by precedence (0 binds least tightly, and level 9 binds most tightly, default is 9) followed by the function/operator name. To see it in action, you can use `:info` to discover this specification for existing well-known operators and infix functions: + +``` +Prelude> :info (+) +... +infixl 6 + +Prelude> :info (&&) +... +infixr 3 && +Prelude> :info div +... +infixl 7 `div` +``` + +You can also check *Table 4.1* of [The Haskell 2010 Language: Chapter 4 - Declarations and Bindings](https://www.haskell.org/onlinereport/haskell2010/haskellch4.html#x10-820061). + +### Own operators + +You already know that operators are just functions and that you can switch always between prefix and infix: + +``` +Prelude> (+) 5 7 +12 +Prelude> 7 `div` 2 +3 +Prelude> foo x y z = x * (y + z) +Prelude> (5 `foo` 3) 12 +75 +``` + +You can define own operator as you would do it with function: + +``` +Prelude> (><) xs ys = reverse xs ++ reverse ys +Prelude> (><) "abc" "xyz" +"cbazyx" +Prelude> "abc" >< "xyz" +"cbazyx" +Prelude> :info (><) +(><) :: [a] -> [a] -> [a] +``` + +By default, its asociativity is left, as you can observe: + +``` +Prelude> "abc" >< "xyz" >< "klm" +"xyzabcmlk" +Prelude> ("abc" >< "xyz") >< "klm" +"xyzabcmlk" +Prelude> "abc" >< ("xyz" >< "klm") +"cbaklmxyz" +``` + +By default, its precedence level is 9. We can observe that by constructing expression with `(++)` which has level 5 and the right associativity. + +``` +Prelude> "abc" >< "xyz" ++ "klm" +"cbazyxklm" +Prelude> "klm" ++ "abc" >< "xyz" +"klmcbazyx" +``` + +You can easily change that and if the new precedence is lower, than `(++)` will be done first. If the precedence is the same, then it is applied in "natural" order (thus, it must have the same associativity, otherwise you get an error). + +```haskell +infixl 5 >< +(><) :: [a] -> [a] -> [a] +(><) xs ys = reverse xs ++ reverse ys + +infixl 2 >-< +(>-<) :: [a] -> [a] -> [a] +xs >-< ys = reverse xs ++ reverse ys + +foo :: Int -> Int -> Int +x `foo` y = 2*x + y +``` + +``` +*Main> :info (><) +(><) :: [a] -> [a] -> [a] -- Defined at test01.hs:3:1 +infixl 5 >< +*Main> "abc" >< "xyz" ++ "klm" + +:6:1: error: + Precedence parsing error + cannot mix `><' [infixl 5] and `++' [infixr 5] in the same infix expression +*Main> ("abc" >< "xyz") ++ "klm" +"cbazyxklm" +*Main> :info (>-<) +(>-<) :: [a] -> [a] -> [a] -- Defined at test01.hs:7:1 +infixl 2 >-< +*Main> "abc" >-< "xyz" ++ "klm" +"cbamlkzyx" +*Main> + +:12:1: error: lexical error at character '\ESC' +*Main> "klm" ++ "abc" >-< "xyz" +"cbamlkzyx" +``` + +For operators you can use *symbol characters* as being any of `!#$%&*+./<=>?@\^|-~:` or "any *non-ascii* Unicode symbol or punctuation". But, an operator symbol starting with a colon `:` is a constructor. + +### Infix and operator-like data constructors + +Data constructors can be treated just as functions. You can pass them to a function as a parameter, return them from a function as a result and also use them in infix: + +``` +Prelude> data MyTuple a b = MyTupleConstr a b deriving Show +Prelude> :type MyTupleConstr +MyTupleConstr :: a -> b -> MyTuple a b +Prelude> MyTupleConstr 5 "Hi" +MyTupleConstr 5 "Hi" +Prelude> 5 `MyTupleConstr` "Hi" +MyTupleConstr 5 "Hi" +``` + +As we said, for constructors you may create operator starting with a colon (and optionally specify also `infix`, `infixl`, or `infixr`). + +``` +Prelude> data MyTuple2 a b = a :@ b deriving Show +Prelude> :type (:@) +(:@) :: a -> b -> MyTuple2 a b +Prelude> 5 :@ "Hi" +5 :@ "Hi" +Prelude> (:@) 5 "Hi" +5 :@ "Hi" +``` + +You can try that using operator which doesn't start with a colon is not possible. But you can always make a synonym and then your code more readable: + +``` +Prelude> data MyTuple3 a b = a @@ b deriving Show + +:15:17: error: Not a data constructor `a' +Prelude> (@@) = (:@) +Prelude> :type (@@) +(@@) :: a -> b -> MyTuple2 a b +Prelude> 5 @@ "Hi" +5 :@ "Hi" +``` + +Another fine feature is, that operators `:@` and `@@` can be specified with different associativity and precedence! + +GHC has an extension of [Generalized Algebraic Data Types (GADTs)](https://en.wikibooks.org/wiki/Haskell/GADT), where the idea of unifying function and data types is pushed even further. However, as they are a more advanced topic, we leave them to your interest. + +### Anonymous functions + +An anonymous function is a function without a name. It is a Lambda abstraction and might look like this: `\x -> x + 1`. Sometimes, it is more convenient to use a lambda expression rather than giving a function a name. You should use anonymous functions only for very simple functions because it decreases readability of the code. + +```haskell +myFunc1 x y z = x * y + z -- <= just syntactic sugar! +myFunc2 = (\x y z -> x * y + z) -- <= still syntactic sugar! +myFunc3 = (\x -> \y -> \z -> x * y + z) -- <= desugarized function +mapFunc1 = map myFunc1 +mapAFunc1 = map (\x y z -> x * y + z) +``` + +Anonymous functions are one of the corner-stones of functional programming and you will meet them in all languages that claim to be at least a little bit "functional". + +## Higher-order functions + +Higher order function is a function that takes a function as an argument and/or returns a function as a result. We already saw some of them: `(.)`, `curry`, `uncurry`, `map`, etc. Higher-order functions are a very important concept in functional programming. Learning them and using them properly leads to readable, declarative, concise and safe code. They are used especially in manipulating lists, where they are preferred over traditional recursion today. + +### Map and filter + +Two widely used functions well-known in the most of functional (but others as well) programming languages are `map` and `filter`. In the `Prelude` module, they are defined for lists, but they work in the same way for other data structures (`Data.Sequence`, `Data.Set`, etc., see the previous lecture). When you need to *transform* a list by applying a function to its every element, then you can use `map`. If you have a list and you need to make a sublist based on some property of its elements, use `filter`. The best for understanding is to look at its possible implementation: + +```haskell +myMap :: (a -> b) -> [a] -> [b] +myMap _ [] = [] +myMap f (x:xs) = f x : myMap xs + +myFilter :: (a -> Bool) -> [a] -> [a] +myFilter _ [] = [] +myFilter p (x:xs) + | p x = x : filter p xs + | otherwise = filter p xs +``` + +That's it. Let us have some examples: + +``` +Prelude> :type map +map :: (a -> b) -> [a] -> [b] +Prelude> map show [1..5] +["1","2","3","4","5"] +Prelude> map (5*) [1..5] +[5,10,15,20,25] +Prelude> map (length . show . abs) [135, (-15), 0, 153151] +[3,2,1,6] +Prelude> :type filter +filter :: (a -> Bool) -> [a] -> [a] +Prelude> filter (\x -> x `mod` 7 == 0) [1..50] +[7,14,21,28,35,42,49] +``` + +Soon we will get into a generalized function called `fmap` while discussing the term *functor*. + +### Folds and scans + +Maybe you've heard about *Map/Reduce*... We know `map`, but there is no `reduce`! Actually, there is, but it is called [fold](https://wiki.haskell.org/Fold) (it is practically a synonym in functional programming). Folds are higher-order functions that process a data structure in some order and build a return value. It (as everything in Haskell) has foundations in math - concretely in [Catamorphism](https://wiki.haskell.org/Catamorphisms) of the Category Theory. + +So `map` takes a list a produces another list of the same length, while `fold` takes a list and produces a single value. + +To get into folds in practice, let's try to implement `sum` and `product` functions (if you want to practice on your own, try it with `and` and `or`). + +```haskell +mySum :: Num a => [a] -> a +mySum [] = 0 +mySum (x:xs) = x + mySum xs + +myProduct :: Num a => [a] -> a +myProduct [] = 1 +myProduct (x:xs) = x * myProduct xs ``` -Semantically, it can be used where the value is not defined (for example when you want to divide by zero). Sometimes you can see it used as a basic placeholder with meaning "Not implemented yet". For such things, you can use custom `error` or some specialized package like [Development.Placeholders](hackage.haskell.org/package/placeholders/docs/Development-Placeholders.html), which are more suitable. +Obviously, there are some similarities: -### throw, try and catch +1. initial value for an empty list (`0` for `sum` and `1` in the case of `product`), +2. use a function and apply it to an element and recursive call to the rest of the list. -We have `throw`, `try` and `catch`, but those are functions - not keywords! +Let's make a generalized higher-order function that also takes an initial value and a function for processing: + +```haskell +process :: (a -> a -> a) -> a -> [a] -> a +process _ initValue [] = initValue +process f initValue (x:xs) = f x (process f initValue xs) + +mySum = process (+) 0 +myProduct = process (*) 1 +``` + +But here we are getting into a problem. Both `(+)` and `(*)` use operands and result of the same type - if we want to convert a number to string and join it in one go with `process`, it is not possible! + +``` +*Main> process (\x str -> show x ++ str) "" [1,2,3,4] + +:18:39: error: + • No instance for (Num [Char]) arising from the literal ‘1’ + • In the expression: 1 + In the third argument of ‘process’, namely ‘[1, 2, 3, 4]’ + In the expression: + process (\ x str -> show x ++ str) "" [1, 2, 3, 4] +``` + +The type of the initial value must be the same as the type which is returned by given function. Now we get this: + + +```haskell +process :: (a -> b -> b) -> b -> [a] -> b +process _ initValue [] = initValue +process f initValue (x:xs) = f x (process f initValue xs) + +mySum = process (+) 0 +myProduct = process (*) 1 + +myToStrJoin :: (Show a) => [a] -> String +myToStrJoin = process (\x str -> show x ++ str) "" +``` + +Now problem is that both `(+)` and `(*)` are commutative, but `(\x str -> show x ++ str)` is not, even type of `x` and `str` can be different. What if we need to apply the function in a different order? Now we have to create two variants. + + +```haskell +processr :: (a -> b -> b) -> b -> [a] -> b -- "accumulates" in the RIGHT operand +processr _ initValue [] = initValue +processr f initValue (x:xs) = f x (processr f initValue xs) + +processl :: (b -> a -> b) -> b -> [a] -> b -- "accumulates" in the LEFT operand +processl _ initValue [] = initValue +processl f initValue (x:xs) = f (processl f initValue xs) x + +mySum = processl (+) 0 +myProduct = processl (*) 1 + +myToStrJoinR :: (Show a) => [a] -> String +myToStrJoinR = processr (\x str -> show x ++ str) "" +myToStrJoinL :: (Show a) => [a] -> String +myToStrJoinL = processl (\str x -> show x ++ str) "" +``` + +This is something so generally useful, that it is prepared for you and not just for lists but for every instance of typeclass `Foldable` - two basic folds `foldl`/`foldr` and related `scanl`/`scanr`, which capture intermediate values in a list: ``` -Prelude> import Control.Exception -Prelude Control.Exception> :type try -try :: Exception e => IO a -> IO (Either e a) -Prelude Control.Exception> :type throw -throw :: Exception e => e -> a -Prelude Control.Exception> :type catch -catch :: Exception e => IO a -> (e -> IO a) -> IO a +Prelude> :type foldl +foldl :: Foldable t => (b -> a -> b) -> b -> t a -> b +Prelude> :type foldr +foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b +Prelude> foldl (-) 0 [1..10] +-55 +Prelude> ((((((((((0-1)-2)-3)-4)-5)-6)-7)-8)-9)-10) +-55 +Prelude> scanl (-) 0 [1..10] +[0,-1,-3,-6,-10,-15,-21,-28,-36,-45,-55] +Prelude> foldr (-) 0 [1..10] +-5 +Prelude> (1-(2-(3-(4-(5-(6-(7-(8-(9-(10-0)))))))))) +-5 +Prelude> scanr (-) 0 [1..10] +[-5,6,-4,7,-3,8,-2,9,-1,10,0] ``` -If you are interested you can read the documentation of [Control.Exception](https://hackage.haskell.org/package/base/docs/Control-Exception.html), however, exceptions are considered an anti-pattern in Haskell and you should always try to deal with potential errors in a more systematic way using types. We will slightly get back to these after getting the notion of Monads. +There are some special variants: + +``` +Prelude> foldr1 (+) [1..10] +Prelude> foldl1 (*) [1..10] +Prelude> foldr1 (+) [] +Prelude> foldl1 (*) [] + +Prelude> foldl' (*) 0 [1..10] -- strict evaluation before reduction +Prelude> foldl'1 (*) [1..10] + +Prelude> minimum [1,2,63,12,5,201,2] +Prelude> maximum [1,2,63,12,5,201,2] +``` + +As an exercise, try to implement `foldl` by using `foldr` (spoiler: [solution](https://wiki.haskell.org/Foldl_as_foldr)). + +## FP in other languages + +Functional programming concepts that you learn in a pure functional language may be more or less applicable in other languages, as well, according to the concepts supported and how well they are implemented. Also, some languages provide serious functional constructs, but they are quite cumbersome syntactically, which repels their common usage (yes, we point to you, JavaScript ;-) + +### C/C++ + +C++ is a general purpose object-oriented programming language based on C, which is an imperative procedural language. In both, it is possible to create functions (and procedures). There is no control if a function is pure or not (i.e. making side effects). And in C/C++ you need to deal with mutability, pointers and working with memory on low level (de/allocation). Typing is strict and you can make higher-order functions with "function pointer" types. + +```cpp +int calculate(int(*binOperation)(const int, const int), const int operandA, const int operandB){ + return binOperation(operandA, operandB); +} +``` + +If you are a normal person and not a bighead, you will most probably use `typedef` to name the type of such functions so the code is more readable and understandable. In newer versions of C++, there are also anonymous functions, combinators (`for_each`, `transform`, `filter`, ...), functors. Then you can of course use simpler functional concepts such as closures or recursion. + +```cpp +typedef int(*binOperation)(const int, const int); /* I am not a bighead */ + +int calculate(binOperation bo, const int operandA, const int operandB){ + return bo(operandA, operandB); +} +``` + +* [libf - C++ as a Pure Functional Programming Language](https://github.com/GJDuck/libf) +* [Functional in C++17 and C++20](http://www.modernescpp.com/index.php/functional-in-c-17-and-c-20) + +### Java + +* [Flying Bytes - An Introduction to Functional Programming in Java 8](https://flyingbytes.github.io/programming/java8/functional/part0/2017/01/16/Java8-Part0.html) +* [Hackernoon - Finally Functional Programming in Java](https://hackernoon.com/finally-functional-programming-in-java-ad4d388fb92e) +* [JavaCodeGeeks - Java 9 Functional Programming Tutorial](https://examples.javacodegeeks.com/core-java/java-9-functional-programming-tutorial/) + +### Python + +* [Functional Programming in Python (free O'Reilly)](http://www.oreilly.com/programming/free/functional-programming-python.csp) +* [Python 3 - Functional Programming HOWTO](https://docs.python.org/3/howto/functional.html) +* [Python 3 - Typing](https://docs.python.org/3/library/typing.html) + +### Smalltalk and Ruby + +* [Smalltalk, A Functional Programming Language](http://monospacedmonologues.com/post/138978728947/smalltalk-a-functional-programming-language) +* [Functional Programming in Ruby for people who don’t know what functional programming is](https://medium.com/craft-academy/functional-programming-in-ruby-for-people-who-dont-know-what-functional-programming-is-f0c4ab7dc68c) +* [Functional Programming in Ruby](http://joelmccracken.github.io/functional-programming-in-ruby/#/) +* [Embracing Functional Programming in Ruby](https://kellysutton.com/2017/09/13/embracing-functional-programming-in-ruby.html) ## Task assignment diff --git a/tutorials/05_functions-typeclasses.md b/tutorials/05_functions-typeclasses.md index 6f2e3f6..b35592b 100644 --- a/tutorials/05_functions-typeclasses.md +++ b/tutorials/05_functions-typeclasses.md @@ -1,527 +1,4 @@ -# Advanced functions and intro to typeclasses - -## More about functions - -Creating new own functions or using the predefined ones from libraries is common in most programming languages. However, in a pure functional language, first-class functions enable to do much more. Generally, we architecture the programme by *composing functions* and other "tricks". - -### Currying - -When we talk about "currying", in Haskell it has (almost) nothing to do with dishes or spices. A famous mathematician and logician [Haskell Curry](https://en.wikipedia.org/wiki/Haskell_Curry) (the language is named after him) developed with others technique called currying: *translating the evaluation of a function that takes multiple arguments (or a tuple of arguments) into evaluating a sequence of functions, each with a single argument*. Technically, the original author of this is [Moses Schönfinkel](https://en.wikipedia.org/wiki/Moses_Sch%C3%B6nfinkel), so sometimes you may even come across a very nice name ["Schönfinkelization"](http://www.natansh.in/2012/07/27/schonfinkelization/). - -Currying can be achieved in all functional programming languages, but Haskell is special in that *all functions are curried by default*, similarly to pure lambda calculus. Let's se how we parenthesize function types: - -```haskell -myFunc1 :: a -> b -> c -myFunc1 :: a -> (b -> c) -``` - -This means that the type annotation is right-associative. We can read that `myFunc1` takes value of `a` and returns a function that takes value of `b` and result is a value of `c`. It is possible to apply value of `a` and "store" the function `b -> c` for later application or reuse: - -``` -Prelude> let myFunc x y z = x * y + z -Prelude> :type myFunc -myFunc :: Num a => a -> a -> a -> a -Prelude> :type (myFunc 8) -(myFunc 8) :: Num a => a -> a -> a -Prelude> :type (myFunc 8 7) -(myFunc 8 7) :: Num a => a -> a -Prelude> :type (myFunc 8 7 1) -(myFunc 8 7 1) :: Num a => a -Prelude> myFunc 8 7 1 -57 -Prelude> myFunc2 = myFunc 8 7 -Prelude> myFunc2 1 -57 -Prelude> myFunc2 2 -58 -``` - -So what is currying useful for? It enables a very powerful abstraction technique called **[partial application](https://en.wikipedia.org/wiki/Partial_application)**. Without going into a detail, partial application is currying + taking care of the context (closure) enabling us to achieve *reification* (a more concrete behaviour). - -Imagine this situation of a polygon library: - -```haskell -type PSize = Int -type NoVertices = Int -data Polygon = -- some representation - -mkPolygon :: NoVertices -> PSize -> Polygon -mkPolygon = -- some code to make a polygon - -mkHexagon :: PSize -> Polygon -mkHexagon = mkPolygon 6 - -mkRectangle :: PSize -> Polygon -mkRectangle = mkPolygon 4 - ---etc. -``` -Here we create *specialized* versions of polygon constructor functions by providing the `PSize` parameter. As functions can be parameters, as well, we can reify the behaviour, as well: - -```haskell -generalSort :: Ord a => (a -> a -> Ordering) -> [a] -> [a] -generalSort orderingFn numbers = -- use the orderingFn to sort the numbers - -fastOrderingFn :: Ord a => a -> a -> Ordering -fastOrderingFn = -- a fast, but not too reliable ordering algorithm - -slowOrderingFn :: Ord a => a -> a -> Ordering -slowOrderingFn = -- a slow, but precise ordering algorithm - -fastSort :: Ord a => [a] -> [a] -fastSort = generalSort fastOrderingFn - -goodSort :: Ord a => [a] -> [a] -goodSort = generalSort slowOrderingFn -``` - -This technique is very elegant, DRY and it is a basis of a good purely functional style. Its object-oriented relatives are the [Template Method design pattern](https://en.wikipedia.org/wiki/Template_method_pattern) brother married with the [Factory Method design pattern](https://en.wikipedia.org/wiki/Factory_method_pattern) – quite some fat, bloated relatives, aren't they? - -As you can see, the "parametrising" parameters must come first, so we can make a curried version of the constructor function. At the same time, the order of parameters can be switched using the `flip` function that takes its (first) two arguments in the reverse order of `f`: - -```haskell -flip :: (a -> b -> c) -> b -> a -> c -``` -Then we can have: - -```haskell -generalSort :: [Something] -> (Something -> Something -> Ordering) -> [Int] -generalSort numbers orderingFn = -- use the orderingFn to sort the numbers - -fastOrderingFn :: Something -> Something -> Ordering -fastOrderingFn = -- a fast, but not too reliable ordering algorithm - -slowOrderingFn :: Something -> Something -> Ordering -slowOrderingFn = -- a slow, but precise ordering algorithm - -fastSort :: [Something] -> [Something] -fastSort = (flip generalSort) fastOrderingFn - -goodSort :: [Something] -> [Something] -goodSort = (flip generalSort) slowOrderingFn -``` - -which is of course equivalent (but bloated and not idiomatic!) to: - -```haskell -fastSort :: [Something] -> [Something] -fastSort numbers = generalSort numbers fastOrderingFn -``` - -As we said, all functions in Haskell are curried. In case you want to make them not curried, you can use tuples to "glue" parameters together: - -```haskell -notCurried :: (a, b) -> (c, d) -> e -``` - -However, we do this *just* in case they are inherently bound together like key-value pairs. - -There are also `curry` and `uncurry` functions available to do such transformations: - -``` -Prelude> :type curry -curry :: ((a, b) -> c) -> a -> b -> c -Prelude> let myFunc (x, y) = x + y -Prelude> :type myFunc -myFunc :: Num a => (a, a) -> a -Prelude> myFunc (1, 5) -6 -Prelude> (curry myFunc) 1 5 -6 -Prelude> :type (curry myFunc) -(curry myFunc) :: Num c => c -> c -> c -Prelude> :type uncurry -uncurry :: (a -> b -> c) -> (a, b) -> c -Prelude> let myFunc x y = x + y -Prelude> :type (uncurry myFunc) -(uncurry myFunc) :: Num c => (c, c) -> c -``` - -If you like math, then it is the same difference as between *f*: ℝ → ℝ → ℝ and *g*: ℝ × ℝ → ℝ. - -In most other functional languages, like Lisp (Clojure) and Javascript, the situation is the opposite to Haskell: the functions are by default not curried and there are functions (usually called `curry`), which enable partial function application – see e.g. [this post](https://blog.benestudio.co/currying-in-javascript-es6-540d2ad09400). - -### Function composition - -As stated in the beginning, function composition is the main means of devising an **architecture** of a functional programme. It works similarly to function composition in math: Having two functions, one with type `a -> b` and second with type `b -> c` you can create a composed one with type `a -> c`. In Haskell, a composition is done using the dot `(.)` operator: - -```haskell -Prelude> :type (5+) -(5+) :: Num a => a -> a -Prelude> :type (5*) -(5*) :: Num a => a -> a -Prelude> :type show -show :: Show a => a -> String -Prelude> show ( (5+) ( (5*) 5 ) ) -"30" -Prelude> (show . (5+) . (5*)) 5 -"30" -``` - -Or using the earlier introduced `($)` application: - -``` -Prelude> show . (5+) . (5*) $ 5 -"30" -``` - -Again, like in math, *f*: A → B and *g*: B → C, then (*f* ∘ *g*): A → C. - -### The "pointfree" style - -It is very common in FP to write functions as a composition of other functions without mentioning the actual arguments they will be applied to. Consider the following two examples and notice that although the result is the same, the first one is a way more declarative, concise and readable. - -```haskell -sumA = foldr (+) 0 -sumB xs = foldr (+) 0 xs -``` - -Those are very simple examples but you can build more complex ones with function composition `(.)` and partially applied or plain functions. - -```haskell -myFunc :: Int -> String -myFunc = show . (5+) . (5*) -``` - -Now you might ask why we call this a "pointfree" style, when there are actually more points. The confusion comes from the origin of the term, which is (again) math: it is a function that does not explicitly mention the points (values) of the space on which the function acts. - -### Fixity and precedence - -You might wonder how it works in Haskell that the following expression is evaluated in the correct order you would expect without using brackets: - -``` -Prelude> 5 + 2^3 - 4 + 2 * 2 -13 -Prelude> 5 * sin pi - 3 * cos pi + 2 -5.0 -``` - -The first basic rule is that a function application binds the most. For example, in `foo 5 + 4` it will first evaluate `foo 5` and then add `4` (`foo 5 + 4` is the same as `(+) (foo 5) 4`. If you want to avoid that, you need to use brackets `foo (5 + 4)` or a function application operator `foo $ 5 + 4` (or strict `$!`). - -For infix operators (`+`, `**`, `/`, `==`, etc.) and functions (with backticks: `div`, `rem`, `quot`, `mod`, etc.), there is a special infix specification with one of three keywords: - -- `infix` = Non-associative operator (for example, comparison operators) -- `infixl` = Left associative operator (for example, `+`, `-`, or `!!`) -- `infixr` = Right associative operator (for example, `^`, `**`, `.`, or `&&`) - -Each of them should be followed by precedence (0 binds least tightly, and level 9 binds most tightly, default is 9) followed by the function/operator name. To see it in action, you can use `:info` to discover this specification for existing well-known operators and infix functions: - -``` -Prelude> :info (+) -... -infixl 6 + -Prelude> :info (&&) -... -infixr 3 && -Prelude> :info div -... -infixl 7 `div` -``` - -You can also check *Table 4.1* of [The Haskell 2010 Language: Chapter 4 - Declarations and Bindings](https://www.haskell.org/onlinereport/haskell2010/haskellch4.html#x10-820061). - -### Own operators - -You already know that operators are just functions and that you can switch always between prefix and infix: - -``` -Prelude> (+) 5 7 -12 -Prelude> 7 `div` 2 -3 -Prelude> foo x y z = x * (y + z) -Prelude> (5 `foo` 3) 12 -75 -``` - -You can define own operator as you would do it with function: - -``` -Prelude> (><) xs ys = reverse xs ++ reverse ys -Prelude> (><) "abc" "xyz" -"cbazyx" -Prelude> "abc" >< "xyz" -"cbazyx" -Prelude> :info (><) -(><) :: [a] -> [a] -> [a] -``` - -By default, its asociativity is left, as you can observe: - -``` -Prelude> "abc" >< "xyz" >< "klm" -"xyzabcmlk" -Prelude> ("abc" >< "xyz") >< "klm" -"xyzabcmlk" -Prelude> "abc" >< ("xyz" >< "klm") -"cbaklmxyz" -``` - -By default, its precedence level is 9. We can observe that by constructing expression with `(++)` which has level 5 and the right associativity. - -``` -Prelude> "abc" >< "xyz" ++ "klm" -"cbazyxklm" -Prelude> "klm" ++ "abc" >< "xyz" -"klmcbazyx" -``` - -You can easily change that and if the new precedence is lower, than `(++)` will be done first. If the precedence is the same, then it is applied in "natural" order (thus, it must have the same associativity, otherwise you get an error). - -```haskell -infixl 5 >< -(><) :: [a] -> [a] -> [a] -(><) xs ys = reverse xs ++ reverse ys - -infixl 2 >-< -(>-<) :: [a] -> [a] -> [a] -xs >-< ys = reverse xs ++ reverse ys - -foo :: Int -> Int -> Int -x `foo` y = 2*x + y -``` - -``` -*Main> :info (><) -(><) :: [a] -> [a] -> [a] -- Defined at test01.hs:3:1 -infixl 5 >< -*Main> "abc" >< "xyz" ++ "klm" - -:6:1: error: - Precedence parsing error - cannot mix `><' [infixl 5] and `++' [infixr 5] in the same infix expression -*Main> ("abc" >< "xyz") ++ "klm" -"cbazyxklm" -*Main> :info (>-<) -(>-<) :: [a] -> [a] -> [a] -- Defined at test01.hs:7:1 -infixl 2 >-< -*Main> "abc" >-< "xyz" ++ "klm" -"cbamlkzyx" -*Main> - -:12:1: error: lexical error at character '\ESC' -*Main> "klm" ++ "abc" >-< "xyz" -"cbamlkzyx" -``` - -For operators you can use *symbol characters* as being any of `!#$%&*+./<=>?@\^|-~:` or "any *non-ascii* Unicode symbol or punctuation". But, an operator symbol starting with a colon `:` is a constructor. - -### Infix and operator-like data constructors - -Data constructors can be treated just as functions. You can pass them to a function as a parameter, return them from a function as a result and also use them in infix: - -``` -Prelude> data MyTuple a b = MyTupleConstr a b deriving Show -Prelude> :type MyTupleConstr -MyTupleConstr :: a -> b -> MyTuple a b -Prelude> MyTupleConstr 5 "Hi" -MyTupleConstr 5 "Hi" -Prelude> 5 `MyTupleConstr` "Hi" -MyTupleConstr 5 "Hi" -``` - -As we said, for constructors you may create operator starting with a colon (and optionally specify also `infix`, `infixl`, or `infixr`). - -``` -Prelude> data MyTuple2 a b = a :@ b deriving Show -Prelude> :type (:@) -(:@) :: a -> b -> MyTuple2 a b -Prelude> 5 :@ "Hi" -5 :@ "Hi" -Prelude> (:@) 5 "Hi" -5 :@ "Hi" -``` - -You can try that using operator which doesn't start with a colon is not possible. But you can always make a synonym and then your code more readable: - -``` -Prelude> data MyTuple3 a b = a @@ b deriving Show - -:15:17: error: Not a data constructor `a' -Prelude> (@@) = (:@) -Prelude> :type (@@) -(@@) :: a -> b -> MyTuple2 a b -Prelude> 5 @@ "Hi" -5 :@ "Hi" -``` - -Another fine feature is, that operators `:@` and `@@` can be specified with different associativity and precedence! - -GHC has an extension of [Generalized Algebraic Data Types (GADTs)](https://en.wikibooks.org/wiki/Haskell/GADT), where the idea of unifying function and data types is pushed even further. However, as they are a more advanced topic, we leave them to your interest. - -### Anonymous functions - -An anonymous function is a function without a name. It is a Lambda abstraction and might look like this: `\x -> x + 1`. Sometimes, it is more convenient to use a lambda expression rather than giving a function a name. You should use anonymous functions only for very simple functions because it decreases readability of the code. - -```haskell -myFunc1 x y z = x * y + z -- <= just syntactic sugar! -myFunc2 = (\x y z -> x * y + z) -- <= still syntactic sugar! -myFunc3 = (\x -> \y -> \z -> x * y + z) -- <= desugarized function -mapFunc1 = map myFunc1 -mapAFunc1 = map (\x y z -> x * y + z) -``` - -Anonymous functions are one of the corner-stones of functional programming and you will meet them in all languages that claim to be at least a little bit "functional". - -## Higher-order functions - -Higher order function is a function that takes a function as an argument and/or returns a function as a result. We already saw some of them: `(.)`, `curry`, `uncurry`, `map`, etc. Higher-order functions are a very important concept in functional programming. Learning them and using them properly leads to readable, declarative, concise and safe code. They are used especially in manipulating lists, where they are preferred over traditional recursion today. - -### Map and filter - -Two widely used functions well-known in the most of functional (but others as well) programming languages are `map` and `filter`. In the `Prelude` module, they are defined for lists, but they work in the same way for other data structures (`Data.Sequence`, `Data.Set`, etc., see the previous lecture). When you need to *transform* a list by applying a function to its every element, then you can use `map`. If you have a list and you need to make a sublist based on some property of its elements, use `filter`. The best for understanding is to look at its possible implementation: - -```haskell -myMap :: (a -> b) -> [a] -> [b] -myMap _ [] = [] -myMap f (x:xs) = f x : myMap xs - -myFilter :: (a -> Bool) -> [a] -> [a] -myFilter _ [] = [] -myFilter p (x:xs) - | p x = x : filter p xs - | otherwise = filter p xs -``` - -That's it. Let us have some examples: - -``` -Prelude> :type map -map :: (a -> b) -> [a] -> [b] -Prelude> map show [1..5] -["1","2","3","4","5"] -Prelude> map (5*) [1..5] -[5,10,15,20,25] -Prelude> map (length . show . abs) [135, (-15), 0, 153151] -[3,2,1,6] -Prelude> :type filter -filter :: (a -> Bool) -> [a] -> [a] -Prelude> filter (\x -> x `mod` 7 == 0) [1..50] -[7,14,21,28,35,42,49] -``` - -Soon we will get into a generalized function called `fmap` while discussing the term *functor*. - -### Folds and scans - -Maybe you've heard about *Map/Reduce*... We know `map`, but there is no `reduce`! Actually, there is, but it is called [fold](https://wiki.haskell.org/Fold) (it is practically a synonym in functional programming). Folds are higher-order functions that process a data structure in some order and build a return value. It (as everything in Haskell) has foundations in math - concretely in [Catamorphism](https://wiki.haskell.org/Catamorphisms) of the Category Theory. - -So `map` takes a list a produces another list of the same length, while `fold` takes a list and produces a single value. - -To get into folds in practice, let's try to implement `sum` and `product` functions (if you want to practice on your own, try it with `and` and `or`). - -```haskell -mySum :: Num a => [a] -> a -mySum [] = 0 -mySum (x:xs) = x + mySum xs - -myProduct :: Num a => [a] -> a -myProduct [] = 1 -myProduct (x:xs) = x * myProduct xs -``` - -Obviously, there are some similarities: - -1. initial value for an empty list (`0` for `sum` and `1` in the case of `product`), -2. use a function and apply it to an element and recursive call to the rest of the list. - -Let's make a generalized higher-order function that also takes an initial value and a function for processing: - -```haskell -process :: (a -> a -> a) -> a -> [a] -> a -process _ initValue [] = initValue -process f initValue (x:xs) = f x (process f initValue xs) - -mySum = process (+) 0 -myProduct = process (*) 1 -``` - -But here we are getting into a problem. Both `(+)` and `(*)` use operands and result of the same type - if we want to convert a number to string and join it in one go with `process`, it is not possible! - -``` -*Main> process (\x str -> show x ++ str) "" [1,2,3,4] - -:18:39: error: - • No instance for (Num [Char]) arising from the literal ‘1’ - • In the expression: 1 - In the third argument of ‘process’, namely ‘[1, 2, 3, 4]’ - In the expression: - process (\ x str -> show x ++ str) "" [1, 2, 3, 4] -``` - -The type of the initial value must be the same as the type which is returned by given function. Now we get this: - - -```haskell -process :: (a -> b -> b) -> b -> [a] -> b -process _ initValue [] = initValue -process f initValue (x:xs) = f x (process f initValue xs) - -mySum = process (+) 0 -myProduct = process (*) 1 - -myToStrJoin :: (Show a) => [a] -> String -myToStrJoin = process (\x str -> show x ++ str) "" -``` - -Now problem is that both `(+)` and `(*)` are commutative, but `(\x str -> show x ++ str)` is not, even type of `x` and `str` can be different. What if we need to apply the function in a different order? Now we have to create two variants. - - -```haskell -processr :: (a -> b -> b) -> b -> [a] -> b -- "accumulates" in the RIGHT operand -processr _ initValue [] = initValue -processr f initValue (x:xs) = f x (processr f initValue xs) - -processl :: (b -> a -> b) -> b -> [a] -> b -- "accumulates" in the LEFT operand -processl _ initValue [] = initValue -processl f initValue (x:xs) = f (processl f initValue xs) x - -mySum = processl (+) 0 -myProduct = processl (*) 1 - -myToStrJoinR :: (Show a) => [a] -> String -myToStrJoinR = processr (\x str -> show x ++ str) "" -myToStrJoinL :: (Show a) => [a] -> String -myToStrJoinL = processl (\str x -> show x ++ str) "" -``` - -This is something so generally useful, that it is prepared for you and not just for lists but for every instance of typeclass `Foldable` - two basic folds `foldl`/`foldr` and related `scanl`/`scanr`, which capture intermediate values in a list: - -``` -Prelude> :type foldl -foldl :: Foldable t => (b -> a -> b) -> b -> t a -> b -Prelude> :type foldr -foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b -Prelude> foldl (-) 0 [1..10] --55 -Prelude> ((((((((((0-1)-2)-3)-4)-5)-6)-7)-8)-9)-10) --55 -Prelude> scanl (-) 0 [1..10] -[0,-1,-3,-6,-10,-15,-21,-28,-36,-45,-55] -Prelude> foldr (-) 0 [1..10] --5 -Prelude> (1-(2-(3-(4-(5-(6-(7-(8-(9-(10-0)))))))))) --5 -Prelude> scanr (-) 0 [1..10] -[-5,6,-4,7,-3,8,-2,9,-1,10,0] -``` - -There are some special variants: - -``` -Prelude> foldr1 (+) [1..10] -Prelude> foldl1 (*) [1..10] -Prelude> foldr1 (+) [] -Prelude> foldl1 (*) [] - -Prelude> foldl' (*) 0 [1..10] -- strict evaluation before reduction -Prelude> foldl'1 (*) [1..10] - -Prelude> minimum [1,2,63,12,5,201,2] -Prelude> maximum [1,2,63,12,5,201,2] -``` - -As an exercise, try to implement `foldl` by using `foldr` (spoiler: [solution](https://wiki.haskell.org/Foldl_as_foldr)). +# Typeclasses, IO, and exceptions ## Typeclasses @@ -742,51 +219,236 @@ When you derive `Enum`, the order will be generated as left-to-right order of da Enumerations have also the `..` syntactic sugar. For example, `[1..10]` is translated to `enumFromThen 1 10` and `[1,5..100]` is translated to `enumFromThenTo` -## FP in other languages +## Basic IO -Functional programming concepts that you learn in a pure functional language may be more or less applicable in other languages, as well, according to the concepts supported and how well they are implemented. Also, some languages provide serious functional constructs, but they are quite cumbersome syntactically, which repels their common usage (yes, we point to you, JavaScript ;-) +When you need to incorporate input and output (CLI, files, sockets, etc.), you bring impureness into your program. Obviously, IO brings side effects (it interacts with the environment and changes the global state). It can be a bit complicated and so we won't go deep into theory this time and instead, we will just show how to use it. Theoretical part will be covered in the future. -### C/C++ +### The main and gets + puts -C++ is a general purpose object-oriented programming language based on C, which is an imperative procedural language. In both, it is possible to create functions (and procedures). There is no control if a function is pure or not (i.e. making side effects). And in C/C++ you need to deal with mutability, pointers and working with memory on low level (de/allocation). Typing is strict and you can make higher-order functions with "function pointer" types. +If you know C/C++, Python, or other programming languages, you should be familiar with "main". As in other languages, `main` is defined to be the entry point of a Haskell program. For Stack projects, it is located in a file inside `app` directory and can be defined in `package.yaml` in `executables` section (it is possible to have multiple entrypoints per program). The type of `main` is `IO ()` -- it can do something (some actions) with `IO` and nothing `()` is returned. You may wonder why it is not `IO Int` (with a return code). It is because giving a return code is also an IO action and you can do it from `main` with functions from `System.Exit`. -```cpp -int calculate(int(*binOperation)(const int, const int), const int operandA, const int operandB){ - return binOperation(operandA, operandB); -} +Now, let's take a look at basic IO examples: + +```haskell +main1 :: IO () +main1 = putStr "Hello, Haskeller!" -- putStr :: String -> IO () + +main2 :: IO () +main2 = putStrLn "Hello, Haskeller!" -- putStrLn :: String -> IO () + +main3 :: IO () +main3 = do + putStr "Haskell " + putChar 'F' -- putChar :: Char -> IO () + putChar 'T' + putChar 'W' + putStrLn "! Don't you think?!" + +-- pure function +sayHello :: String -> String +sayHello name = "Hello, " ++ name ++ "!" + +main4 :: IO () +main4 = do + putStrLn "Enter your name:" + name <- getLine -- getLine :: IO String, see getChar & getContents + putStrLn . sayHello $ name + +-- custom IO action +promptInt :: IO Int +promptInt = do + putStr "Enter single integer: " + inpt <- getLine -- unwraps from IO (inpt :: String) + return (read inpt) -- return wraps with IO, read :: String -> Int + +compute x y = 50 * x + y + +main5 :: IO () +main5 = do + intA <- promptInt + intB <- promptInt + putStrLn ("Result: ++ show . compute $ intA intB) + +main6 :: IO () +main6 = print 1254 -- print = putStrLn . show +``` + +### What does `do` do? + +It doesn't look so weird if you recall how imperative programming works... But we are in the functional world now, so what is going on? Haskell provides [do notation](https://en.wikibooks.org/wiki/Haskell/do_notation), which is just a syntactic sugar for chaining actions and bindings (not just IO, in general!) in a simple manner instead of using `>>` (*then*) and `>>=` (*bind*) operators of the typeclass `Monad`. We cover this topic in detail in the next lecture, right now you can remember that although `do` looks imperative, it is actually still pure thanks to a smart "trick". + +When you use the binding operator `<-`, it means that the result of a bound action can be used in following actions. In the example with `main4`, IO action `getLine` is of type `IO String` and you want to use the wrapped `String` - you *bind* the result to name `name` and then use it in combination with pure function `sayHello` for the following action that will do the output. The `do` block consists of actions and bindings and binding cannot be the last one! + +You might have noticed the `return` in custom `promptInt` action. This is a confusing thing for beginners, as `return` here has **nothing to do** with imperative languages return. The confusing thing is that it *looks* very much like it. However, conceptually it is not a control-flow expression, but just a function of the typeclass `Monad` which is used for wrapping back something, in this case `return :: String -> IO String`. This is one of the reasons why PureScript got rid of `return` and uses `pure` instead. Again, we will look at this in detail in the next lecture. + +### Be `interact`ive + +A very interesting construct for building a simple CLI is `interact :: (String -> String) -> IO ()`. The interact function takes a function of type `String -> String` as its argument. The **entire** input from the standard input device is passed to this function as its argument, and the resulting string is output on the standard output device. Btw. this is a nice example of a higher-order function at work, right? + +```haskell +import Data.Char + +main1 :: IO () +main1 = interact (map toUpper) + +main2 :: IO () +main2 = interact (show . length) + +main3 :: IO () +main3 = interact reverse +``` + +As is emphasized, it works with an entire input. If you've tried the examples above, you could observe a difference made by lazy evaluation in the first case. If you need to interact by lines or by words, you can create helper functions for that easily. + +```haskell +eachLine :: (String -> String) -> (String -> String) +eachLine f = unlines . f . lines + +eachWord :: (String -> String) -> (String -> String) +eachWord f = unwords . f . words + +main5 :: IO () +main5 = interact (eachLine reverse) + +main6 :: IO () +main6 = interact (eachWord reverse) + +chatBot "Hello" = "Hi, how are you?" +chatBot "Fine" = "Lucky you... bye!" +chatBot "Bad" = "Me too!" +chatBot _ = "Sorry, I'm too dumb to understand this..." + +main7 :: IO () +main7 = interact (eachLine chatBot) +``` + +### IO with files + +Working with files is very similar to working with console IO. As you may already know, most of IO for consoles is built by using IO for files with system "file" stdin and stdout. Such thing is called a `Handle` in Haskell and it is well described in [System.IO](http://hackage.haskell.org/package/base/docs/System-IO.html#t:Handle). + +```haskell +main1 :: IO () +main1 = withFile "test.txt" ReadMode $ \handle -> do + fileSize <- hFileSize handle + print fileSize + xs <- getlines handle + sequence_ $ map (putStrLn . reverse) xs + +main2 :: IO () +main2 = do + handle <- openFile "test.txt" ReadMode -- :: IO Handle + fileSize <- hFileSize handle + print fileSize + hClose handle +``` + +In a similar manner, you can work with binary files (you would use `ByteString`s) and temporary files. To work with sockets (network communication), you can use a library like [network](hackage.haskell.org/package/network/) or specifically for HTTP [wreq](https://hackage.haskell.org/package/wreq) and [req](https://hackage.haskell.org/package/req). + +For some well-known file formats there are libraries ready, so you don't have to work with them over and over again just with functions from `Prelude`: + +* JSON: [aeson](https://hackage.haskell.org/package/aeson) +* YAML: [yaml](https://hackage.haskell.org/package/yaml) +* XML: [xml](https://hackage.haskell.org/package/xml), [hxt](https://hackage.haskell.org/package/hxt), or [xeno](https://hackage.haskell.org/package/xeno) +* CSV: [cassava](https://hackage.haskell.org/package/cassava) or [csv](https://hackage.haskell.org/package/csv/docs/Text-CSV.html) +* INI: [ini](https://hackage.haskell.org/package/ini) + +... and so on. Also, you probably know the fabulous [pandoc](https://pandoc.org), which is written in Haskell -- and you can use it as a [library](https://hackage.haskell.org/package/pandoc)! + +Hmmm, who said that Haskell is just for math and mad academics? ;-) + +### Arguments and env variables + +Another way of interacting with a program is via its command-line arguments and environment variables. Again, there is a little bit clumsy but simple way in [System.Environment](https://hackage.haskell.org/package/base/docs/System-Environment.html) and then some fancy libraries that can help you with more complex cases... + +```haskell +main :: IO () +main = do + progName <- getProgName -- IO String + print progName + path <- getExecutablePath -- IO String + print path + args <- getArgs -- :: IO [String] + print args + user <- lookupEnv "USER" -- :: IO (Maybe String), vs. getEnv :: IO String + print user + env <- getEnvironment -- :: IO [(String, String)] + print env +``` + +The most used library for [command line option parser](https://wiki.haskell.org/Command_line_option_parsers) is [cmdargs](http://hackage.haskell.org/package/cmdargs): + +```haskell +{-# LANGUAGE DeriveDataTypeable #-} +module Sample where +import System.Console.CmdArgs + +data Sample = Hello {whom :: String} + | Goodbye + deriving (Show, Data, Typeable) + +hello = Hello{whom = def} +goodbye = Goodbye + +main = do + args <- cmdArgs (modes [hello, goodbye]) + print args ``` -If you are a normal person and not a bighead, you will most probably use `typedef` to name the type of such functions so the code is more readable and understandable. In newer versions of C++, there are also anonymous functions, combinators (`for_each`, `transform`, `filter`, ...), functors. Then you can of course use simpler functional concepts such as closures or recursion. +For a more complex example, visit their documentation -- for example, `hlint` or `diffy` use this one. + +## Handling errors + +As we saw, a very elegant way way how to handle errors is using `Maybe` or `Either` types. This is a preferred way with obvious advantages, however, in practice, it may still come to a more explosive situation. + +### error + +`error` is a special function which stops execution with given message: + +``` +Prelude> error "Stop now" +*** Exception: Stop now +CallStack (from HasCallStack): + error, called at :1:1 in interactive:Ghci1 +``` -```cpp -typedef int(*binOperation)(const int, const int); /* I am not a bighead */ +There is another quite similar one - `errorWithoutStackTrace`: -int calculate(binOperation bo, const int operandA, const int operandB){ - return bo(operandA, operandB); -} ``` +Prelude> errorWithoutStackTrace "Stop now without stack trace" +*** Exception: Stop now without stack trace +``` + +It is obviously even worse than just `error` because you somewhere deep in your code say something about rendering the error... + +### undefined -* [libf - C++ as a Pure Functional Programming Language](https://github.com/GJDuck/libf) -* [Functional in C++17 and C++20](http://www.modernescpp.com/index.php/functional-in-c-17-and-c-20) +Special case of error is that something is `undefined` and it does not accept any message: -### Java +``` +Prelude> undefined +*** Exception: Prelude.undefined +CallStack (from HasCallStack): + error, called at libraries/base/GHC/Err.hs:79:14 in base:GHC.Err + undefined, called at :5:1 in interactive:Ghci1 +``` -* [Flying Bytes - An Introduction to Functional Programming in Java 8](https://flyingbytes.github.io/programming/java8/functional/part0/2017/01/16/Java8-Part0.html) -* [Hackernoon - Finally Functional Programming in Java](https://hackernoon.com/finally-functional-programming-in-java-ad4d388fb92e) -* [JavaCodeGeeks - Java 9 Functional Programming Tutorial](https://examples.javacodegeeks.com/core-java/java-9-functional-programming-tutorial/) +Semantically, it can be used where the value is not defined (for example when you want to divide by zero). Sometimes you can see it used as a basic placeholder with meaning "Not implemented yet". For such things, you can use custom `error` or some specialized package like [Development.Placeholders](hackage.haskell.org/package/placeholders/docs/Development-Placeholders.html), which are more suitable. -### Python +### throw, try and catch -* [Functional Programming in Python (free O'Reilly)](http://www.oreilly.com/programming/free/functional-programming-python.csp) -* [Python 3 - Functional Programming HOWTO](https://docs.python.org/3/howto/functional.html) -* [Python 3 - Typing](https://docs.python.org/3/library/typing.html) +We have `throw`, `try` and `catch`, but those are functions - not keywords! -### Smalltalk and Ruby +``` +Prelude> import Control.Exception +Prelude Control.Exception> :type try +try :: Exception e => IO a -> IO (Either e a) +Prelude Control.Exception> :type throw +throw :: Exception e => e -> a +Prelude Control.Exception> :type catch +catch :: Exception e => IO a -> (e -> IO a) -> IO a +``` -* [Smalltalk, A Functional Programming Language](http://monospacedmonologues.com/post/138978728947/smalltalk-a-functional-programming-language) -* [Functional Programming in Ruby for people who don’t know what functional programming is](https://medium.com/craft-academy/functional-programming-in-ruby-for-people-who-dont-know-what-functional-programming-is-f0c4ab7dc68c) -* [Functional Programming in Ruby](http://joelmccracken.github.io/functional-programming-in-ruby/#/) -* [Embracing Functional Programming in Ruby](https://kellysutton.com/2017/09/13/embracing-functional-programming-in-ruby.html) +If you are interested you can read the documentation of [Control.Exception](https://hackage.haskell.org/package/base/docs/Control-Exception.html), however, exceptions are considered an anti-pattern in Haskell and you should always try to deal with potential errors in a more systematic way using types. We will slightly get back to these after getting the notion of Monads. ## Task assignment diff --git a/tutorials/06_io-test-doc.md b/tutorials/06_io-test-doc.md index 476b3b2..4943cdb 100644 --- a/tutorials/06_io-test-doc.md +++ b/tutorials/06_io-test-doc.md @@ -1,184 +1,5 @@ # Basic IO, tests, and documentation -So far, we were working with pure functions (without side effects). You should be able to build complex libraries, use standard containers and other data types, write clean Haskell code, and understand most of the basic programs written by Haskellers. This time we will take a look at basics of working with a user (or other) input/output, writing tests and documentation. - -## Basic IO - -When you need to incorporate input and output (CLI, files, sockets, etc.), you bring impureness into your program. Obviously, IO brings side effects (it interacts with the environment and changes the global state). It can be a bit complicated and so we won't go deep into theory this time and instead, we will just show how to use it. Theoretical part will be covered in the future. - -### The main and gets + puts - -If you know C/C++, Python, or other programming languages, you should be familiar with "main". As in other languages, `main` is defined to be the entry point of a Haskell program. For Stack projects, it is located in a file inside `app` directory and can be defined in `package.yaml` in `executables` section (it is possible to have multiple entrypoints per program). The type of `main` is `IO ()` -- it can do something (some actions) with `IO` and nothing `()` is returned. You may wonder why it is not `IO Int` (with a return code). It is because giving a return code is also an IO action and you can do it from `main` with functions from `System.Exit`. - -Now, let's take a look at basic IO examples: - -```haskell -main1 :: IO () -main1 = putStr "Hello, Haskeller!" -- putStr :: String -> IO () - -main2 :: IO () -main2 = putStrLn "Hello, Haskeller!" -- putStrLn :: String -> IO () - -main3 :: IO () -main3 = do - putStr "Haskell " - putChar 'F' -- putChar :: Char -> IO () - putChar 'T' - putChar 'W' - putStrLn "! Don't you think?!" - --- pure function -sayHello :: String -> String -sayHello name = "Hello, " ++ name ++ "!" - -main4 :: IO () -main4 = do - putStrLn "Enter your name:" - name <- getLine -- getLine :: IO String, see getChar & getContents - putStrLn . sayHello $ name - --- custom IO action -promptInt :: IO Int -promptInt = do - putStr "Enter single integer: " - inpt <- getLine -- unwraps from IO (inpt :: String) - return (read inpt) -- return wraps with IO, read :: String -> Int - -compute x y = 50 * x + y - -main5 :: IO () -main5 = do - intA <- promptInt - intB <- promptInt - putStrLn ("Result: ++ show . compute $ intA intB) - -main6 :: IO () -main6 = print 1254 -- print = putStrLn . show -``` - -### What does `do` do? - -It doesn't look so weird if you recall how imperative programming works... But we are in the functional world now, so what is going on? Haskell provides [do notation](https://en.wikibooks.org/wiki/Haskell/do_notation), which is just a syntactic sugar for chaining actions and bindings (not just IO, in general!) in a simple manner instead of using `>>` (*then*) and `>>=` (*bind*) operators of the typeclass `Monad`. We cover this topic in detail in the next lecture, right now you can remember that although `do` looks imperative, it is actually still pure thanks to a smart "trick". - -When you use the binding operator `<-`, it means that the result of a bound action can be used in following actions. In the example with `main4`, IO action `getLine` is of type `IO String` and you want to use the wrapped `String` - you *bind* the result to name `name` and then use it in combination with pure function `sayHello` for the following action that will do the output. The `do` block consists of actions and bindings and binding cannot be the last one! - -You might have noticed the `return` in custom `promptInt` action. This is a confusing thing for beginners, as `return` here has **nothing to do** with imperative languages return. The confusing thing is that it *looks* very much like it. However, conceptually it is not a control-flow expression, but just a function of the typeclass `Monad` which is used for wrapping back something, in this case `return :: String -> IO String`. This is one of the reasons why PureScript got rid of `return` and uses `pure` instead. Again, we will look at this in detail in the next lecture. - -### Be `interact`ive - -A very interesting construct for building a simple CLI is `interact :: (String -> String) -> IO ()`. The interact function takes a function of type `String -> String` as its argument. The **entire** input from the standard input device is passed to this function as its argument, and the resulting string is output on the standard output device. Btw. this is a nice example of a higher-order function at work, right? - -```haskell -import Data.Char - -main1 :: IO () -main1 = interact (map toUpper) - -main2 :: IO () -main2 = interact (show . length) - -main3 :: IO () -main3 = interact reverse -``` - -As is emphasized, it works with an entire input. If you've tried the examples above, you could observe a difference made by lazy evaluation in the first case. If you need to interact by lines or by words, you can create helper functions for that easily. - -```haskell -eachLine :: (String -> String) -> (String -> String) -eachLine f = unlines . f . lines - -eachWord :: (String -> String) -> (String -> String) -eachWord f = unwords . f . words - -main5 :: IO () -main5 = interact (eachLine reverse) - -main6 :: IO () -main6 = interact (eachWord reverse) - -chatBot "Hello" = "Hi, how are you?" -chatBot "Fine" = "Lucky you... bye!" -chatBot "Bad" = "Me too!" -chatBot _ = "Sorry, I'm too dumb to understand this..." - -main7 :: IO () -main7 = interact (eachLine chatBot) -``` - -### IO with files - -Working with files is very similar to working with console IO. As you may already know, most of IO for consoles is built by using IO for files with system "file" stdin and stdout. Such thing is called a `Handle` in Haskell and it is well described in [System.IO](http://hackage.haskell.org/package/base/docs/System-IO.html#t:Handle). - -```haskell -main1 :: IO () -main1 = withFile "test.txt" ReadMode $ \handle -> do - fileSize <- hFileSize handle - print fileSize - xs <- getlines handle - sequence_ $ map (putStrLn . reverse) xs - -main2 :: IO () -main2 = do - handle <- openFile "test.txt" ReadMode -- :: IO Handle - fileSize <- hFileSize handle - print fileSize - hClose handle -``` - -In a similar manner, you can work with binary files (you would use `ByteString`s) and temporary files. To work with sockets (network communication), you can use a library like [network](hackage.haskell.org/package/network/) or specifically for HTTP [wreq](https://hackage.haskell.org/package/wreq) and [req](https://hackage.haskell.org/package/req). - -For some well-known file formats there are libraries ready, so you don't have to work with them over and over again just with functions from `Prelude`: - -* JSON: [aeson](https://hackage.haskell.org/package/aeson) -* YAML: [yaml](https://hackage.haskell.org/package/yaml) -* XML: [xml](https://hackage.haskell.org/package/xml), [hxt](https://hackage.haskell.org/package/hxt), or [xeno](https://hackage.haskell.org/package/xeno) -* CSV: [cassava](https://hackage.haskell.org/package/cassava) or [csv](https://hackage.haskell.org/package/csv/docs/Text-CSV.html) -* INI: [ini](https://hackage.haskell.org/package/ini) - -... and so on. Also, you probably know the fabulous [pandoc](https://pandoc.org), which is written in Haskell -- and you can use it as a [library](https://hackage.haskell.org/package/pandoc)! - -Hmmm, who said that Haskell is just for math and mad academics? ;-) - -### Arguments and env variables - -Another way of interacting with a program is via its command-line arguments and environment variables. Again, there is a little bit clumsy but simple way in [System.Environment](https://hackage.haskell.org/package/base/docs/System-Environment.html) and then some fancy libraries that can help you with more complex cases... - -```haskell -main :: IO () -main = do - progName <- getProgName -- IO String - print progName - path <- getExecutablePath -- IO String - print path - args <- getArgs -- :: IO [String] - print args - user <- lookupEnv "USER" -- :: IO (Maybe String), vs. getEnv :: IO String - print user - env <- getEnvironment -- :: IO [(String, String)] - print env -``` - -The most used library for [command line option parser](https://wiki.haskell.org/Command_line_option_parsers) is [cmdargs](http://hackage.haskell.org/package/cmdargs): - -```haskell -{-# LANGUAGE DeriveDataTypeable #-} -module Sample where -import System.Console.CmdArgs - -data Sample = Hello {whom :: String} - | Goodbye - deriving (Show, Data, Typeable) - -hello = Hello{whom = def} -goodbye = Goodbye - -main = do - args <- cmdArgs (modes [hello, goodbye]) - print args -``` - -For a more complex example, visit their documentation -- for example, `hlint` or `diffy` use this one. - ## Testing Haskellers sometimes say that "When the programme compiles, it is correct!" There is a lot of truth to it, as you may have already experienced: the strong static type system does not allow you to make many errors, especially the most common (and insidious) "stupid" ones. At the same time, this saying is obviously exaggerated and there is still quite some space for a programme to be buggy. This is why traditional unit testing has its place in Haskell. Moreover, Haskell also offers an even more powerful types of testing such as property testing and mutation testing. From e0d6d53b0f7c37a58fb9fba52d651024256b025b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Sun, 10 Mar 2019 07:53:53 +0100 Subject: [PATCH 04/26] Rename 4,5,6 according to content --- tutorials/{04_types-errors.md => 04_containers-functions.md} | 0 .../{05_functions-typeclasses.md => 05_typeclasses-io-exc.md} | 0 tutorials/{06_io-test-doc.md => 06_test-doc-debug.md} | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename tutorials/{04_types-errors.md => 04_containers-functions.md} (100%) rename tutorials/{05_functions-typeclasses.md => 05_typeclasses-io-exc.md} (100%) rename tutorials/{06_io-test-doc.md => 06_test-doc-debug.md} (100%) diff --git a/tutorials/04_types-errors.md b/tutorials/04_containers-functions.md similarity index 100% rename from tutorials/04_types-errors.md rename to tutorials/04_containers-functions.md diff --git a/tutorials/05_functions-typeclasses.md b/tutorials/05_typeclasses-io-exc.md similarity index 100% rename from tutorials/05_functions-typeclasses.md rename to tutorials/05_typeclasses-io-exc.md diff --git a/tutorials/06_io-test-doc.md b/tutorials/06_test-doc-debug.md similarity index 100% rename from tutorials/06_io-test-doc.md rename to tutorials/06_test-doc-debug.md From 399d31301cc825c82c0bcf391398eb2eaaafe0e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Sun, 10 Mar 2019 09:40:16 +0100 Subject: [PATCH 05/26] Fix and improve tut04 --- tutorials/04_containers-functions.md | 65 +++++++++++++++++----------- 1 file changed, 39 insertions(+), 26 deletions(-) diff --git a/tutorials/04_containers-functions.md b/tutorials/04_containers-functions.md index f0e75af..b80cabf 100644 --- a/tutorials/04_containers-functions.md +++ b/tutorials/04_containers-functions.md @@ -11,8 +11,8 @@ In most programming languages, there is a notion of `null` or `nil` or even `Non If we were to design such a solution, we may use ADTs like that: ```haskell -data IntOrNull = I Int | Null -data StringOrNull = S String | Null +data IntOrNull = I Int | NullInt +data StringOrNull = S String | NullString data ValueOrNull a = Value a | Null myDiv :: Int -> Int -> ValueOrNull Int @@ -21,8 +21,8 @@ myDiv x y = Value (x `div` y) divString :: Int -> Int -> String divString x y = case (myDiv x y) of - Null -> "Division by zero is not allowed!" - Value res -> "Result: " ++ (show res) + Null -> "Division by zero is not allowed!" + Value res -> "Result: " ++ show res ``` In Haskell, we have a pretty structure called `Maybe` which does exactly that for us and there are some functions helping with common usage. It is a very important structure and you will be dealing with it very often. You can find more about in the documentation of [Data.Maybe](https://hackage.haskell.org/package/base/docs/Data-Maybe.html). @@ -50,6 +50,8 @@ Prelude Data.Maybe> catMaybes [Just 6, Just 7, Nothing, Just 8, Nothing, Just 9] [6,7,8,9] ``` +Is `Maybe` a good container for the following case? What if we need to propage details about the error in the communication (unknown recipient, timeout, bad metadata, etc.)? + ```haskell -- Communicator interface data Message = Message { msgSender :: String @@ -59,7 +61,7 @@ data Message = Message { msgSender :: String } sendAndReceive :: Communicator -> Message -> Maybe Message -sendAndReceive comm msg = sendSync comm msg -- some library "magic" +sendAndReceive comm msg = sendSync comm msg -- some library "magic", various errors printReceivedMessage :: Maybe Message -> String printReceivedMessage Nothing = "Unknown error occured during communication." @@ -76,7 +78,7 @@ myCommunicator = printReceivedMessage . sendAndReceive comm data Either a b = Left a | Right b ``` -The `Left` variant holds an error value (such as a message) and the `Right` variant holds the success result value. There are again several utility functions available (see [Data.Either](https://hackage.haskell.org/package/base/docs/Data-Either.html)) +The `Left` variant holds an error value (such as a message) and the `Right` variant holds the success result value. There are again several utility functions available (see [Data.Either](https://hackage.haskell.org/package/base/docs/Data-Either.html)): ``` @@ -100,8 +102,12 @@ data Message = Message { msgSender :: String , msgBody :: String } -data CommError = Timeout | Disconnected | UnkownRecipient | IncorrectMetadata | UnknownError - deriving Show +data CommError = Timeout + | Disconnected + | UnkownRecipient + | IncorrectMetadata + | GeneralError String + deriving Show sendAndReceive :: Communicator -> Message -> Either CommError Message sendAndReceive comm msg = sendSync comm msg -- some library "magic" @@ -128,7 +134,7 @@ It is semantically more similar to `void` from other languages and you can use i ## Other containers -As in other programming languages or programming theory, there are various types of containers - data types/structures, whose instances are collections of other objects. As for collections with an arbitrary number of elements, we talked about lists, which are simple to use and have a nice syntactic-sugar notation in Haskell. However, there are also other versatile types of containers available in the package [containers] and others, such as [array](https://hackage.haskell.org/package/array), [vector](https://hackage.haskell.org/package/vector), and more (use [Hoogle], [Hayoo], [Hackage]). +As in other programming languages or programming theory, there are various types of containers - data types/structures, whose instances are collections of other objects. As for collections with an arbitrary number of elements, we talked about lists, which are simple to use and have a nice syntactic-sugar notation in Haskell. However, there are also other versatile types of containers available in the package [containers] and others, such as [array](https://hackage.haskell.org/package/array), [vector](https://hackage.haskell.org/package/vector), and more (use [Hoogle] or [Hackage]). ### Sequence @@ -265,12 +271,18 @@ So what is currying useful for? It enables a very powerful abstraction technique Imagine this situation of a polygon library: ```haskell -type PSize = Int -type NoVertices = Int -data Polygon = -- some representation +type Size = Double +type NoVertices = Word +newtype Polygon = Polygon [(Double, Double)] + +computeRegularPolygonPoints :: (Double, Double) -> NoVertices -> Size -> [(Double, Double)] +computeRegularPolygonPoints (cX, cY) nVertices r = [ (x i, y i) | i <- map fromIntegral [0..(nVertices-1)] ] + where n = fromIntegral nVertices + x i = cX + r * cos(2 * pi * i / n) + y i = cY + r * sin(2 * pi * i / n) -mkPolygon :: NoVertices -> PSize -> Polygon -mkPolygon = -- some code to make a polygon +mkPolygon :: NoVertices -> Size -> Polygon +mkPolygon = computeRegularPolygonPoints (0, 0) mkHexagon :: PSize -> Polygon mkHexagon = mkPolygon 6 @@ -280,23 +292,23 @@ mkRectangle = mkPolygon 4 --etc. ``` -Here we create *specialized* versions of polygon constructor functions by providing the `PSize` parameter. As functions can be parameters, as well, we can reify the behaviour, as well: +Here we create *specialized* versions of polygon constructor functions by providing the `Size` parameter. As functions can be parameters, as well, we can reify the behaviour, as well: ```haskell -generalSort :: Ord a => (a -> a -> Ordering) -> [a] -> [a] -generalSort orderingFn numbers = -- use the orderingFn to sort the numbers +genericSort :: Ord a => (a -> a -> Ordering) -> [a] -> [a] +genericSort orderingFn numbers = undefined -- use the orderingFn to sort the numbers fastOrderingFn :: Ord a => a -> a -> Ordering -fastOrderingFn = -- a fast, but not too reliable ordering algorithm +fastOrderingFn = undefined -- a fast, but not too reliable ordering algorithm slowOrderingFn :: Ord a => a -> a -> Ordering -slowOrderingFn = -- a slow, but precise ordering algorithm +slowOrderingFn = undefined -- a slow, but precise ordering algorithm fastSort :: Ord a => [a] -> [a] -fastSort = generalSort fastOrderingFn +fastSort = genericSort fastOrderingFn goodSort :: Ord a => [a] -> [a] -goodSort = generalSort slowOrderingFn +goodSort = genericSort slowOrderingFn ``` This technique is very elegant, DRY and it is a basis of a good purely functional style. Its object-oriented relatives are the [Template Method design pattern](https://en.wikipedia.org/wiki/Template_method_pattern) brother married with the [Factory Method design pattern](https://en.wikipedia.org/wiki/Factory_method_pattern) – quite some fat, bloated relatives, aren't they? @@ -309,8 +321,10 @@ flip :: (a -> b -> c) -> b -> a -> c Then we can have: ```haskell -generalSort :: [Something] -> (Something -> Something -> Ordering) -> [Int] -generalSort numbers orderingFn = -- use the orderingFn to sort the numbers +data Something = SomethingRecord { complexFields :: () } + +genericSort :: [Something] -> (Something -> Something -> Ordering) -> [Int] +genericSort numbers orderingFn = -- use the orderingFn to sort the numbers fastOrderingFn :: Something -> Something -> Ordering fastOrderingFn = -- a fast, but not too reliable ordering algorithm @@ -603,8 +617,8 @@ myMap f (x:xs) = f x : myMap xs myFilter :: (a -> Bool) -> [a] -> [a] myFilter _ [] = [] myFilter p (x:xs) - | p x = x : filter p xs - | otherwise = filter p xs + | p x = x : myFilter p xs + | otherwise = myFilter p xs ``` That's it. Let us have some examples: @@ -807,5 +821,4 @@ The homework to practice working with new types, list comprehensions, containers [containers]: https://hackage.haskell.org/package/containers [GHC]: https://www.haskell.org/ghc/ [Hackage]: https://hackage.haskell.org -[Hayoo]: https://hayoo.fh-wedel.de [Hoogle]: https://www.haskell.org/hoogle/ From 2351a43022ae935e093d547513dac50bf617da09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Sun, 17 Mar 2019 10:04:03 +0100 Subject: [PATCH 06/26] Merging 07 into 05 --- tutorials/05_typeclasses-io-exc.md | 537 +++++++++++++++++++++++++- tutorials/07_common-typeclasses-1.md | 551 --------------------------- 2 files changed, 531 insertions(+), 557 deletions(-) delete mode 100644 tutorials/07_common-typeclasses-1.md diff --git a/tutorials/05_typeclasses-io-exc.md b/tutorials/05_typeclasses-io-exc.md index b35592b..ba525c3 100644 --- a/tutorials/05_typeclasses-io-exc.md +++ b/tutorials/05_typeclasses-io-exc.md @@ -219,10 +219,533 @@ When you derive `Enum`, the order will be generated as left-to-right order of da Enumerations have also the `..` syntactic sugar. For example, `[1..10]` is translated to `enumFromThen 1 10` and `[1,5..100]` is translated to `enumFromThenTo` -## Basic IO +## Mathematical Typeclasses + +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 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 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 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 + +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; 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 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 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 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 + (<>) :: 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 -- fold with mappend (catamorphism) +``` + +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 +-- 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: + +* 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. + + +``` +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 the very practical usages of `mappend` is string concatenation, which is independent of 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 = ""`. + +#### Example: Maybe + +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") +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 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 + +Apart from basic `Monoid` from algebra, there are also other variants. You might find interesting to learn more about: + +* [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. + +### Functor + +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: + +```haskell +-- identity (fmap doesn't do anything more than applying given function) +fmap id == id +-- composition +fmap (f . g) == fmap f . fmap g +``` + +Let's try it with basic containers like list, `Maybe`, and `Either`: + +``` +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 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 `(<&>)`. + +``` +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 +``` + +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 + +[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 + 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 -> 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 +origin = liftF0 0 + +doublePoint :: Point2D Int -> Point2D Int +doublePoint = liftF1 (*2) + +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)) + +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 +-- 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: + +```haskell +fmap id == id + +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 - it is **Applicative functor**. + +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 + 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): + +```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 +``` + +``` +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 +``` + +#### 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 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 + +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 + (>>=) :: 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 `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. + +`>>` is a sequencing operator, which "passes" computation from monad to another. + +Again, 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) +``` + +``` +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 + +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 +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 +``` + +Haskell provides the `do` notation so we can avoid writing all the lambdas: + +```haskell +foo :: Maybe String +foo = do + x <- Just 7 + y <- Just "!" + Just (show x ++ y) +``` + +or + +```haskell +main = do + print 3 + print 5 + print 7 +``` + +In `do`, you can use basic sequencing `>>`, `>>=` 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 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 +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*: + +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` + +## Working with IO When you need to incorporate input and output (CLI, files, sockets, etc.), you bring impureness into your program. Obviously, IO brings side effects (it interacts with the environment and changes the global state). It can be a bit complicated and so we won't go deep into theory this time and instead, we will just show how to use it. Theoretical part will be covered in the future. +```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 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). + ### The main and gets + puts If you know C/C++, Python, or other programming languages, you should be familiar with "main". As in other languages, `main` is defined to be the entry point of a Haskell program. For Stack projects, it is located in a file inside `app` directory and can be defined in `package.yaml` in `executables` section (it is possible to have multiple entrypoints per program). The type of `main` is `IO ()` -- it can do something (some actions) with `IO` and nothing `()` is returned. You may wonder why it is not `IO Int` (with a return code). It is because giving a return code is also an IO action and you can do it from `main` with functions from `System.Exit`. @@ -456,12 +979,14 @@ The homework to practice working with advanced functional patterns, operators, a ## Further reading -* [Haskell - Currying](https://wiki.haskell.org/Currying) -* [Haskell - Pointfree](https://wiki.haskell.org/Pointfree) -* [Haskell - Higher order function](https://wiki.haskell.org/Higher_order_function) -* [Haskell - Fold](https://wiki.haskell.org/Fold) -* [Learn You a Haskell for Great Good](http://learnyouahaskell.com) (chapters 3, 6, 8) * [Haskell - Polymorphism](https://wiki.haskell.org/Polymorphism) * [Typeclassopedia](https://wiki.haskell.org/Typeclassopedia) * [Haskell - OOP vs type classes](https://wiki.haskell.org/OOP_vs_type_classes) * [WikiBooks - Haskell: Classes and types](https://en.wikibooks.org/wiki/Haskell/Classes_and_types) +* [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) +* [LYAH - A Fistful of Monads](http://learnyouahaskell.com/a-fistful-of-monads +* [Haskell - Monad](https://wiki.haskell.org/Monad) +* [Haskell - IO Monad](https://wiki.haskell.org/Introduction_to_IO) diff --git a/tutorials/07_common-typeclasses-1.md b/tutorials/07_common-typeclasses-1.md deleted file mode 100644 index 1adf385..0000000 --- a/tutorials/07_common-typeclasses-1.md +++ /dev/null @@ -1,551 +0,0 @@ -# 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 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 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 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 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 - -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; 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 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 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 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 - (<>) :: 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 -- fold with mappend (catamorphism) -``` - -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 --- 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: - -* 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. - - -``` -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 the very practical usages of `mappend` is string concatenation, which is independent of 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 = ""`. - -### Example: Maybe - -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") -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 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 - -Apart from basic `Monoid` from algebra, there are also other variants. You might find interesting to learn more about: - -* [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. - -## Functor - -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: - -```haskell --- identity (fmap doesn't do anything more than applying given function) -fmap id == id --- composition -fmap (f . g) == fmap f . fmap g -``` - -Let's try it with basic containers like list, `Maybe`, and `Either`: - -``` -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 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 `(<&>)`. - -``` -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 -``` - -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 - -[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 - 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 -> 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 -origin = liftF0 0 - -doublePoint :: Point2D Int -> Point2D Int -doublePoint = liftF1 (*2) - -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)) - -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 --- 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: - -```haskell -fmap id == id - -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 - it is **Applicative functor**. - -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 - 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): - -```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 -``` - -``` -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 -``` - -### 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 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 - -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 - (>>=) :: 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 `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. - -`>>` is a sequencing operator, which "passes" computation from monad to another. - -Again, 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) -``` - -``` -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 - -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 -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 -``` - -Haskell provides the `do` notation so we can avoid writing all the lambdas: - -```haskell -foo :: Maybe String -foo = do - x <- Just 7 - y <- Just "!" - Just (show x ++ y) -``` - -or - -```haskell -main = do - print 3 - print 5 - print 7 -``` - -In `do`, you can use basic sequencing `>>`, `>>=` 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 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 -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*: - -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. - -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 -``` - -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 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). - -## The task assignment - -The homework to practice typeclasses from this tutorial is in repository [MI-AFP/hw07](https://github.com/MI-AFP/hw07). - -## Further reading - -* [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) -* [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 010048cdcdd62244d68df27dfaa38700e5e58629 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Sun, 17 Mar 2019 11:20:04 +0100 Subject: [PATCH 07/26] Reordering tutorials --- ...eclasses-2.md => 06_io-exc-typeclasses.md} | 0 ...test-doc-debug.md => 07_test-doc-debug.md} | 0 tutorials/{09_webapp.md => 08_webapp.md} | 0 tutorials/10_frontend-frp.md | 417 ---------------- tutorials/11_performance-debug.md | 468 ------------------ .../{12_exts-deptypes.md => 99_bonus.md} | 0 6 files changed, 885 deletions(-) rename tutorials/{08_common-typeclasses-2.md => 06_io-exc-typeclasses.md} (100%) rename tutorials/{06_test-doc-debug.md => 07_test-doc-debug.md} (100%) rename tutorials/{09_webapp.md => 08_webapp.md} (100%) delete mode 100644 tutorials/10_frontend-frp.md delete mode 100644 tutorials/11_performance-debug.md rename tutorials/{12_exts-deptypes.md => 99_bonus.md} (100%) diff --git a/tutorials/08_common-typeclasses-2.md b/tutorials/06_io-exc-typeclasses.md similarity index 100% rename from tutorials/08_common-typeclasses-2.md rename to tutorials/06_io-exc-typeclasses.md diff --git a/tutorials/06_test-doc-debug.md b/tutorials/07_test-doc-debug.md similarity index 100% rename from tutorials/06_test-doc-debug.md rename to tutorials/07_test-doc-debug.md diff --git a/tutorials/09_webapp.md b/tutorials/08_webapp.md similarity index 100% rename from tutorials/09_webapp.md rename to tutorials/08_webapp.md diff --git a/tutorials/10_frontend-frp.md b/tutorials/10_frontend-frp.md deleted file mode 100644 index 01b7d19..0000000 --- a/tutorials/10_frontend-frp.md +++ /dev/null @@ -1,417 +0,0 @@ -# Frontend and FRP - -In the previous tutorial, we focused on web frameworks and especially on building a backend and some frontend generation by blaze or hastache on the server-side. This time, we will cover building frontend apps that are standalone or communicate with backend via (REST) API. At the end of this tutorial, there is a section about a very interesting concept *Functional Reactive Programming* that is important when building purely functional user interfaces. - -## Haskell and Haskell-like frontends - -### The JavaScript Problem - -We all know what is JavaScript -- it is a dynamic, weakly typed, prototype-based and multi-paradigm programming language. Together with HTML and CSS, it is one of the three core technologies of the World Wide Web. JavaScript is used for interactive web pages and thus is an essential part of modern web applications. These days, JavaScript is often also used for the server-side or even desktop applications (e.g. [Atom editor](https://atom.io/)). - -As obvious from above, we need JavaScript. On the other hand, JavaScript has some issues that make working with it inconvenient and make developing software harder. Some things are improving with time (newer versions of [ECMAScript](https://en.wikipedia.org/wiki/ECMAScript)) but most of them remain from the very basic principles of the language: weak-typing, late binding, [weird automatic conversions](https://youtu.be/ryJSRZzAvUs), `this` behaviour, and lack of static types. There are solutions in the form of "improved syntax" like [CoffeeScript](http://coffeescript.org) and [TypeScript](https://www.typescriptlang.org) that are dealing with some of those... - -But since we are now Haskellists, we would like to have something even better - a Haskell-like JavaScript to solve these problems. Luckily, we are not the only ones and there are already several solutions how to compile Haskell to JavaScript or similar languages based on Haskell that are adapted for this very specific purpose. - -Take a look at [Slant - What are the best solutions to "The JavaScript Problem"?](https://www.slant.co/topics/1515/~solutions-to-the-javascript-problem). We are going to look at some now! - -### GHCJS - -GHCJS is a Haskell to JavaScript compiler that uses the GHC API. - -GHCJS supports many modern Haskell features, including: - - * All type system extensions supported by GHC - * Lightweight preemptive threading with blackholes, MVar, STM, asynchronous exceptions - * Weak references, CAF deallocation, StableName, StablePtr - * Unboxed arrays, emulated pointers - * Integer support through [JSBN](http://www-cs-students.stanford.edu/~tjw/jsbn/), 32 and 64 bit signed and unsigned arithmetic (`Word64`, `Int32` etc.) - * Cost-centres, stack traces - * Cabal support, GHCJS has its own package database - -And some JavaScript-specific features: - - * new JavaScriptFFI extension, with convenient import patterns, asynchronous FFI and a JSVal FFI type, - * synchronous and asynchronous threads. - -- Project: [ghcjs/ghcjs](https://github.com/ghcjs/ghcjs) -- Nice example: [Full stack web Haskell with Servant and GHCJS](http://blog.wuzzeb.org/full-stack-web-haskell/index.html) - -The dark side of GHCJS is big resulting JavaScript code and it is hard to make work (just try for yourself ;-). Also, the community around GHCJS and its ecosystem is not the most active one. - -### Haste - -[Haste](https://haste-lang.org) is an implementation of the Haskell functional programming language, geared towards web applications. Haste is based on the GHC, which means that it supports the full Haskell language, including GHC extensions and produces highly optimized code but comes with an extended set of standard libraries. However, compared to GHCJS, Template Haskell is not supported. Haste supports modern web technologies such as WebSockets, LocalStorage, Canvas, etc. out of the box. In addition, Haste comes pre-packaged with facilities for preemptive multitasking, working with binary data and other niceties. - -A Haste program can be compiled into a single JavaScript file, much like traditional browser-side programs, or into a JavaScript file and a server-side binary, with strongly typed communication between the two. In essence, Haste lets you write your client-server web application as a single, type-safe program, rather than two separate programs that just happen to talk to each other over some web API as is traditional. - -You don’t need to throw away all of your old code to start using Haste. In addition to the standard Haskell FFI, Haste provides its own flexible mechanism for easy Haskell-JavaScript integration, using fancy type magic to allow data of any type to be used by both Haskell and JavaScript code with minimal effort. - -Haste programs are more compact to GHCJS. While a certain increase in code size over hand-rolled JavaScript is unavoidable, an optimized but uncompressed Haste program is normally less than 3x the size of an equivalent hand-written program and the compiler takes special care to produce minifiable code, making the latency penalty of using Haste minimal. Sadly, similarly to GHCJS, the project is not much active (although not dead), the ecosystem, documentation and tutorials are not rich. - -- Examples: [valderman/haste-compiler](https://github.com/valderman/haste-compiler/tree/master/examples) -- API doc: [haste-compiler-0.5.5.0: Haskell To ECMAScript compiler](https://haste-lang.org/docs/haddock/0.5.5/) -- Our example: [DataStewardshipWizard/ds-wizard](https://github.com/DataStewardshipWizard/ds-wizard) and [DataStewardshipWizard/ds-form-engine](https://github.com/DataStewardshipWizard/ds-form-engine), built around JQuery bindings. - -### Miso - -**Miso** is a small "[isomorphic](http://nerds.airbnb.com/isomorphic-javascript-future-web-apps/)" [Haskell](https://www.haskell.org/) front-end framework for quickly building highly interactive single-page web applications. It features a virtual-dom, diffing / patching algorithm, attribute, and property normalization, event delegation, event batching, SVG, Server-sent events, Websockets, type-safe [servant](https://haskell-servant.github.io/)-style routing and an extensible Subscription-based subsystem. Inspired by [Elm](http://elm-lang.org/), [Redux](http://redux.js.org/) and [Bobril](http://github.com/bobris/bobril). **Miso** is pure by default, but side effects (like `XHR`) can be introduced into the system via the `Effect` data type. **Miso** makes heavy use of the [GHCJS](https://github.com/ghcjs/ghcjs) FFI and therefore has minimal dependencies. **Miso** can be considered a shallow [embedded domain-specific language](https://wiki.haskell.org/Embedded_domain_specific_language) for modern web programming. ([dmjio/miso](https://github.com/dmjio/miso/edit/master/README.md)) - -### PureScript - -PureScript is a strict, purely functional programming language inspired by Haskell which compiles to readable JavaScript with a simple foreign function interface and no runtime dependency. PureScript is sometimes called "Haskell done right" -- it learned from the long Haskell history, took the best of it (type system, category theory), refactored some parts, mostly basic libraries structure (Prelude) and added some goodies (records and row polymorphism) -- here is the overview of [differences](https://github.com/purescript/documentation/blob/master/language/Differences-from-Haskell.md). - -- Website: [purescript.org](http://www.purescript.org) -- Guide: [leanpub.com/purescript](https://leanpub.com/purescript/read) - -Although the ecosystem and documentation is considerably better than GHCJS's and Haste's, it has not reached broader adoption, (yet?). - -### Elm - -Elm is a functional language that compiles to JavaScript. It is not a Haskell, but language inspired by and in some ways very similar to Haskell (see [main differences](https://gist.github.com/cobalamin/c1b83f5626df1409b512ce2faf05cf84)) - it is more different from Haskell than PureScript. It offers an interesting type-safe alternative to projects such as React as a tool for creating websites and web apps. Elm has a very strong emphasis on simplicity, ease-of-use, and quality tooling. The compiler of Elm is written in Haskell and you can work with Elm in Haskell with [Language.Elm](https://hackage.haskell.org/package/Elm). - -- Guide: [guide.elm-lang.org](https://guide.elm-lang.org) -- Examples: [elm-lang.org/examples](http://elm-lang.org/examples) -- Our example: [DataStewardshipWizard/dsw-client](https://github.com/DataStewardshipWizard/dsw-client) - -Simplicity, good ecosystem, documentation and active community earned Elm quite some interest. At the same time, the lack of type classes hinders flexibility, reuse and DRY. - -### ReasonML - -[ReasonML](https://reasonml.github.io/) is a notable project that should be mentioned here. Although it is not based on Haskell, it shares the same ancestor -- the [ML language](https://en.wikipedia.org/wiki/ML_(programming_language)), the first FP language with Hindley-Milner type system that influenced many today's languages. ML (and its newer dialects Standard ML, Caml and OCaml) are not entirely pure (and as such they are being scorned by Haskellists ;-), but you find a strong type system, ADTs, etc. there, as well. - -What makes ReasonML notable is that it was created by Facebook and thus gets a strong warp. 50% of FB Messanger has been rewritten into ReasonML and there are quite some [impressive statistics](https://reasonml.github.io/blog/2017/09/08/messenger-50-reason.html). It is a project that is worth at least to be observed. - -## FRP - Functional Reactive Programming - -Functional reactive programming (FRP) is a programming paradigm for asynchronous dataflow programming using the building blocks of functional programming (such as `map`, `filter`, `fold`s, higher-order functions, etc.). It has been used often for programming graphical user interfaces (GUIs), robotics, and music, aiming to simplify these problems by explicitly modelling the concept of time. A good example to imagine what is it about is an ordinary spreadsheet calculator (Excel). You have cells that compute something from different cells and when you edit some, the related will recalculate - you do not tell what should be recalculated nor recalculate by yourself, all changes automatically propagate. See? It is "action and reaction"! - -The original idea was introduced more than 20 years ago by Conal Elliott in his [paper](http://conal.net/papers/ActiveVRML/ActiveVRML.pdf). Since then, he published several [other papers](http://conal.net/papers/) and there are also videos about the [FRP essence](https://begriffs.com/posts/2015-07-22-essence-of-frp.html). Several different trade-off approaches has been developed for practical usage. You can see the list [here](https://wiki.haskell.org/Functional_Reactive_Programming#Libraries). Also, of course, you can find FRP implementations in other languages than Haskell. - -### FRP principles - -For better understanding what FRP is about and what are the basic concepts, please read [The introduction to Reactive Programming you've been missing (by @andrestaltz)](https://gist.github.com/staltz/868e7e9bc2a7b8c1f754)... - -### Reactive - -[Reactive](https://hackage.haskell.org/package/reactive) is a simple foundation for programming reactive systems functionally. Like Fran/FRP, it has a notion of (reactive) behaviours and events. Unlike most previous FRP implementations, Reactive has a hybrid demand/data-driven implementation, as described in the paper "Push-pull functional reactive programming", http://conal.net/papers/push-pull-frp/. - -Sadly the documentation, tutorials, and examples are not currently in a good shape. - -### Reactive-banana - -[Reactive-banana](https://wiki.haskell.org/Reactive-banana) is meant to be used in conjunction with existing libraries that are specific to your problem domain. For instance, you can hook it into any event-based GUI framework, like `wxHaskell` or `Gtk2Hs`. Several helper packages such as `reactive-banana-wx` provide a small amount of glue code that can make life easier. - -The goal of the library is to provide a solid foundation. - -* Programmers interested implementing FRP will have a reference for a simple semantics with a working implementation. The library stays close to the semantics pioneered by Conal Elliott. -* The library features an efficient implementation. No more spooky time leaks, predicting space & time usage should be straightforward. -* A plethora of [example code](https://wiki.haskell.org/Reactive-banana/Examples) helps with getting started. - -### Yampa - -[Yampa](https://wiki.haskell.org/Yampa) is a domain-specific embedded language for programming of hybrid (discrete and continuous time) systems using the concepts of FRP. Yampa is structured using Arrows, which greatly reduce the chance of introducing space- and time-leaks into reactive, time-varying systems. - -![Signals in Yampa](https://wiki.haskell.org/wikiupload/thumb/1/10/Yampa_signal_functions.svg/624px-Yampa_signal_functions.svg.png) - -## Reactive programming with Elm - -We introduced Elm as a "convenient language" and it also supports reactive programming, so let us show a simple example to demonstrate the clean [architecture of Elm apps](https://guide.elm-lang.org/architecture/) - Model, View, and Update. This app will be just one module `Main` (although you can have multi-module apps just as in Haskell) and it will have 4 pages: - -1. Simple static landing -2. Unit converter for metres, yards, feet, and inches (reactive update: Update->Model->View cycle) -3. GitHub API info about user (demonstrate HTTP communication with some API) -4. Not found page as default - -You need to install [Node.js](https://nodejs.org/en/) and [Elm](https://guide.elm-lang.org/install.html). Then you can use `elm-repl` to try something (like GHCi), `elm-reactor` for development, `elm-package` to work with dependencies, and `elm-make` to build it into JavaScript. - -In this example we need some dependencies so the final `elm-package.json` looks like this: - -```json -{ - "version": "1.0.0", - "summary": "Example simple Elm project", - "repository": "https://github.com/MI-AFP/elm-example.git", - "license": "MIT", - "source-directories": [ - "." - ], - "exposed-modules": [], - "dependencies": { - "elm-lang/core": "5.1.1 <= v < 6.0.0", - "elm-lang/html": "2.0.0 <= v < 3.0.0", - "elm-lang/http": "1.0.0 <= v < 2.0.0", - "elm-lang/navigation": "2.1.0 <= v < 3.0.0", - "evancz/url-parser": "2.0.1 <= v < 3.0.0", - "rundis/elm-bootstrap": "4.0.0 <= v < 5.0.0" - }, - "elm-version": "0.18.0 <= v < 0.19.0" -} -``` - -```elm -module Main exposing (..) - -import Html exposing (..) -import Html.Attributes exposing (..) -import Html.Events exposing (onInput) -import Http -import Navigation exposing (Location) -import UrlParser exposing (()) - --- Entrypoint (we use Navigation) -main : Program Never Model Msg -main = Navigation.program UrlChange - { view = view - , update = update - , subscriptions = (\_ -> Sub.none) - , init = init - } - --- Model = state of the app -type alias Model = - { page : Page - , metres : Float - , token : GitHubToken - , githubData : String - } - --- Page = enum of different views -type Page - = Home - | UnitConverter - | GitHubInfo - | NotFound - --- Own type for GitHub token -type GitHubToken - = Valid String - | Invalid String - --- Units for the conversion -type LengthUnit - = Metres - | Inches - | Yards - | Feets - --- Types of messages in the app with content type(s) -type Msg - = UrlChange Location - | UnitUpdate LengthUnit String - | TokenUpdate String - | GitHubResponse (Result Http.Error String) - --- Initial app state and command -init : Location -> ( Model, Cmd Msg ) -init location = urlUpdate location { page = Home - , metres = 0 - , token = Invalid "" - , githubData = "" - } - --- Update (when message comes, update model), this is just "router" -update : Msg -> Model -> (Model, Cmd Msg) -update msg model = - case msg of - UrlChange location -> - urlUpdate location model - UnitUpdate lu str -> - metresUpdate lu str model - TokenUpdate str -> - tokenUpdate str model - GitHubResponse res -> - githubUpdate res model - -githubUpdate : (Result Http.Error String) -> Model -> (Model, Cmd Msg) -githubUpdate res model = - case res of - Ok str -> ({ model | githubData = str }, Cmd.none) - Err _ -> ({ model | githubData = "Error!" }, Cmd.none) - -tokenUpdate : String -> Model -> (Model, Cmd Msg) -tokenUpdate str model = - if isTokenValid str then - ( { model | token = Valid str }, gitHubInfoRequest str ) - else - ( { model | token = Invalid str }, Cmd.none ) - --- Send request to GitHub and then it will send appropriate message in this app -gitHubInfoRequest : String -> Cmd Msg -gitHubInfoRequest token = - Http.send GitHubResponse <| Http.request - { method = "GET" - , headers = [ Http.header "Authorization" ("token " ++ token)] - , url = "https://api.github.com/user" - , body = Http.emptyBody - , expect = Http.expectString - , timeout = Nothing - , withCredentials = False - } - -isTokenValid : String -> Bool -isTokenValid str = String.length str == 40 - -metresUpdate : LengthUnit -> String -> Model -> ( Model, Cmd Msg ) -metresUpdate lu x model = - case String.toFloat x of - Ok v -> ( { model | metres = v / (unitCoefficient lu)}, Cmd.none ) - Err _ -> ( model, Cmd.none ) - -urlUpdate : Navigation.Location -> Model -> ( Model, Cmd Msg ) -urlUpdate location model = - case decode location of - Nothing -> - ( { model | page = NotFound }, Cmd.none ) - Just route -> - ( { model | page = route }, Cmd.none ) - -decode : Location -> Maybe Page -decode location = - UrlParser.parseHash routeParser location - -routeParser : UrlParser.Parser (Page -> a) a -routeParser = - UrlParser.oneOf - [ UrlParser.map Home UrlParser.top - , UrlParser.map UnitConverter (UrlParser.s "unit-converter") - , UrlParser.map GitHubInfo (UrlParser.s "github-info") - ] - ---> VIEW -view : Model -> Html Msg -view model = - div [] - [ menu model - , mainContent model - ] - -menu : Model -> Html Msg -menu model = - div [] - [ viewLink "" "Home" - , viewLink "unit-converter" "Unit Converter" - , viewLink "github-info" "GitHub Info" - ] - -viewLink : String -> String -> Html msg -viewLink slug name = - li [] [ a [ href ("#" ++ slug) ] [ text name ] ] - -mainContent : Model -> Html Msg -mainContent model = - div [] ( - case model.page of - Home -> - pageHome model - UnitConverter -> - pageUnitConverter model - GitHubInfo -> - pageGitHubInfo model - NotFound -> - pageNotFound - ) - -pageHome : Model -> List (Html Msg) -pageHome model = - [ h1 [] [ text "Home" ] - , p [] [ text "This is very simple Elm example" ] - , hr [] [] - , p [] [ text "Enjoy learning " - , a [href "http://elm-lang.org"] [text "Elm"] - , text "!" - ] - ] - -pageUnitConverter : Model -> List (Html Msg) -pageUnitConverter model = - [ h1 [] [ text "Unit Converter" ] - , hr [] [] - , makeUnitInput Metres model - , makeUnitInput Inches model - , makeUnitInput Feets model - , makeUnitInput Yards model - ] - -makeUnitInput : LengthUnit -> Model -> Html Msg -makeUnitInput lu model = - div [] - [ label [] [text (unitToString lu)] - , input [ type_ "number" - , onInput (UnitUpdate lu) - , value (toString (computeUnit lu model)) - ] - [] - ] - -pageGitHubInfo : Model -> List (Html Msg) -pageGitHubInfo model = - [ h1 [] [ text "GitHub Info" ] - , div [] - [ label [] [text "GitHub token: "] - , input [ type_ "text" - , onInput TokenUpdate - , value (tokenToString model.token) - ] - [] - ] - , case model.token of - Valid token -> githubInfo model - Invalid _ -> invalidTokenMsg - ] - -githubInfo : Model -> (Html Msg) -githubInfo model = - pre [] [text (model.githubData)] - - -invalidTokenMsg : (Html Msg) -invalidTokenMsg = - div [] - [ p [] [text "Your token is not valid (40 chars required)"] - ] - -tokenToString : GitHubToken -> String -tokenToString t = - case t of - Valid s -> s - Invalid s -> s - -pageNotFound : List (Html Msg) -pageNotFound = - [ h1 [] [ text "Not found" ] - , text "Sorry couldn't find that page" - ] - ---> LOGIC -unitToString : LengthUnit -> String -unitToString lu = - case lu of - Metres -> "Metres" - Inches -> "Inches" - Yards -> "Yards" - Feets -> "Feets" - -computeUnit : LengthUnit -> Model -> Float -computeUnit lu model = model.metres * (unitCoefficient lu) - -unitCoefficient : LengthUnit -> Float -unitCoefficient lu = - case lu of - Metres -> 1 - Inches -> 39.3700787 - Yards -> 1.0936133 - Feets -> 3.2808399 -``` - -You can play with this app from [MI-AFP/elm-example](https://github.com/MI-AFP/elm-example). - -## Task assignment - -The homework to create a simple frontend for a REST API described in the repository [MI-AFP/hw10](https://github.com/MI-AFP/hw10). - -## Further reading - -* [Haskell on the front end](https://www.reddit.com/r/haskell/comments/7ax2ji/haskell_on_the_front_end/) -* [Zdroják.cz - Elm (czech only)](https://www.zdrojak.cz/clanky/elm-uvod/) -* [gelisam/frp-zoo (FRP libs comparison)](https://github.com/gelisam/frp-zoo) -* [FRP explanation using reactive-banana](https://wiki.haskell.org/FRP_explanation_using_reactive-banana) diff --git a/tutorials/11_performance-debug.md b/tutorials/11_performance-debug.md deleted file mode 100644 index 264bad0..0000000 --- a/tutorials/11_performance-debug.md +++ /dev/null @@ -1,468 +0,0 @@ -# Performance and Debugging - -During this tutorial, we will take a look how to improve the performance of a Haskell program and how to debug it. We will use very simple example - [Fibonacci numbers](https://en.wikipedia.org/wiki/Fibonacci_number). - -```haskell -import System.Environment - --- | Naive recursive algorithm for n-th Fibonacci number -fibonacci :: Integer -> Integer -fibonacci 0 = 0 -fibonacci 1 = 1 -fibonacci n = fibonacci (n-1) + fibonacci (n-2) - -main :: IO () -main = do - args <- getArgs - print . fibonacci . read . head $ args -``` - -## Measuring time and memory - -When you want to check the performance of a program and compare two programs or algorithms in terms of time or memory consumption, you need to measure it. - -### Basic `time` - -The `time` command is one of the well-known Linux commands for programmers. It can be used to show how long a command takes to run. That makes it Very useful if you are a developer and you want to test the performance of your program or script. Especially to compare the time of programs written in other languages "from outside". For basic usage, you will get three numbers: - -- `real` = total time is taken to run the command (the same as if you use your normal stopwatch) -- `user` = amount of time that was spent in user mode -- `sys` = amount of time spent in kernel mode - -Then `user`+`sys` gives information how much actual CPU time your process used - in total on all cores. This number can be then higher than `real` if your program uses multiple threads. - -``` -% /usr/bin/time -p runhaskell FibonacciNaive.hs 25 -75025 -real 0.33 -user 0.31 -sys 0.01 -``` - -But `time` can do a bit more, you can tell how output should look like with additional "numbers" - number of page faults, average total memory use of the process in kilobytes, number of signals delivered to the process, number of socket messages received/sent by the process, exit status of the command, and many others. - -``` -% /usr/bin/time -f "Elapsed Time: %E\nExit Status: %X\nPage Faults: %F" runhaskell FibonacciNaive.hs 25 -75025 -Elapsed Time: 0:00.34 -Exit Status: 0 -Page Faults: 0 -``` - -### Benchmarking with Criterion - -If you are interested in such optimizations and improving your application or comparing various algorithms or their implementations, then you might find interesting to use a benchmarking library. In Haskell is the most used one called [Criterion](http://www.serpentine.com/criterion/). It provides a powerful but simple way to measure software performance. It provides both a framework for executing and analyzing benchmarks and a set of driver functions that makes it easy to build and run benchmarks and to analyze their results. - -For simple usage, you just need to work with the `defaultMain` from [Criterion.Main](https://hackage.haskell.org/package/criterion/docs/Criterion-Main.html) as they show in their example: - -```haskell -import Criterion.Main - --- | Naive recursive algorithm for n-th Fibonacci number -fibonacci :: Integer -> Integer -fibonacci 0 = 0 -fibonacci 1 = 1 -fibonacci n = fibonacci (n-1) + fibonacci (n-2) - -main :: IO () -main = defaultMain [ - bgroup "fib" [ bench " 5" $ whnf fibonacci 5 - , bench "10" $ whnf fibonacci 10 - , bench "25" $ whnf fibonacci 25 - ] - ] -``` - -It has very nice outputs with a form of interactive HTML pages with charts and comparisons and has many options to use. - -``` -% runhaskell FibonacciNaiveCriterion.hs -benchmarking fib/ 5 -time 7.319 μs (6.980 μs .. 7.821 μs) - 0.966 R² (0.934 R² .. 0.995 R²) -mean 7.248 μs (6.966 μs .. 7.847 μs) -std dev 1.321 μs (805.8 ns .. 2.043 μs) -variance introduced by outliers: 96% (severely inflated) - -benchmarking fib/10 -time 81.34 μs (81.15 μs .. 81.54 μs) - 1.000 R² (1.000 R² .. 1.000 R²) -mean 81.58 μs (81.38 μs .. 81.85 μs) -std dev 811.3 ns (577.5 ns .. 1.191 μs) - -benchmarking fib/25 -time 111.6 ms (110.5 ms .. 112.2 ms) - 1.000 R² (1.000 R² .. 1.000 R²) -mean 112.1 ms (111.7 ms .. 112.9 ms) -std dev 853.6 μs (534.0 μs .. 1.215 ms) -variance introduced by outliers: 11% (moderately inflated) - -runhaskell FibonacciNaiveCriterion.hs 15.98s user 0.04s system 99% cpu 16.055 total -``` - -### Measure allocations with Weigh - -The package [weigh](https://hackage.haskell.org/package/weigh) provides a simple interface to measure the memory usage of a Haskell value or function. - -```haskell -import Weigh - --- | Naive recursive algorithm for n-th Fibonacci number -fibonacci :: Integer -> Integer -fibonacci 0 = 0 -fibonacci 1 = 1 -fibonacci n = fibonacci (n-1) + fibonacci (n-2) - -main :: IO () -main = mainWith $ do - func "fib 5" fibonacci 5 - func "fib 10" fibonacci 10 - func "fib 25" fibonacci 25 -``` - -It provides a nice output as plain text table, but it is also possible to change the format to markdown. - -``` -% ./FibonacciNaiveWeigh - -Case Allocated GCs -fib 5 1,968 0 -fib 10 24,304 0 -fib 25 33,509,936 63 -``` - -## Performance - -Now we are able to measure something and compare algorithms, but how to improve the numbers we get if we really need it? - -### Basic ideas - -When you are not satisfied with the performance of your application, then before any sophisticated optimization steps by using strictness, unboxed types, calling FFI, etc., you should consider if you prefer faster application over better readability. Then another important thing to think about is design if it is not slow by using "naive" algorithm, using an inappropriate data structure (List instead of Set or Map), etc. - -**Always** rethink your own code before using other optimization techniques! - -```haskell -import System.Environment - --- | Improved recursive algorithm for n-th Fibonacci number -fibonacci :: Integer -> Integer -fibonacci = fib 0 1 - where - fib x _ 0 = x - fib x y n = fib y (x+y) (n-1) -- just "one-way" recursion! - -main :: IO () -main = do - args <- getArgs - print . fibonacci . read . head $ args -``` - -Just a very simple re-thinking can have some impact: - -``` -% /usr/bin/time -p runhaskell FibonacciBetter.hs 25 -75025 -real 0.24 -user 0.22 -sys 0.02 -``` - -``` -% runhaskell FibonacciBetterCriterion.hs -benchmarking fib/ 5 -time 3.412 μs (3.235 μs .. 3.591 μs) - 0.988 R² (0.983 R² .. 0.998 R²) -mean 3.191 μs (3.129 μs .. 3.277 μs) -std dev 253.6 ns (168.4 ns .. 360.9 ns) -variance introduced by outliers: 82% (severely inflated) - -benchmarking fib/10 -time 5.930 μs (5.871 μs .. 6.013 μs) - 0.997 R² (0.994 R² .. 0.998 R²) -mean 6.209 μs (6.075 μs .. 6.464 μs) -std dev 625.6 ns (377.2 ns .. 1.088 μs) -variance introduced by outliers: 87% (severely inflated) - -benchmarking fib/25 -time 14.53 μs (14.31 μs .. 14.90 μs) - 0.990 R² (0.972 R² .. 0.999 R²) -mean 14.78 μs (14.40 μs .. 15.89 μs) -std dev 1.953 μs (712.6 ns .. 4.110 μs) -variance introduced by outliers: 91% (severely inflated) - -runhaskell FibonacciBetterCriterion.hs 15.90s user 0.07s system 100% cpu 15.954 total -``` - -``` -% ./FibonacciBetterWeigh - -Case Allocated GCs -fib 5 872 0 -fib 10 1,712 0 -fib 25 37,000 0 -``` - -### Boxed vs. Unboxed types - -Now, we are going to briefly mention is the difference between boxed and unboxed types. Although it is a low-level concern and with regular Haskell programming, you can avoid these terms, it is good to know what is it about when you see it in other's code or in a documentation. - -To support laziness, parametric polymorphism, and other properties, by default Haskell data types are represented uniformly as a pointer to a closure on the heap. These are "boxed" values. An unboxed is represented directly by raw value (i.e., without any indirection). Using unboxed types can lead to time/space optimizations. Having always pointers to a heap-allocated object is fairly slow, so compilers attempt to replace these boxed values with unboxed raw values when possible. Unboxed values are a feature of some compilers that allow directly manipulating these low-level values. Since they behave differently than normal Haskell types, generally the type system is extended to type these unboxed values. - -In GHC, unboxed values have a hash mark as a suffix to their name. For instance, the unboxed representation of 42 is 42#. However, you can't pass them to polymorphic functions (like `show` for instance). To allow that, you need to use constructor `I#` that takes an unboxed integer and returns the `Int` (wraps). You can observe [kind](https://wiki.haskell.org/Kind) (*kind of type*, we will look again at kinds with typeclasses) of boxed and unboxed types: - -* By default, kind of type is `*` (try in GHCi: `:kind Int`) -* Kind of unboxed type is `#` (try in GHCi: `:kind Int#`) - -```haskell -{-# LANGUAGE MagicHash #-} -module Main where - -import GHC.Exts - --- | Naive recursive algorithm for n-th Fibonacci number with --- unboxed Int types -fibonacci :: Int# -> Int# -fibonacci 0# = 0# -fibonacci 1# = 1# -fibonacci n = fibonacci (n -# 1#) +# fibonacci (n -# 2#) - -main :: IO () -main = print (I# (fibonacci 25#)) -``` - -``` -% /usr/bin/time -p runhaskell FibonacciUnboxed.hs -75025 -real 0.30 -user 0.27 -sys 0.03 -``` - -For more information, visit [GHC.Exts]() and [GHC.Prim](). - -### Strictness with types - -In the previous lessons, we touched the topic of enforcing strictness with `!` in patterns ([bang patterns](https://ocharles.org.uk/blog/posts/2014-12-05-bang-patterns.html)) and in function application with `$!` operator. Similarly, we can use `!` with type fields like this: - -```haskell -data MyType = MyConstr Int !Int - -data MyRec = MyRecConstr { xA :: Int - , xB :: !Int - } -``` - -For both cases it means that when data constructor is evaluated, it must fully evaluate ([weak head normal form](https://wiki.haskell.org/Weak_head_normal_form)) the second parameter, but the first one will stay unevaluated in a lazy way. All depends on language implementation in the used compiler. - -#### Unpacking strict fields - -One of the most used optimization techniques when talking about unboxed types and strictness with [GHC] is [unpacking strict fields](https://wiki.haskell.org/Performance/Data_types#Unpacking_strict_fields). When a constructor field is marked strict, and it is a single-constructor type, then it is possible to ask GHC to unpack the contents of the field directly in its parent with `{-# UNPACK #-}` pragma: - -```haskell -data T1 = T1 {-# UNPACK #-} !(Int, Float) -- => T1 Int Float -data T2 = T2 Double {-# UNPACK #-} !Int -- => T2 Double Int# -``` - -We mention this just because of differences in performance of types we are going to describe now. You don't need to use strict or unboxed types within your work if you don't need to have time/space optimizations and if yes, consider reading [Haskell High Performance Programming](https://github.com/TechBookHunter/Free-Haskell-Books/blob/master/book/Haskell%20High%20Performance%20Programming.pdf). - -### GHC optimization flags - -If you know optimization with GCC, then you won't be surprised how it works with GHC: - -* `-O0` = turn off all optimization -* `-O` or `-O1` = generate good-quality code without taking too long about it -* `-O2` = apply every non-dangerous optimization, even if it means significantly longer compile times (in most cases, there is no significant difference between `-O1` and `-O2`) - -Then there are also `-f*` platform-independent flags, that allows you to turn on and off individual optimizations. For more information, please visit [GHC documentation](http://downloads.haskell.org/~ghc/latest/docs/html/users_guide/using-optimisation.html). - -### Concurrency and Parallelism - -Haskell (of course) supports parallelism or concurrency in order to achieve faster and efficient computation. For parallelism and concurrency visit [wiki.haskell.org/Parallel](https://wiki.haskell.org/Parallel). You can both: - -* run parallel threads with [Control.Parallel](http://hackage.haskell.org/package/parallel/docs/Control-Parallel.html), -* run simultaneous IO actions with forks. - -It is also possible to do distributed computations on clusters but it is far beyond the scope of this course. - -```haskell -import Control.Parallel - -parfib 0 = return 1 -parfib 1 = return 1 -parfib n = do - n1 <- parfib (n - 1) - n2 <- parfib (n - 2) - n3 <- (n1 `par` (n2 `seq` (return (n1 + n2 + 1)))) - return n3 - -main = do x <- parfib 30; print x -``` - -GHC supports running programs in parallel on an SMP (symmetric multiprocessor) or multi-core machine. Just compile your program using the `-threaded` switch and then run it with RTS option `-N ` (where `` is the number of simultaneous threads). See [GHC docs](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/parallel.html) for more information. - -### FFI - -As with many other programming languages, Haskell supports [FFI (Foreign Function Interface)](https://wiki.haskell.org/Foreign_Function_Interface) that allows co-operating with programs written with other languages. We've already could see that in the example of Haste in DS Wizard where there were some JS bindings. But you can also use it to call some functions from C++ or Rust: - -```cpp -extern "C"{ // need to expose with extern, could use header file .h or .hpp for that - extern int fib(int n) { - if(n < 0) return -1; - int x = 0, y = 1, tmp; - while(n-- > 0) { - tmp = x; - x = y; - y = tmp + x; - } - return x; - } -} -``` - -```haskell -{-# LANGUAGE ForeignFunctionInterface #-} - -import Foreign.C -import System.Environment - -foreign import ccall "fib" cfib :: CInt -> CInt - -main :: IO () -main = do - args <- getArgs - print . cfib . read . head $ args -``` - -``` -% gcc -c -o fib.o fib.cpp -% ghc --make -o ffi_fib FibonacciFFI.hs fib.o -Linking ffi_fib ... -% /usr/bin/time -p ./ffi_fib 25 -75025 -real 0.00 -user 0.00 -sys 0.00 -``` - -Similarly, there is `foreign export` to expose some Haskell functions to other FFIs. Nice example is here: [jarrett/cpphs](https://github.com/jarrett/cpphs). - -## Debugging - -Even if you are a good Haskell programmer, things can go wrong and especially in big projects it is a nontrivial challenge to find out where you did some mistake. Going thru the code in multiple functions, inner functions, various modules, etc. can be painful. Luckilly, there are some ways how to debug Haskell program and some are pretty easy and similar to well-known. - -### Tracing with `Debug.Trace` - -You should already know how to use GHC and GHCi to compile, link and examine Haskell programs. The simplest tool to use for debugging is the `trace` from [Debug.Trace](https://hackage.haskell.org/package/base.0/docs/Debug-Trace.html) which outputs the trace message given as its first argument, before returning the second argument as its result. There are many more *traces* defined for different cases: `traceShow`, `traceId`, `traceStack`, `traceIO`, `traceM`, etc. So you can use it for custom debugging output anywhere in the code. - -For example: - -```haskell -func a b = trace ("func " ++ show a ++ " " ++ show b) undefined -``` - -Or better usage with our example of Fibonacci numbers to see the calls: - -```haskell -module Main where - -import Debug.Trace - --- | Naive recursive algorithm for n-th Fibonacci number -fib1 :: Integer -> Integer -fib1 0 = trace "fib1 0" 0 -fib1 1 = trace "fib1 1" 1 -fib1 n = trace ("fib1 " ++ show n) (fib1 (n-1) + fib1 (n-2)) - --- | Improved recursive algorithm for n-th Fibonacci number -fib2 :: Integer -> Integer -fib2 = fib 0 1 - where - fib x _ 0 = trace "fib2 0" x - fib x y n = trace ("fib2 " ++ show n) (fib y (x+y) (n-1)) - -main :: IO () -main = do - print (fib1 4) - putStrLn "------------" - print (fib2 4) -``` - -``` -% runhaskell FibonacciTrace.hs -fib1 4 -fib1 2 -fib1 0 -fib1 1 -fib1 3 -fib1 1 -fib1 2 -fib1 0 -fib1 1 -3 ------------- -fib2 4 -fib2 3 -fib2 2 -fib2 1 -fib2 0 -3 -``` - -### GHCi debugger - -If you need a better debugger, you can use [GHCi debugger](https://downloads.haskell.org/~ghc/7.4.1/docs/html/users_guide/ghci-debugger.html) (other compilers, such as Hugs, have some different), which allows: - -* setting breakpoints and stepping, -* inspecting variables, -* tracing, -* working with exceptions, -* and so on. - -``` -Prelude> :l FibonacciNaive.hs -[1 of 1] Compiling Main ( FibonacciNaive.hs, interpreted ) -Ok, modules loaded: Main. -*Main> :break 9 -Breakpoint 0 activated at FibonacciNaive.hs:9:10-60 -*Main> fib1 5 -Stopped in Main.fib1, FibonacciNaive.hs:9:10-60 -_result :: Integer = _ -n :: Integer = 5 -[FibonacciNaive.hs:9:10-60] *Main> :continue -fib1 5 -Stopped in Main.fib1, FibonacciNaive.hs:9:10-60 -_result :: Integer = _ -n :: Integer = 3 -[FibonacciNaive.hs:9:28-33] *Main> :show breaks -[0] Main FibonacciNaive.hs:9:10-60 -[FibonacciNaive.hs:9:28-33] *Main> :abandon -*Main> -``` - -### `debug` package - -An interesting solution brings also the [debug](https://hackage.haskell.org/package/debug) package (and related extensions). It uses *Template Haskell* to examine the code and algorithms. - -```haskell -{-# LANGUAGE TemplateHaskell, ViewPatterns, PartialTypeSignatures #-} -{-# OPTIONS_GHC -Wno-partial-type-signatures #-} -module QuickSort(quicksort) where -import Data.List -import Debug - -debug [d| - quicksort :: Ord a => [a] -> [a] - quicksort [] = [] - quicksort (x:xs) = quicksort lt ++ [x] ++ quicksort gt - where (lt, gt) = partition (<= x) xs - |] -``` - -## Further reading - -* [Haskell - Debugging](https://wiki.haskell.org/Debugging) -* [Haskell - Performance](https://wiki.haskell.org/Performance) -* [Haskell - Concurrency](https://wiki.haskell.org/Concurrency) -* [Real World Haskell - Concurrent and Multicore Programming](http://book.realworldhaskell.org/read/concurrent-and-multicore-programming.html) -* [GHC - Concurrent and Parallel Haskell](https://downloads.haskell.org/~ghc/7.0.3/docs/html/users_guide/lang-parallel.html) - diff --git a/tutorials/12_exts-deptypes.md b/tutorials/99_bonus.md similarity index 100% rename from tutorials/12_exts-deptypes.md rename to tutorials/99_bonus.md From 0a87367f93529335472ac9b506e135a3ea65e6fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Wed, 20 Mar 2019 19:08:45 +0100 Subject: [PATCH 08/26] Shorten 5th tutorial (move to 6th) --- ...ypeclasses-io-exc.md => 05_typeclasses.md} | 288 +---------- tutorials/06_io-exc-typeclasses.md | 287 ++++++++++- tutorials/07_test-doc-debug.md | 470 +++++++++++++++++- 3 files changed, 756 insertions(+), 289 deletions(-) rename tutorials/{05_typeclasses-io-exc.md => 05_typeclasses.md} (71%) diff --git a/tutorials/05_typeclasses-io-exc.md b/tutorials/05_typeclasses.md similarity index 71% rename from tutorials/05_typeclasses-io-exc.md rename to tutorials/05_typeclasses.md index ba525c3..6d8a204 100644 --- a/tutorials/05_typeclasses-io-exc.md +++ b/tutorials/05_typeclasses.md @@ -689,293 +689,10 @@ Again, monad comes from math and more specifically from category theory. A monad 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` -## Working with IO - -When you need to incorporate input and output (CLI, files, sockets, etc.), you bring impureness into your program. Obviously, IO brings side effects (it interacts with the environment and changes the global state). It can be a bit complicated and so we won't go deep into theory this time and instead, we will just show how to use it. Theoretical part will be covered in the future. - -```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 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). - -### The main and gets + puts - -If you know C/C++, Python, or other programming languages, you should be familiar with "main". As in other languages, `main` is defined to be the entry point of a Haskell program. For Stack projects, it is located in a file inside `app` directory and can be defined in `package.yaml` in `executables` section (it is possible to have multiple entrypoints per program). The type of `main` is `IO ()` -- it can do something (some actions) with `IO` and nothing `()` is returned. You may wonder why it is not `IO Int` (with a return code). It is because giving a return code is also an IO action and you can do it from `main` with functions from `System.Exit`. - -Now, let's take a look at basic IO examples: - -```haskell -main1 :: IO () -main1 = putStr "Hello, Haskeller!" -- putStr :: String -> IO () - -main2 :: IO () -main2 = putStrLn "Hello, Haskeller!" -- putStrLn :: String -> IO () - -main3 :: IO () -main3 = do - putStr "Haskell " - putChar 'F' -- putChar :: Char -> IO () - putChar 'T' - putChar 'W' - putStrLn "! Don't you think?!" - --- pure function -sayHello :: String -> String -sayHello name = "Hello, " ++ name ++ "!" - -main4 :: IO () -main4 = do - putStrLn "Enter your name:" - name <- getLine -- getLine :: IO String, see getChar & getContents - putStrLn . sayHello $ name - --- custom IO action -promptInt :: IO Int -promptInt = do - putStr "Enter single integer: " - inpt <- getLine -- unwraps from IO (inpt :: String) - return (read inpt) -- return wraps with IO, read :: String -> Int - -compute x y = 50 * x + y - -main5 :: IO () -main5 = do - intA <- promptInt - intB <- promptInt - putStrLn ("Result: ++ show . compute $ intA intB) - -main6 :: IO () -main6 = print 1254 -- print = putStrLn . show -``` - -### What does `do` do? - -It doesn't look so weird if you recall how imperative programming works... But we are in the functional world now, so what is going on? Haskell provides [do notation](https://en.wikibooks.org/wiki/Haskell/do_notation), which is just a syntactic sugar for chaining actions and bindings (not just IO, in general!) in a simple manner instead of using `>>` (*then*) and `>>=` (*bind*) operators of the typeclass `Monad`. We cover this topic in detail in the next lecture, right now you can remember that although `do` looks imperative, it is actually still pure thanks to a smart "trick". - -When you use the binding operator `<-`, it means that the result of a bound action can be used in following actions. In the example with `main4`, IO action `getLine` is of type `IO String` and you want to use the wrapped `String` - you *bind* the result to name `name` and then use it in combination with pure function `sayHello` for the following action that will do the output. The `do` block consists of actions and bindings and binding cannot be the last one! - -You might have noticed the `return` in custom `promptInt` action. This is a confusing thing for beginners, as `return` here has **nothing to do** with imperative languages return. The confusing thing is that it *looks* very much like it. However, conceptually it is not a control-flow expression, but just a function of the typeclass `Monad` which is used for wrapping back something, in this case `return :: String -> IO String`. This is one of the reasons why PureScript got rid of `return` and uses `pure` instead. Again, we will look at this in detail in the next lecture. - -### Be `interact`ive - -A very interesting construct for building a simple CLI is `interact :: (String -> String) -> IO ()`. The interact function takes a function of type `String -> String` as its argument. The **entire** input from the standard input device is passed to this function as its argument, and the resulting string is output on the standard output device. Btw. this is a nice example of a higher-order function at work, right? - -```haskell -import Data.Char - -main1 :: IO () -main1 = interact (map toUpper) - -main2 :: IO () -main2 = interact (show . length) - -main3 :: IO () -main3 = interact reverse -``` - -As is emphasized, it works with an entire input. If you've tried the examples above, you could observe a difference made by lazy evaluation in the first case. If you need to interact by lines or by words, you can create helper functions for that easily. - -```haskell -eachLine :: (String -> String) -> (String -> String) -eachLine f = unlines . f . lines - -eachWord :: (String -> String) -> (String -> String) -eachWord f = unwords . f . words - -main5 :: IO () -main5 = interact (eachLine reverse) - -main6 :: IO () -main6 = interact (eachWord reverse) - -chatBot "Hello" = "Hi, how are you?" -chatBot "Fine" = "Lucky you... bye!" -chatBot "Bad" = "Me too!" -chatBot _ = "Sorry, I'm too dumb to understand this..." - -main7 :: IO () -main7 = interact (eachLine chatBot) -``` - -### IO with files - -Working with files is very similar to working with console IO. As you may already know, most of IO for consoles is built by using IO for files with system "file" stdin and stdout. Such thing is called a `Handle` in Haskell and it is well described in [System.IO](http://hackage.haskell.org/package/base/docs/System-IO.html#t:Handle). - -```haskell -main1 :: IO () -main1 = withFile "test.txt" ReadMode $ \handle -> do - fileSize <- hFileSize handle - print fileSize - xs <- getlines handle - sequence_ $ map (putStrLn . reverse) xs - -main2 :: IO () -main2 = do - handle <- openFile "test.txt" ReadMode -- :: IO Handle - fileSize <- hFileSize handle - print fileSize - hClose handle -``` - -In a similar manner, you can work with binary files (you would use `ByteString`s) and temporary files. To work with sockets (network communication), you can use a library like [network](hackage.haskell.org/package/network/) or specifically for HTTP [wreq](https://hackage.haskell.org/package/wreq) and [req](https://hackage.haskell.org/package/req). - -For some well-known file formats there are libraries ready, so you don't have to work with them over and over again just with functions from `Prelude`: - -* JSON: [aeson](https://hackage.haskell.org/package/aeson) -* YAML: [yaml](https://hackage.haskell.org/package/yaml) -* XML: [xml](https://hackage.haskell.org/package/xml), [hxt](https://hackage.haskell.org/package/hxt), or [xeno](https://hackage.haskell.org/package/xeno) -* CSV: [cassava](https://hackage.haskell.org/package/cassava) or [csv](https://hackage.haskell.org/package/csv/docs/Text-CSV.html) -* INI: [ini](https://hackage.haskell.org/package/ini) - -... and so on. Also, you probably know the fabulous [pandoc](https://pandoc.org), which is written in Haskell -- and you can use it as a [library](https://hackage.haskell.org/package/pandoc)! - -Hmmm, who said that Haskell is just for math and mad academics? ;-) - -### Arguments and env variables - -Another way of interacting with a program is via its command-line arguments and environment variables. Again, there is a little bit clumsy but simple way in [System.Environment](https://hackage.haskell.org/package/base/docs/System-Environment.html) and then some fancy libraries that can help you with more complex cases... - -```haskell -main :: IO () -main = do - progName <- getProgName -- IO String - print progName - path <- getExecutablePath -- IO String - print path - args <- getArgs -- :: IO [String] - print args - user <- lookupEnv "USER" -- :: IO (Maybe String), vs. getEnv :: IO String - print user - env <- getEnvironment -- :: IO [(String, String)] - print env -``` - -The most used library for [command line option parser](https://wiki.haskell.org/Command_line_option_parsers) is [cmdargs](http://hackage.haskell.org/package/cmdargs): - -```haskell -{-# LANGUAGE DeriveDataTypeable #-} -module Sample where -import System.Console.CmdArgs - -data Sample = Hello {whom :: String} - | Goodbye - deriving (Show, Data, Typeable) - -hello = Hello{whom = def} -goodbye = Goodbye - -main = do - args <- cmdArgs (modes [hello, goodbye]) - print args -``` - -For a more complex example, visit their documentation -- for example, `hlint` or `diffy` use this one. - -## Handling errors - -As we saw, a very elegant way way how to handle errors is using `Maybe` or `Either` types. This is a preferred way with obvious advantages, however, in practice, it may still come to a more explosive situation. - -### error - -`error` is a special function which stops execution with given message: - -``` -Prelude> error "Stop now" -*** Exception: Stop now -CallStack (from HasCallStack): - error, called at :1:1 in interactive:Ghci1 -``` - -There is another quite similar one - `errorWithoutStackTrace`: - -``` -Prelude> errorWithoutStackTrace "Stop now without stack trace" -*** Exception: Stop now without stack trace -``` - -It is obviously even worse than just `error` because you somewhere deep in your code say something about rendering the error... - -### undefined - -Special case of error is that something is `undefined` and it does not accept any message: - -``` -Prelude> undefined -*** Exception: Prelude.undefined -CallStack (from HasCallStack): - error, called at libraries/base/GHC/Err.hs:79:14 in base:GHC.Err - undefined, called at :5:1 in interactive:Ghci1 -``` - -Semantically, it can be used where the value is not defined (for example when you want to divide by zero). Sometimes you can see it used as a basic placeholder with meaning "Not implemented yet". For such things, you can use custom `error` or some specialized package like [Development.Placeholders](hackage.haskell.org/package/placeholders/docs/Development-Placeholders.html), which are more suitable. - -### throw, try and catch - -We have `throw`, `try` and `catch`, but those are functions - not keywords! - -``` -Prelude> import Control.Exception -Prelude Control.Exception> :type try -try :: Exception e => IO a -> IO (Either e a) -Prelude Control.Exception> :type throw -throw :: Exception e => e -> a -Prelude Control.Exception> :type catch -catch :: Exception e => IO a -> (e -> IO a) -> IO a -``` - -If you are interested you can read the documentation of [Control.Exception](https://hackage.haskell.org/package/base/docs/Control-Exception.html), however, exceptions are considered an anti-pattern in Haskell and you should always try to deal with potential errors in a more systematic way using types. We will slightly get back to these after getting the notion of Monads. ## Task assignment -The homework to practice working with advanced functional patterns, operators, and typeclasses is in repository [MI-AFP/hw05](https://github.com/MI-AFP/hw05). +The homework to practice working with typeclasses is in repository [MI-AFP/hw05](https://github.com/MI-AFP/hw05). ## Further reading @@ -987,6 +704,5 @@ The homework to practice working with advanced functional patterns, operators, a * [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 +* [LYAH - A Fistful of Monads](http://learnyouahaskell.com/a-fistful-of-monads) * [Haskell - Monad](https://wiki.haskell.org/Monad) -* [Haskell - IO Monad](https://wiki.haskell.org/Introduction_to_IO) diff --git a/tutorials/06_io-exc-typeclasses.md b/tutorials/06_io-exc-typeclasses.md index 7240301..177f50e 100644 --- a/tutorials/06_io-exc-typeclasses.md +++ b/tutorials/06_io-exc-typeclasses.md @@ -1,7 +1,291 @@ -# Common typeclasses 2 +# IO, Exceptions, and More Typeclasses In this tutorial, we will take a brief look at few more advanced typeclasses that you might want to use in some projects. They are not described in high detail, but just in an introductory manner, so when you encouter some problem - you should know what you can use and learn specific details for your case. +## Working with IO + +When you need to incorporate input and output (CLI, files, sockets, etc.), you bring impureness into your program. Obviously, IO brings side effects (it interacts with the environment and changes the global state). It can be a bit complicated and so we won't go deep into theory this time and instead, we will just show how to use it. Theoretical part will be covered in the future. + +```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 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). + +### The main and gets + puts + +If you know C/C++, Python, or other programming languages, you should be familiar with "main". As in other languages, `main` is defined to be the entry point of a Haskell program. For Stack projects, it is located in a file inside `app` directory and can be defined in `package.yaml` in `executables` section (it is possible to have multiple entrypoints per program). The type of `main` is `IO ()` -- it can do something (some actions) with `IO` and nothing `()` is returned. You may wonder why it is not `IO Int` (with a return code). It is because giving a return code is also an IO action and you can do it from `main` with functions from `System.Exit`. + +Now, let's take a look at basic IO examples: + +```haskell +main1 :: IO () +main1 = putStr "Hello, Haskeller!" -- putStr :: String -> IO () + +main2 :: IO () +main2 = putStrLn "Hello, Haskeller!" -- putStrLn :: String -> IO () + +main3 :: IO () +main3 = do + putStr "Haskell " + putChar 'F' -- putChar :: Char -> IO () + putChar 'T' + putChar 'W' + putStrLn "! Don't you think?!" + +-- pure function +sayHello :: String -> String +sayHello name = "Hello, " ++ name ++ "!" + +main4 :: IO () +main4 = do + putStrLn "Enter your name:" + name <- getLine -- getLine :: IO String, see getChar & getContents + putStrLn . sayHello $ name + +-- custom IO action +promptInt :: IO Int +promptInt = do + putStr "Enter single integer: " + inpt <- getLine -- unwraps from IO (inpt :: String) + return (read inpt) -- return wraps with IO, read :: String -> Int + +compute x y = 50 * x + y + +main5 :: IO () +main5 = do + intA <- promptInt + intB <- promptInt + putStrLn ("Result: ++ show . compute $ intA intB) + +main6 :: IO () +main6 = print 1254 -- print = putStrLn . show +``` + +### What does `do` do? + +It doesn't look so weird if you recall how imperative programming works... But we are in the functional world now, so what is going on? Haskell provides [do notation](https://en.wikibooks.org/wiki/Haskell/do_notation), which is just a syntactic sugar for chaining actions and bindings (not just IO, in general!) in a simple manner instead of using `>>` (*then*) and `>>=` (*bind*) operators of the typeclass `Monad`. We cover this topic in detail in the next lecture, right now you can remember that although `do` looks imperative, it is actually still pure thanks to a smart "trick". + +When you use the binding operator `<-`, it means that the result of a bound action can be used in following actions. In the example with `main4`, IO action `getLine` is of type `IO String` and you want to use the wrapped `String` - you *bind* the result to name `name` and then use it in combination with pure function `sayHello` for the following action that will do the output. The `do` block consists of actions and bindings and binding cannot be the last one! + +You might have noticed the `return` in custom `promptInt` action. This is a confusing thing for beginners, as `return` here has **nothing to do** with imperative languages return. The confusing thing is that it *looks* very much like it. However, conceptually it is not a control-flow expression, but just a function of the typeclass `Monad` which is used for wrapping back something, in this case `return :: String -> IO String`. This is one of the reasons why PureScript got rid of `return` and uses `pure` instead. Again, we will look at this in detail in the next lecture. + +### Be `interact`ive + +A very interesting construct for building a simple CLI is `interact :: (String -> String) -> IO ()`. The interact function takes a function of type `String -> String` as its argument. The **entire** input from the standard input device is passed to this function as its argument, and the resulting string is output on the standard output device. Btw. this is a nice example of a higher-order function at work, right? + +```haskell +import Data.Char + +main1 :: IO () +main1 = interact (map toUpper) + +main2 :: IO () +main2 = interact (show . length) + +main3 :: IO () +main3 = interact reverse +``` + +As is emphasized, it works with an entire input. If you've tried the examples above, you could observe a difference made by lazy evaluation in the first case. If you need to interact by lines or by words, you can create helper functions for that easily. + +```haskell +eachLine :: (String -> String) -> (String -> String) +eachLine f = unlines . f . lines + +eachWord :: (String -> String) -> (String -> String) +eachWord f = unwords . f . words + +main5 :: IO () +main5 = interact (eachLine reverse) + +main6 :: IO () +main6 = interact (eachWord reverse) + +chatBot "Hello" = "Hi, how are you?" +chatBot "Fine" = "Lucky you... bye!" +chatBot "Bad" = "Me too!" +chatBot _ = "Sorry, I'm too dumb to understand this..." + +main7 :: IO () +main7 = interact (eachLine chatBot) +``` + +### IO with files + +Working with files is very similar to working with console IO. As you may already know, most of IO for consoles is built by using IO for files with system "file" stdin and stdout. Such thing is called a `Handle` in Haskell and it is well described in [System.IO](http://hackage.haskell.org/package/base/docs/System-IO.html#t:Handle). + +```haskell +main1 :: IO () +main1 = withFile "test.txt" ReadMode $ \handle -> do + fileSize <- hFileSize handle + print fileSize + xs <- getlines handle + sequence_ $ map (putStrLn . reverse) xs + +main2 :: IO () +main2 = do + handle <- openFile "test.txt" ReadMode -- :: IO Handle + fileSize <- hFileSize handle + print fileSize + hClose handle +``` + +In a similar manner, you can work with binary files (you would use `ByteString`s) and temporary files. To work with sockets (network communication), you can use a library like [network](hackage.haskell.org/package/network/) or specifically for HTTP [wreq](https://hackage.haskell.org/package/wreq) and [req](https://hackage.haskell.org/package/req). + +For some well-known file formats there are libraries ready, so you don't have to work with them over and over again just with functions from `Prelude`: + +* JSON: [aeson](https://hackage.haskell.org/package/aeson) +* YAML: [yaml](https://hackage.haskell.org/package/yaml) +* XML: [xml](https://hackage.haskell.org/package/xml), [hxt](https://hackage.haskell.org/package/hxt), or [xeno](https://hackage.haskell.org/package/xeno) +* CSV: [cassava](https://hackage.haskell.org/package/cassava) or [csv](https://hackage.haskell.org/package/csv/docs/Text-CSV.html) +* INI: [ini](https://hackage.haskell.org/package/ini) + +... and so on. Also, you probably know the fabulous [pandoc](https://pandoc.org), which is written in Haskell -- and you can use it as a [library](https://hackage.haskell.org/package/pandoc)! + +Hmmm, who said that Haskell is just for math and mad academics? ;-) + +### Arguments and env variables + +Another way of interacting with a program is via its command-line arguments and environment variables. Again, there is a little bit clumsy but simple way in [System.Environment](https://hackage.haskell.org/package/base/docs/System-Environment.html) and then some fancy libraries that can help you with more complex cases... + +```haskell +main :: IO () +main = do + progName <- getProgName -- IO String + print progName + path <- getExecutablePath -- IO String + print path + args <- getArgs -- :: IO [String] + print args + user <- lookupEnv "USER" -- :: IO (Maybe String), vs. getEnv :: IO String + print user + env <- getEnvironment -- :: IO [(String, String)] + print env +``` + +The most used library for [command line option parser](https://wiki.haskell.org/Command_line_option_parsers) is [cmdargs](http://hackage.haskell.org/package/cmdargs): + +```haskell +{-# LANGUAGE DeriveDataTypeable #-} +module Sample where +import System.Console.CmdArgs + +data Sample = Hello {whom :: String} + | Goodbye + deriving (Show, Data, Typeable) + +hello = Hello{whom = def} +goodbye = Goodbye + +main = do + args <- cmdArgs (modes [hello, goodbye]) + print args +``` + +For a more complex example, visit their documentation -- for example, `hlint` or `diffy` use this one. + +## Handling errors + +As we saw, a very elegant way way how to handle errors is using `Maybe` or `Either` types. This is a preferred way with obvious advantages, however, in practice, it may still come to a more explosive situation. + +### error + +`error` is a special function which stops execution with given message: + +``` +Prelude> error "Stop now" +*** Exception: Stop now +CallStack (from HasCallStack): + error, called at :1:1 in interactive:Ghci1 +``` + +There is another quite similar one - `errorWithoutStackTrace`: + +``` +Prelude> errorWithoutStackTrace "Stop now without stack trace" +*** Exception: Stop now without stack trace +``` + +It is obviously even worse than just `error` because you somewhere deep in your code say something about rendering the error... + +### undefined + +Special case of error is that something is `undefined` and it does not accept any message: + +``` +Prelude> undefined +*** Exception: Prelude.undefined +CallStack (from HasCallStack): + error, called at libraries/base/GHC/Err.hs:79:14 in base:GHC.Err + undefined, called at :5:1 in interactive:Ghci1 +``` + +Semantically, it can be used where the value is not defined (for example when you want to divide by zero). Sometimes you can see it used as a basic placeholder with meaning "Not implemented yet". For such things, you can use custom `error` or some specialized package like [Development.Placeholders](hackage.haskell.org/package/placeholders/docs/Development-Placeholders.html), which are more suitable. + +### throw, try and catch + +We have `throw`, `try` and `catch`, but those are functions - not keywords! + +``` +Prelude> import Control.Exception +Prelude Control.Exception> :type try +try :: Exception e => IO a -> IO (Either e a) +Prelude Control.Exception> :type throw +throw :: Exception e => e -> a +Prelude Control.Exception> :type catch +catch :: Exception e => IO a -> (e -> IO a) -> IO a +``` + +If you are interested you can read the documentation of [Control.Exception](https://hackage.haskell.org/package/base/docs/Control-Exception.html), however, exceptions are considered an anti-pattern in Haskell and you should always try to deal with potential errors in a more systematic way using types. We will slightly get back to these after getting the notion of Monads. + ## Foldable Recall the time when we were talking about folds... The `Foldable` type class provides a generalization of list folding (`foldr` and friends) and operations derived from it to arbitrary data structures. The class does not require the Functor superclass in order to allow containers like Set or StorableVector that have additional constraints on the element type. But many interesting Foldables are also Functors. A foldable container is a container with the added property that its items can be 'folded' to a summary value. Recall what `foldr` and `foldl` do... @@ -509,4 +793,3 @@ The homework to practice typeclasses from this tutorial is in repository [MI-AFP * [SchoolOfHaskell - Lens tutorial](https://www.schoolofhaskell.com/school/to-infinity-and-beyond/pick-of-the-week/a-little-lens-starter-tutorial) * [Lenses In Pictures](http://adit.io/posts/2013-07-22-lenses-in-pictures.html) * [Next Level MTL - George Wilson - BFPG 2016-06 (Lens, Monad transformers)](https://www.youtube.com/watch?v=GZPup5Iuaqw) - diff --git a/tutorials/07_test-doc-debug.md b/tutorials/07_test-doc-debug.md index 4943cdb..22e0495 100644 --- a/tutorials/07_test-doc-debug.md +++ b/tutorials/07_test-doc-debug.md @@ -1,4 +1,4 @@ -# Basic IO, tests, and documentation +# Tests, Documentation, Debugging and Performance ## Testing @@ -413,3 +413,471 @@ The homework to practice IO basics, testing, and writing project documentation i * [WikiBooks - Haskell: Testing](https://en.wikibooks.org/wiki/Haskell/Testing) * [Haddock User Guide](https://www.haskell.org/haddock/doc/html/index.html) * [QuickCheck and Magic of Testing](https://www.fpcomplete.com/blog/2017/01/quickcheck) + +# Performance and Debugging + +During this tutorial, we will take a look how to improve the performance of a Haskell program and how to debug it. We will use very simple example - [Fibonacci numbers](https://en.wikipedia.org/wiki/Fibonacci_number). + +```haskell +import System.Environment + +-- | Naive recursive algorithm for n-th Fibonacci number +fibonacci :: Integer -> Integer +fibonacci 0 = 0 +fibonacci 1 = 1 +fibonacci n = fibonacci (n-1) + fibonacci (n-2) + +main :: IO () +main = do + args <- getArgs + print . fibonacci . read . head $ args +``` + +## Measuring time and memory + +When you want to check the performance of a program and compare two programs or algorithms in terms of time or memory consumption, you need to measure it. + +### Basic `time` + +The `time` command is one of the well-known Linux commands for programmers. It can be used to show how long a command takes to run. That makes it Very useful if you are a developer and you want to test the performance of your program or script. Especially to compare the time of programs written in other languages "from outside". For basic usage, you will get three numbers: + +- `real` = total time is taken to run the command (the same as if you use your normal stopwatch) +- `user` = amount of time that was spent in user mode +- `sys` = amount of time spent in kernel mode + +Then `user`+`sys` gives information how much actual CPU time your process used - in total on all cores. This number can be then higher than `real` if your program uses multiple threads. + +```console +% /usr/bin/time -p runhaskell FibonacciNaive.hs 25 +75025 +real 0.33 +user 0.31 +sys 0.01 +``` + +But `time` can do a bit more, you can tell how output should look like with additional "numbers" - number of page faults, average total memory use of the process in kilobytes, number of signals delivered to the process, number of socket messages received/sent by the process, exit status of the command, and many others. + +``` +% /usr/bin/time -f "Elapsed Time: %E\nExit Status: %X\nPage Faults: %F" runhaskell FibonacciNaive.hs 25 +75025 +Elapsed Time: 0:00.34 +Exit Status: 0 +Page Faults: 0 +``` + +### Benchmarking with Criterion + +If you are interested in such optimizations and improving your application or comparing various algorithms or their implementations, then you might find interesting to use a benchmarking library. In Haskell is the most used one called [Criterion](http://www.serpentine.com/criterion/). It provides a powerful but simple way to measure software performance. It provides both a framework for executing and analyzing benchmarks and a set of driver functions that makes it easy to build and run benchmarks and to analyze their results. + +For simple usage, you just need to work with the `defaultMain` from [Criterion.Main](https://hackage.haskell.org/package/criterion/docs/Criterion-Main.html) as they show in their example: + +```haskell +import Criterion.Main + +-- | Naive recursive algorithm for n-th Fibonacci number +fibonacci :: Integer -> Integer +fibonacci 0 = 0 +fibonacci 1 = 1 +fibonacci n = fibonacci (n-1) + fibonacci (n-2) + +main :: IO () +main = defaultMain [ + bgroup "fib" [ bench " 5" $ whnf fibonacci 5 + , bench "10" $ whnf fibonacci 10 + , bench "25" $ whnf fibonacci 25 + ] + ] +``` + +It has very nice outputs with a form of interactive HTML pages with charts and comparisons and has many options to use. + +```console +% runhaskell FibonacciNaiveCriterion.hs +benchmarking fib/ 5 +time 7.319 μs (6.980 μs .. 7.821 μs) + 0.966 R² (0.934 R² .. 0.995 R²) +mean 7.248 μs (6.966 μs .. 7.847 μs) +std dev 1.321 μs (805.8 ns .. 2.043 μs) +variance introduced by outliers: 96% (severely inflated) + +benchmarking fib/10 +time 81.34 μs (81.15 μs .. 81.54 μs) + 1.000 R² (1.000 R² .. 1.000 R²) +mean 81.58 μs (81.38 μs .. 81.85 μs) +std dev 811.3 ns (577.5 ns .. 1.191 μs) + +benchmarking fib/25 +time 111.6 ms (110.5 ms .. 112.2 ms) + 1.000 R² (1.000 R² .. 1.000 R²) +mean 112.1 ms (111.7 ms .. 112.9 ms) +std dev 853.6 μs (534.0 μs .. 1.215 ms) +variance introduced by outliers: 11% (moderately inflated) + +runhaskell FibonacciNaiveCriterion.hs 15.98s user 0.04s system 99% cpu 16.055 total +``` + +### Measure allocations with Weigh + +The package [weigh](https://hackage.haskell.org/package/weigh) provides a simple interface to measure the memory usage of a Haskell value or function. + +```haskell +import Weigh + +-- | Naive recursive algorithm for n-th Fibonacci number +fibonacci :: Integer -> Integer +fibonacci 0 = 0 +fibonacci 1 = 1 +fibonacci n = fibonacci (n-1) + fibonacci (n-2) + +main :: IO () +main = mainWith $ do + func "fib 5" fibonacci 5 + func "fib 10" fibonacci 10 + func "fib 25" fibonacci 25 +``` + +It provides a nice output as plain text table, but it is also possible to change the format to markdown. + +```console +% ./FibonacciNaiveWeigh + +Case Allocated GCs +fib 5 1,968 0 +fib 10 24,304 0 +fib 25 33,509,936 63 +``` + +## Performance + +Now we are able to measure something and compare algorithms, but how to improve the numbers we get if we really need it? + +### Basic ideas + +When you are not satisfied with the performance of your application, then before any sophisticated optimization steps by using strictness, unboxed types, calling FFI, etc., you should consider if you prefer faster application over better readability. Then another important thing to think about is design if it is not slow by using "naive" algorithm, using an inappropriate data structure (List instead of Set or Map), etc. + +**Always** rethink your own code before using other optimization techniques! + +```haskell +import System.Environment + +-- | Improved recursive algorithm for n-th Fibonacci number +fibonacci :: Integer -> Integer +fibonacci = fib 0 1 + where + fib x _ 0 = x + fib x y n = fib y (x+y) (n-1) -- just "one-way" recursion! + +main :: IO () +main = do + args <- getArgs + print . fibonacci . read . head $ args +``` + +Just a very simple re-thinking can have some impact: + +```console +% /usr/bin/time -p runhaskell FibonacciBetter.hs 25 +75025 +real 0.24 +user 0.22 +sys 0.02 +``` + +```console +% runhaskell FibonacciBetterCriterion.hs +benchmarking fib/ 5 +time 3.412 μs (3.235 μs .. 3.591 μs) + 0.988 R² (0.983 R² .. 0.998 R²) +mean 3.191 μs (3.129 μs .. 3.277 μs) +std dev 253.6 ns (168.4 ns .. 360.9 ns) +variance introduced by outliers: 82% (severely inflated) + +benchmarking fib/10 +time 5.930 μs (5.871 μs .. 6.013 μs) + 0.997 R² (0.994 R² .. 0.998 R²) +mean 6.209 μs (6.075 μs .. 6.464 μs) +std dev 625.6 ns (377.2 ns .. 1.088 μs) +variance introduced by outliers: 87% (severely inflated) + +benchmarking fib/25 +time 14.53 μs (14.31 μs .. 14.90 μs) + 0.990 R² (0.972 R² .. 0.999 R²) +mean 14.78 μs (14.40 μs .. 15.89 μs) +std dev 1.953 μs (712.6 ns .. 4.110 μs) +variance introduced by outliers: 91% (severely inflated) + +runhaskell FibonacciBetterCriterion.hs 15.90s user 0.07s system 100% cpu 15.954 total +``` + +```console +% ./FibonacciBetterWeigh + +Case Allocated GCs +fib 5 872 0 +fib 10 1,712 0 +fib 25 37,000 0 +``` + +### Boxed vs. Unboxed types + +Now, we are going to briefly mention is the difference between boxed and unboxed types. Although it is a low-level concern and with regular Haskell programming, you can avoid these terms, it is good to know what is it about when you see it in other's code or in a documentation. + +To support laziness, parametric polymorphism, and other properties, by default Haskell data types are represented uniformly as a pointer to a closure on the heap. These are "boxed" values. An unboxed is represented directly by raw value (i.e., without any indirection). Using unboxed types can lead to time/space optimizations. Having always pointers to a heap-allocated object is fairly slow, so compilers attempt to replace these boxed values with unboxed raw values when possible. Unboxed values are a feature of some compilers that allow directly manipulating these low-level values. Since they behave differently than normal Haskell types, generally the type system is extended to type these unboxed values. + +In GHC, unboxed values have a hash mark as a suffix to their name. For instance, the unboxed representation of 42 is 42#. However, you can't pass them to polymorphic functions (like `show` for instance). To allow that, you need to use constructor `I#` that takes an unboxed integer and returns the `Int` (wraps). You can observe [kind](https://wiki.haskell.org/Kind) (*kind of type*, we will look again at kinds with typeclasses) of boxed and unboxed types: + +* By default, kind of type is `*` (try in GHCi: `:kind Int`) +* Kind of unboxed type is `#` (try in GHCi: `:kind Int#`) + +```haskell +{-# LANGUAGE MagicHash #-} +module Main where + +import GHC.Exts + +-- | Naive recursive algorithm for n-th Fibonacci number with +-- unboxed Int types +fibonacci :: Int# -> Int# +fibonacci 0# = 0# +fibonacci 1# = 1# +fibonacci n = fibonacci (n -# 1#) +# fibonacci (n -# 2#) + +main :: IO () +main = print (I# (fibonacci 25#)) +``` + +```console +% /usr/bin/time -p runhaskell FibonacciUnboxed.hs +75025 +real 0.30 +user 0.27 +sys 0.03 +``` + +For more information, visit [GHC.Exts]() and [GHC.Prim](). + +### Strictness with types + +In the previous lessons, we touched the topic of enforcing strictness with `!` in patterns ([bang patterns](https://ocharles.org.uk/blog/posts/2014-12-05-bang-patterns.html)) and in function application with `$!` operator. Similarly, we can use `!` with type fields like this: + +```haskell +data MyType = MyConstr Int !Int + +data MyRec = MyRecConstr { xA :: Int + , xB :: !Int + } +``` + +For both cases it means that when data constructor is evaluated, it must fully evaluate ([weak head normal form](https://wiki.haskell.org/Weak_head_normal_form)) the second parameter, but the first one will stay unevaluated in a lazy way. All depends on language implementation in the used compiler. + +#### Unpacking strict fields + +One of the most used optimization techniques when talking about unboxed types and strictness with [GHC] is [unpacking strict fields](https://wiki.haskell.org/Performance/Data_types#Unpacking_strict_fields). When a constructor field is marked strict, and it is a single-constructor type, then it is possible to ask GHC to unpack the contents of the field directly in its parent with `{-# UNPACK #-}` pragma: + +```haskell +data T1 = T1 {-# UNPACK #-} !(Int, Float) -- => T1 Int Float +data T2 = T2 Double {-# UNPACK #-} !Int -- => T2 Double Int# +``` + +We mention this just because of differences in performance of types we are going to describe now. You don't need to use strict or unboxed types within your work if you don't need to have time/space optimizations and if yes, consider reading [Haskell High Performance Programming](https://github.com/TechBookHunter/Free-Haskell-Books/blob/master/book/Haskell%20High%20Performance%20Programming.pdf). + +### GHC optimization flags + +If you know optimization with GCC, then you won't be surprised how it works with GHC: + +* `-O0` = turn off all optimization +* `-O` or `-O1` = generate good-quality code without taking too long about it +* `-O2` = apply every non-dangerous optimization, even if it means significantly longer compile times (in most cases, there is no significant difference between `-O1` and `-O2`) + +Then there are also `-f*` platform-independent flags, that allows you to turn on and off individual optimizations. For more information, please visit [GHC documentation](http://downloads.haskell.org/~ghc/latest/docs/html/users_guide/using-optimisation.html). + +### Concurrency and Parallelism + +Haskell (of course) supports parallelism or concurrency in order to achieve faster and efficient computation. For parallelism and concurrency visit [wiki.haskell.org/Parallel](https://wiki.haskell.org/Parallel). You can both: + +* run parallel threads with [Control.Parallel](http://hackage.haskell.org/package/parallel/docs/Control-Parallel.html), +* run simultaneous IO actions with forks. + +It is also possible to do distributed computations on clusters but it is far beyond the scope of this course. + +```haskell +import Control.Parallel + +parfib 0 = return 1 +parfib 1 = return 1 +parfib n = do + n1 <- parfib (n - 1) + n2 <- parfib (n - 2) + n3 <- (n1 `par` (n2 `seq` (return (n1 + n2 + 1)))) + return n3 + +main = do x <- parfib 30; print x +``` + +GHC supports running programs in parallel on an SMP (symmetric multiprocessor) or multi-core machine. Just compile your program using the `-threaded` switch and then run it with RTS option `-N ` (where `` is the number of simultaneous threads). See [GHC docs](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/parallel.html) for more information. + +### FFI + +As with many other programming languages, Haskell supports [FFI (Foreign Function Interface)](https://wiki.haskell.org/Foreign_Function_Interface) that allows co-operating with programs written with other languages. We've already could see that in the example of Haste in DS Wizard where there were some JS bindings. But you can also use it to call some functions from C++ or Rust: + +```cpp +extern "C"{ // need to expose with extern, could use header file .h or .hpp for that + extern int fib(int n) { + if(n < 0) return -1; + int x = 0, y = 1, tmp; + while(n-- > 0) { + tmp = x; + x = y; + y = tmp + x; + } + return x; + } +} +``` + +```haskell +{-# LANGUAGE ForeignFunctionInterface #-} + +import Foreign.C +import System.Environment + +foreign import ccall "fib" cfib :: CInt -> CInt + +main :: IO () +main = do + args <- getArgs + print . cfib . read . head $ args +``` + +```console +% gcc -c -o fib.o fib.cpp +% ghc --make -o ffi_fib FibonacciFFI.hs fib.o +Linking ffi_fib ... +% /usr/bin/time -p ./ffi_fib 25 +75025 +real 0.00 +user 0.00 +sys 0.00 +``` + +Similarly, there is `foreign export` to expose some Haskell functions to other FFIs. Nice example is here: [jarrett/cpphs](https://github.com/jarrett/cpphs). + +## Debugging + +Even if you are a good Haskell programmer, things can go wrong and especially in big projects it is a nontrivial challenge to find out where you did some mistake. Going thru the code in multiple functions, inner functions, various modules, etc. can be painful. Luckilly, there are some ways how to debug Haskell program and some are pretty easy and similar to well-known. + +### Tracing with `Debug.Trace` + +You should already know how to use GHC and GHCi to compile, link and examine Haskell programs. The simplest tool to use for debugging is the `trace` from [Debug.Trace](https://hackage.haskell.org/package/base.0/docs/Debug-Trace.html) which outputs the trace message given as its first argument, before returning the second argument as its result. There are many more *traces* defined for different cases: `traceShow`, `traceId`, `traceStack`, `traceIO`, `traceM`, etc. So you can use it for custom debugging output anywhere in the code. + +For example: + +```haskell +func a b = trace ("func " ++ show a ++ " " ++ show b) undefined +``` + +Or better usage with our example of Fibonacci numbers to see the calls: + +```haskell +module Main where + +import Debug.Trace + +-- | Naive recursive algorithm for n-th Fibonacci number +fib1 :: Integer -> Integer +fib1 0 = trace "fib1 0" 0 +fib1 1 = trace "fib1 1" 1 +fib1 n = trace ("fib1 " ++ show n) (fib1 (n-1) + fib1 (n-2)) + +-- | Improved recursive algorithm for n-th Fibonacci number +fib2 :: Integer -> Integer +fib2 = fib 0 1 + where + fib x _ 0 = trace "fib2 0" x + fib x y n = trace ("fib2 " ++ show n) (fib y (x+y) (n-1)) + +main :: IO () +main = do + print (fib1 4) + putStrLn "------------" + print (fib2 4) +``` + +```console +% runhaskell FibonacciTrace.hs +fib1 4 +fib1 2 +fib1 0 +fib1 1 +fib1 3 +fib1 1 +fib1 2 +fib1 0 +fib1 1 +3 +------------ +fib2 4 +fib2 3 +fib2 2 +fib2 1 +fib2 0 +3 +``` + +### GHCi debugger + +If you need a better debugger, you can use [GHCi debugger](https://downloads.haskell.org/~ghc/7.4.1/docs/html/users_guide/ghci-debugger.html) (other compilers, such as Hugs, have some different), which allows: + +* setting breakpoints and stepping, +* inspecting variables, +* tracing, +* working with exceptions, +* and so on. + +``` +Prelude> :l FibonacciNaive.hs +[1 of 1] Compiling Main ( FibonacciNaive.hs, interpreted ) +Ok, modules loaded: Main. +*Main> :break 9 +Breakpoint 0 activated at FibonacciNaive.hs:9:10-60 +*Main> fib1 5 +Stopped in Main.fib1, FibonacciNaive.hs:9:10-60 +_result :: Integer = _ +n :: Integer = 5 +[FibonacciNaive.hs:9:10-60] *Main> :continue +fib1 5 +Stopped in Main.fib1, FibonacciNaive.hs:9:10-60 +_result :: Integer = _ +n :: Integer = 3 +[FibonacciNaive.hs:9:28-33] *Main> :show breaks +[0] Main FibonacciNaive.hs:9:10-60 +[FibonacciNaive.hs:9:28-33] *Main> :abandon +*Main> +``` + +### `debug` package + +An interesting solution brings also the [debug](https://hackage.haskell.org/package/debug) package (and related extensions). It uses *Template Haskell* to examine the code and algorithms. + +```haskell +{-# LANGUAGE TemplateHaskell, ViewPatterns, PartialTypeSignatures #-} +{-# OPTIONS_GHC -Wno-partial-type-signatures #-} +module QuickSort(quicksort) where +import Data.List +import Debug + +debug [d| + quicksort :: Ord a => [a] -> [a] + quicksort [] = [] + quicksort (x:xs) = quicksort lt ++ [x] ++ quicksort gt + where (lt, gt) = partition (<= x) xs + |] +``` + +## Further reading + +* [Haskell - Debugging](https://wiki.haskell.org/Debugging) +* [Haskell - Performance](https://wiki.haskell.org/Performance) +* [Haskell - Concurrency](https://wiki.haskell.org/Concurrency) +* [Real World Haskell - Concurrent and Multicore Programming](http://book.realworldhaskell.org/read/concurrent-and-multicore-programming.html) +* [GHC - Concurrent and Parallel Haskell](https://downloads.haskell.org/~ghc/7.0.3/docs/html/users_guide/lang-parallel.html) From 5cdc036a8e42f01a6a45e65e8cb94fa4d0d56fcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Wed, 20 Mar 2019 19:27:34 +0100 Subject: [PATCH 09/26] Minor fix of tut05 --- tutorials/05_typeclasses.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tutorials/05_typeclasses.md b/tutorials/05_typeclasses.md index 6d8a204..a4d678e 100644 --- a/tutorials/05_typeclasses.md +++ b/tutorials/05_typeclasses.md @@ -1,4 +1,4 @@ -# Typeclasses, IO, and exceptions +# Typeclasses - custom and predefined ## Typeclasses @@ -696,13 +696,13 @@ The homework to practice working with typeclasses is in repository [MI-AFP/hw05] ## Further reading -* [Haskell - Polymorphism](https://wiki.haskell.org/Polymorphism) +* [Haskell: Polymorphism](https://wiki.haskell.org/Polymorphism) * [Typeclassopedia](https://wiki.haskell.org/Typeclassopedia) -* [Haskell - OOP vs type classes](https://wiki.haskell.org/OOP_vs_type_classes) -* [WikiBooks - Haskell: Classes and types](https://en.wikibooks.org/wiki/Haskell/Classes_and_types) +* [Haskell: OOP vs type classes](https://wiki.haskell.org/OOP_vs_type_classes) +* [WikiBooks Haskell: Classes and types](https://en.wikibooks.org/wiki/Haskell/Classes_and_types) * [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) -* [LYAH - A Fistful of Monads](http://learnyouahaskell.com/a-fistful-of-monads) -* [Haskell - Monad](https://wiki.haskell.org/Monad) +* [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: Monad](https://wiki.haskell.org/Monad) From 0f382d2c95b107f1551ff6db858a6d6345ce11ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Wed, 27 Mar 2019 15:19:30 +0100 Subject: [PATCH 10/26] Minor improvements in tut06 --- tutorials/06_io-exc-typeclasses.md | 60 ++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 20 deletions(-) diff --git a/tutorials/06_io-exc-typeclasses.md b/tutorials/06_io-exc-typeclasses.md index 177f50e..378a303 100644 --- a/tutorials/06_io-exc-typeclasses.md +++ b/tutorials/06_io-exc-typeclasses.md @@ -1,6 +1,6 @@ # IO, Exceptions, and More Typeclasses -In this tutorial, we will take a brief look at few more advanced typeclasses that you might want to use in some projects. They are not described in high detail, but just in an introductory manner, so when you encouter some problem - you should know what you can use and learn specific details for your case. +In this tutorial, we will take a brief look at IO including exceptions and then at few more advanced typeclasses that you might want to use in some projects. They are not described in high detail, but just in an introductory manner, so when you encouter some problem - you should know what you can use and learn specific details for your case. ## Working with IO @@ -286,7 +286,25 @@ catch :: Exception e => IO a -> (e -> IO a) -> IO a If you are interested you can read the documentation of [Control.Exception](https://hackage.haskell.org/package/base/docs/Control-Exception.html), however, exceptions are considered an anti-pattern in Haskell and you should always try to deal with potential errors in a more systematic way using types. We will slightly get back to these after getting the notion of Monads. -## Foldable +```haskell +import System.IO +import Control.Exception + +myHandler :: Exception e => (e -> IO a) +myHandler exc = do + putStrLn "Oops, error occured while trying to read the file" + putStrLn $ "It failed with: " ++ show exc + +main = handle myHandler $ do + fp <- openFile "test.txt" ReadMode + fileSize <- hFileSize fp + print fileSize + hClose fp +``` + +## Advanced Typeclasses + +### Foldable Recall the time when we were talking about folds... The `Foldable` type class provides a generalization of list folding (`foldr` and friends) and operations derived from it to arbitrary data structures. The class does not require the Functor superclass in order to allow containers like Set or StorableVector that have additional constraints on the element type. But many interesting Foldables are also Functors. A foldable container is a container with the added property that its items can be 'folded' to a summary value. Recall what `foldr` and `foldl` do... @@ -317,7 +335,7 @@ class Foldable (t :: * -> *) where This class is very straight-forward, it has no specific laws, but it is very powerful as we've already known... It allows you to create new or use various containers with same generic functions like `null`, `length`, `elem`, `minimum`, `maximum`, and others seamlessly and without any problems. For more, see [Data.Foldable](https://hackage.haskell.org/package/base/docs/Data-Foldable.html). -### Specialized folds +#### Specialized folds Aside functions defined in `Foldable` typeclass, there are some additional specialized folds that can be very useful and avoid reinventing the wheel in your code: @@ -338,7 +356,7 @@ notElem :: (Foldable t, Eq a) => a -> t a -> Bool find :: Foldable t => (a -> Bool) -> t a -> Maybe a ``` -### Foldable and Applicative +#### Foldable and Applicative Then, there are some specialized functions that are useful when you have `Applicative` objects in a `Foldable` structure or want to apply them over a `Foldable` structure. *(Notice the underscores)* @@ -385,7 +403,7 @@ Prelude Data.Foldable> asum [Nothing, Just "b"] Just "b" ``` -### Foldable and Monad +#### Foldable and Monad Similarly, there are also same folds for `Monad`s, just naming is a bit different: @@ -399,7 +417,7 @@ sequence_ :: (Foldable t, Monad m) => t (m a) -> m () msum :: (Foldable t, MonadPlus m) => t (m a) -> m a -- An alternative is described in this tutorial ``` -## Traversable +### Traversable A `Traversable` type is a kind of upgraded `Foldable` with use of `Functor`. Where Foldable gives you the ability to go through the structure processing the elements (*catamorphism*) but throwing away the "shape", `Traversable` allows you to do that whilst preserving the "shape" and, e.g., putting new values in. Traversable is what we need for `mapM` and `sequence`: note the apparently surprising fact that the versions ending with an underscore (e.g., `mapM_`) are in a different typeclass - in `Foldable`. @@ -414,7 +432,7 @@ class (Functor t, Foldable t) => Traversable (t :: * -> *) where `Traversable` has, unlike `Foldable`, a few laws (naturality, identity, composition, ...). For more, see [Data.Traversable](https://hackage.haskell.org/package/base/docs/Data-Traversable.html). -### No more underscore +#### No more underscore Indeed, some functions from `Foldable` are in `Traversable` without trailing `_` and it means "preserving the structure": @@ -447,7 +465,7 @@ ciao ["ahoj","hello","ciao"] ``` -## State +### State As you know, Haskell is great, there is no mutability, which results in reference transparency, everything has a mathematical foundations, and life is perfect. Or not? Using a mutable state is clearly over-used in imperative and object-oriented programming, at the same time, the concept of "state" may be inherently present in the modelled domain and so we need to deal with it. @@ -474,7 +492,7 @@ instance Monad (State s) where There are two interesting things. First, `State` is a record type with one field of type `s -> (a, s)`. Then `(>>=)` operator returns a `State` with a function that first runs `p` on given state `s0`, get intermediary result `(x, s)` and returns the result of running `k x` on `s1` -### Example: simple counter +#### Example: simple counter Let's look at a simple example: @@ -499,7 +517,7 @@ main = do If still not clear, try to read about `Reader` and `Writer` monads and look [here](http://adit.io/posts/2013-06-10-three-useful-monads.html) or into the classic [LYAH](http://learnyouahaskell.com/for-a-few-monads-more#state). -### Random in Haskell +#### Random in Haskell When you are using `System.Random`, you work with `State`: `State` is the generator for pseudorandom numbers (some equation with "memory"). @@ -512,7 +530,7 @@ main = do print $ take 10 ns ``` -### Parser +#### Parser Another typical example where you use `State` is when you want to parse something. So for this purpose, we have Parser monadic combinator as follows: @@ -522,7 +540,7 @@ newtype Parser a = Parser (parse :: String -> [(a,String)]) A very nice example is [here](http://dev.stephendiehl.com/fun/002_parsers.html). -## Alternative and MonadPlus +### Alternative and MonadPlus We are used use type `Maybe` when the result can be something or fail/nothing, and lists when there are many results of the same type and arbitrary size. Typeclasses `Alternative` and `MonadPlus` are here to provide a generic way of aggregating results together. `Maybe` and `[]` are its instances - read more: [Control.Applicative#Alternative](https://hackage.haskell.org/package/base/docs/Control-Applicative.html#t:Alternative) and [Control.Monad#MonadPlus](https://hackage.haskell.org/package/base/docs/Control-Monad.html#t:MonadPlus). You might find this very useful for [parsing](https://en.wikibooks.org/wiki/Haskell/Alternative_and_MonadPlus#Example:_parallel_parsing). @@ -548,7 +566,7 @@ a "a" ``` -### `guard` (don't mix with guards!) +#### `guard` (don't mix with guards!) An interesting function related to `Alternative` is `guard :: Alternative f => Bool -> f ()`. What does it do? It works like a guard in a sequence of actions! @@ -567,13 +585,13 @@ main = do print "OK, it is bigger than 100" ``` -## Monad Transformers +### Monad Transformers We have seen how monads can help handling IO actions, Maybe, lists, and state. With monads providing a common way to use such useful general-purpose tools, a natural thing we might want to do is using the capabilities of several monads at once. For instance, a function could use both I/O and Maybe exception handling. While a type like `IO (Maybe a)` would work just fine, it would force us to do pattern matching within `IO` do-blocks to extract values, something that the `Maybe` monad was meant to spare us from. Sounds like a dead end, right?! Luckily, we have monad transformers that can be used to combine monads in this way, save us time, and make the code easier to read. -### MaybeT +#### MaybeT Consider following simple program: @@ -616,7 +634,7 @@ askPassphrase = do lift $ putStrLn "Insert your new passphrase:" For more about monad transformers visit [this](https://en.wikibooks.org/wiki/Haskell/Monad_transformers) and the [transformers](https://hackage.haskell.org/package/transformers) package. There is also a very nice chapter about them in http://haskellbook.com. -## Category and Arrow +### Category and Arrow Recall what was told about Category Theory in the last tutorial. In Haskell, we have also typeclasses `Category` and `Arrow` (Do you remember? Alias for *morphisms*.). We mention it here just as an interesting part of Haskell and let you explore it if you are interested... @@ -693,7 +711,7 @@ arrow3 :: Arrow a => a [a1] [a1] A good explanation with nice visualization is in the chapter [Understanding Arrows](https://en.wikibooks.org/wiki/Haskell/Understanding_arrows) at wikibooks. -## Lens (and the taste of Template Haskell) +### Lens (and the taste of Template Haskell) The last thing we are going to get into this time is *Lens*. It is something that can make you a way more productive while working with records and especially nested records - which is something really common in non-trivial programs. @@ -707,7 +725,7 @@ The combinators in [Control.Lens](https://hackage.haskell.org/package/lens) prov If you are interested in `Control.Lens`, follow links in *Further reading* sections... -### Lens example +#### Lens example First, let's try example without *lens*: @@ -765,7 +783,7 @@ Line {_pA = Point2D {_x = 0, _y = 2}, _pB = Point2D {_x = 5, _y = 7}} Line {_pA = Point2D {_x = 0, _y = 0}, _pB = Point2D {_x = 10, _y = 7}} ``` -### What is `makeLenses` +#### What is `makeLenses` The function `makeLenses` indeed does some magic! From its type signature `makeLenses :: Language.Haskell.TH.Syntax.Name -> Language.Haskell.TH.Lib.DecsQ`, you can see it has something to do with [Template Haskell](https://wiki.haskell.org/Template_Haskell). It is GHC extension that allows metaprogramming. In this case, the function `makeLenses` builds lenses (and traversals) with a sensible default configuration. You need to provide the data type name where the record starts with an underscore and it will basically generate lenses for you. @@ -773,10 +791,12 @@ Template Haskell is very powerful and allows you to do interesting stuff, but it ## Task assignment -The homework to practice typeclasses from this tutorial is in repository [MI-AFP/hw08](https://github.com/MI-AFP/hw08). +The homework to practice typeclasses from this tutorial is in repository [MI-AFP/hw06](https://github.com/MI-AFP/hw06). ## Further reading +* [Haskell - Introduction to IO](https://wiki.haskell.org/Introduction_to_IO) +* [Haskell - Handling errors in Haskell](https://wiki.haskell.org/Handling_errors_in_Haskell) * [Haskell - Foldable](https://en.wikibooks.org/wiki/Haskell/Foldable) * [Haskell - Traversable](https://en.wikibooks.org/wiki/Haskell/Traversable) * [Haskell - State monad](https://en.wikibooks.org/wiki/Haskell/Understanding_monads/State) From f80152fccf33979e974da36f8dbd1953733b47bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Wed, 27 Mar 2019 17:38:17 +0100 Subject: [PATCH 11/26] Finalizing TUT06 --- tutorials/06_io-exc-typeclasses.md | 31 ++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/tutorials/06_io-exc-typeclasses.md b/tutorials/06_io-exc-typeclasses.md index 378a303..17f30b0 100644 --- a/tutorials/06_io-exc-typeclasses.md +++ b/tutorials/06_io-exc-typeclasses.md @@ -290,10 +290,9 @@ If you are interested you can read the documentation of [Control.Exception](http import System.IO import Control.Exception -myHandler :: Exception e => (e -> IO a) myHandler exc = do putStrLn "Oops, error occured while trying to read the file" - putStrLn $ "It failed with: " ++ show exc + putStrLn $ "It failed with: " ++ show (exc :: SomeException) main = handle myHandler $ do fp <- openFile "test.txt" ReadMode @@ -540,6 +539,34 @@ newtype Parser a = Parser (parse :: String -> [(a,String)]) A very nice example is [here](http://dev.stephendiehl.com/fun/002_parsers.html). +For custom `Read` instance, you can do something simple, but it still works as a parser and uses `ReadS` (S ~ state): + +```haskell +import Data.Char + +data Time = Time Int Int Int + +timePart x + | x < 10 = '0' : show x + | otherwise = show x + +instance Show Time where + show (Time hours minutes seconds) = timePart hours ++ ":" ++ timePart minutes ++ ":" ++ timePart seconds + +instance Read Time where + readsPrec _ (h1:h2:':':m1:m2:':':s1:s2:remaining) + | all isDigit [h1,h2,m1,m2,s1,s2] = [(Time h m s, remaining)] + | otherwise = [] + where + h = mkTimePart h1 h2 + m = mkTimePart m1 m2 + s = mkTimePart s1 s2 + mkTimePart x1 x2 = 10 * digitToInt x1 + digitToInt x2 + readsPrec _ _ = [] +``` + +Notice that you have to return list of tuples of type `(a, String)` just like in `parse`. The `readsPrec` gets and `Int` and then `String` where the number serves for the operator precedence of the enclosing context (can be often omitted). + ### Alternative and MonadPlus We are used use type `Maybe` when the result can be something or fail/nothing, and lists when there are many results of the same type and arbitrary size. Typeclasses `Alternative` and `MonadPlus` are here to provide a generic way of aggregating results together. `Maybe` and `[]` are its instances - read more: [Control.Applicative#Alternative](https://hackage.haskell.org/package/base/docs/Control-Applicative.html#t:Alternative) and [Control.Monad#MonadPlus](https://hackage.haskell.org/package/base/docs/Control-Monad.html#t:MonadPlus). You might find this very useful for [parsing](https://en.wikibooks.org/wiki/Haskell/Alternative_and_MonadPlus#Example:_parallel_parsing). From 2013345ceb34d9853bb6524e1d110d57dd3e0535 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Tue, 2 Apr 2019 15:49:05 +0200 Subject: [PATCH 12/26] Improve structure in tut07 --- tutorials/07_test-doc-debug.md | 61 ++++++++++++++++------------------ 1 file changed, 29 insertions(+), 32 deletions(-) diff --git a/tutorials/07_test-doc-debug.md b/tutorials/07_test-doc-debug.md index 22e0495..55a1a58 100644 --- a/tutorials/07_test-doc-debug.md +++ b/tutorials/07_test-doc-debug.md @@ -357,7 +357,7 @@ For more information about using Haddock and writing the documentation of source For building the documentation within a *stack project*, you can use `stack haddock` command, which generates `index.html` file. -## Publish your project +### Publish your project If you think that other people might be interested in your project and want to use it standalone or as part of their project (as a dependency), you can publish your project on GitHub and also on Hackage: @@ -371,7 +371,7 @@ Your project should be: Another advantage of publishing is that your project can get attention and community can help you improve it -- they create issues, forks and pull requests. -## Using CI (Travis CI) +### Using CI (Travis CI) When you are developing a project and sharing it with a community, you want to show that it is working well and you also want to check if contributions to your code are not breaking it. For that, you can use CI tools (continuous integration) which allows you to run tests (or other scripts) automatically. There are many CI tools these days: Travis CI, Jenkins, Circle CI, Appveyor, Semaphore, GitLab CI, etc. @@ -401,22 +401,9 @@ script: For Haskell, you can use `.travis.yml` above or read the [documentation](https://docs.travis-ci.com/user/languages/haskell/). -## Task assignment - -The homework to practice IO basics, testing, and writing project documentation is in repository [MI-AFP/hw06](https://github.com/MI-AFP/hw06). - -## Further reading - -* [A Gentle Introduction to Haskell - Input/Output](https://www.haskell.org/tutorial/io.html) -* [Haskell - Simple input and output](https://en.wikibooks.org/wiki/Haskell/Simple_input_and_output) -* [Real World Haskell - Testing and quality assurance](http://book.realworldhaskell.org/read/testing-and-quality-assurance.html) -* [WikiBooks - Haskell: Testing](https://en.wikibooks.org/wiki/Haskell/Testing) -* [Haddock User Guide](https://www.haskell.org/haddock/doc/html/index.html) -* [QuickCheck and Magic of Testing](https://www.fpcomplete.com/blog/2017/01/quickcheck) +## Performance and Debugging -# Performance and Debugging - -During this tutorial, we will take a look how to improve the performance of a Haskell program and how to debug it. We will use very simple example - [Fibonacci numbers](https://en.wikipedia.org/wiki/Fibonacci_number). +During this tutorial, we will also take a look how to improve the performance of a Haskell program and how to debug it. We will use very simple example - [Fibonacci numbers](https://en.wikipedia.org/wiki/Fibonacci_number). ```haskell import System.Environment @@ -433,11 +420,11 @@ main = do print . fibonacci . read . head $ args ``` -## Measuring time and memory +### Measuring time and memory When you want to check the performance of a program and compare two programs or algorithms in terms of time or memory consumption, you need to measure it. -### Basic `time` +#### Basic `time` The `time` command is one of the well-known Linux commands for programmers. It can be used to show how long a command takes to run. That makes it Very useful if you are a developer and you want to test the performance of your program or script. Especially to compare the time of programs written in other languages "from outside". For basic usage, you will get three numbers: @@ -465,7 +452,7 @@ Exit Status: 0 Page Faults: 0 ``` -### Benchmarking with Criterion +#### Benchmarking with Criterion If you are interested in such optimizations and improving your application or comparing various algorithms or their implementations, then you might find interesting to use a benchmarking library. In Haskell is the most used one called [Criterion](http://www.serpentine.com/criterion/). It provides a powerful but simple way to measure software performance. It provides both a framework for executing and analyzing benchmarks and a set of driver functions that makes it easy to build and run benchmarks and to analyze their results. @@ -516,7 +503,7 @@ variance introduced by outliers: 11% (moderately inflated) runhaskell FibonacciNaiveCriterion.hs 15.98s user 0.04s system 99% cpu 16.055 total ``` -### Measure allocations with Weigh +#### Measure allocations with Weigh The package [weigh](https://hackage.haskell.org/package/weigh) provides a simple interface to measure the memory usage of a Haskell value or function. @@ -547,11 +534,11 @@ fib 10 24,304 0 fib 25 33,509,936 63 ``` -## Performance +### Performance Now we are able to measure something and compare algorithms, but how to improve the numbers we get if we really need it? -### Basic ideas +#### Basic ideas When you are not satisfied with the performance of your application, then before any sophisticated optimization steps by using strictness, unboxed types, calling FFI, etc., you should consider if you prefer faster application over better readability. Then another important thing to think about is design if it is not slow by using "naive" algorithm, using an inappropriate data structure (List instead of Set or Map), etc. @@ -618,7 +605,7 @@ fib 10 1,712 0 fib 25 37,000 0 ``` -### Boxed vs. Unboxed types +#### Boxed vs. Unboxed types Now, we are going to briefly mention is the difference between boxed and unboxed types. Although it is a low-level concern and with regular Haskell programming, you can avoid these terms, it is good to know what is it about when you see it in other's code or in a documentation. @@ -656,7 +643,7 @@ sys 0.03 For more information, visit [GHC.Exts]() and [GHC.Prim](). -### Strictness with types +#### Strictness with types In the previous lessons, we touched the topic of enforcing strictness with `!` in patterns ([bang patterns](https://ocharles.org.uk/blog/posts/2014-12-05-bang-patterns.html)) and in function application with `$!` operator. Similarly, we can use `!` with type fields like this: @@ -681,7 +668,7 @@ data T2 = T2 Double {-# UNPACK #-} !Int -- => T2 Double Int# We mention this just because of differences in performance of types we are going to describe now. You don't need to use strict or unboxed types within your work if you don't need to have time/space optimizations and if yes, consider reading [Haskell High Performance Programming](https://github.com/TechBookHunter/Free-Haskell-Books/blob/master/book/Haskell%20High%20Performance%20Programming.pdf). -### GHC optimization flags +#### GHC optimization flags If you know optimization with GCC, then you won't be surprised how it works with GHC: @@ -691,7 +678,7 @@ If you know optimization with GCC, then you won't be surprised how it works with Then there are also `-f*` platform-independent flags, that allows you to turn on and off individual optimizations. For more information, please visit [GHC documentation](http://downloads.haskell.org/~ghc/latest/docs/html/users_guide/using-optimisation.html). -### Concurrency and Parallelism +#### Concurrency and Parallelism Haskell (of course) supports parallelism or concurrency in order to achieve faster and efficient computation. For parallelism and concurrency visit [wiki.haskell.org/Parallel](https://wiki.haskell.org/Parallel). You can both: @@ -716,7 +703,7 @@ main = do x <- parfib 30; print x GHC supports running programs in parallel on an SMP (symmetric multiprocessor) or multi-core machine. Just compile your program using the `-threaded` switch and then run it with RTS option `-N ` (where `` is the number of simultaneous threads). See [GHC docs](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/parallel.html) for more information. -### FFI +#### FFI As with many other programming languages, Haskell supports [FFI (Foreign Function Interface)](https://wiki.haskell.org/Foreign_Function_Interface) that allows co-operating with programs written with other languages. We've already could see that in the example of Haste in DS Wizard where there were some JS bindings. But you can also use it to call some functions from C++ or Rust: @@ -762,11 +749,11 @@ sys 0.00 Similarly, there is `foreign export` to expose some Haskell functions to other FFIs. Nice example is here: [jarrett/cpphs](https://github.com/jarrett/cpphs). -## Debugging +### Debugging Even if you are a good Haskell programmer, things can go wrong and especially in big projects it is a nontrivial challenge to find out where you did some mistake. Going thru the code in multiple functions, inner functions, various modules, etc. can be painful. Luckilly, there are some ways how to debug Haskell program and some are pretty easy and similar to well-known. -### Tracing with `Debug.Trace` +#### Tracing with `Debug.Trace` You should already know how to use GHC and GHCi to compile, link and examine Haskell programs. The simplest tool to use for debugging is the `trace` from [Debug.Trace](https://hackage.haskell.org/package/base.0/docs/Debug-Trace.html) which outputs the trace message given as its first argument, before returning the second argument as its result. There are many more *traces* defined for different cases: `traceShow`, `traceId`, `traceStack`, `traceIO`, `traceM`, etc. So you can use it for custom debugging output anywhere in the code. @@ -824,7 +811,7 @@ fib2 0 3 ``` -### GHCi debugger +#### GHCi debugger If you need a better debugger, you can use [GHCi debugger](https://downloads.haskell.org/~ghc/7.4.1/docs/html/users_guide/ghci-debugger.html) (other compilers, such as Hugs, have some different), which allows: @@ -855,7 +842,7 @@ n :: Integer = 3 *Main> ``` -### `debug` package +#### `debug` package An interesting solution brings also the [debug](https://hackage.haskell.org/package/debug) package (and related extensions). It uses *Template Haskell* to examine the code and algorithms. @@ -874,8 +861,18 @@ debug [d| |] ``` +## Task assignment + +The homework to practice testing, and writing project documentation is in repository [MI-AFP/hw07](https://github.com/MI-AFP/hw07). + ## Further reading +* [A Gentle Introduction to Haskell - Input/Output](https://www.haskell.org/tutorial/io.html) +* [Haskell - Simple input and output](https://en.wikibooks.org/wiki/Haskell/Simple_input_and_output) +* [Real World Haskell - Testing and quality assurance](http://book.realworldhaskell.org/read/testing-and-quality-assurance.html) +* [WikiBooks - Haskell: Testing](https://en.wikibooks.org/wiki/Haskell/Testing) +* [Haddock User Guide](https://www.haskell.org/haddock/doc/html/index.html) +* [QuickCheck and Magic of Testing](https://www.fpcomplete.com/blog/2017/01/quickcheck) * [Haskell - Debugging](https://wiki.haskell.org/Debugging) * [Haskell - Performance](https://wiki.haskell.org/Performance) * [Haskell - Concurrency](https://wiki.haskell.org/Concurrency) From 71e90d1ab4fd90266355fada1ab271370748e6ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Thu, 4 Apr 2019 18:23:26 +0200 Subject: [PATCH 13/26] HW info fix --- tutorials/07_test-doc-debug.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tutorials/07_test-doc-debug.md b/tutorials/07_test-doc-debug.md index 55a1a58..6f04c30 100644 --- a/tutorials/07_test-doc-debug.md +++ b/tutorials/07_test-doc-debug.md @@ -863,7 +863,7 @@ debug [d| ## Task assignment -The homework to practice testing, and writing project documentation is in repository [MI-AFP/hw07](https://github.com/MI-AFP/hw07). +The homework to practice IO (again), testing, and writing project documentation is in repository [MI-AFP/hw07](https://github.com/MI-AFP/hw07). ## Further reading From d241d8bbdb7b7a9649df0046b78ebaddda200fa9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Tue, 9 Apr 2019 14:32:35 +0200 Subject: [PATCH 14/26] Fix hw and add ginger to tut08 --- tutorials/08_webapp.md | 103 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 96 insertions(+), 7 deletions(-) diff --git a/tutorials/08_webapp.md b/tutorials/08_webapp.md index 6e30cd7..7d44dc3 100644 --- a/tutorials/08_webapp.md +++ b/tutorials/08_webapp.md @@ -236,6 +236,10 @@ main = scotty 3000 $ do Surprisingly easy, right?! +### Templating + +Writing HTML fragments as strings and compose them together can be fairly bothersome. For that purpose, there are libraries for templating known from other languages and frameworks as well. + #### Blaze templates One of the well-known and widely used solution for HTML templates is [Blaze HTML](https://hackage.haskell.org/package/blaze-html). It is "a blazingly fast HTML combinator library for the Haskell programming language". A huge advantage of Blaze is that you write HTML via HTML-like lightweight DSL in Haskell with the great type system. Blaze and Haskell won't allow you to make a non-sense HTML, although it does not check a full conformity, of course. @@ -293,7 +297,92 @@ context "name" = MuVariable "Haskell" A useful source of information what can you do with Hastache are [examples](https://github.com/lymar/hastache/tree/master/examples). -#### Databases +#### Ginger + +If you are familiar with Python and more specifically with Jinja2 templates, then you might be a fan of [Ginger](https://ginger.tobiasdammers.nl/guide/) library. It is implementation of Jinja2 templates in Haskell and it have quite nice documentation. Usage is quite simple, just look at the example: + +You have some HTML file with Jinja2 tags: + +```html +{# There could be some "extends" for layout #} + + + + {{ title }} + + +

Hello, {{ name }}!

+ + {% if condition %} +

Condition is true

+ {% else %} +

Condition is false or undefined

+ {% endif %} + + +``` + +Then you can load template, supply context into it, and render as text: + +```haskell +{-# LANGUAGE OverloadedStrings #-} +module Main where + +import Data.HashMap.Strict (fromList, HashMap) +import qualified Data.HashMap.Strict as HashMap +import Data.Hashable +import Data.Text (Text) +import System.Exit (exitFailure) +import System.IO (IOMode(ReadMode), openFile, hGetContents) +import System.IO.Error (tryIOError) +import Text.Ginger + (makeContextHtml, Template, toGVal, runGinger, parseGingerFile, VarName) +import Text.Ginger.GVal (ToGVal, GVal) +import Text.Ginger.Html (htmlSource) + + +-- A simple hashmap that we'll use as our template context +sampleContext :: HashMap Text Text +sampleContext = fromList [("name", "Alice")] + + +-- Given a Template and a HashMap of context, render the template to Text +render :: Template -> HashMap VarName Text -> Text +render template contextMap = + let contextLookup = flip scopeLookup contextMap + context = makeContextHtml contextLookup + in htmlSource $ runGinger context template + + +-- Wrapper around HashMap.lookup that applies toGVal to the value found. +-- Any value referenced in a template, returned from within a template, or used +-- in a template context, will be a GVal +scopeLookup + :: (Hashable k, Eq k, ToGVal m b) + => k -> HashMap.HashMap k b -> GVal m +scopeLookup key context = toGVal $ HashMap.lookup key context + + +loadFileMay :: FilePath -> IO (Maybe String) +loadFileMay fn = + tryIOError (loadFile fn) >>= \e -> + case e of + Right contents -> return (Just contents) + Left _ -> return Nothing + + where + loadFile :: FilePath -> IO String + loadFile fn' = openFile fn' ReadMode >>= hGetContents + +main :: IO () +main = do + template <- parseGingerFile loadFileMay "base.html" + case template of + Left err -> print err >> exitFailure + Right template' -> print $ render template' sampleContext +``` + +### Databases Again, several abstraction levels are available. First, you can employ a low-level approach where you incorporate SQL in the code. For that, you can usually use module `Database.X` where `X` is type of datase: @@ -476,24 +565,24 @@ This is just a simple (but often sufficient) example. Of course, you can test mu Here are a few examples of simple and more complex web apps: * [dbushenko/scotty-blog](https://github.com/dbushenko/scotty-blog) -* [DataStewardshipWizard/ds-wizard](https://github.com/DataStewardshipWizard/ds-wizard/tree/master/DSServer) -* [DataStewardshipWizard/dsw-server](https://github.com/DataStewardshipWizard/dsw-server) +* [ds-wizard/legacy-wizard](https://github.com/ds-wizard/legacy-wizard) +* [ds-wizard/dsw-server](https://github.com/ds-wizard/dsw-server) ## Continuation-style web development -We would also like to raise your attention to an interesting approach to web development based on the [continuation](https://wiki.haskell.org/Continuation). A continuation is "something" that enables you to save the state of computation, suspend it (do something else) and later resume it. This "something" may be a first-class language feature (such as in Scheme), or a library feature -- in Haskell, surprisingly, we have a continuation monad ;-). +We would also like to raise your attention to an interesting approach to web development based on the [continuation](https://wiki.haskell.org/Continuation). A continuation is "something" that enables you to save the state of computation, suspend it (do something else) and later resume it. This "something" may be a first-class language feature (such as in Scheme), or a library feature - in Haskell, surprisingly, we have a continuation monad ;-). -A need for continuation occurs typically in web development (and generally in UI development) when you want a modal dialogue. Today, most of the dialogues are handled on client-side, however if you need to do a modal dialogue on server-side, it is hard -- HTTP behaves like a programming language, which does not have subroutines, only GOTOs (URLSs are the 'line numbers'). Continuation can provide the missing abstraction here, which is embodied in the [MFlow](http://mflowdemo.herokuapp.com) library. Sadly, the project seems abandoned for several years. +A need for continuation occurs typically in web development (and generally in UI development) when you want a modal dialogue. Today, most of the dialogues are handled on client-side, however if you need to do a modal dialogue on server-side, it is hard - HTTP behaves like a programming language, which does not have subroutines, only GOTOs (URLSs are the 'line numbers'). Continuation can provide the missing abstraction here, which is embodied in the [MFlow](http://mflowdemo.herokuapp.com) library. Sadly, the project seems abandoned for several years. -At the same time, the continuation-style web server programming is typically the first choice in the Smalltalk (OOP) world -- [Seaside](http://seaside.st/) is purely continuation-based, and as such it gives a "desktop programming" experience for the web development resulting in no need of dealing with routing and URLs. As for the FP world, continuation-style web programming is surprisingly not used much in practice, but there are solutions such as the [Racket web server](https://docs.racket-lang.org/web-server/index.html) or [cl-weblocks](https://www.cliki.net/cl-weblocks) in Common Lisp. +At the same time, the continuation-style web server programming is typically the first choice in the Smalltalk (OOP) world - [Seaside](http://seaside.st/) is purely continuation-based, and as such it gives a "desktop programming" experience for the web development resulting in no need of dealing with routing and URLs. As for the FP world, continuation-style web programming is surprisingly not used much in practice, but there are solutions such as the [Racket web server](https://docs.racket-lang.org/web-server/index.html) or [cl-weblocks](https://www.cliki.net/cl-weblocks) in Common Lisp. The next time, we will deal a bit with frontend technologies for Haskell, functional reactive programming and [The JavaScript problem](https://wiki.haskell.org/The_JavaScript_Problem). So you will also see how to develop server-side and client-side separately and connect them through a (REST) API. ## Task assignment -The homework to complete a simple web app is in repository [MI-AFP/hw09](https://github.com/MI-AFP/hw09). +The homework to complete a simple web app is in repository [MI-AFP/hw08](https://github.com/MI-AFP/hw08). ## Further reading From 2e98d2a96b418ca26c2a5d12f1b52a4fa835e445 Mon Sep 17 00:00:00 2001 From: Jan Slifka Date: Fri, 8 Mar 2019 13:29:34 +0100 Subject: [PATCH 15/26] Add elm intro --- tutorials/09_elm-intro.md | 924 ++++++++++++++++++++++++++++++ tutorials/09_webapp.md | 506 ---------------- tutorials/10_frontend-frp.md | 417 -------------- tutorials/11_performance-debug.md | 468 --------------- tutorials/12_exts-deptypes.md | 254 -------- tutorials/images/tea.png | Bin 0 -> 10401 bytes 6 files changed, 924 insertions(+), 1645 deletions(-) create mode 100644 tutorials/09_elm-intro.md delete mode 100644 tutorials/09_webapp.md delete mode 100644 tutorials/10_frontend-frp.md delete mode 100644 tutorials/11_performance-debug.md delete mode 100644 tutorials/12_exts-deptypes.md create mode 100644 tutorials/images/tea.png diff --git a/tutorials/09_elm-intro.md b/tutorials/09_elm-intro.md new file mode 100644 index 0000000..f1cb312 --- /dev/null +++ b/tutorials/09_elm-intro.md @@ -0,0 +1,924 @@ +# Elm - Introduction + +## Installation, Editors and Plugins + +To install Elm, follow the official [installation guide](https://guide.elm-lang.org/install.html). There is also a section about how to configure different editors to work with Elm. + +Make sure to install [elm-format](https://github.com/avh4/elm-format) to your editor as well. + +There is also an online live editor for Elm called [Ellie](https://ellie-app.com). + + +## What is Elm + +According to the official website [elm-lang.org](https://elm-lang.org): + +> A delightful language for reliable webapps. +> +> Generate JavaScript with great performance and no runtime exceptions. + +It is a reactive pure functional programming language with syntax inspired by Haskell that compiles to JavaScript. It is designed for building reliable web applications with no runtime exceptions. Elm is one of the solutions for [the JavaScript problem](https://wiki.haskell.org/The_JavaScript_Problem). The [compiler](https://github.com/elm/compiler) is implemented in Haskell. + + +Elm is language **and** a framework for building front-end web applications. + +### Advantages + +- static strong type system, no `null` or `undefined` (static code analysis, when it compiles, it works) +- pure functions (no side effects, allows tree shaking on a function level) +- everything necessary for building front end apps is already included in the language +- standard ways how to do things, so it is easy to understand other people's code +- easy refactoring + +### Disadvantages + +- need for learning a new language +- sometimes, more code is needed than it would be in JavaScript (e.g., when parsing JSONs) +- lightweight Haskell (e.g., no type classes, which can result in more boilerplate code) +- harder to find developers for Elm projects than for JavaScript projects. + +### Compared to JavaScript + +Elm has built-in common tools and features that are part of typical JavaScript stack. + +| JavaScript | Elm| +| --- | --- | +| npm/yarn | built-in | +| Webpack | built-in | +| React | built-in | +| Redux | built-in | +| TypeScript/Flow | built-in | +| Immutable.JS | built-in | + + +## Alternatives + +### [Haste](https://haste-lang.org) + +Haste is a tool for compiling Haskell code into a JavaScript code and a server-side binary. Both programs can talk to each other ensuring type-safe communication. + +### [GHCJS](https://github.com/ghcjs/ghcjs) + +GHCJS is a compiler for Haskell to JavaScript that uses GHC API. It supports a wide range of Haskell features, including all type system extensions supported by GHC. There are some interesting frameworks for building web applications based on GHCJS: + +- [Reflex](https://reflex-frp.org) - A composable, cross-platform functional reactive programming framework for Haskell. +- [miso](https://haskell-miso.org) - A tasty Haskell front-end framework. + +### [PureScript](http://www.purescript.org) + +PureScript is a strongly-typed functional programming language that compiles to JavaScript. It is similar to Haskell with [some differences](https://github.com/purescript/documentation/blob/master/language/Differences-from-Haskell.md). It has a lot of packages published in [Pursuit](https://pursuit.purescript.org). Also, some frameworks for building web applications are there, e.g.: + +- [Thermite](https://github.com/paf31/purescript-thermite) - A simple PureScript wrapper for React. +- [Halogen](https://github.com/slamdata/purescript-halogen) - A declarative, type-safe UI library for PureScript. +- [Pux](https://github.com/alexmingoia/purescript-pux) - A library for building type-safe web applications. + +If you are interested, you can have a look at this comparison: [Benchmarks: GHCJS (Reflex, Miso) & Purescript (Pux, Thermite, Halogen)](https://medium.com/@saurabhnanda/benchmarks-fp-languages-libraries-for-front-end-development-a11af0542f7e) + +### [ReasonML](https://reasonml.github.io) + +Reason is a new syntax and toolchain based on OCaml programing language created by Facebook. The syntax is closer to JavaScript than OCaml. It is intended for development of front-end web applications and compiles to JavaScript. Using existing JavaScript and OCaml packages is possible. + + +## Elm REPL + +If you have Elm installed, you can run Elm REPL by `elm repl` command. It is like `ghci` for Elm. + +``` +$ elm repl +---- Elm 0.19.0 ---------------------------------------------------------------- +Read to learn more: exit, help, imports, etc. +-------------------------------------------------------------------------------- +> +``` + + +## Elm Language + +### Basic types + +Strings are enclosed in double quotation mark `"`. We use `++` operator to join them. + +#### String + +```elm +> "Hello world!" +"Hello world!" : String + +> "Hello " ++ "world!" +"Hello world!" : String +``` + +#### Numbers + +Elm has two number types `Int` and `Float` and constrained type variable `number` which can be either `Int` or `Float`. + +```elm +> 5 + 5 +10 : number + +> 5 + 5 * 3 +20 : number + +> (5 + 5) * 3 +30 : number + +> 2 ^ 8 +256 : number + +> 2 / 3 +0.6666666666666666 : Float + +> 7 // 2 +3 : Int + +> modBy 7 2 +2 : Int +``` + +#### Bool and logical operators + +Elm has standard operators for comparison and boolean operations. Same as in Haskell, it uses `/=` operator for inequality. + +```elm +> 5 > 7 +False : Bool + +> (5 == 7) +False : Bool + +> 5 /= 7 +True : Bool + +> not (5 /= 7) +False : Bool + +> False || True +True : Bool + +> False && True +False : Bool + +> not False && True +True : Bool +``` + +### Naming things + +If we want to give a name to expression, we use the `=` operator. + + +```elm +> x = 5 +5 : number + +> x +5 : number +``` + +### Function + +The definition and function call looks the same as in Haskell. + +```elm +> linear a b x = a * x + b + : number -> number -> number -> number + +> linear 5 3 7 +38 : number +``` + +### If expression + +```elm +> if True then "It is true!" else "It is not true." +"It is true!" : String +``` + + +### Comments + +Elm has multiline and single-line comments. + +```elm +{- + a multiline comment +-} + +-- a single line comment + +``` + + +### The Elm project + +The easiest way to initialize an Elm project is to use `elm init` command. + +``` +$ elm init +Hello! Elm projects always start with an elm.json file. I can create them! + +Now you may be wondering, what will be in this file? How do I add Elm files to +my project? How do I see it in the browser? How will my code grow? Do I need +more directories? What about tests? Etc. + +Check out for all the answers! + +Knowing all that, would you like me to create an elm.json file now? [Y/n]: y +Okay, I created it. Now read that link! + +$ ls +elm.json src +``` + + +It generates `elm.json` file that defines where the source files are and what are the project dependencies. + +```json +{ + "type": "application", + "source-directories": [ + "src" + ], + "elm-version": "0.19.0", + "dependencies": { + "direct": { + "elm/browser": "1.0.1", + "elm/core": "1.0.2", + "elm/html": "1.0.0" + }, + "indirect": { + "elm/json": "1.1.3", + "elm/time": "1.0.0", + "elm/url": "1.0.0", + "elm/virtual-dom": "1.0.2" + } + }, + "test-dependencies": { + "direct": {}, + "indirect": {} + } +} +``` + +### Modules + +Now, when we have our project ready, we can create some modules. A module has a name which should be the same as the file name. It has to state what expression from the module should be exposed explicitly. + + +```elm +-- src/Lib.elm + +module Lib exposing (linear) + + +linear a b x = + a * x + b +``` + +We can import the module to other modules or the repl using `import` statement. If we use just `import Lib` we need to use the full name for the expressions from the module. + +```elm +> import Lib +> Lib.linear 5 3 7 +38 : Int +``` + +We can also expose some expression and then use them without the full module name. + +```elm +> import Lib exposing (linear) +> linear 5 3 7 +38 : Int +``` + +Or we can expose everything from the module. + +```elm +> import Lib exposing (..) +> linear 5 3 7 +38 : Int +``` + +Or we can import a module with a different name. + +```elm +> import Lib as Math +> Math.linear 5 3 7 +38 : Int +``` + +### Type annotation + +Elm can infer the types based on what we are doing. However, it is a good practice to define the types. + +```elm +linear : Float -> Float -> Float -> Float +linear a b x = + a * x + b +``` + + +### Type variables + +When the specific type is not important, we can use a type variable. Type names start with an uppercase letter (e.g., `Float`), type variable can be almost any string starting with a lowercase letter. + +```elm +> List.isEmpty + : List a -> Bool + +> List.map + : (a -> b) -> List a -> List b + +``` + +#### Constrained Type Variables + +There are several constrained type variables with a special meaning defined by the Elm language. + +- `number` permits `Int` and `Float` +- `appendable` permits `String` and `List a` +- `comparable` permits `Int`, `Float`, `Char`, `String`, and lists/tuples of `comparable` values +- `compappend` permits `String` and `List comparable` + + +```elm +linear : number -> number -> number -> number +linear a b x = + a * x + b +``` + +### List + +A list is a collection of items of the same type with variable length. There is a [List](https://package.elm-lang.org/packages/elm/core/latest/List) module with various functions for working with lists. + +```elm +> numbers = [1, 3, 5, 7, 11] +[1,3,5,7,11] : List number + +> List.length numbers +5 : Int + +> List.isEmpty numbers +False : Bool + +> double n = n * 2 + : number -> number +> List.map double numbers +[2,6,10,14,22] : List number + +> List.map (\n -> n * 2) numbers +[2,6,10,14,22] : List number + + +> List.map ((*) 2) numbers +[2,6,10,14,22] : List number +``` + + +### Dict + +Dict is a mapping of unique keys to values. There is a [Dict](https://package.elm-lang.org/packages/elm-lang/core/latest/Dict) module with functions for working with dicts. + +```elm +> Dict.fromList [("Spencer", 25), ("Zoe", 21)] +Dict.fromList [("Spencer",25),("Zoe",21)] : Dict.Dict String number + +> Dict.insert "Spencer" 25 Dict.empty +Dict.fromList [("Spencer",25)] : Dict.Dict String number + +> dict = Dict.fromList [("Spencer", 25), ("Zoe", 21)] +Dict.fromList [("Spencer",25),("Zoe",21)] : Dict.Dict String number +> Dict.isEmpty dict +False : Bool +> Dict.get "Zoe" dict +Just 21 : Maybe number +> Dict.get "Frankie" dict +Nothing : Maybe number +``` + +### Tuple + +A tuple is a collection of items of various type with the fixed size. There is a [Tuple](https://package.elm-lang.org/packages/elm/core/latest/Tuple) module for working with tuples. Tuples can be used when a function returns more than one value. + + +```elm +> person = ("Joe", 21) +("Joe",21) : ( String, number ) + +> Tuple.first person +"Joe" : String + +> Tuple.second person +21 : number +``` + +We can use pattern matching for tuples in functions: + +```elm +bio : (String, Int) -> String +bio (name, age) = name ++ " is " ++ (String.fromInt age) ++ " years old." +``` + + +Elm has a limit on the maximum number of items in the tuple to be 3. If you need more, you should use a record or your own custom type. + +``` +> vector4 = (4, 10, 12, 3) +-- BAD TUPLE --------------------------------------------------------------- elm + +I only accept tuples with two or three items. This has too many: + +8| vector4 = (4, 10, 12, 3) + ^^^^^^^^^^^^^^ +I recommend switching to records. Each item will be named, and you can use the +`point.x` syntax to access them. + +Note: Read for more comprehensive advice on +working with large chunks of data in Elm. +``` + + +### Record + +Records contain keys and values. Each value can have a different type. + +```elm +> vector4 = { w = 4, x = 10, y = 12, z = 3 } +{ w = 4, x = 10, y = 12, z = 3 } + : { w : number, x : number1, y : number2, z : number3 } +``` + + +For accessing record properties, Elm has by default accessors defined as `.`. They can be used as `.`, but it is just syntactic sugar, they are just functions. + +```elm +> vector4.x +10 : number + +> .x vector4 +10 : number + +> List.map .x [vector4, vector4, vector4] +[10,10,10] : List number +``` + +If we have a look at the type of `.x` accessor, it says it is any record that has a field `x` of type `a` and returns `a`. + +```elm +> .x + : { b | x : a } -> a +``` + + +Since everything is immutable, records cannot be updated. We can create updated records though: + +```elm +> { vector4 | x = 20 } +{ w = 4, x = 20, y = 12, z = 3 } + : { w : number1, x : number, y : number2, z : number3 } +``` + + +We can use pattern matching for record keys: + +```elm +> length {w, x, y, z} = sqrt (w * w + x * x + y * y + w * w) + : { b | w : Float, x : Float, y : Float, z : a } -> Float +> length vector4 +16.61324772583615 : Float +``` + +### Type alias + +Type aliases are used to give a new name to existing types. It is useful for naming record types. + + +```elm +type alias Name = + String + + +type alias Age = + Int + + +type alias Person = + { name : Name + , age : Age + } + + +isAdult : Person -> Bool +isAdult { age } = + age >= 18 +``` + +```elm +> import Lib exposing (..) + +> joe = { name = "Joe", age = 21 } +{ age = 21, name = "Joe" } + : { age : number, name : String } + +> isAdult joe +True : Bool + +> joe = Person "Joe" 21 +{ age = 21, name = "Joe" } : Person +``` + +*Note*: Type aliases are resolved in compiled time. Therefore, they cannot be recursive. For recursion, we need to use custom types. + + +### Custom Types + +We can define custom types that have several variants. We can also associate data with a variant. + + +```elm +type Gender + = Male + | Female + + +type Tree a + = Leaf a + | Branch (Tree a) (Tree a) + + +type Profile + = Loading + | Error String + | Success Person + + + +gender = Female + +tree = Branch (Leaf 1) (Branch (Leaf 2) (Leaf 0)) + +profile = Error "Cannot load profile" + +``` + +### Pattern Matching + +```elm +isFemale : Gender -> Bool +isFemale gender = + case gender of + Male -> + False + + Female -> + True +``` + +We can use wildcard `_` for all other branches in the `case` statement or for the variables we don't need. + +```elm +isLoading : Profile -> Bool +isLoading profile = + case profile of + Loading -> + True + + _ -> + False + + +profileStatus : Profile -> String +profileStatus profile = + case profile of + Loading -> + "Loading" + + Error error -> + "Error: " ++ error + + Success _ -> + "Success!" + +``` + +We can use `::` operator for matching first element and rest of the list. + +```elm +sum : List number -> number +sum list = + case list of + head :: tail -> + head + sum tail + + [] -> + 0 +``` + + + +### Maybe + +`Maybe` is used when a result doesn't have to exist. Unlike `null` in JavaScript, we are forced to handle that case. + +```elm +type Maybe a + = Just a + | Nothing +``` + +For example empty list doesn't have a head. + +```elm +> List.head + : List a -> Maybe a +``` + +We can use the `Maybe` type in `case` statement as any other custom type. + +```elm +hello : String -> String +hello name = + "Hello, " ++ name ++ "!" + + +greet : Maybe String -> String +greet maybeName = + case maybeName of + Just name -> + hello name + + Nothing -> + "Nobody's here" +``` + +[Maybe](https://package.elm-lang.org/packages/elm/core/latest/Maybe) package contains a handful of useful functions to simplify working with maybes. + +```elm +> Maybe.withDefault + : a -> Maybe a -> a + +> Maybe.withDefault "default" (Just "value") +"value" : String + +> Maybe.withDefault "default" Nothing +"default" : String +``` + +```elm +> Maybe.map + : (a -> b) -> Maybe a -> Maybe b + +> Maybe.map ((*) 2) (Just 4) +Just 8 : Maybe number + +> Maybe.map ((*) 2) Nothing +Nothing : Maybe number +``` + +```elm +greet2 : Maybe String -> String +greet2 maybeName = + Maybe.withDefault "Nobody's here" (Maybe.map hello maybeName) +``` + + + +### Result + +`Result` is used for computations that may fail. + +```elm +type Result error value + = Ok value + | Err error +``` + +For example, we cannot calculate area with of rectangle with negative sides. + +```elm +rectArea : Float -> Float -> Result String Float +rectArea a b = + if a < 0 || b < 0 then + Err "Cannot calculate area with negative sides" + else + Ok (a * b) +``` + +There are again helpful functions in [Result](https://package.elm-lang.org/packages/elm/core/latest/Result) package. + + + +### let expressions + +It is sometimes handy to define some expression within a function to avoid repetition. We have let expressions for that. + +```elm +cubeArea : Float -> Float +cubeArea edge = + let + face = + edge ^ 2 + in + 6 * face +``` + +### Operators |>, <|, >>, << + +Elm has several operators for chaining functions and function calls together. + +#### |> + +`|>` operator takes a value and a function and applies the function to the value. + +```elm +> (|>) + : a -> (a -> b) -> b +``` + +It is useful when chaining more steps together to write readable code. + +```elm +greet3 : Maybe String -> String +greet3 maybeName = + maybeName + |> Maybe.map hello + |> Maybe.withDefault "Nobody's here" +``` + +#### <| + +`<|` operator is the opposite. It takes a function and a value and apply the function to the value. + +```elm +> (<|) + : (a -> b) -> a -> b +``` + +It is useful to avoid parentheses, the same as `$` in Haskell. + +```elm +greet4 : Maybe String -> String +greet4 maybeName = + Maybe.withDefault "Nobody's here" <| Maybe.map hello maybeName +``` + +#### >> + +`>>` is used for function composition - `(f >> g) x == g(f x)`. + + +```elm +> (>>) + : (a -> b) -> (b -> c) -> a -> c +``` + +```elm +greet5 : Maybe String -> String +greet5 = + Maybe.map hello >> Maybe.withDefault "Nobody's here" +``` + + +#### << + +`>>` is used for function composition in an opposite direction - `(f << g) x == f(g x)`. This is same as `.` in Haskell. + +```elm +> (<<) + : (b -> c) -> (a -> b) -> a -> c +``` + +```elm +greet6 : Maybe String -> String +greet6 = + Maybe.withDefault "Nobody's here" << Maybe.map hello +``` + + +### Debug + +Elm has a [Debug](https://package.elm-lang.org/packages/elm-lang/core/latest/Debug) package intended for debugging. It +should not be used in production code. + +`log` function can be used to write a value to console. + +```elm +> Debug.log "value" 1 +value: 1 +1 : number +``` + +```elm +> 5 - Debug.log "number" 4 +number: 4 +1 : number +``` + + +## Packages + +Elm packages are published on [package.elm-lang.org](https://package.elm-lang.org). There is forced [semantic versioning](https://semver.org) for Elm packages. Therefore, you don't have to worry about breaking your application while updating packages. + +In 2018, Elm 0.19 was released, and not all packages have been updated yet, so you need to check first whether the package is supported in the latest Elm version. + + + +To install a package, we use `elm install` command in the project directory. + +``` +$ elm install elm-community/maybe-extra +Here is my plan: + + Add: + elm-community/maybe-extra 5.0.0 + +Would you like me to update your elm.json accordingly? [Y/n]: y +Dependencies loaded from local cache. +Dependencies ready! +``` + +Then we can use the new package the same as we used our package before: + +```elm +> import Maybe.Extra exposing (isNothing) + +> isNothing Nothing +True : Bool + +> isNothing (Just 2) +False : Bool +``` + + + +## The Elm Architecture (TEA) + +The Elm Architecture is a pattern used by Elm applications to define the architecture. It is perfect for modularity, refactoring, code reuse and testing. It is easy to keep even the complex applications clean and maintainable with the TEA. +The Elm application has three main parts: + +- **Model** - The state of the application. +- **Update** - How to change the state. +- **View** - How to display the state. + +There are also Subscribers and Commands. We will talk about them later. + +![The Elm Architecture](./images/tea.png) + + +### Example + +Example form [Elm guide](https://guide.elm-lang.org/#a-quick-sample): + +```elm +import Browser +import Html exposing (Html, button, div, text) +import Html.Events exposing (onClick) + +main = + Browser.sandbox { init = 0, update = update, view = view } + +type Msg = Increment | Decrement + +update msg model = + case msg of + Increment -> + model + 1 + + Decrement -> + model - 1 + +view model = + div [] + [ button [ onClick Decrement ] [ text "-" ] + , div [] [ text (String.fromInt model) ] + , button [ onClick Increment ] [ text "+" ] + ] +``` + +## Running the Elm application + +### Elm Reactor + +It is a quick and simple tool to run Elm project during development. Run `elm reactor` in the project root. It starts a server at [http://localhost:8000](http://localhost:8000) where you can navigate to Elm files. + + +### Elm Make + +Tool for building Elm project. It can compile to HTML or JavaScript. For example: + +``` +$ elm make src/Main.elm --output=main.html +``` + +Generates `main.html` file with the Elm application. + + + +## Further reading + +- [An Introduction to Elm](https://guide.elm-lang.org) +- [Elm Syntax](https://elm-lang.org/docs/syntax) +- [Blazing Fast HTML](https://elm-lang.org/blog/blazing-fast-html-round-two) +- [Small Assets without the Headache](https://elm-lang.org/blog/small-assets-without-the-headache) +- [Elm in Production: Surprises & Pain Points](https://www.youtube.com/watch?v=LZj_1qVURL0) + diff --git a/tutorials/09_webapp.md b/tutorials/09_webapp.md deleted file mode 100644 index 6e30cd7..0000000 --- a/tutorials/09_webapp.md +++ /dev/null @@ -1,506 +0,0 @@ -# Web application in Haskell - -Haskell can be (of course) used for network communication and also for building various web applications. In this tutorial, we are going to look at basics of network communication in Haskell, some specialized libraries making it simpler, and then at web frameworks. - -## Network communication - -On the way to web applications, it is good to know how you can work with network communication on lower levels than is some web framework. - -### Sockets - -The most low-level solutions work directly with sockets via [Network.Socket](https://hackage.haskell.org/package/network/docs/Network-Socket.html) module. With that, you have a full control over the communication. Essentially the entire C socket API is exposed through this module, so if you are familiar with sockets from C, then it will be easy for you in Haskell: `bind`, `listen`, `receive`, `send`, `getAddrInfo`, etc. - -### Server-client demo with sockets - -There is a demo with echo server and client in the [Network.Socket](https://hackage.haskell.org/package/network/docs/Network-Socket.html) documentation. We will show a bit simpler example without forking. - -```haskell -{-# LANGUAGE OverloadedStrings #-} -module Main (main) where - -import qualified Control.Exception as E -import Control.Monad (unless, forever, void) -import qualified Data.ByteString as S -import qualified Data.ByteString.Char8 as C -import Network.Socket hiding (recv) -import Network.Socket.ByteString (recv, sendAll) - -main :: IO () -main = withSocketsDo $ do - addr <- mkAddr "localhost" "3000" - E.bracket (open addr) close loop - where - mkAddr host port = do - let hints = defaultHints { - addrFlags = [AI_PASSIVE] - , addrSocketType = Stream - } - addr:_ <- getAddrInfo (Just hints) (Just host) (Just port) - return addr - open addr = do - sock <- socket (addrFamily addr) (addrSocketType addr) (addrProtocol addr) - setSocketOption sock ReuseAddr 1 - bind sock (addrAddress addr) - listen sock 10 - return sock - loop sock = forever $ do - (conn, peer) <- accept sock - putStrLn $ "Connection from " ++ show peer - msg <- recv conn 1024 - C.putStrLn $ msg - unless (S.null msg) $ do - sendAll conn (S.reverse msg) - close conn -``` - -```haskell -{-# LANGUAGE OverloadedStrings #-} -module Main (main) where - -import qualified Control.Exception as E -import qualified Data.ByteString.Char8 as C -import Network.Socket hiding (recv) -import Network.Socket.ByteString (recv, sendAll) - -main :: IO () -main = withSocketsDo $ do - addr <- mkAddr "localhost" "3000" - E.bracket (open addr) close talk - where - mkAddr host port = do - let hints = defaultHints { addrSocketType = Stream } - addr:_ <- getAddrInfo (Just hints) (Just host) (Just port) - return addr - open addr = do - sock <- socket (addrFamily addr) (addrSocketType addr) (addrProtocol addr) - connect sock $ addrAddress addr - return sock - talk sock = do - putStrLn "What do you want to send?" - toSend <- getLine - sendAll sock (C.pack toSend) - msg <- recv sock 1024 - putStr "You received: " - C.putStrLn msg -``` - -A you can see, most of the work happens in `do` of `IO` and it highly resembles classic imperative programming. Indeed, networking and also most of UI is inherently not a show room of beautiful Haskell code, but it gets the job done ;-). - -### Specialized libraries - -Naturally, there are many specialized libraries that provide a higher-level interface for network communication than plain sockets when you want to work with some specific protocol (POP3, SMTP, SSH, or HTTP). Some are listed [here](https://wiki.haskell.org/Applications_and_libraries/Network) but you can find more on [Hackage](https://hackage.haskell.org). - -The need of REST API client is something very common. For writing a simple one, you may use [wreq](https://hackage.haskell.org/package/wreq) package. It provides simple but powerful lens-based API and it supports often-used techniques like OAuth, decompression, file upload, etc. - -```haskell --- GitHub API: list public repositories of user -{-# LANGUAGE OverloadedStrings #-} -import Control.Lens -import Data.Aeson.Lens -import Data.ByteString.Char8 hiding (putStrLn, getLine) -import qualified Data.Text as T (unpack) -import Data.Foldable -import Network.Wreq - - -mkURI :: String -> String -mkURI username = "https://api.github.com/users/" ++ username ++ "/repos" - -getRepos :: String -> IO [String] -getRepos username = do - r <- get (mkURI username) - return . fmap T.unpack $ r ^.. responseBody . values . key "full_name" . _String - -main :: IO () -main = do - putStrLn "Enter GitHub username:" - username <- getLine - repos <- getRepos username - putStrLn $ "## First 25 public repos: " - traverse_ putStrLn repos -``` - -## Web Frameworks overview - -As with other languages, you usually don't want to build a web application from the scratch which would bind ports, listen and parse requests and compose responses. For a higher abstraction, you might want to use a web framework. - -There are several frameworks in Haskell (see [here](https://wiki.haskell.org/Web/Frameworks)) and here is our list of the most used ones: - -- [Happstack](http://happstack.com) -- [Scotty](https://github.com/scotty-web/scotty) -- [Servant](https://haskell-servant.github.io) -- [Snap](http://snapframework.com) -- [Spock](https://www.spock.li) -- [Yesod](https://www.yesodweb.com) - -As you can see, there is quite an above-average offer of them. They mostly differ at the level of abstraction and scope: Scotty being relatively low-abstraction routing and middleware and Yesod being a complete solution including templating and persistence, everything on a high abstraction level. The choice depends on your preference and needs. As always, a higher abstraction means the system does a lot of job for yourself, you write fewer code, which means a higher effectiveness and less bugs. On the other hand, you may face a [leaky abstraction problem](https://blog.codinghorror.com/all-abstractions-are-failed-abstractions/) at some point. - -We are going to show briefly Snap and Yesod, because they are used often and then we will go deeper with our favourite versatile Scotty. Next time, we will look at a different one to build quickly a REST API for our front-end app(s). - -However, before we dive into the topic, there is one more note, which may excite you. In the first lecture, we explained what a referential transparency is and that it brings certain qualities to code -- ability to reason about, reusability, testability, parallelism "for free". In the case of web frameworks, you can experience reusability coming from reference transparency very clearly: web frameworks are typically built of certain independent, shared components like a web server ([warp](https://hackage.haskell.org/package/warp)) or a web application interface ([wai](https://hackage.haskell.org/package/wai)). These highly-specialised components are developed independently, tested independently and as such, the whole ecosystem exercises an unparalleled separation of concerns and thanks to it, it is easier evolvable, reliable and lively. Moreover, you can use the low-level components independently and integrate them easily in another framework or even an non-web application -- you can e.g. use [templating from Yesod](https://hackage.haskell.org/package/shakespeare) in Scotty, if you like, or its [persistence layer](https://hackage.haskell.org/package/persistent) in a simple CLI application. - -### Snap - -[Snap](http://snapframework.com) is a simple web development framework for UNIX systems, written in the Haskell programming language. It consists of: - -* A fast HTTP server library -* A sensible and clean monad for web programming -* An HTML-based templating system for generating pages (heist) - -More examples are in the [documentation](http://snapframework.com/docs). - -#### "Hello World" - -```haskell -import Snap - -site :: Snap () -site = - ifTop (writeBS "hello world") <|> - route [ ("foo", writeBS "bar") - , ("echo/:echoparam", echoHandler) - ] <|> - dir "static" (serveDirectory ".") - -echoHandler :: Snap () -echoHandler = do - param <- getParam "echoparam" - maybe (writeBS "must specify echo/param in URL") - writeBS param - -main :: IO () -main = quickHttpServe site -``` - -#### Snaplets - -Snap also has a very nice philosophy in form of an optional system for building reusable pieces web functionality called “snaplets”. Snaplets make it easy to share and reuse common code across multiple web apps. The default snaplets let you get a full-featured web application up and running very fast. - -If you want to build such application, read [this](http://snapframework.com/docs/tutorials/snaplets-tutorial). - -### Yesod - -[Yesod](https://www.yesodweb.com) is a Haskell web framework for productive development of type-safe, RESTful, high performance web applications. It builds on Haskell features such as compile-time errors (instead of runtime), seamlessly asynchronous computation, scalability, good performance and light-weight syntax. - -Another advantage of Yesod is comprehensive documentation including: - -* [quick start guide](https://www.yesodweb.com/page/quickstart), -* [book](https://www.yesodweb.com/book) (O'Reilly), -* [screencasts](https://www.yesodweb.com/page/screencasts), -* and [cookbook](https://github.com/yesodweb/yesod-cookbook). - -If that is not enough you can ask the [community](https://www.yesodweb.com/page/community). - -Yesod is a "Mercedes" of Haskell web frameworks. It means a lot of comfort is prepared for you to enjoy, however it also means that people needing an agile small car for Italian crooked streets may experience troubles ;-). - -#### "Hello World" - -From the following example, you can see that Yesod uses a lot of *Template Haskell* which makes it a little bit hard to get at the beginning, but it enchants you with a lot of pleasant magic. And yes, every magic has some costs ;-) (see the previous lecture). - -```haskell -{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE QuasiQuotes #-} -{-# LANGUAGE TemplateHaskell #-} -{-# LANGUAGE TypeFamilies #-} -import Yesod - -data HelloWorld = HelloWorld - -mkYesod "HelloWorld" [parseRoutes| -/ HomeR GET -|] - -instance Yesod HelloWorld - -getHomeR :: Handler Html -getHomeR = defaultLayout [whamlet|Hello World!|] - -main :: IO () -main = warp 3000 HelloWorld -``` - -### Scotty - -[Scotty](https://github.com/scotty-web/scotty) is another Haskell web framework inspired by Ruby's [Sinatra](http://sinatrarb.com), using [WAI](https://hackage.haskell.org/package/wai) and [Warp](https://hackage.haskell.org/package/warp) (a fast, light-weight web server for WAI applications). You can write your own application just with WAI (Web Application Interface), but Scotty provides you with abstractions from a low-level communication. Sadly, there is not so much documentation about Scotty, everything is just on [GitHub](https://github.com/scotty-web/scotty). Scotty uses primarily [Blaze HTML](https://hackage.haskell.org/package/blaze-html) for HTML "templates", however, as we explained, you may also integrate it with any templating library you like. - -#### "Hello World" - -```haskell -{-# LANGUAGE OverloadedStrings #-} -import Web.Scotty - -main = scotty 3000 $ do - get "/" $ do - html "Hello World!" -``` - -Surprisingly easy, right?! - -#### Blaze templates - -One of the well-known and widely used solution for HTML templates is [Blaze HTML](https://hackage.haskell.org/package/blaze-html). It is "a blazingly fast HTML combinator library for the Haskell programming language". A huge advantage of Blaze is that you write HTML via HTML-like lightweight DSL in Haskell with the great type system. Blaze and Haskell won't allow you to make a non-sense HTML, although it does not check a full conformity, of course. - -```haskell -{-# LANGUAGE OverloadedStrings #-} -import Data.Text as T -import Text.Blaze.Html5 as H hiding (main) -import Text.Blaze.Html5.Attributes as A -import Text.Blaze.Html.Renderer.Pretty (renderHtml) - -type User = String - -userInfo :: Maybe User -> Html -userInfo u = H.div ! A.id "user-info" $ case u of - Nothing -> - a ! href "/login" $ "Please login." - Just user -> do - "Logged in as " - toHtml $ T.pack user - -somePage :: Maybe User -> Html -somePage u = html $ do - H.head $ do - H.title "Some page." - H.body $ do - userInfo u - "The rest of the page." - -main :: IO () -main = putStr . renderHtml $ somePage (Just "Marek") -``` - -An interesting tool, that you might find useful, is [blaze-from-html](https://hackage.haskell.org/package/blaze-from-html). - -You might ask "What about styles?" or "What if want to have some JavaScript there?". For styles, there is [clay](https://hackage.haskell.org/package/clay) - a CSS preprocessor like LESS and Sass, but implemented as an embedded domain specific language (EDSL) in Haskell. Similarly to Blaze, you write CSS in Haskell. For JavaScript, stay tuned for the next tutorial ;-). - -#### Hastache templates - -If you are already familiar with some web development, you've probably heard about the popular [{{ mustache }}](http://mustache.github.io) templates. In Haskell, we have Haskell implementation of Mustache templates called [hastache](https://hackage.haskell.org/package/hastache). - -```haskell -import Text.Hastache -import Text.Hastache.Context -import qualified Data.Text.Lazy.IO as TL - -main = hastacheStr defaultConfig (encodeStr template) (mkStrContext context) - >>= TL.putStrLn - -template = "Hello, {{#reverse}}world{{/reverse}}! We know you, {{name}}!" - -context "reverse" = MuLambda (reverse . decodeStr) -context "name" = MuVariable "Haskell" -``` - -A useful source of information what can you do with Hastache are [examples](https://github.com/lymar/hastache/tree/master/examples). - -#### Databases - -Again, several abstraction levels are available. First, you can employ a low-level approach where you incorporate SQL in the code. For that, you can usually use module `Database.X` where `X` is type of datase: - -- [Database.SQLite](http://hackage.haskell.org/package/sqlite-simple) -- [Database.MySQL](http://hackage.haskell.org/package/mysql) -- [Database.PostgreSQL](http://hackage.haskell.org/package/PostgreSQL) -- [Database.MongoDB](http://hackage.haskell.org/package/mongoDB) -- [Database.Redis](http://hackage.haskell.org/package/redis) -- etc. - -A slightly better services are provided by mid-level libraries: - -- [Database.MySQL.Simple](https://hackage.haskell.org/package/mysql-simple) -- [Database.PostgreSQL.Simple](https://hackage.haskell.org/package/postgresql-simple) - -Going higher with the abstraction, you can then use [Haskell Database Connectivity (HDBC)](http://hackage.haskell.org/package/HDBC) for SQL databases. A good introduction to HDBC is in [Chapter 21 - Using Databases](http://book.realworldhaskell.org/read/using-databases.html) of the [Real World Haskell](http://book.realworldhaskell.org/) book. - -```sql -CREATE TABLE test(id INTEGER PRIMARY KEY, str TEXT);\ -INSERT INTO test(str) VALUES ('test string 1'); -INSERT INTO test(str) VALUES ('test string 2'); -``` - -```haskell -{-# LANGUAGE OverloadedStrings #-} -import Control.Applicative -import Database.SQLite.Simple -import Database.SQLite.Simple.FromRow - -data TestField = TestField Int String deriving (Show) - -instance FromRow TestField where - fromRow = TestField <$> field <*> field - -main :: IO () -main = do - conn <- open "test.db" - execute conn "INSERT INTO test (str) VALUES (?)" - (Only ("test string 2" :: String)) - r <- query_ conn "SELECT * from test" :: IO [TestField] - mapM_ print r -``` - -#### Persistence with Persistent - -Now skyrocketing the abstraction to the heights of Template Haskell, we get to [persistent](https://hackage.haskell.org/package/persistent) that comes also with various [extensions](https://hackage.haskell.org/packages/search?terms=persistent). There is a nice documentation of this package in the Yesod [book](https://www.yesodweb.com/book/persistent), but, as we already explained, you can use it with any framework or even without any framework — just whenever you need to persist some data in a database. - -```haskell -{-# LANGUAGE EmptyDataDecls #-} -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE GADTs #-} -{-# LANGUAGE GeneralizedNewtypeDeriving #-} -{-# LANGUAGE MultiParamTypeClasses #-} -{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE QuasiQuotes #-} -{-# LANGUAGE TemplateHaskell #-} -{-# LANGUAGE TypeFamilies #-} -import Control.Monad.IO.Class (liftIO) -import Database.Persist -import Database.Persist.Sqlite -import Database.Persist.TH - -share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase| -Person - name String - age Int Maybe - deriving Show -BlogPost - title String - authorId PersonId - deriving Show -|] - -main :: IO () -main = runSqlite ":memory:" $ do - runMigration migrateAll :: IO () - - johnId <- insert $ Person "John Doe" $ Just 35 - janeId <- insert $ Person "Jane Doe" Nothing - - insert $ BlogPost "My fr1st p0st" johnId - insert $ BlogPost "One more for good measure" johnId - - oneJohnPost <- selectList [BlogPostAuthorId ==. johnId] [LimitTo 1] - liftIO $ print (oneJohnPost :: [Entity BlogPost]) - - john <- get johnId - liftIO $ print (john :: Maybe Person) - - delete janeId - deleteWhere [BlogPostAuthorId ==. johnId] -``` - -As you noticed, Persistent uses *Template Haskell* for a declaration of a persistent model. - -For other possibilities of persistence libraries, take a look [here](https://wiki.haskell.org/Web/Databases_and_Persistence) or search the [Hackage](https://hackage.haskell.org). - -## WAI and testing web apps - -There must be some interface between a web application and the web server where the application is running. You may have heard about something like [CGI](https://en.wikipedia.org/wiki/Common_Gateway_Interface), [FastCGI](https://en.wikipedia.org/wiki/FastCGI), [WSGI](https://cs.wikipedia.org/wiki/Web_Server_Gateway_Interface), or similar. As is [WSGI](https://cs.wikipedia.org/wiki/Web_Server_Gateway_Interface) for Python web applications, we have [Web Application Interface (WAI)](https://www.stackage.org/package/wai) in Haskell. - -### Web app with plain WAI - -It is possible to write a simple web application with just WAI and without any additional web framework. - -```haskell -{-# LANGUAGE OverloadedStrings #-} -import Network.Wai -import Network.HTTP.Types -import Network.Wai.Handler.Warp (run) - -app :: Application -app _ respond = do - putStrLn "I've done some IO here" - respond $ responseLBS - status200 - [("Content-Type", "text/plain")] - "Hello, Web!" - -main :: IO () -main = do - putStrLn $ "http://localhost:8080/" - run 8080 app -``` - -### HSpec & WAI - -Web applications in Haskell can be tested via WAI. All applications that conform with WAI can be tested in the same way like a black box - send a request and check the response. In our favourite [Hspec](https://hspec.github.io), there is an extension [hspec-wai](https://github.com/hspec/hspec-wai) that allows you to test web applications in a very easy and readable way, as we are used to with hspec. - -```haskell -{-# LANGUAGE OverloadedStrings, QuasiQuotes #-} -module Main (main) where - -import Test.Hspec -import Test.Hspec.Wai -import Test.Hspec.Wai.JSON - -import Network.Wai (Application) -import qualified Web.Scotty as S -import Data.Aeson (Value(..), object, (.=)) - -main :: IO () -main = hspec spec - -app :: IO Application -app = S.scottyApp $ do - S.get "/" $ do - S.text "hello" - - S.get "/some-json" $ do - S.json $ object ["foo" .= Number 23, "bar" .= Number 42] - -spec :: Spec -spec = with app $ do - describe "GET /" $ do - it "responds with 200" $ do - get "/" `shouldRespondWith` 200 - - it "responds with 'hello'" $ do - get "/" `shouldRespondWith` "hello" - - it "responds with 200 / 'hello'" $ do - get "/" `shouldRespondWith` "hello" {matchStatus = 200} - - it "has 'Content-Type: text/plain; charset=utf-8'" $ do - get "/" `shouldRespondWith` 200 {matchHeaders = ["Content-Type" <:> "text/plain; charset=utf-8"]} - - describe "GET /some-json" $ do - it "responds with some JSON" $ do - get "/some-json" `shouldRespondWith` [json|{foo: 23, bar: 42}|] -``` - -This is just a simple (but often sufficient) example. Of course, you can test much more: - -- https://begriffs.com/posts/2014-10-19-warp-server-controller-test.html -- https://www.spock.li/tutorials/testing - -## Example apps: - -Here are a few examples of simple and more complex web apps: - -* [dbushenko/scotty-blog](https://github.com/dbushenko/scotty-blog) -* [DataStewardshipWizard/ds-wizard](https://github.com/DataStewardshipWizard/ds-wizard/tree/master/DSServer) -* [DataStewardshipWizard/dsw-server](https://github.com/DataStewardshipWizard/dsw-server) - - -## Continuation-style web development - -We would also like to raise your attention to an interesting approach to web development based on the [continuation](https://wiki.haskell.org/Continuation). A continuation is "something" that enables you to save the state of computation, suspend it (do something else) and later resume it. This "something" may be a first-class language feature (such as in Scheme), or a library feature -- in Haskell, surprisingly, we have a continuation monad ;-). - -A need for continuation occurs typically in web development (and generally in UI development) when you want a modal dialogue. Today, most of the dialogues are handled on client-side, however if you need to do a modal dialogue on server-side, it is hard -- HTTP behaves like a programming language, which does not have subroutines, only GOTOs (URLSs are the 'line numbers'). Continuation can provide the missing abstraction here, which is embodied in the [MFlow](http://mflowdemo.herokuapp.com) library. Sadly, the project seems abandoned for several years. - -At the same time, the continuation-style web server programming is typically the first choice in the Smalltalk (OOP) world -- [Seaside](http://seaside.st/) is purely continuation-based, and as such it gives a "desktop programming" experience for the web development resulting in no need of dealing with routing and URLs. As for the FP world, continuation-style web programming is surprisingly not used much in practice, but there are solutions such as the [Racket web server](https://docs.racket-lang.org/web-server/index.html) or [cl-weblocks](https://www.cliki.net/cl-weblocks) in Common Lisp. - - -The next time, we will deal a bit with frontend technologies for Haskell, functional reactive programming and [The JavaScript problem](https://wiki.haskell.org/The_JavaScript_Problem). So you will also see how to develop server-side and client-side separately and connect them through a (REST) API. - -## Task assignment - -The homework to complete a simple web app is in repository [MI-AFP/hw09](https://github.com/MI-AFP/hw09). - -## Further reading - -* [YesodBook - Persistent](https://www.yesodweb.com/book/persistent) -* [adit.io - Making A Website With Haskell](http://adit.io/posts/2013-04-15-making-a-website-with-haskell.html) -* [24 Days of Hackage: blaze-html](https://ocharles.org.uk/blog/posts/2012-12-22-24-days-of-hackage-blaze.html) -* [Haskell web frameworks](https://wiki.haskell.org/Web/Frameworks) -* [Reddit: What Haskell web framework do you use and why? ](https://www.reddit.com/r/haskell/comments/332s1k/what_haskell_web_framework_do_you_use_and_why/) -* [Reddit: Web development using Haskell](https://www.reddit.com/r/haskell/comments/2wfap0/web_development_using_haskell/) -* [Is Haskell a Good Choice for Web Applications?](http://jekor.com/article/is-haskell-a-good-choice-for-web-applications) diff --git a/tutorials/10_frontend-frp.md b/tutorials/10_frontend-frp.md deleted file mode 100644 index 01b7d19..0000000 --- a/tutorials/10_frontend-frp.md +++ /dev/null @@ -1,417 +0,0 @@ -# Frontend and FRP - -In the previous tutorial, we focused on web frameworks and especially on building a backend and some frontend generation by blaze or hastache on the server-side. This time, we will cover building frontend apps that are standalone or communicate with backend via (REST) API. At the end of this tutorial, there is a section about a very interesting concept *Functional Reactive Programming* that is important when building purely functional user interfaces. - -## Haskell and Haskell-like frontends - -### The JavaScript Problem - -We all know what is JavaScript -- it is a dynamic, weakly typed, prototype-based and multi-paradigm programming language. Together with HTML and CSS, it is one of the three core technologies of the World Wide Web. JavaScript is used for interactive web pages and thus is an essential part of modern web applications. These days, JavaScript is often also used for the server-side or even desktop applications (e.g. [Atom editor](https://atom.io/)). - -As obvious from above, we need JavaScript. On the other hand, JavaScript has some issues that make working with it inconvenient and make developing software harder. Some things are improving with time (newer versions of [ECMAScript](https://en.wikipedia.org/wiki/ECMAScript)) but most of them remain from the very basic principles of the language: weak-typing, late binding, [weird automatic conversions](https://youtu.be/ryJSRZzAvUs), `this` behaviour, and lack of static types. There are solutions in the form of "improved syntax" like [CoffeeScript](http://coffeescript.org) and [TypeScript](https://www.typescriptlang.org) that are dealing with some of those... - -But since we are now Haskellists, we would like to have something even better - a Haskell-like JavaScript to solve these problems. Luckily, we are not the only ones and there are already several solutions how to compile Haskell to JavaScript or similar languages based on Haskell that are adapted for this very specific purpose. - -Take a look at [Slant - What are the best solutions to "The JavaScript Problem"?](https://www.slant.co/topics/1515/~solutions-to-the-javascript-problem). We are going to look at some now! - -### GHCJS - -GHCJS is a Haskell to JavaScript compiler that uses the GHC API. - -GHCJS supports many modern Haskell features, including: - - * All type system extensions supported by GHC - * Lightweight preemptive threading with blackholes, MVar, STM, asynchronous exceptions - * Weak references, CAF deallocation, StableName, StablePtr - * Unboxed arrays, emulated pointers - * Integer support through [JSBN](http://www-cs-students.stanford.edu/~tjw/jsbn/), 32 and 64 bit signed and unsigned arithmetic (`Word64`, `Int32` etc.) - * Cost-centres, stack traces - * Cabal support, GHCJS has its own package database - -And some JavaScript-specific features: - - * new JavaScriptFFI extension, with convenient import patterns, asynchronous FFI and a JSVal FFI type, - * synchronous and asynchronous threads. - -- Project: [ghcjs/ghcjs](https://github.com/ghcjs/ghcjs) -- Nice example: [Full stack web Haskell with Servant and GHCJS](http://blog.wuzzeb.org/full-stack-web-haskell/index.html) - -The dark side of GHCJS is big resulting JavaScript code and it is hard to make work (just try for yourself ;-). Also, the community around GHCJS and its ecosystem is not the most active one. - -### Haste - -[Haste](https://haste-lang.org) is an implementation of the Haskell functional programming language, geared towards web applications. Haste is based on the GHC, which means that it supports the full Haskell language, including GHC extensions and produces highly optimized code but comes with an extended set of standard libraries. However, compared to GHCJS, Template Haskell is not supported. Haste supports modern web technologies such as WebSockets, LocalStorage, Canvas, etc. out of the box. In addition, Haste comes pre-packaged with facilities for preemptive multitasking, working with binary data and other niceties. - -A Haste program can be compiled into a single JavaScript file, much like traditional browser-side programs, or into a JavaScript file and a server-side binary, with strongly typed communication between the two. In essence, Haste lets you write your client-server web application as a single, type-safe program, rather than two separate programs that just happen to talk to each other over some web API as is traditional. - -You don’t need to throw away all of your old code to start using Haste. In addition to the standard Haskell FFI, Haste provides its own flexible mechanism for easy Haskell-JavaScript integration, using fancy type magic to allow data of any type to be used by both Haskell and JavaScript code with minimal effort. - -Haste programs are more compact to GHCJS. While a certain increase in code size over hand-rolled JavaScript is unavoidable, an optimized but uncompressed Haste program is normally less than 3x the size of an equivalent hand-written program and the compiler takes special care to produce minifiable code, making the latency penalty of using Haste minimal. Sadly, similarly to GHCJS, the project is not much active (although not dead), the ecosystem, documentation and tutorials are not rich. - -- Examples: [valderman/haste-compiler](https://github.com/valderman/haste-compiler/tree/master/examples) -- API doc: [haste-compiler-0.5.5.0: Haskell To ECMAScript compiler](https://haste-lang.org/docs/haddock/0.5.5/) -- Our example: [DataStewardshipWizard/ds-wizard](https://github.com/DataStewardshipWizard/ds-wizard) and [DataStewardshipWizard/ds-form-engine](https://github.com/DataStewardshipWizard/ds-form-engine), built around JQuery bindings. - -### Miso - -**Miso** is a small "[isomorphic](http://nerds.airbnb.com/isomorphic-javascript-future-web-apps/)" [Haskell](https://www.haskell.org/) front-end framework for quickly building highly interactive single-page web applications. It features a virtual-dom, diffing / patching algorithm, attribute, and property normalization, event delegation, event batching, SVG, Server-sent events, Websockets, type-safe [servant](https://haskell-servant.github.io/)-style routing and an extensible Subscription-based subsystem. Inspired by [Elm](http://elm-lang.org/), [Redux](http://redux.js.org/) and [Bobril](http://github.com/bobris/bobril). **Miso** is pure by default, but side effects (like `XHR`) can be introduced into the system via the `Effect` data type. **Miso** makes heavy use of the [GHCJS](https://github.com/ghcjs/ghcjs) FFI and therefore has minimal dependencies. **Miso** can be considered a shallow [embedded domain-specific language](https://wiki.haskell.org/Embedded_domain_specific_language) for modern web programming. ([dmjio/miso](https://github.com/dmjio/miso/edit/master/README.md)) - -### PureScript - -PureScript is a strict, purely functional programming language inspired by Haskell which compiles to readable JavaScript with a simple foreign function interface and no runtime dependency. PureScript is sometimes called "Haskell done right" -- it learned from the long Haskell history, took the best of it (type system, category theory), refactored some parts, mostly basic libraries structure (Prelude) and added some goodies (records and row polymorphism) -- here is the overview of [differences](https://github.com/purescript/documentation/blob/master/language/Differences-from-Haskell.md). - -- Website: [purescript.org](http://www.purescript.org) -- Guide: [leanpub.com/purescript](https://leanpub.com/purescript/read) - -Although the ecosystem and documentation is considerably better than GHCJS's and Haste's, it has not reached broader adoption, (yet?). - -### Elm - -Elm is a functional language that compiles to JavaScript. It is not a Haskell, but language inspired by and in some ways very similar to Haskell (see [main differences](https://gist.github.com/cobalamin/c1b83f5626df1409b512ce2faf05cf84)) - it is more different from Haskell than PureScript. It offers an interesting type-safe alternative to projects such as React as a tool for creating websites and web apps. Elm has a very strong emphasis on simplicity, ease-of-use, and quality tooling. The compiler of Elm is written in Haskell and you can work with Elm in Haskell with [Language.Elm](https://hackage.haskell.org/package/Elm). - -- Guide: [guide.elm-lang.org](https://guide.elm-lang.org) -- Examples: [elm-lang.org/examples](http://elm-lang.org/examples) -- Our example: [DataStewardshipWizard/dsw-client](https://github.com/DataStewardshipWizard/dsw-client) - -Simplicity, good ecosystem, documentation and active community earned Elm quite some interest. At the same time, the lack of type classes hinders flexibility, reuse and DRY. - -### ReasonML - -[ReasonML](https://reasonml.github.io/) is a notable project that should be mentioned here. Although it is not based on Haskell, it shares the same ancestor -- the [ML language](https://en.wikipedia.org/wiki/ML_(programming_language)), the first FP language with Hindley-Milner type system that influenced many today's languages. ML (and its newer dialects Standard ML, Caml and OCaml) are not entirely pure (and as such they are being scorned by Haskellists ;-), but you find a strong type system, ADTs, etc. there, as well. - -What makes ReasonML notable is that it was created by Facebook and thus gets a strong warp. 50% of FB Messanger has been rewritten into ReasonML and there are quite some [impressive statistics](https://reasonml.github.io/blog/2017/09/08/messenger-50-reason.html). It is a project that is worth at least to be observed. - -## FRP - Functional Reactive Programming - -Functional reactive programming (FRP) is a programming paradigm for asynchronous dataflow programming using the building blocks of functional programming (such as `map`, `filter`, `fold`s, higher-order functions, etc.). It has been used often for programming graphical user interfaces (GUIs), robotics, and music, aiming to simplify these problems by explicitly modelling the concept of time. A good example to imagine what is it about is an ordinary spreadsheet calculator (Excel). You have cells that compute something from different cells and when you edit some, the related will recalculate - you do not tell what should be recalculated nor recalculate by yourself, all changes automatically propagate. See? It is "action and reaction"! - -The original idea was introduced more than 20 years ago by Conal Elliott in his [paper](http://conal.net/papers/ActiveVRML/ActiveVRML.pdf). Since then, he published several [other papers](http://conal.net/papers/) and there are also videos about the [FRP essence](https://begriffs.com/posts/2015-07-22-essence-of-frp.html). Several different trade-off approaches has been developed for practical usage. You can see the list [here](https://wiki.haskell.org/Functional_Reactive_Programming#Libraries). Also, of course, you can find FRP implementations in other languages than Haskell. - -### FRP principles - -For better understanding what FRP is about and what are the basic concepts, please read [The introduction to Reactive Programming you've been missing (by @andrestaltz)](https://gist.github.com/staltz/868e7e9bc2a7b8c1f754)... - -### Reactive - -[Reactive](https://hackage.haskell.org/package/reactive) is a simple foundation for programming reactive systems functionally. Like Fran/FRP, it has a notion of (reactive) behaviours and events. Unlike most previous FRP implementations, Reactive has a hybrid demand/data-driven implementation, as described in the paper "Push-pull functional reactive programming", http://conal.net/papers/push-pull-frp/. - -Sadly the documentation, tutorials, and examples are not currently in a good shape. - -### Reactive-banana - -[Reactive-banana](https://wiki.haskell.org/Reactive-banana) is meant to be used in conjunction with existing libraries that are specific to your problem domain. For instance, you can hook it into any event-based GUI framework, like `wxHaskell` or `Gtk2Hs`. Several helper packages such as `reactive-banana-wx` provide a small amount of glue code that can make life easier. - -The goal of the library is to provide a solid foundation. - -* Programmers interested implementing FRP will have a reference for a simple semantics with a working implementation. The library stays close to the semantics pioneered by Conal Elliott. -* The library features an efficient implementation. No more spooky time leaks, predicting space & time usage should be straightforward. -* A plethora of [example code](https://wiki.haskell.org/Reactive-banana/Examples) helps with getting started. - -### Yampa - -[Yampa](https://wiki.haskell.org/Yampa) is a domain-specific embedded language for programming of hybrid (discrete and continuous time) systems using the concepts of FRP. Yampa is structured using Arrows, which greatly reduce the chance of introducing space- and time-leaks into reactive, time-varying systems. - -![Signals in Yampa](https://wiki.haskell.org/wikiupload/thumb/1/10/Yampa_signal_functions.svg/624px-Yampa_signal_functions.svg.png) - -## Reactive programming with Elm - -We introduced Elm as a "convenient language" and it also supports reactive programming, so let us show a simple example to demonstrate the clean [architecture of Elm apps](https://guide.elm-lang.org/architecture/) - Model, View, and Update. This app will be just one module `Main` (although you can have multi-module apps just as in Haskell) and it will have 4 pages: - -1. Simple static landing -2. Unit converter for metres, yards, feet, and inches (reactive update: Update->Model->View cycle) -3. GitHub API info about user (demonstrate HTTP communication with some API) -4. Not found page as default - -You need to install [Node.js](https://nodejs.org/en/) and [Elm](https://guide.elm-lang.org/install.html). Then you can use `elm-repl` to try something (like GHCi), `elm-reactor` for development, `elm-package` to work with dependencies, and `elm-make` to build it into JavaScript. - -In this example we need some dependencies so the final `elm-package.json` looks like this: - -```json -{ - "version": "1.0.0", - "summary": "Example simple Elm project", - "repository": "https://github.com/MI-AFP/elm-example.git", - "license": "MIT", - "source-directories": [ - "." - ], - "exposed-modules": [], - "dependencies": { - "elm-lang/core": "5.1.1 <= v < 6.0.0", - "elm-lang/html": "2.0.0 <= v < 3.0.0", - "elm-lang/http": "1.0.0 <= v < 2.0.0", - "elm-lang/navigation": "2.1.0 <= v < 3.0.0", - "evancz/url-parser": "2.0.1 <= v < 3.0.0", - "rundis/elm-bootstrap": "4.0.0 <= v < 5.0.0" - }, - "elm-version": "0.18.0 <= v < 0.19.0" -} -``` - -```elm -module Main exposing (..) - -import Html exposing (..) -import Html.Attributes exposing (..) -import Html.Events exposing (onInput) -import Http -import Navigation exposing (Location) -import UrlParser exposing (()) - --- Entrypoint (we use Navigation) -main : Program Never Model Msg -main = Navigation.program UrlChange - { view = view - , update = update - , subscriptions = (\_ -> Sub.none) - , init = init - } - --- Model = state of the app -type alias Model = - { page : Page - , metres : Float - , token : GitHubToken - , githubData : String - } - --- Page = enum of different views -type Page - = Home - | UnitConverter - | GitHubInfo - | NotFound - --- Own type for GitHub token -type GitHubToken - = Valid String - | Invalid String - --- Units for the conversion -type LengthUnit - = Metres - | Inches - | Yards - | Feets - --- Types of messages in the app with content type(s) -type Msg - = UrlChange Location - | UnitUpdate LengthUnit String - | TokenUpdate String - | GitHubResponse (Result Http.Error String) - --- Initial app state and command -init : Location -> ( Model, Cmd Msg ) -init location = urlUpdate location { page = Home - , metres = 0 - , token = Invalid "" - , githubData = "" - } - --- Update (when message comes, update model), this is just "router" -update : Msg -> Model -> (Model, Cmd Msg) -update msg model = - case msg of - UrlChange location -> - urlUpdate location model - UnitUpdate lu str -> - metresUpdate lu str model - TokenUpdate str -> - tokenUpdate str model - GitHubResponse res -> - githubUpdate res model - -githubUpdate : (Result Http.Error String) -> Model -> (Model, Cmd Msg) -githubUpdate res model = - case res of - Ok str -> ({ model | githubData = str }, Cmd.none) - Err _ -> ({ model | githubData = "Error!" }, Cmd.none) - -tokenUpdate : String -> Model -> (Model, Cmd Msg) -tokenUpdate str model = - if isTokenValid str then - ( { model | token = Valid str }, gitHubInfoRequest str ) - else - ( { model | token = Invalid str }, Cmd.none ) - --- Send request to GitHub and then it will send appropriate message in this app -gitHubInfoRequest : String -> Cmd Msg -gitHubInfoRequest token = - Http.send GitHubResponse <| Http.request - { method = "GET" - , headers = [ Http.header "Authorization" ("token " ++ token)] - , url = "https://api.github.com/user" - , body = Http.emptyBody - , expect = Http.expectString - , timeout = Nothing - , withCredentials = False - } - -isTokenValid : String -> Bool -isTokenValid str = String.length str == 40 - -metresUpdate : LengthUnit -> String -> Model -> ( Model, Cmd Msg ) -metresUpdate lu x model = - case String.toFloat x of - Ok v -> ( { model | metres = v / (unitCoefficient lu)}, Cmd.none ) - Err _ -> ( model, Cmd.none ) - -urlUpdate : Navigation.Location -> Model -> ( Model, Cmd Msg ) -urlUpdate location model = - case decode location of - Nothing -> - ( { model | page = NotFound }, Cmd.none ) - Just route -> - ( { model | page = route }, Cmd.none ) - -decode : Location -> Maybe Page -decode location = - UrlParser.parseHash routeParser location - -routeParser : UrlParser.Parser (Page -> a) a -routeParser = - UrlParser.oneOf - [ UrlParser.map Home UrlParser.top - , UrlParser.map UnitConverter (UrlParser.s "unit-converter") - , UrlParser.map GitHubInfo (UrlParser.s "github-info") - ] - ---> VIEW -view : Model -> Html Msg -view model = - div [] - [ menu model - , mainContent model - ] - -menu : Model -> Html Msg -menu model = - div [] - [ viewLink "" "Home" - , viewLink "unit-converter" "Unit Converter" - , viewLink "github-info" "GitHub Info" - ] - -viewLink : String -> String -> Html msg -viewLink slug name = - li [] [ a [ href ("#" ++ slug) ] [ text name ] ] - -mainContent : Model -> Html Msg -mainContent model = - div [] ( - case model.page of - Home -> - pageHome model - UnitConverter -> - pageUnitConverter model - GitHubInfo -> - pageGitHubInfo model - NotFound -> - pageNotFound - ) - -pageHome : Model -> List (Html Msg) -pageHome model = - [ h1 [] [ text "Home" ] - , p [] [ text "This is very simple Elm example" ] - , hr [] [] - , p [] [ text "Enjoy learning " - , a [href "http://elm-lang.org"] [text "Elm"] - , text "!" - ] - ] - -pageUnitConverter : Model -> List (Html Msg) -pageUnitConverter model = - [ h1 [] [ text "Unit Converter" ] - , hr [] [] - , makeUnitInput Metres model - , makeUnitInput Inches model - , makeUnitInput Feets model - , makeUnitInput Yards model - ] - -makeUnitInput : LengthUnit -> Model -> Html Msg -makeUnitInput lu model = - div [] - [ label [] [text (unitToString lu)] - , input [ type_ "number" - , onInput (UnitUpdate lu) - , value (toString (computeUnit lu model)) - ] - [] - ] - -pageGitHubInfo : Model -> List (Html Msg) -pageGitHubInfo model = - [ h1 [] [ text "GitHub Info" ] - , div [] - [ label [] [text "GitHub token: "] - , input [ type_ "text" - , onInput TokenUpdate - , value (tokenToString model.token) - ] - [] - ] - , case model.token of - Valid token -> githubInfo model - Invalid _ -> invalidTokenMsg - ] - -githubInfo : Model -> (Html Msg) -githubInfo model = - pre [] [text (model.githubData)] - - -invalidTokenMsg : (Html Msg) -invalidTokenMsg = - div [] - [ p [] [text "Your token is not valid (40 chars required)"] - ] - -tokenToString : GitHubToken -> String -tokenToString t = - case t of - Valid s -> s - Invalid s -> s - -pageNotFound : List (Html Msg) -pageNotFound = - [ h1 [] [ text "Not found" ] - , text "Sorry couldn't find that page" - ] - ---> LOGIC -unitToString : LengthUnit -> String -unitToString lu = - case lu of - Metres -> "Metres" - Inches -> "Inches" - Yards -> "Yards" - Feets -> "Feets" - -computeUnit : LengthUnit -> Model -> Float -computeUnit lu model = model.metres * (unitCoefficient lu) - -unitCoefficient : LengthUnit -> Float -unitCoefficient lu = - case lu of - Metres -> 1 - Inches -> 39.3700787 - Yards -> 1.0936133 - Feets -> 3.2808399 -``` - -You can play with this app from [MI-AFP/elm-example](https://github.com/MI-AFP/elm-example). - -## Task assignment - -The homework to create a simple frontend for a REST API described in the repository [MI-AFP/hw10](https://github.com/MI-AFP/hw10). - -## Further reading - -* [Haskell on the front end](https://www.reddit.com/r/haskell/comments/7ax2ji/haskell_on_the_front_end/) -* [Zdroják.cz - Elm (czech only)](https://www.zdrojak.cz/clanky/elm-uvod/) -* [gelisam/frp-zoo (FRP libs comparison)](https://github.com/gelisam/frp-zoo) -* [FRP explanation using reactive-banana](https://wiki.haskell.org/FRP_explanation_using_reactive-banana) diff --git a/tutorials/11_performance-debug.md b/tutorials/11_performance-debug.md deleted file mode 100644 index 264bad0..0000000 --- a/tutorials/11_performance-debug.md +++ /dev/null @@ -1,468 +0,0 @@ -# Performance and Debugging - -During this tutorial, we will take a look how to improve the performance of a Haskell program and how to debug it. We will use very simple example - [Fibonacci numbers](https://en.wikipedia.org/wiki/Fibonacci_number). - -```haskell -import System.Environment - --- | Naive recursive algorithm for n-th Fibonacci number -fibonacci :: Integer -> Integer -fibonacci 0 = 0 -fibonacci 1 = 1 -fibonacci n = fibonacci (n-1) + fibonacci (n-2) - -main :: IO () -main = do - args <- getArgs - print . fibonacci . read . head $ args -``` - -## Measuring time and memory - -When you want to check the performance of a program and compare two programs or algorithms in terms of time or memory consumption, you need to measure it. - -### Basic `time` - -The `time` command is one of the well-known Linux commands for programmers. It can be used to show how long a command takes to run. That makes it Very useful if you are a developer and you want to test the performance of your program or script. Especially to compare the time of programs written in other languages "from outside". For basic usage, you will get three numbers: - -- `real` = total time is taken to run the command (the same as if you use your normal stopwatch) -- `user` = amount of time that was spent in user mode -- `sys` = amount of time spent in kernel mode - -Then `user`+`sys` gives information how much actual CPU time your process used - in total on all cores. This number can be then higher than `real` if your program uses multiple threads. - -``` -% /usr/bin/time -p runhaskell FibonacciNaive.hs 25 -75025 -real 0.33 -user 0.31 -sys 0.01 -``` - -But `time` can do a bit more, you can tell how output should look like with additional "numbers" - number of page faults, average total memory use of the process in kilobytes, number of signals delivered to the process, number of socket messages received/sent by the process, exit status of the command, and many others. - -``` -% /usr/bin/time -f "Elapsed Time: %E\nExit Status: %X\nPage Faults: %F" runhaskell FibonacciNaive.hs 25 -75025 -Elapsed Time: 0:00.34 -Exit Status: 0 -Page Faults: 0 -``` - -### Benchmarking with Criterion - -If you are interested in such optimizations and improving your application or comparing various algorithms or their implementations, then you might find interesting to use a benchmarking library. In Haskell is the most used one called [Criterion](http://www.serpentine.com/criterion/). It provides a powerful but simple way to measure software performance. It provides both a framework for executing and analyzing benchmarks and a set of driver functions that makes it easy to build and run benchmarks and to analyze their results. - -For simple usage, you just need to work with the `defaultMain` from [Criterion.Main](https://hackage.haskell.org/package/criterion/docs/Criterion-Main.html) as they show in their example: - -```haskell -import Criterion.Main - --- | Naive recursive algorithm for n-th Fibonacci number -fibonacci :: Integer -> Integer -fibonacci 0 = 0 -fibonacci 1 = 1 -fibonacci n = fibonacci (n-1) + fibonacci (n-2) - -main :: IO () -main = defaultMain [ - bgroup "fib" [ bench " 5" $ whnf fibonacci 5 - , bench "10" $ whnf fibonacci 10 - , bench "25" $ whnf fibonacci 25 - ] - ] -``` - -It has very nice outputs with a form of interactive HTML pages with charts and comparisons and has many options to use. - -``` -% runhaskell FibonacciNaiveCriterion.hs -benchmarking fib/ 5 -time 7.319 μs (6.980 μs .. 7.821 μs) - 0.966 R² (0.934 R² .. 0.995 R²) -mean 7.248 μs (6.966 μs .. 7.847 μs) -std dev 1.321 μs (805.8 ns .. 2.043 μs) -variance introduced by outliers: 96% (severely inflated) - -benchmarking fib/10 -time 81.34 μs (81.15 μs .. 81.54 μs) - 1.000 R² (1.000 R² .. 1.000 R²) -mean 81.58 μs (81.38 μs .. 81.85 μs) -std dev 811.3 ns (577.5 ns .. 1.191 μs) - -benchmarking fib/25 -time 111.6 ms (110.5 ms .. 112.2 ms) - 1.000 R² (1.000 R² .. 1.000 R²) -mean 112.1 ms (111.7 ms .. 112.9 ms) -std dev 853.6 μs (534.0 μs .. 1.215 ms) -variance introduced by outliers: 11% (moderately inflated) - -runhaskell FibonacciNaiveCriterion.hs 15.98s user 0.04s system 99% cpu 16.055 total -``` - -### Measure allocations with Weigh - -The package [weigh](https://hackage.haskell.org/package/weigh) provides a simple interface to measure the memory usage of a Haskell value or function. - -```haskell -import Weigh - --- | Naive recursive algorithm for n-th Fibonacci number -fibonacci :: Integer -> Integer -fibonacci 0 = 0 -fibonacci 1 = 1 -fibonacci n = fibonacci (n-1) + fibonacci (n-2) - -main :: IO () -main = mainWith $ do - func "fib 5" fibonacci 5 - func "fib 10" fibonacci 10 - func "fib 25" fibonacci 25 -``` - -It provides a nice output as plain text table, but it is also possible to change the format to markdown. - -``` -% ./FibonacciNaiveWeigh - -Case Allocated GCs -fib 5 1,968 0 -fib 10 24,304 0 -fib 25 33,509,936 63 -``` - -## Performance - -Now we are able to measure something and compare algorithms, but how to improve the numbers we get if we really need it? - -### Basic ideas - -When you are not satisfied with the performance of your application, then before any sophisticated optimization steps by using strictness, unboxed types, calling FFI, etc., you should consider if you prefer faster application over better readability. Then another important thing to think about is design if it is not slow by using "naive" algorithm, using an inappropriate data structure (List instead of Set or Map), etc. - -**Always** rethink your own code before using other optimization techniques! - -```haskell -import System.Environment - --- | Improved recursive algorithm for n-th Fibonacci number -fibonacci :: Integer -> Integer -fibonacci = fib 0 1 - where - fib x _ 0 = x - fib x y n = fib y (x+y) (n-1) -- just "one-way" recursion! - -main :: IO () -main = do - args <- getArgs - print . fibonacci . read . head $ args -``` - -Just a very simple re-thinking can have some impact: - -``` -% /usr/bin/time -p runhaskell FibonacciBetter.hs 25 -75025 -real 0.24 -user 0.22 -sys 0.02 -``` - -``` -% runhaskell FibonacciBetterCriterion.hs -benchmarking fib/ 5 -time 3.412 μs (3.235 μs .. 3.591 μs) - 0.988 R² (0.983 R² .. 0.998 R²) -mean 3.191 μs (3.129 μs .. 3.277 μs) -std dev 253.6 ns (168.4 ns .. 360.9 ns) -variance introduced by outliers: 82% (severely inflated) - -benchmarking fib/10 -time 5.930 μs (5.871 μs .. 6.013 μs) - 0.997 R² (0.994 R² .. 0.998 R²) -mean 6.209 μs (6.075 μs .. 6.464 μs) -std dev 625.6 ns (377.2 ns .. 1.088 μs) -variance introduced by outliers: 87% (severely inflated) - -benchmarking fib/25 -time 14.53 μs (14.31 μs .. 14.90 μs) - 0.990 R² (0.972 R² .. 0.999 R²) -mean 14.78 μs (14.40 μs .. 15.89 μs) -std dev 1.953 μs (712.6 ns .. 4.110 μs) -variance introduced by outliers: 91% (severely inflated) - -runhaskell FibonacciBetterCriterion.hs 15.90s user 0.07s system 100% cpu 15.954 total -``` - -``` -% ./FibonacciBetterWeigh - -Case Allocated GCs -fib 5 872 0 -fib 10 1,712 0 -fib 25 37,000 0 -``` - -### Boxed vs. Unboxed types - -Now, we are going to briefly mention is the difference between boxed and unboxed types. Although it is a low-level concern and with regular Haskell programming, you can avoid these terms, it is good to know what is it about when you see it in other's code or in a documentation. - -To support laziness, parametric polymorphism, and other properties, by default Haskell data types are represented uniformly as a pointer to a closure on the heap. These are "boxed" values. An unboxed is represented directly by raw value (i.e., without any indirection). Using unboxed types can lead to time/space optimizations. Having always pointers to a heap-allocated object is fairly slow, so compilers attempt to replace these boxed values with unboxed raw values when possible. Unboxed values are a feature of some compilers that allow directly manipulating these low-level values. Since they behave differently than normal Haskell types, generally the type system is extended to type these unboxed values. - -In GHC, unboxed values have a hash mark as a suffix to their name. For instance, the unboxed representation of 42 is 42#. However, you can't pass them to polymorphic functions (like `show` for instance). To allow that, you need to use constructor `I#` that takes an unboxed integer and returns the `Int` (wraps). You can observe [kind](https://wiki.haskell.org/Kind) (*kind of type*, we will look again at kinds with typeclasses) of boxed and unboxed types: - -* By default, kind of type is `*` (try in GHCi: `:kind Int`) -* Kind of unboxed type is `#` (try in GHCi: `:kind Int#`) - -```haskell -{-# LANGUAGE MagicHash #-} -module Main where - -import GHC.Exts - --- | Naive recursive algorithm for n-th Fibonacci number with --- unboxed Int types -fibonacci :: Int# -> Int# -fibonacci 0# = 0# -fibonacci 1# = 1# -fibonacci n = fibonacci (n -# 1#) +# fibonacci (n -# 2#) - -main :: IO () -main = print (I# (fibonacci 25#)) -``` - -``` -% /usr/bin/time -p runhaskell FibonacciUnboxed.hs -75025 -real 0.30 -user 0.27 -sys 0.03 -``` - -For more information, visit [GHC.Exts]() and [GHC.Prim](). - -### Strictness with types - -In the previous lessons, we touched the topic of enforcing strictness with `!` in patterns ([bang patterns](https://ocharles.org.uk/blog/posts/2014-12-05-bang-patterns.html)) and in function application with `$!` operator. Similarly, we can use `!` with type fields like this: - -```haskell -data MyType = MyConstr Int !Int - -data MyRec = MyRecConstr { xA :: Int - , xB :: !Int - } -``` - -For both cases it means that when data constructor is evaluated, it must fully evaluate ([weak head normal form](https://wiki.haskell.org/Weak_head_normal_form)) the second parameter, but the first one will stay unevaluated in a lazy way. All depends on language implementation in the used compiler. - -#### Unpacking strict fields - -One of the most used optimization techniques when talking about unboxed types and strictness with [GHC] is [unpacking strict fields](https://wiki.haskell.org/Performance/Data_types#Unpacking_strict_fields). When a constructor field is marked strict, and it is a single-constructor type, then it is possible to ask GHC to unpack the contents of the field directly in its parent with `{-# UNPACK #-}` pragma: - -```haskell -data T1 = T1 {-# UNPACK #-} !(Int, Float) -- => T1 Int Float -data T2 = T2 Double {-# UNPACK #-} !Int -- => T2 Double Int# -``` - -We mention this just because of differences in performance of types we are going to describe now. You don't need to use strict or unboxed types within your work if you don't need to have time/space optimizations and if yes, consider reading [Haskell High Performance Programming](https://github.com/TechBookHunter/Free-Haskell-Books/blob/master/book/Haskell%20High%20Performance%20Programming.pdf). - -### GHC optimization flags - -If you know optimization with GCC, then you won't be surprised how it works with GHC: - -* `-O0` = turn off all optimization -* `-O` or `-O1` = generate good-quality code without taking too long about it -* `-O2` = apply every non-dangerous optimization, even if it means significantly longer compile times (in most cases, there is no significant difference between `-O1` and `-O2`) - -Then there are also `-f*` platform-independent flags, that allows you to turn on and off individual optimizations. For more information, please visit [GHC documentation](http://downloads.haskell.org/~ghc/latest/docs/html/users_guide/using-optimisation.html). - -### Concurrency and Parallelism - -Haskell (of course) supports parallelism or concurrency in order to achieve faster and efficient computation. For parallelism and concurrency visit [wiki.haskell.org/Parallel](https://wiki.haskell.org/Parallel). You can both: - -* run parallel threads with [Control.Parallel](http://hackage.haskell.org/package/parallel/docs/Control-Parallel.html), -* run simultaneous IO actions with forks. - -It is also possible to do distributed computations on clusters but it is far beyond the scope of this course. - -```haskell -import Control.Parallel - -parfib 0 = return 1 -parfib 1 = return 1 -parfib n = do - n1 <- parfib (n - 1) - n2 <- parfib (n - 2) - n3 <- (n1 `par` (n2 `seq` (return (n1 + n2 + 1)))) - return n3 - -main = do x <- parfib 30; print x -``` - -GHC supports running programs in parallel on an SMP (symmetric multiprocessor) or multi-core machine. Just compile your program using the `-threaded` switch and then run it with RTS option `-N ` (where `` is the number of simultaneous threads). See [GHC docs](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/parallel.html) for more information. - -### FFI - -As with many other programming languages, Haskell supports [FFI (Foreign Function Interface)](https://wiki.haskell.org/Foreign_Function_Interface) that allows co-operating with programs written with other languages. We've already could see that in the example of Haste in DS Wizard where there were some JS bindings. But you can also use it to call some functions from C++ or Rust: - -```cpp -extern "C"{ // need to expose with extern, could use header file .h or .hpp for that - extern int fib(int n) { - if(n < 0) return -1; - int x = 0, y = 1, tmp; - while(n-- > 0) { - tmp = x; - x = y; - y = tmp + x; - } - return x; - } -} -``` - -```haskell -{-# LANGUAGE ForeignFunctionInterface #-} - -import Foreign.C -import System.Environment - -foreign import ccall "fib" cfib :: CInt -> CInt - -main :: IO () -main = do - args <- getArgs - print . cfib . read . head $ args -``` - -``` -% gcc -c -o fib.o fib.cpp -% ghc --make -o ffi_fib FibonacciFFI.hs fib.o -Linking ffi_fib ... -% /usr/bin/time -p ./ffi_fib 25 -75025 -real 0.00 -user 0.00 -sys 0.00 -``` - -Similarly, there is `foreign export` to expose some Haskell functions to other FFIs. Nice example is here: [jarrett/cpphs](https://github.com/jarrett/cpphs). - -## Debugging - -Even if you are a good Haskell programmer, things can go wrong and especially in big projects it is a nontrivial challenge to find out where you did some mistake. Going thru the code in multiple functions, inner functions, various modules, etc. can be painful. Luckilly, there are some ways how to debug Haskell program and some are pretty easy and similar to well-known. - -### Tracing with `Debug.Trace` - -You should already know how to use GHC and GHCi to compile, link and examine Haskell programs. The simplest tool to use for debugging is the `trace` from [Debug.Trace](https://hackage.haskell.org/package/base.0/docs/Debug-Trace.html) which outputs the trace message given as its first argument, before returning the second argument as its result. There are many more *traces* defined for different cases: `traceShow`, `traceId`, `traceStack`, `traceIO`, `traceM`, etc. So you can use it for custom debugging output anywhere in the code. - -For example: - -```haskell -func a b = trace ("func " ++ show a ++ " " ++ show b) undefined -``` - -Or better usage with our example of Fibonacci numbers to see the calls: - -```haskell -module Main where - -import Debug.Trace - --- | Naive recursive algorithm for n-th Fibonacci number -fib1 :: Integer -> Integer -fib1 0 = trace "fib1 0" 0 -fib1 1 = trace "fib1 1" 1 -fib1 n = trace ("fib1 " ++ show n) (fib1 (n-1) + fib1 (n-2)) - --- | Improved recursive algorithm for n-th Fibonacci number -fib2 :: Integer -> Integer -fib2 = fib 0 1 - where - fib x _ 0 = trace "fib2 0" x - fib x y n = trace ("fib2 " ++ show n) (fib y (x+y) (n-1)) - -main :: IO () -main = do - print (fib1 4) - putStrLn "------------" - print (fib2 4) -``` - -``` -% runhaskell FibonacciTrace.hs -fib1 4 -fib1 2 -fib1 0 -fib1 1 -fib1 3 -fib1 1 -fib1 2 -fib1 0 -fib1 1 -3 ------------- -fib2 4 -fib2 3 -fib2 2 -fib2 1 -fib2 0 -3 -``` - -### GHCi debugger - -If you need a better debugger, you can use [GHCi debugger](https://downloads.haskell.org/~ghc/7.4.1/docs/html/users_guide/ghci-debugger.html) (other compilers, such as Hugs, have some different), which allows: - -* setting breakpoints and stepping, -* inspecting variables, -* tracing, -* working with exceptions, -* and so on. - -``` -Prelude> :l FibonacciNaive.hs -[1 of 1] Compiling Main ( FibonacciNaive.hs, interpreted ) -Ok, modules loaded: Main. -*Main> :break 9 -Breakpoint 0 activated at FibonacciNaive.hs:9:10-60 -*Main> fib1 5 -Stopped in Main.fib1, FibonacciNaive.hs:9:10-60 -_result :: Integer = _ -n :: Integer = 5 -[FibonacciNaive.hs:9:10-60] *Main> :continue -fib1 5 -Stopped in Main.fib1, FibonacciNaive.hs:9:10-60 -_result :: Integer = _ -n :: Integer = 3 -[FibonacciNaive.hs:9:28-33] *Main> :show breaks -[0] Main FibonacciNaive.hs:9:10-60 -[FibonacciNaive.hs:9:28-33] *Main> :abandon -*Main> -``` - -### `debug` package - -An interesting solution brings also the [debug](https://hackage.haskell.org/package/debug) package (and related extensions). It uses *Template Haskell* to examine the code and algorithms. - -```haskell -{-# LANGUAGE TemplateHaskell, ViewPatterns, PartialTypeSignatures #-} -{-# OPTIONS_GHC -Wno-partial-type-signatures #-} -module QuickSort(quicksort) where -import Data.List -import Debug - -debug [d| - quicksort :: Ord a => [a] -> [a] - quicksort [] = [] - quicksort (x:xs) = quicksort lt ++ [x] ++ quicksort gt - where (lt, gt) = partition (<= x) xs - |] -``` - -## Further reading - -* [Haskell - Debugging](https://wiki.haskell.org/Debugging) -* [Haskell - Performance](https://wiki.haskell.org/Performance) -* [Haskell - Concurrency](https://wiki.haskell.org/Concurrency) -* [Real World Haskell - Concurrent and Multicore Programming](http://book.realworldhaskell.org/read/concurrent-and-multicore-programming.html) -* [GHC - Concurrent and Parallel Haskell](https://downloads.haskell.org/~ghc/7.0.3/docs/html/users_guide/lang-parallel.html) - diff --git a/tutorials/12_exts-deptypes.md b/tutorials/12_exts-deptypes.md deleted file mode 100644 index b95cbcb..0000000 --- a/tutorials/12_exts-deptypes.md +++ /dev/null @@ -1,254 +0,0 @@ -# GHC Extensions and Dependent Types - -This lecture is a sort of "gourmet" -- the concepts presented here are not used every day nor are common in production, nor are they topics to speak over coffee with mediocre programmers. Rather they represent cutting-edge topics that may potentially write the future of programming. Enjoy ;-) - -## GHC Language Extensions - -Language extensions are used to enable language features in Haskell that may seem useful in certain cases. They can be used to loosen restrictions in the type system or add completely new language constructs to Haskell. As you already know, they can be enabled using the `{-# LANGUAGE #-}` pragma or using flags `-X`. You should always consider using those extensions over normal Haskell, because it may potentially bring some risks. It is advisable to read some discussions on forums. - -### TypeFamilies - -This extension allows use and definition of indexed type and data families to facilitate type-level programming. Indexed type families, or type families for short, are type constructors that represent sets of types. Set members are denoted by supplying the type family constructor with type parameters, which are called type indices. The difference between vanilla parametrized type constructors and family constructors is much like between parametrically polymorphic functions and (ad-hoc polymorphic) methods of type classes. Parametric polymorphic functions behave the same in all type instances, whereas class methods can change their behaviour in dependence on the class type parameters. Similarly, vanilla type constructors imply the same data representation for all type instances, but family constructors can have varying representation types for varying type indices. (see [GHC docs](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/glasgow_exts.html#type-families)) - -```haskell -{-# LANGUAGE TypeFamilies #-} - --- Declare a list-like data family -data family XList a - --- Declare a list-like instance for Char -data instance XList Char = XCons !Char !(XList Char) | XNil - --- Declare a number-like instance for () -data instance XList () = XListUnit !Int - -class XLength a where - xlength :: XList a -> Int - -instance XLength Char where - xlength XNil = 0 - xlength (XCons _ r) = 1 + xlength r - -instance XLength () where - xlength (XListUnit _) = 1 -``` - -### GADTs - -[Generalized algebraic data type](https://en.wikipedia.org/wiki/Generalized_algebraic_data_type) are a generalization of the algebraic data types that you are familiar with. Basically, they allow you to explicitly write down the types of the constructors. In this chapter, you'll learn why this is useful and how to declare your own. GADTs are mainly used to implement domain-specific languages, and so this section will introduce them with a corresponding example. - -```haskell -{-# LANGUAGE GADTs #-} - -data Expr a where - I :: Int -> Expr Int - B :: Bool -> Expr Bool - Add :: Expr Int -> Expr Int -> Expr Int - Mul :: Expr Int -> Expr Int -> Expr Int - Eq :: Expr Int -> Expr Int -> Expr Bool - And :: Expr Bool -> Expr Bool -> Expr Bool - -eval :: Expr a -> a -eval (I n) = n -- return Int -eval (B b) = b -- returns bool -eval (Add e1 e2) = eval e1 + eval e2 -- return Int -eval (Mul e1 e2) = eval e1 * eval e2 -- return Int -eval (Eq e1 e2) = eval e1 == eval e2 -- returns bool -eval (And e1 e2) = eval e1 && eval e2 -- returns bool -``` - -Complete example: [Haskell - GADT](https://en.wikibooks.org/wiki/Haskell/GADT) - -### QuasiQuotes - -[Quasiquoting](https://wiki.haskell.org/Quasiquotation) allows programmers to use custom, domain-specific syntax to construct fragments of their program. Along with Haskell's existing support for domain specific languages, you are now free to use new syntactic forms for your EDSLs. We've already seen it used in Yesod or Debug. Another simple use is with [Text.RawString.QQ](http://hackage.haskell.org/package/raw-strings-qq/docs/Text-RawString-QQ.html) to allow multiline strings: - -```haskell -{-# LANGUAGE QuasiQuotes #-} -import Text.RawString.QQ - -multiline :: String -multiline = [r| - -Auto-generated html formated source - - - -

-
|]
-```
-
-You can, of course, write your own DSL or simplify the syntax for yourself. All you have to do is implement your [QuasiQuoter](http://hackage.haskell.org/package/template-haskell/docs/Language-Haskell-TH-Quote.html#t:QuasiQuoter) (part of Template Haskell). For example, you can create a simple string-string map with semicolon and newlines:
-
-```haskell
-{-# LANGUAGE TemplateHaskell #-}
-module MapBuilder (mapBuilder) where
-
-import Language.Haskell.TH
-import Language.Haskell.TH.Quote
-
--- | Map Builder quasiquoter
-mapBuilder = QuasiQuoter
-    { quoteExp  = mapBuilderParser -- expressions
-    , quotePat  = undefined        -- patterns
-    , quoteType = undefined        -- types
-    , quoteDec  = undefined        -- declarations
-    }
-
--- | Split string to two parts by given char
-splitByFirst :: String -> Char -> (String, String)
-splitByFirst str sep = splitByFirst' "" str
-  where
-    splitByFirst' a [] = (a, "")
-    splitByFirst' a (x:xs)
-       | x == sep  = (a, xs)
-       | otherwise = splitByFirst' (a++[x]) xs
-
--- | Trim spaces and tabs from left of the string
-trimLeft :: String -> String
-trimLeft "" = ""
-trimLeft (x:xs)
-  | x `elem` [' ', '\t'] = trimLeft xs
-  | otherwise        = x : trimLeft xs
-
--- | Parse [(String, String)] map from String
-mapBuilderParser :: String -> Q Exp
-mapBuilderParser = return . ListE . map parseTuples . filter (/="") . map trimLeft . lines
-  where
-    parseTuples :: String -> Exp
-    parseTuples xs = TupE [LitE . StringL $ key, LitE . StringL $ val]
-      where
-        parts = splitByFirst xs ':'
-        key = fst parts
-        val = snd parts
-```
-
-Then you can simply import defined quasiquoter and use it:
-
-```haskell
-{-# LANGUAGE QuasiQuotes #-}
-
-import MapBuilder
-
-mymap1 :: [(String, String)]
-mymap1 = [mapBuilder|
-           a:10
-           b:22
-           c:hello
-           it:has:no:problem
-         |]
-
-mymap2 :: [(String, Int)]
-mymap2 = map strstr2strint [mapBuilder|
-           suchama4:1210
-           perglr:1535
-         |]
-
-strstr2strint :: (String, String) -> (String, Int)
-strstr2strint (x, y) = (x, read y)
-```
-
-Beautiful, right?!
-
-### Template Haskell
-
-[Template Haskell](http://hackage.haskell.org/package/template-haskell) is a GHC extension to Haskell that adds compile-time metaprogramming facilities. The original design can be found here: http://research.microsoft.com/en-us/um/people/simonpj/papers/meta-haskell/. You could have seen part of it in action in the previous section about quasiquoting but it can do much more although quasiquotes are an important part of it. Great explanation is [here](https://ocharles.org.uk/blog/guest-posts/2014-12-22-template-haskell.html) and [here](https://markkarpov.com/tutorial/th.html).
-
-## Dependent and Refinement Types
-
-A dependent type is a type whose definition depends on a value. Such types can be for example:
-
-* pair of integers where the second is greater than the first,
-* people with age between 18 and 65,
-* string in email format (matches given regex).
-
-Dependent types add complexity to a type system. Deciding the equality of dependent types in a program may require computations. If arbitrary values are allowed in dependent types, then deciding type equality may involve deciding whether two arbitrary programs produce the same result; hence type checking may become undecidable.
-
-### Agda
-
-[Agda](http://wiki.portal.chalmers.se/agda/pmwiki.php) is a dependently typed functional programming language originally developed by Ulf Norell at Chalmers University of Technology with the implementation described in his PhD thesis. But current version, Agda 2, is a completely rewritten previous Agda from 1999.
-
-Visit https://github.com/agda/agda where you find some examples as well!
-
-### Idris
-
-[Idris](https://www.idris-lang.org) is a general-purpose purely functional programming language with dependent types, strict or optional lazy evaluation and features such as a totality checker. Idris is highly affected by Haskell and Agda which is visible in its syntax.
-
-Its features are influenced by Haskell and ML, and include:
-
-* Full dependent types with dependent pattern matching
-* Simple foreign function interface (to C)
-* Compiler-supported interactive editing: the compiler helps you write code using the types
-where clauses, with a rule, simple case expressions, pattern matching let and lambda bindings
-* Dependent records with projection and update
-* Interfaces (similar to type classes in Haskell)
-* Type-driven overloading resolution
-* `do` notation and idiom brackets
-* Indentation significant syntax
-* Extensible syntax
-* Cumulative universes
-* Totality checking
-* Hugs-style interactive environment
-
-On their website, you can find a documentation with [examples](https://www.idris-lang.org/example/) such as Vectors:
-
-```idris
-infixr 5 ::
-
-data Vect : Nat -> Type -> Type where
-    Nil  : Vect Z a
-    (::) : a -> Vect k a -> Vect (S k) a
-
-app : Vect n a -> Vect m a -> Vect (n + m) a
-app Nil       ys = ys
-app (x :: xs) ys = x :: app xs ys
-```
-
-### LiquidHaskell
-
-LiquidHaskell is a static verifier for Haskell, based on Liquid Types. It allows annotating code with invariants that complement the invariants imposed by the types. These invariants are checked with a SMT solver. It is not about dependent types but [refinement types](https://en.wikipedia.org/wiki/Refinement_(computing)#Refinement_types) (you refine some defined type with rules, not build it dependent from the scratch).
-
-Visit: https://ucsd-progsys.github.io/liquidhaskell-blog/
-
-```haskell
-{--! run liquid with no-termination -}
-
-module SimpleRefinements where
-import Prelude hiding ((!!), length)
-import Language.Haskell.Liquid.Prelude
-
-
--- |Simple Refinement Types
-
-{-@ zero :: {v:Int | v = 0} @-}
-zero     :: Int
-zero     =  0
-
-{-@ type Even = {v:Int | v mod 2 = 0} @-}
-
-{-@ zero'' :: Even @-}
-zero''     :: Int
-zero''     =  0
-
--- |Lists
-
-infixr `C`
-data L a = N | C a (L a)
-
-{-@ natList :: L Nat @-}
-natList     :: L Int
-natList     =  0 `C` 1 `C` 3 `C` N
-
-{-@ evenList :: L Even @-}
-evenList     :: L Int
-evenList     =  0 `C` 2 `C` 8 `C` N
-```
-
-## Further reading
-
-* [Haskell Wiki - Language extensions](https://wiki.haskell.org/Language_extensions)
-* [24 Days of GHC Extensions](https://ocharles.org.uk/blog/pages/2014-12-01-24-days-of-ghc-extensions.html)
-* [Agda](https://github.com/agda/agda)
-* [Idris](https://www.idris-lang.org)
-* [Idris - tutorial](http://docs.idris-lang.org/en/latest/tutorial/)
-* [LiquidHaskell](https://ucsd-progsys.github.io/liquidhaskell-blog/)
diff --git a/tutorials/images/tea.png b/tutorials/images/tea.png
new file mode 100644
index 0000000000000000000000000000000000000000..4b58d5bc4ab82594f7c7f2134c3d3d4df5e5d9ce
GIT binary patch
literal 10401
zcmb7pb983GmhTsIoQ^uS%`Z+mw#|-{FSc!U)UjubF$XVhc#nbwP=!Jjgkx#Q{SuJ1sHV$H1P(J5M6JSFz-fPmv5Ni@1;hN2
zNMb4a4L%|O9K$J)4t%859$isT({2Mh^8uf~{Ug
z>z|e3Xl$%+qmUa^k=aQ-SGP_O8*^HsG|&Z)`#
zsFb|sR{mcZq?nH$Q+17+ADb*28e50H?x)h@U3AZJJ11j0KIm`&JnCoMuOA^Fju$^w
zI0J4MONOk936lTbej^j_rx5W`zWhjh#V-^G6<3ScIE+vTS~FcsD7*!2J`Is%AZIz6@$0Z!-O0?$+G^47nr6TAT2
z=a)dp)DMr6L_|awKk!2VC@OH(99SoR6eftIKNy?<%uO&aLF7fiBM}rCIM@*QZ+&Pg
zfT%tpCrp_Dy%|6@2R#ESbCb6Pyee>IlK~4V#vfTGAXxx%-Two*>IF)Pk=^
z0%FLxbs=~}97DKp0YbTERInp{4!M~MC@OHOg3bzPxA0D1Tfx_YpmIYeIawjz5WRy?
zQXppxzGy(qhb}Qey99f0-Py5bz#aT~y43wl7b@R_e~JFc&WixQm3)Z@j!e=ckbt5S
z6lI5kM1~bE1UaNufJ`lZ9IIAtdT+Hydr4{@u=4&KeaoqHYp!awGZZBOzh?&aDe&!glkxM08^5)BkDSo#tSGamg#$j#$h3Xqkc%o&e3k64a~j}TL3
z=80C~0*8-wJ9a6qRj-w=J(<%|vasaogsjpv8Z|-}e=X9&W#!3jDX=RzQ0*lE6L=Cd
z?b};IIMsP&yvp4gAGxj+uee~-f^vgGMe;;yMe6%x!_8@u$^@Nr#1w8y2TRmT(O83u
zq;{qs8!{W9mf4oc@P$pM+;2HOP~J?R0Xk%oiL6Pt$)iaXN$o_`#zY8+P%*K8s0=bd
zkxYD2)DrduB!%}9jZ%n`W72;mSER(HFr}I$k)(YS3`RJI`u?6KA0@bxM8wS{-NlW?
zeJAmhby16EFr^+$rcL0Xe~=(ZT1a|G+Mx55>D2R)6IAS$Bo@t8+A8a*AQ7HYW0tFx
zxysv)M3o)ZqE;)FIf|QxFCvTYmC;vY@=PT$aW^sDL)hcq1Kaz8p7b+YDoZMT1Wh%7
zMw?BlQKnH`wV&NQEzcb_-Dw+Sc;C|Ib^xk4-rVF+;#Sqt&SHOIY*DvLU=
zrl@xL(P8bpaJ(?UJrFw}9!Z!oDYGi;l75@w#li+ePiaaUPbp0ePMb@KsynihcVT`B
z;aXlD_ey_qzd^z%!Z^Yxrhl)SZH#QTYRb^<)k6DSWH1(#_)|4SH8XKC%^cstdsfRV
z-wF++Yg&=#O5AAo#Z!7yFXY$|AEo#5{9A{k6TAbT@
z&l%34R|n_Is%5oSj=*@`2%veh-0FChzx&?xxVd|%dVYUkza76jzsY^Fx;4LdKd?N|
z-hNq>pJD8+9?ae*+}_ybC)6iYz#&4IMOsC5>KvM(!-ud
zXGk$kQ^)E+GeT3wYQeos^DJ;H6Dcd>K59kB(L{6aoZa#DgnndV6D^vfhRY0P8-r{{~E3ult~``;19B6YBLQs-0W
zQZMRX>&K0yjVVnYY^T>7OlMT0jmG8E71N*6JslDqU3a5xx2#H6;H(ihmg{AmwcneD
z&*WC*Pl-;$Hmmh}4Lvu-2@9x7|a}BGvLEoN9Iy
zJ4_t(g!O2PLW%B)M)bdKYxCp0Yh3M2ua|T{kQb4Q-y7VMpW!aq)_;hUikQnC^?^M=
z;G2xr_0%;(a}cy^+WgS<46~!!`Bl?XnOCk<>7ch~s46pO*Qn#H9pyEamG;z&5*ix4
zNMK&6T0&p;=Eiz|7|31R8toDFd~K9slscHj@yK!e*7sgos@POpay4^Ru+xLKPU(?8
znwFNfmoBZfnG~6n8c$4l@ox3us9tVkse_wedH9Vp(f+ufF}Eu+!{z&$V~BUrUB&ZK
znv0gF0rYHbsqifJ4D~78F%Iv6LsjugUE7;_hh9v!I-j1m;I+`OXixuZgmkh4!~>CLpwnK~TgSb)y0j(Fwd%&){;qmM0G8XRNfO3VZQjr+Y@0RPo>Oang#D{CmP<{eI$pdA;w_`y3fW3~FA}&$Dk!cQ=bl+tbthLUg}6
z;~iyHJ~vK8MiNT00DuPt0N@t{06c#}eun^nGZO%CtPcQirvLz$b{VaTyZ`{$zJiR3
z=*P#$r_KMC;H?Yb?MvaEDiOR|5xm;|(Y!zTr~H4~XFyo}UvS1rum*Ae0e%XQRJ@RM
zLXec){~7!=hEel}v&#Q>@Sg#_T0e0J0y-EuCwP}y1n>5LY3t^XKWqLE(%09QkdO!t
z4*nNXRaKRglyq}*GdMV?sHjLyP5p^fOdqbC-Yevef6}LFU|`@M(f(QRXNu3T=l>*D
zR#sG0)cE*#baeFm{QSA?BQ(EubpMWjY5&D9E-wD_@L%rmb|rA2R5*(qSnV))rz$8R
zBN$~bILllJVirhhzUZEf&)Ty7?rfaj>y%7&uAa$ekA6=Y!VB)InmH5^5%K=LJid2j
zT{BM?)!WwAHaa?basRxwww9Wj>gwvMs;WvtLh_ju1qB5J0)>Tz0fE4>va*<%7+YK0
z>gwu*KTG*TYlnx23kwT7J3HOo-8D5epU;?`o!!{jSWr+fJw3fJ(E9dStA&%2oH9TJ
z1sDcOZ7Vw;bzM^>*%*s^yWZKD`jZ^yDgu1DdwLmdDl-Kw6-;$
zAEOOI84M#40XAF*w1EZ>Vv+|pvL_U-5Bsiu@NZpSg2Lu53Qx0R9_~nh6RKMxD5+PP
z7p^s*S-}jY#YF&NU+^V92e5V$nvS3SKV%7j*svwvrvU9FDJu%S0|A2wj{GEP2L%AY
zxp}B)I4K#p64^P}g3PTCUI?GsxrcK$FU4{twJd
zJ;q}da-pY}o4YZ&BPElME3b!(3AC-(psN$#Y<`TxiHVpGgTsS^SYP(p;nC!BHs3R*
zdZWXKi4S9+=eyAj{>J<3uXGeWFOtvcK`?`=TTzi|jozVR&Ff0GG9*&AIDdZ(T;#vH
z7R~rBzuU@wJU^}6p71=sCXw^u^ADxf#)iY$F21|pF4&tj?y2GYdeaFP!9^O~YZEUF
zd)b(qewet}m#lc^(n`NV4+V8)YmBWw%s-{7?`wYWT^Nj+Of0~)E@k4P>z?VS05ViQaR
zYoAR+`%a{d(2KthdpsJ*5!+S>p&>jw3XDB4LOjDN26n7vsol~p)g!_t#7pHj`xY`}
zgU$xV^(lzuwhk-~-drS*=!Xr-?@1h+=y9so`O5IRUP2%N@n5NN8ch
zfs!%svvLIeH$=Gk^f?f#gQJ1@NI5KiLx0L^v2c&<2e4tSt^!$o-#PPC#$txP$OoN<
zSJ1U~XPMT4E@_rBlTWs~`w%g(&!s4w
zKy}4Zsxr0ha;brja>#QUZ=e5w*T3P9*q`GC%Lmhia2sHbijwhQZ?uZvAX+^uMPq%Fng@)iPp*c7B*cIGlYgi4-uO7Y;jz*{MicVl)h&e
zY{hw6F2W<%6SBJ~q`RWx^ab4b;ee|^*Zy2n*cr0db4M$bg5r*(&Cs)7Vz;?@J=E5q
z+U?tHgZA>2O4S`9(XuIA9o}kCP%pe!EV~stN@&$89dG&dM0z_SumHCW1IC1rau0@r
zAf+r-eCfd<;*rSbdUPW2HTgSnsM23ECm~_DIxx*sl>xqB
zuCStwkut6Fd2X@F_-tB>@6cnK=<8*6s@C(CH)$3TgGq{>{7$IR182(<9&@VD@u5t=
zp0^?ehEJ3o2WA)ARe#67ZpXTmm#JVw-Etng99s$AKwDu%XXu`V(~H6K=6TXs30-Xx
zS&tg#i$3S>_=#Ao$>x}pr-u{e@mbt}=JwPEa|nZh9R%ABD#r#pj@{%rzt@!eft){R
z*_646eso%Bly)nU=vT4pGyb$y>@Zb^7Wf^{C#1r@p@`dAs8-l$fxCVYm0Bq{E}P%@
zU7OSdU+*YZt9j)))rqAN@zGu88CY%Im&?h@rWnv=6K@$NYWpnG+kP~~E^W(7WG!bq
zb6}~)C&|KIH`Wc&+B-U(g(EJinP7D927Af~ju#hMtbRnj%0?m(VPhs
zA%kN4Ge>8d*H|beF=0gN7{{Y&OW*Ig6>H?b*z*cn{qa#l^<~N0l!v^9V#M}RkY`LX
zE-DKaKE`KFWWNeE
z%Ubo=@`6A`_=OPyEN89fiO?}(MCJwhb;tETr?U)-VkEPoYmbBYG
zhs@*bxoUeONhdk}VbJ37elzBS$R5v0(l!9E+T2?hvJ?wlP9f-}FvvS-p_hfV>0wl3
z;e)C^iVnxpKc}ca_{{^HI3S^NH(U8qt(;3`mqXw!?Q6+uS-Et!T-Rn%+RONucjZ-E
zHWY-PpBLc2=u-Uo>cph8Gi~C`&}P}0WSFN||9JqyA_EO39*W8;TlVdZ7p-E#huQ@r
zs_`gV*NN7DE9q|Bn7Nj-7|YnMSa2Eih~ui1WX_<6R+`;scYb*UZghDnpcBeQX}B)$
za2^?Ah2stEz&*oRgPIn)(VUkF@e)}6J9({62bC{0#z|
zvjOgQoJkXzHF!dRnnzVMRoTxms$aK(22$T2TfqfWw=(>f%<|5cZkB#CkQcoOp{Qm$
z%gVwpCp|ezH|`D?EuX3Ah*SR8?I|Bu9;vu0%R*V)y1#-o+&?dvyh-m*9E6T%OLnL4
zQzG6Gy5`vXpbqy3aHZ0(`Bp)j`POtHg%8UR(#eEKrY3D?3zw(DmVaS$>^bQbd=gj#
zisIB*^tj;^aYB>yQw8pRL53CJGe9)FO;*Nqa$%bt{&>s8757DieKZ?9a1rNU{A;FA
zgch+|6Krc!tKslDyCR|pOe;7L)uTeWWeF5WaW7J0@zi-jDLuKd{u0HAP6iU_K>
zEuUq=`jQT7hB`N#lR|0;ByrJE*TivQ;C`DGWn2WRYvTt;lbRdj~EMC#sb
zEeX6HPa*9b0KUkU=9`?9R555CA0^%S`V5b#sXs^@i`#bCsyg$af_-j&|G)Go!HNU_
zOzx*3B*A)^3=j%mjpSqw@G&6L-vyEB4~&p{MPfh6
z&~UJlf(l?Hv6)S~5QdAX3?C%?&p<@VIs|!N?(P$A#xPC!MGs*?WJ`{kRl-+cTTpooutOnJW)V3TP__8kf-FTJ^MREAc|PXtQ9eP+a?ip2
z`{9IHf0#HTX(GwYtFhd)$27uK`c?`G_L7(*Y#cV%(+&tBHuXxGf9x^!;v=1_U#w7z
zCh>1$4u6BE9J571CU}6ca)?0csnM
zDB=6d!-sI#)qNDnom75<=GSMm_RzjOD?fkQSavv4pngwewky4S#tklRTC78s?8ZLk
zHuKgkJ+*39t~hJ#XxztZHInZZ=I?J^x8sZ-QYMyEFo?uqMDTej68lR>6AF|?oprYj
zKI;lQ&p3mRWWwGO*D&
z6H64%ilDL(jzh~Ri3$2V??~P?FKy;4PmM-lpMIl+HTYR5Swxj5m%y(ezunO6FhHk7
zrf1wOg%_M$9==pI-_rfuY3$@(ITE>O!P-n3dkre30Ur`GLR|a17IskA^OK8WIN}tb
z88^la+BHv-)RC^YRy0kop_uR;-ZcyDm-p?F)L)#ivZ9-~Pj57%$8jq5V!$YcbV*v`i95x?z)wN@h%&v2@Pb4$bZGAvK8F-gwRkj8x<9(C{%80pJPq@c@$oEEi5X
zY5LznnizcYg2MAYR80c%pQHE<9>pc_~L43_gn+W85?YqA3L@
zFa?(tv*W0py<8^n3QN)QnywL!i^5=w#E6c&8Ox+4ni5MR+OzGkcmQ17q|Qc%(ONLt
zUZaKFKdXfUKp(v;mg4PPtVftt{yN|2buVNVky4tz@>T%)hU7wT9-G~8cuOHoxRPX;1B*_YjW#`P
zu)`IGF~A4iHbDebA&%lLC5nOHq)Abys?{GExR*)0FB&wlVlwzL&cY_Z064K8o%_q_
z&@3ECD@ym>*#{dD_^Oz0JT1|bggy>C2TDv}WaV%$Js$$ZLHaJT}NUhVx-BUO<
zRE%VvtgY>JOK{TGObiu!wMI;iZpY!bRc}Rkl|b!1L2A*{;Z+oN6>=f+h%v0U{}qrxcFimt4ZnH5EGXYXwS@!-uYY;
zXKppik9;*tj#<#DhJ(xJSHXb%%q3h!IXC3)%3p$xAU($Yk6CJri}t=j$ykl`bHEvC
zN-nG{+m9qN*0sU*iryGm$F6z~!+~07D;FVaC}N#*@nt6A?NI-i4n86qRXa
z`b?Xc5uJi+1U@glf-N5kZ13a`NkN|*2-E}O0S=kvb@{%$8Sn~3Ee-M!B
z`tB|stro^gO@2sQ4{TBsvl>s*HLURkV-tv=`)ZnY*vMf}Nt+MsM&R@E*FiD$Ml=}C
z*K(=mtReyBvZhoT;DNK>BnP~|NcUE_5$Nko9|iqa;+afeCT?G)_d<|
z?8Ll(e!77KDt!~UVlLR%Y2Vm5nR^e{5vJcID`1~PZnP5Gdr4P`O2
zO4D9XCSsd|?+&0GO0Q#J9?20@jw*W~mO4)C7u;!;f-O;miaMiL-qCWS_YEM)>dqGK
z#AS|Cw4(oeFh8&~FR2atLs7*L+fZ0)pvDgOq(xZYugwiIi~8B&4p$<*Pr|5OTsy;T{%3KcSu0a5^j)5AVaXMkuZFbar|whK
z;HDP-r_buib)bv*WMS3x6@T47MbC@dJgPOc7^Kr>XFw2?UhgF57*w)m?R
zEbqPY%4$yjvaj_zNYaxE)e_*(yTIeKv?(H1LDJA)wM20QOT9F0gX%G&nWI=KG!Hh{G8Nw!-{Ui32hwd*wPr}7n0};w
z6CUP9LRvjmDqpa9C_bKvTW6a0zyj^W`i}QQq^}9)Oq>h$inbJ5cA3eiD$elk;d<2e
ztJe+jA8gGdyzHW_5NL?&yqM|N^N{}Z#E@-R;N2VBbetr?cpB@k#11mhK8r`Y-rhCd
zG#p6NbrphN$l1{RT3_KPIOb-vk{!mAb|qlXLS+52KcE&5I&`5-yQ_@J0j45ZKpFK#
zHr?gf{!YtX$+Rl_Xo>sy#N%TTZU-WpMk3k90$302Cn34xpHh}0oyYdP3jNyRS-aWB
z9hof#l*?D{SV`+lEbuuG&&lFbKd@-W!mz!2Y>xO@^W{ZqSsKNKcL;bR^~>X_s#sFv
zp^c2RA)?s0TZPf*1gh16HKVq2tKx%eqb26L3wWpc>Tql)8SOk=f%nBt7GhDgxyfdS
zIJ-#Lqeb*M7a6)7Q8QfF&Xg7i1U{A9DM1_fE4>g*^a3;zk34u1>%jMTG<29X
zuN9_%EjZANh<;RI)Lod>+-RZnSPmr<&4FweL5ZSRjjr3$h*znP=&Lq451JPx*)PeR`4`F?^cN8kt
z76ROmn0hh!gvS&%L>+a2-uh?YzZDQck3!LI(L|j_$CZA$KCsn
zj|*szP^Bi%k8_Zh@;WJ<%Uqn{=iM<-g~BAbKhqr@5K{E%;+i%Lv0BSd|*{IsSl#@p7^$X0nU=@_Wfb{?ib-t*4LsxGNT(PN#?afNPUyH6!B@
z(Cg%~INT@;e@Q)AI>oP|6}w~RME3&y?c*-B;mthe_)i;=Y4UpFSR3~I>QQ!8-~5(*
z;6nc3Y1TbP(plqtRzxDeXySdoKv)5$Dd53Y7?!BCOVlPBbKi8Y=
zE3SI}VEgfsY2eLCcrPPZxe-*v%eP_;{4{$}`6bnhuy+RF&bI2so&I!W{>s{*H%}My
z&V7oG4`7+L1MV3uC2@|qw;N@1J`(6dQ9OqHqrP}>3~Om^EHWb9Xj&=>G0Tg_MVmrx
z5CP+XT8`V^a^O!tf>!$Etsh7BQe<}+HtF28QY|-V=mxf{UvnY`?)2nY7RHG{>b_pV$;``@2|h5<#m(!UD>B}gFYC1
zPjz)W+mYon9RnFc;vdCX;c9iz2aR|3r5BPbqOtYW{`*Dt->kp?t2)R&Hyhvx@Y(vK
z*Xb$FjLdq@_2ISfOYmvFInd|s4@W0YC{_YeC&W4Bjr;%Tq~ae(83H9wzP-<-6tG{$
zkw1szPNEu4#s*F%+(r&2pB;dOiJ6O@2}sYxslv>{&BVgZ%udV1%+17f%rQ;%|2SCN
z8k>XM|7(YI3yXwL2hx9Jurmg6OPDK}I11T1+ZdbMm93@mK4Otef?
sS_!wG=HLF^T+PJ6(cIPspdcbf&&CR*IRF3v

literal 0
HcmV?d00001


From 0ee68b07712c854d2ee98a13f7974202ca55efbb Mon Sep 17 00:00:00 2001
From: Jan Slifka 
Date: Thu, 2 May 2019 16:30:15 +0200
Subject: [PATCH 16/26] Add elm TEA

---
 tutorials/10_elm-tea.md | 291 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 291 insertions(+)
 create mode 100644 tutorials/10_elm-tea.md

diff --git a/tutorials/10_elm-tea.md b/tutorials/10_elm-tea.md
new file mode 100644
index 0000000..2cc8c84
--- /dev/null
+++ b/tutorials/10_elm-tea.md
@@ -0,0 +1,291 @@
+# Elm - The Elm Architecture
+
+## Elm program
+
+Elm program is set up using [Browser](https://package.elm-lang.org/packages/elm/browser/latest/Browser) module from [elm/browser](https://package.elm-lang.org/packages/elm/browser/latest/) package. There are several functions to do that based on the use case.
+
+- `sandbox` - Program that interacts with the user input but cannot communicate with the outside world.
+- `element` - HTML element controlled by Elm that can talk to the outside world (e.g. HTTP requests). Can be embedded into a JavaScript project.
+- `document` - Controls the whole HTML document, view controls `` and `<body>` elements.
+- `application` - Creates single page application, Elm controls not only the whole document but also Url changes.
+
+
+## Forms
+
+Form elements are created the same way as other HTML elements using functions from [Html](https://package.elm-lang.org/packages/elm/html/latest/Html) module and attributes from [Html.Attributes](https://package.elm-lang.org/packages/elm/html/latest/Html-Attributes) module from [elm/html](https://package.elm-lang.org/packages/elm/html/latest/) package.
+
+We can use `onInput` from [Html.Events](https://package.elm-lang.org/packages/elm/html/latest/Html-Events) module to detect input events and create a message for our update function.
+
+The loop is the following:
+- user changes the value in an input field
+- a new message is created
+- the update function is called with the message and it updates the model with the new value
+- input field is re-rendered with the new value
+
+
+Here is a simple example with a single input field:
+
+```elm
+import Browser
+import Html exposing (Html, input)
+import Html.Attributes exposing (placeholder, value)
+import Html.Events exposing (onInput)
+
+main = Browser.sandbox { init = init, update = update, view = view }
+
+type Msg = NameChanged String
+
+type alias Model = { name : String }
+
+init : Model
+init =
+    { name = "" }
+
+update : Msg -> Model -> Model
+update msg model =
+    case msg of
+        NameChanged newName ->
+            { model | name = newName }
+
+view : Model -> Html Msg
+view model =
+    input
+        [ placeholder "Your name"
+        , value model.name
+        , onInput NameChanged ]
+        []
+```
+
+When you need more complex forms in your application, there are packags to handle forms like [etaque/elm-form](https://package.elm-lang.org/packages/etaque/elm-form/latest/).
+
+
+## JSON
+
+It is very common to use JSON format when communicating with different APIs. In JavaScript, JSON is usually turned into a JavaScript object and used within the application. However, this is not the case in Elm since we have a strong type system. Before we can use JSON data, we need to convert it into a type defined in Elm. There is the [elm/json](https://package.elm-lang.org/packages/elm/json/latest/) package for that.
+
+
+### Decoders
+
+Elm use decoders for that. It is a declarative way how to define what should be in the JSON and how to convert it into Elm types. Functions for that are defined in [Json.Decode](https://package.elm-lang.org/packages/elm/json/latest/Json-Decode) module.
+
+For example, we have this JSON representing a TODO:
+
+```json
+{
+    "id": 24,
+    "label": "Finish the home",
+    "completed": false
+}
+```
+
+To get the `label` field, we can define a decoder like this:
+
+```elm
+import Json.Decode as D exposing (Decoder)
+
+labelDecoder : Decoder String
+labelDecoder =
+    D.field "label" D.string
+```
+
+There are functions to decode other primitives, like `bool` or `int`. However, we usually need more than just one field. We can combine decoders using `map` functions from `Json.Decode` module, e.g. `map3`.
+
+```elm
+map3 :
+    (a -> b -> c -> value)
+    -> Decoder a
+    -> Decoder b
+    -> Decoder c
+    -> Decoder value
+```
+
+We can then define our own type for TODO and a decoder.
+
+```elm
+import Json.Decode as D exposing (Decoder)
+
+type alias Todo =
+    { id : Int
+    , label : String
+    , completed : Bool
+    }
+
+todoDecoder : Decoder Todo
+todoDecoder =
+    D.map3 Todo
+        (D.field "id" D.int)
+        (D.field "name" D.string)
+        (D.field "completed" D.bool)
+```
+
+There is a package [NoRedInk/elm-json-decode-pipeline](https://package.elm-lang.org/packages/NoRedInk/elm-json-decode-pipeline/latest) for more convenient JSON decoder. It is especially useful for large and more complex objects. We could rewrite the previous example using pipeline:
+
+```elm
+import Json.Decode as D exposing (Decoder)
+import Json.Decode.Pipeline exposing (required)
+
+type alias Todo =
+    { id : Int
+    , label : String
+    , completed : Bool
+    }
+
+todoDecoder : Decoder Todo
+todoDecoder =
+    D.succeed Todo
+        |> required "id" D.int
+        |> required "name" D.string
+        |> required "completed" D.bool
+```
+
+It is not that big change in this case, however, we only have `map8` function in `Json.Decode` so this library comes handy if we need more. Moreover, it has other functions to define for example [optional](https://package.elm-lang.org/packages/NoRedInk/elm-json-decode-pipeline/latest/Json-Decode-Pipeline#optional) or [hardcoded](https://package.elm-lang.org/packages/NoRedInk/elm-json-decode-pipeline/latest/Json-Decode-Pipeline#hardcoded) values.
+
+
+### Encoders
+
+When we want to send something to an API we need to do the opposite -- turn the Elm value into JSON value. We use functions form [Json.Encode](https://package.elm-lang.org/packages/elm/json/latest/Json-Encode) package for that. There is a type called `Value` which represents a JavaScript value and functions to convert Elm primitives, lists and objects into `Value` type.
+
+Here's an example using the TODO from decoders example.
+
+```elm
+import Json.Encode as E
+
+type alias Todo =
+    { id : Int
+    , label : String
+    , completed : Bool
+    }
+
+encodeTodo : Todo -> E.Value
+encodeTodo todo =
+    E.object
+        [ ( "id", E.int todo.id )
+        , ( "label", E.string todo.label )
+        , ( "completed", E.bool todo.completed )
+        ]
+```
+
+The object is representend as a list of key value tuples.
+
+
+## Http
+
+There is [Http](https://package.elm-lang.org/packages/elm/http/latest/Http) module in [elm/http](https://package.elm-lang.org/packages/elm/http/latest/) package for making HTTP requests in Elm. The functions creating requests create a command for Elm runtime which defines what request should be made, what is the expected response and what message should be send to update function when the request is done.
+
+Here is an example for getting TODO using the decoder defined in previous section.
+
+```elm
+import Http
+
+type Msg = GotTodo (Result Http.Error Todo)
+
+getTodo : Cmd Msg
+getTodo =
+    Http.get
+        { url = "http://example.com/todo"
+        , expect = Http.expectJson GotTodo todoDecoder
+        }
+```
+
+The function `getTodo` creates a command with HTTP request that expect JSON to be returned and uses `todoDecoder` to get `Todo` type form the returned JSON. Once the request is finished, we get `GotTodo` message containing the `Result` with either `Http.Error` if the request failed or `Todo` if the request was successful.
+
+There are other functions we can use for expected response like `expectString` to get the string as is or `expectWhatever` when we don't really care about the response as long as it's ok.
+
+When we want to do a POST request we also need to define the body. Here's an example of posting TODO to the server, using encoder function from previous section.
+
+```elm
+import Http
+
+type Msg = TodoSaved (Result Http.Error ())
+
+postTodo : Todo -> Cmd Msg
+postTodo todo =
+    Http.post
+        { url = "http://example.com/todo"
+        , body = Http.jsonBody <| encodeTodo todo
+        , expect = Http.expectWhatever TodoSaved
+        }
+```
+
+Of course, we can send different types of body, not just JSON, e.g., `stringBody` for plain string or `emptyBody` when we don't want to send anything.
+
+When we want to do a different type of request than GET and POST or we want to set headers, we need to use `Http.request` function (`Http.post` and `Http.get` are actually just a shorthand for calling `Http.request`).
+
+```elm
+request :
+    { method : String
+    , headers : List Header
+    , url : String
+    , body : Body
+    , expect : Expect msg
+    , timeout : Maybe Float
+    , tracker : Maybe String
+    }
+    -> Cmd msg
+```
+
+
+## Subscriptions
+
+[Subscirptions](https://package.elm-lang.org/packages/elm/core/latest/Platform-Sub) are used to tell Elm that you want to be informed if something happend (e.g., web socket message or clock tick).
+
+
+Here's an example of subscriptions defining that a message `Tick` with current time should be send to update function every 1000 milliseconds.
+
+
+```elm
+import Time
+
+
+type Msg = Tick Time.Posix
+
+
+subscriptions : Model -> Sub Msg
+subscriptions model =
+    Time.every 1000 Tick
+```
+
+
+## Random
+
+There is a [Random](https://package.elm-lang.org/packages/elm/random/latest/Random) module in [elm/random](https://package.elm-lang.org/packages/elm/random/latest/) package for generating pseudo-random values in Elm. It defines a type called `Generator` which can be think of as a recipe for generating random values.
+
+Here is a definition of genrator for random numbers between 1 and 4.
+
+```elm
+import Random exposing (Generator)
+
+randomGrade : Generator Int
+randomGrade =
+    Random.int 1 4
+```
+
+If we want to use it, we have two options. The first is using `generate` function to create a command. Then we got the generated value back with a defined message to our update function. Here's an example:
+
+
+```elm
+import Random exposing (Generator)
+
+
+type Msg = NewGrade Int
+
+generateGrade : Cmd
+generateGrade =
+    Random.generate NewGrade generateGrade
+```
+
+The other option is to use `step` functions. It requires the generator and also a `Seed` and returns a tuple with generated value and a new `Seed`. The initial seed can be hardcoded (but then the generated values are same each time we run the application), send to Elm via Flags (we'll cover those in the next lesson) or using `generate` function first to get the seed and then use it to generate other random values.
+
+```elm
+import Random exposing (Seed)
+
+
+generateGrade : Seed -> (Int, Seed)
+generateGrade seed =
+    Random.step randomGrade seed
+```
+
+## Further Reading
+
+- [Commands and Subscriptions](https://guide.elm-lang.org/effects/)
+- [Elm Europe 2017 - Evan Czaplicki - The life of a file](https://www.youtube.com/watch?v=XpDsk374LDE)
\ No newline at end of file

From b5c9048b6cb710c452c2730114baf26cd95b2d17 Mon Sep 17 00:00:00 2001
From: Jan Slifka <jan.slifka@gmail.com>
Date: Fri, 3 May 2019 13:41:20 +0200
Subject: [PATCH 17/26] Add link to examples to Elm TEA

---
 tutorials/10_elm-tea.md | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/tutorials/10_elm-tea.md b/tutorials/10_elm-tea.md
index 2cc8c84..c3e70eb 100644
--- a/tutorials/10_elm-tea.md
+++ b/tutorials/10_elm-tea.md
@@ -271,7 +271,7 @@ type Msg = NewGrade Int
 
 generateGrade : Cmd
 generateGrade =
-    Random.generate NewGrade generateGrade
+    Random.generate NewGrade randomGrade
 ```
 
 The other option is to use `step` functions. It requires the generator and also a `Seed` and returns a tuple with generated value and a new `Seed`. The initial seed can be hardcoded (but then the generated values are same each time we run the application), send to Elm via Flags (we'll cover those in the next lesson) or using `generate` function first to get the seed and then use it to generate other random values.
@@ -287,5 +287,6 @@ generateGrade seed =
 
 ## Further Reading
 
+- [Examples from this lesson](https://github.com/MI-AFP/elm-examples)
 - [Commands and Subscriptions](https://guide.elm-lang.org/effects/)
-- [Elm Europe 2017 - Evan Czaplicki - The life of a file](https://www.youtube.com/watch?v=XpDsk374LDE)
\ No newline at end of file
+- [Elm Europe 2017 - Evan Czaplicki - The life of a file](https://www.youtube.com/watch?v=XpDsk374LDE)

From 985fa5543fedba633d50fbcfbf22379b0c1f98cd Mon Sep 17 00:00:00 2001
From: Jan Slifka <jan.slifka@gmail.com>
Date: Fri, 10 May 2019 07:56:08 +0200
Subject: [PATCH 18/26] Add Elm Web Apps

---
 tutorials/11_elm-building-web-apps.md | 346 ++++++++++++++++++++++++++
 1 file changed, 346 insertions(+)
 create mode 100644 tutorials/11_elm-building-web-apps.md

diff --git a/tutorials/11_elm-building-web-apps.md b/tutorials/11_elm-building-web-apps.md
new file mode 100644
index 0000000..722a5e8
--- /dev/null
+++ b/tutorials/11_elm-building-web-apps.md
@@ -0,0 +1,346 @@
+# Elm - Building Web Applications
+
+## Webpack
+
+[Webpack](https://webpack.js.org) is a module bundler for JavaScript applications. It builds a dependency graph of source modules and creates static assets. It uses different loaders for different file types, e.g., to convert new EcmaScript syntax into the one supported by browsers or to convert Sass to CSS. It can also minify those assets.
+
+Besides other loaders, there is also [elm-webpack-laoder](https://github.com/elm-community/elm-webpack-loader). If you require an Elm module from JavaScript code, it will use `elm make` under the hood to build it.
+
+Here's an example of configuration:
+
+```js
+module.exports = {
+  module: {
+    rules: [{
+      test: /\.elm$/,  // use the loader only for elm files
+      exclude: [/elm-stuff/, /node_modules/],  // exclude project dependencies
+      use: {
+        loader: 'elm-webpack-loader',
+        options: {}
+      }
+    }]
+  }
+};
+```
+
+## Initializing Elm App
+
+Till now, we used `elm reactor` to run our Elm applications. However, we can't use that in a production environment. If we try to build the Todo list form [elm-examples](https://github.com/MI-AFP/elm-examples) using `elm make`, we can look into the generated JavaScript, how the app is initialized. At the very end of the document, there is the following line of code:
+
+```js
+var app = Elm.Todos.init({ node: document.getElementById("elm-f0111bc4e658d0f98db96260c16f7e49") });
+```
+
+Todos is the name of the module (it was in `src/Todos.elm`). The `init` function is called to initialize the app. We used [Browser.element](https://package.elm-lang.org/packages/elm/browser/latest/Browser#element), therefore there is `node` in init arguments.
+
+When we are using webpack, we can do something very similar ourselves. We need a JavaScript entrypoint, e.g., `index.js`. We can require an Elm module from there, and the elm-webpack-loader will take care of compiling Elm into JavaScript. Then, we can call the init function.
+
+```js
+// index.js
+var program = require('src/Todos.elm');
+
+var app = program.Elm.Todos.init({
+    node: document.getElementById('node-id')
+});
+```
+
+We also need to create the element in our HTML structure. In case we would use [Browswer.document](https://package.elm-lang.org/packages/elm/browser/latest/Browser#document) or [Browser.application](https://package.elm-lang.org/packages/elm/browser/latest/Browser#application) instead, we don't need to specify the node since it will load into the whole document body.
+
+
+## JavaScript Interop
+
+In real-world applications, we usually need at least some interoperability with JavaScript. There are two options in Elm -- using flags or ports.
+
+### Flags
+
+Flags are used to pass some values when initializing the Elm app. For example, we can send a random initial seed generated using JavaScript. The object we pass to the `init` function can have another property called `flags`.
+
+```js
+// index.js
+var program = require('src/Todos.elm');
+
+var app = program.Elm.Todos.init({
+    node: document.getElementById('node-id'),
+    flags: Math.random()
+});
+```
+
+Then, on the Elm side, we receive these flags as the first argument of `init` function.
+
+```elm
+init : Float -> (Model, Cmd Msg)
+init randomNumber =
+    ...
+```
+
+The flags can be one of the following types:
+
+- Basic types (`Bool`, `Int`, `Float`, `String`)
+- `Maybe`
+- Lists (`List`, `Array`)
+- Tuples
+- Records
+- `Json.Decode.Value`
+
+If you use anything else than `Json.Decode.Value` and provide an incorrect type, you get an error on the JavaScript side. Therefore it is safer to use `Json.Decode.Value`, define a decoder and handle possible errors on the Elm side when the decoding fails.
+
+### Ports
+
+While Flags are used for sending initial values to the Elm app, Ports are used for sending messages between JavaScript and Elm. The communication is not based on request/response like in HTTP though. We only have one-way messages send from Elm to JavaScript or vice versa.
+
+#### Outgoing Messages
+
+Sending messages from Elm to JavaScript is realized through commands. We need to define the `port` using a `port module`.
+
+A common example is using localStorage, so for example, here we want to save user data into localStorage.
+
+```elm
+port module Ports exposing (saveUser)
+
+import Json.Encode as E
+
+port saveUser : E.Value -> Cmd msg
+```
+
+The port declaration is similar to a function. However, it starts with a keyword `port` and has no function body. The module where we define ports must be a `port module`.
+
+Once we define the port for outgoing messages, we should subscribe to it on the JavaScript side after the app initialization.
+
+```js
+var program = require('src/Todos.elm');
+
+var app = program.Elm.Todos.init({
+    node: document.getElementById('node-id')
+});
+
+app.ports.saveUser.subscribe(function(data) {
+    localStorage.setItem('user', JSON.stringify(data));
+});
+```
+
+And then we can create a command using the port in our update function.
+
+```elm
+import Ports exposing (saveUser)
+
+
+update msg model =
+    case msg of
+        SaveUser user ->
+            (model, saveUser <| encdeUser user)
+        ...
+```
+
+#### Incoming messages
+
+Sending messages from JavaScript to Elm is realized through Subscriptions. We need to define the port but this time slightly different again.
+
+For example, we want to send user data back to the Elm app.
+
+```elm
+port module Ports exposing (gotUser)
+
+import Json.Encode as E
+
+port gotUser : (E.Value -> msg) -> Sub msg
+```
+
+Then in our subscriptions function, we need to subscribe to use the port with proper message constructor.
+
+```elm
+import Json.Encode as E
+import Ports exposing (gotUser)
+
+
+type Msg
+    = GotUser E.Value
+
+subscriptions model =
+    gotUser GotUser
+
+```
+
+On JavaScript side, you can send a message to the Elm app using the port.
+
+```js
+var program = require('src/Todos.elm');
+
+var app = program.Elm.Todos.init({
+    node: document.getElementById('node-id')
+});
+
+
+app.ports.gotUser.send(userData);
+```
+
+## Single Page Applications
+
+When we are building real applications, we usually need more than one screen. We also want to have different URLs for different screens, so it is, for example, easier to send links to the application. We need to handle navigation and URL parsing.
+
+### Navigation
+
+We use [Browser.application](https://package.elm-lang.org/packages/elm/browser/latest/Browser#application) which avoids loading new HTML when URL changes. It has more complex annotation:
+
+```elm
+application :
+  { init : flags -> Url -> Key -> ( model, Cmd msg )
+  , view : model -> Document msg
+  , update : msg -> model -> ( model, Cmd msg )
+  , subscriptions : model -> Sub msg
+  , onUrlRequest : UrlRequest -> msg
+  , onUrlChange : Url -> msg
+  }
+  -> Program flags model msg
+```
+
+The `init` function now gets not only flags but also initial `Url` and navigation `Key` that is needed for changing URL using navigation commands.
+
+When a link is clicked within the application, it is intercepted as `UrlRequest`, the message is created using `onUrlRequest` and sent to the update function.
+
+When the URL is changed, the message is created using `onUrlChange` and sent to the update function.
+
+Here is a simple example from [An Introduction to Elm](https://guide.elm-lang.org/webapps/navigation.html).
+
+```elm
+import Browser
+import Browser.Navigation as Nav
+import Html exposing (..)
+import Html.Attributes exposing (..)
+import Url
+
+
+
+-- MAIN
+
+
+main : Program () Model Msg
+main =
+  Browser.application
+    { init = init
+    , view = view
+    , update = update
+    , subscriptions = subscriptions
+    , onUrlChange = UrlChanged
+    , onUrlRequest = LinkClicked
+    }
+
+
+
+-- MODEL
+
+
+type alias Model =
+  { key : Nav.Key
+  , url : Url.Url
+  }
+
+
+init : () -> Url.Url -> Nav.Key -> ( Model, Cmd Msg )
+init flags url key =
+  ( Model key url, Cmd.none )
+
+
+
+-- UPDATE
+
+
+type Msg
+  = LinkClicked Browser.UrlRequest
+  | UrlChanged Url.Url
+
+
+update : Msg -> Model -> ( Model, Cmd Msg )
+update msg model =
+  case msg of
+    LinkClicked urlRequest ->
+      case urlRequest of
+        Browser.Internal url ->
+          ( model, Nav.pushUrl model.key (Url.toString url) )
+
+        Browser.External href ->
+          ( model, Nav.load href )
+
+    UrlChanged url ->
+      ( { model | url = url }
+      , Cmd.none
+      )
+
+
+
+-- SUBSCRIPTIONS
+
+
+subscriptions : Model -> Sub Msg
+subscriptions _ =
+  Sub.none
+
+
+
+-- VIEW
+
+
+view : Model -> Browser.Document Msg
+view model =
+  { title = "URL Interceptor"
+  , body =
+      [ text "The current URL is: "
+      , b [] [ text (Url.toString model.url) ]
+      , ul []
+          [ viewLink "/home"
+          , viewLink "/profile"
+          , viewLink "/reviews/the-century-of-the-self"
+          , viewLink "/reviews/public-opinion"
+          , viewLink "/reviews/shah-of-shahs"
+          ]
+      ]
+  }
+
+
+viewLink : String -> Html msg
+viewLink path =
+  li [] [ a [ href path ] [ text path ] ]
+```
+
+
+### URL Parsing
+
+In the previous example, we used Url as is. However, we can use [Url.Parser](https://package.elm-lang.org/packages/elm/url/latest/Url-Parser) module from [elm/url](https://package.elm-lang.org/packages/elm/url/latest/) package to parse the URL into useful Elm types.
+
+
+Here's an example form the documentation converting different routes with parameters into `Route` type.
+
+```elm
+type Route
+  = Topic String
+  | Blog Int
+  | User String
+  | Comment String Int
+
+route : Parser (Route -> a) a
+route =
+  oneOf
+    [ map Topic   (s "topic" </> string)
+    , map Blog    (s "blog" </> int)
+    , map User    (s "user" </> string)
+    , map Comment (s "user" </> string </> s "comment" </> int)
+    ]
+
+-- /topic/wolf           ==>  Just (Topic "wolf")
+-- /topic/               ==>  Nothing
+
+-- /blog/42               ==>  Just (Blog 42)
+-- /blog/wolf             ==>  Nothing
+
+-- /user/sam/             ==>  Just (User "sam")
+-- /user/bob/comment/42  ==>  Just (Comment "bob" 42)
+-- /user/tom/comment/35  ==>  Just (Comment "tom" 35)
+-- /user/                 ==>  Nothing
+```
+
+
+## Further Reading
+
+- [elm-webpack-boilerplate](https://github.com/MI-AFP/elm-webpack-boilerplate)
+- [Webpack Concepts](https://webpack.js.org/concepts)
+- [Web Apps · An Introduction to Elm](https://guide.elm-lang.org/webapps/)
+- [Elm Europe 2017 - Richard Feldman - Scaling Elm Apps](https://www.youtube.com/watch?v=DoA4Txr4GUs)

From 1fe232ddf1d9d41d8508bd65856e9a5a39801b64 Mon Sep 17 00:00:00 2001
From: Jan Slifka <jan.slifka@gmail.com>
Date: Thu, 16 May 2019 23:58:01 +0200
Subject: [PATCH 19/26] Add Elm Real World Use Cases

---
 tutorials/12_elm-real-world-use-cases.md | 297 +++++++++++++++++++++++
 1 file changed, 297 insertions(+)
 create mode 100644 tutorials/12_elm-real-world-use-cases.md

diff --git a/tutorials/12_elm-real-world-use-cases.md b/tutorials/12_elm-real-world-use-cases.md
new file mode 100644
index 0000000..06578c5
--- /dev/null
+++ b/tutorials/12_elm-real-world-use-cases.md
@@ -0,0 +1,297 @@
+# Elm - Real World Use Cases
+
+## Complex Forms
+
+Sometimes, we need more complex forms in our application. Using common Elm approach with a message per input field can result in a lot of boilerplate code. Luckily there are some libraries to help with that. One of them is [etaque/elm-form](https://package.elm-lang.org/packages/etaque/elm-form/latest).
+At the price of losing some type safety (field names are using strings), we get nice validation API similar to JSON decoders API with some basic validation and a possibility to create our own, support for nested fields and lists.
+
+First, we need to define a type that should be represented in our form, e.g., a person.
+
+```elm
+type alias Person =
+    { name : String
+    , age : Int
+    }
+```
+
+Then, we define validation (notice that the API is basically the same as using `Json.Decode` module):
+
+```elm
+import Form.Validate as Validate exposing (..)
+
+
+personValidation : Validation CustomFormError Person
+personValidation =
+    Validate.map2 Person
+        (Validate.field "name" Validate.string)
+        (Validate.field "age" Validate.int)
+```
+
+After that, we can initialize the form, either empty:
+
+```elm
+initPersonForm : Form CustomFormError Person
+initPersonForm =
+    Form.initial [] personValidation
+```
+
+Or using existing person data (notice that the API for the initial data is basically the same as using `Json.Encode` module):
+
+```elm
+import Form.Field as Field
+
+
+initPersonFormWithPerson : Person -> Form CustomFormError Person
+initPersonFormWithPerson person=
+    let
+        initials =
+            [ ( "name", Field.string person.name )
+            , ( "age", Field.int person.age )
+            ]
+    in
+    Form.initial initials personValidation
+```
+
+The library comes with functions for generating views. We need to create our own functions for converting form errors to string (because we can add our own errors). Also, all fields are represented as string or bool (for checkboxes), so we cannot really use for example input type number.
+
+```elm
+import Form exposing (Form)
+import Form.Input as Input
+
+
+viewForm : Form () Person -> Html Form.Msg
+viewForm form =
+    let
+        viewError field =
+            case field.liveError of
+                Just error ->
+                    p [ class "error" ] [ text (errorToString error) ]
+
+                Nothing ->
+                    text ""
+
+        nameField =
+            Form.getFieldAsString "name" form
+
+        ageField =
+            Form.getFieldAsString "age" form
+    in
+    form [ onSubmit Form.Submit ]
+        [ label [] [ text "name" ]
+        , Input.textInput nameField []
+        , viewError nameField
+        , label [] [ text "age" ]
+        , Input.textInput ageField []
+        , viewError ageField
+        , button [ type_ "submit" ] [ text "Submit" ]
+        ]
+```
+
+The last thing is handling Form messages. If the message is `Form.Submit`, and the form is valid, we want to handle submitting the form. To get the output, there is a function `Form.getOutput`, it either returns `Just` the type in the form or `Nothing` if the form contains invalid values.
+
+We want to use `Form.update` function for other messages to update the form model.
+
+```elm
+type Msg
+    = FormMsg Form.Msg
+
+update : Msg -> Model -> ( Model, Cmd Msg )
+update msg model =
+    case msg of
+        FormMsg formMsg ->
+            case ( formMsg, Form.getOutput model.personForm ) of
+                ( Form.Submit, Just form ) ->
+                    -- The output is the original type (Person in this case)
+                    -- We get it only if the validation passes
+                    let
+                        _ =
+                            Debug.log "Submit form" form
+                    in
+                    ( model, Cmd.none )
+
+                _ ->
+                    ( { model | personForm = Form.update personValidation formMsg model.personForm }
+                    , Cmd.none
+                    )
+```
+
+
+## SVG
+
+Elm has a package [elm/svg](https://package.elm-lang.org/packages/elm/svg/latest/) for creating SVG images in Elm. The API looks like corresponding packages for Html. Now we have `Svg` module with functions for SVG elements (e.g., `rect` or `circle`), `Svg.Attributes` for the attributes used by SVG elements (e.g., `strokeWidth` or `x`) and `Svg.Events` for JavaScript events, same as `Html.Events`.
+
+SVG is good for visualisations. We can start at [SVG element reference](https://developer.mozilla.org/en-US/docs/Web/SVG/Element) to find the elements we need. Here's an example from package documentation of drawing a rounded rectangle:
+
+```elm
+import Svg exposing (..)
+import Svg.Attributes exposing (..)
+
+
+roundRect =
+    svg
+      [ width "120", height "120", viewBox "0 0 120 120" ]
+      [ rect [ x "10", y "10", width "100", height "100", rx "15", ry "15" ] [] ]
+```
+
+
+## Files
+
+Since Elm 0.19 there is [elm/file](https://package.elm-lang.org/packages/elm/file/latest/) package for working with files. We can use it for allowing users to download a file generated in Elm, or for uploading files.
+
+
+Example of download a markdown file generated from a string in Elm:
+
+```elm
+import File.Download as Download
+
+save : String -> Cmd msg
+save markdown =
+  Download.string "draft.md" "text/markdown" markdown
+```
+
+Example of file select:
+
+```elm
+import File.Select as Select
+
+type Msg
+  = ImagesRequested
+  | ImagesLoaded File (List File)
+
+requestImages : Cmd Msg
+requestImages =
+  Select.files ["image/png","image/jpg"] ImagesLoaded
+```
+
+If we get `File` from the previous example, we can send it to the server using [elm/http](https://package.elm-lang.org/packages/elm/http/2.0.0/) package. There is a [fileBody](https://package.elm-lang.org/packages/elm/http/latest/Http#fileBody) function for that. We can explore [examples](https://github.com/elm/file/tree/master/examples) in elm/file package to see how it works.
+
+
+## Graph QL
+
+There is a couple of packages for working with GraphQL in Elm.
+
+### [dillonkearns/elm-graphql](https://github.com/dillonkearns/elm-graphql/tree/4.2.1)
+
+This is one of the most popular GraphQL packages for Elm. It comes with a command-line code generator to create type-safe Elm code for GraphQL endpoint. Then, we get type-safe GraphQL queries. It is also eliminating GraphQL features in favour of Elm language constructs.
+
+Here's an example from the documentation.
+
+The GraphQL query:
+
+```graphql
+query {
+  human(id: "1001") {
+    name
+    homePlanet
+  }
+}
+```
+
+It looks like this in the Elm code (`StarWars` packages are auto-generated using the command line tool):
+
+```elm
+import Graphql.Operation exposing (RootQuery)
+import Graphql.SelectionSet as SelectionSet exposing (SelectionSet)
+import StarWars.Object.Human as Human
+import StarWars.Query as Query
+import StarWars.Scalar exposing (Id(..))
+
+
+query : SelectionSet (Maybe Human) RootQuery
+query =
+    Query.human { id = Id "1001" } humanSelection
+
+
+type alias Human =
+    { name : String
+    , homePlanet : Maybe String
+    }
+
+
+humanSelection : SelectionSet Human StarWars.Object.Human
+humanSelection =
+    SelectionSet.map2 Human
+        Human.name
+        Human.homePlanet
+```
+
+### [jamesmacaulay/elm-graphql](https://package.elm-lang.org/packages/jamesmacaulay/elm-graphql/latest)
+
+This is another popular package for GraphQL. It provides an interface for working with GraphQL queries and schemas in Elm. Building requests works similarly as JSON decoders.
+
+Here's an example from the documentation, we need to define the types by ourselves:
+
+```elm
+type alias Photo =
+    { url : String
+    , caption : String
+    }
+
+type alias User =
+    { name : String
+    , photos : List Photo }
+```
+
+Then we build a query document using the library:
+
+```elm
+userQuery : Document Query User { vars | userID : String }
+userQuery =
+    let
+        userIDVar =
+            Var.required "userID" .userID Var.id
+
+        photo =
+            object Photo
+                |> with (field "url" [] string)
+                |> with (field "caption" [] string)
+
+        user =
+            object User
+                |> with (field "name" [] string)
+                |> with (field "photos" [] (list photo))
+
+        queryRoot =
+            extract
+                (field "user"
+                    [ ( "id", Arg.variable userIDVar ) ]
+                    user
+                )
+    in
+        queryDocument queryRoot
+```
+
+The document would be encoded into this string:
+
+```graphql
+query ($userID: ID!) {
+  user(id: $userID) {
+    name
+    photos {
+      url
+      caption
+    }
+  }
+}
+```
+
+
+## WebSockets
+
+There is a package [elm-lang/websockets](https://package.elm-lang.org/packages/elm-lang/websocket/latest), however, it was **not yet updated** to Elm 0.19. It [should be updated](https://discourse.elm-lang.org/t/updating-packages/1771) at some point in the future. There is a 3rd party package [billstclair/elm-websocket-client](https://package.elm-lang.org/packages/billstclair/elm-websocket-client/latest/) that is converting the original package to Elm 0.19.
+
+The other option is to [use ports](https://stackoverflow.com/a/52569683/2492795) and to implement WebSocket interactions on the JavaScript side.
+
+
+## Materials
+
+- [Complex Form Example](https://github.com/MI-AFP/elm-examples/tree/master/form)
+- [SVG Clock Example](https://github.com/MI-AFP/elm-examples/tree/master/clock)
+
+## Further Reading
+
+- [SVG: Scalable Vector Graphics](https://developer.mozilla.org/en-US/docs/Web/SVG)
+- [Line Charts - A library for plotting line charts in SVG. Written in all Elm.](https://github.com/terezka/line-charts)
+- [Working with Files](https://elm-lang.org/blog/working-with-files)
+- [Type-Safe & Composable GraphQL in Elm](https://medium.com/open-graphql/type-safe-composable-graphql-in-elm-b3378cc8d021)
+- [Elm Port Examples](https://github.com/MattCheely/elm-port-examples)

From d9b660369d0c9f5cbc057dba21053779a363b832 Mon Sep 17 00:00:00 2001
From: Jan Slifka <jan.slifka@gmail.com>
Date: Fri, 17 May 2019 00:04:08 +0200
Subject: [PATCH 20/26] Update links to materials in Elm tutorials

---
 tutorials/09_elm-intro.md                | 10 +++++-----
 tutorials/10_elm-tea.md                  | 10 +++++++---
 tutorials/11_elm-building-web-apps.md    | 12 ++++++++----
 tutorials/12_elm-real-world-use-cases.md |  4 ++--
 4 files changed, 22 insertions(+), 14 deletions(-)

diff --git a/tutorials/09_elm-intro.md b/tutorials/09_elm-intro.md
index f1cb312..0108720 100644
--- a/tutorials/09_elm-intro.md
+++ b/tutorials/09_elm-intro.md
@@ -81,7 +81,7 @@ Reason is a new syntax and toolchain based on OCaml programing language created
 
 ## Elm REPL
 
-If you have Elm installed, you can run Elm REPL by `elm repl` command. It is like `ghci` for Elm.
+If we have Elm installed, we can run Elm REPL by `elm repl` command. It is like `ghci` for Elm.
 
 ```
 $ elm repl
@@ -420,7 +420,7 @@ bio (name, age) = name ++ " is " ++ (String.fromInt age) ++ " years old."
 ```
 
 
-Elm has a limit on the maximum number of items in the tuple to be 3. If you need more, you should use a record or your own custom type.
+Elm has a limit on the maximum number of items in the tuple to be 3. If we need more, we should use a record or our own custom type.
 
 ```
 > vector4 = (4, 10, 12, 3)
@@ -817,9 +817,9 @@ number: 4
 
 ## Packages
 
-Elm packages are published on [package.elm-lang.org](https://package.elm-lang.org). There is forced [semantic versioning](https://semver.org) for Elm packages. Therefore, you don't have to worry about breaking your application while updating packages.
+Elm packages are published on [package.elm-lang.org](https://package.elm-lang.org). There is forced [semantic versioning](https://semver.org) for Elm packages. Therefore, we don't have to worry about breaking our application while updating packages.
 
-In 2018, Elm 0.19 was released, and not all packages have been updated yet, so you need to check first whether the package is supported in the latest Elm version.
+In 2018, Elm 0.19 was released, and not all packages have been updated yet, so we need to check first whether the package is supported in the latest Elm version.
 
 
 
@@ -899,7 +899,7 @@ view model =
 
 ### Elm Reactor
 
-It is a quick and simple tool to run Elm project during development. Run `elm reactor` in the project root. It starts a server at [http://localhost:8000](http://localhost:8000) where you can navigate to Elm files.
+It is a quick and simple tool to run Elm project during development. Run `elm reactor` in the project root. It starts a server at [http://localhost:8000](http://localhost:8000) where we can navigate to Elm files.
 
 
 ### Elm Make
diff --git a/tutorials/10_elm-tea.md b/tutorials/10_elm-tea.md
index c3e70eb..00f1b0f 100644
--- a/tutorials/10_elm-tea.md
+++ b/tutorials/10_elm-tea.md
@@ -56,7 +56,7 @@ view model =
         []
 ```
 
-When you need more complex forms in your application, there are packags to handle forms like [etaque/elm-form](https://package.elm-lang.org/packages/etaque/elm-form/latest/).
+When we need more complex forms in our application, there are packags to handle forms like [etaque/elm-form](https://package.elm-lang.org/packages/etaque/elm-form/latest/).
 
 
 ## JSON
@@ -227,7 +227,7 @@ request :
 
 ## Subscriptions
 
-[Subscirptions](https://package.elm-lang.org/packages/elm/core/latest/Platform-Sub) are used to tell Elm that you want to be informed if something happend (e.g., web socket message or clock tick).
+[Subscirptions](https://package.elm-lang.org/packages/elm/core/latest/Platform-Sub) are used to tell Elm that we want to be informed if something happend (e.g., web socket message or clock tick).
 
 
 Here's an example of subscriptions defining that a message `Tick` with current time should be send to update function every 1000 milliseconds.
@@ -285,8 +285,12 @@ generateGrade seed =
     Random.step randomGrade seed
 ```
 
+## Materials
+
+- [Examples - TODO List](https://github.com/MI-AFP/elm-examples/tree/master/todo)
+- [Examples - Timer](https://github.com/MI-AFP/elm-examples/tree/master/timer)
+
 ## Further Reading
 
-- [Examples from this lesson](https://github.com/MI-AFP/elm-examples)
 - [Commands and Subscriptions](https://guide.elm-lang.org/effects/)
 - [Elm Europe 2017 - Evan Czaplicki - The life of a file](https://www.youtube.com/watch?v=XpDsk374LDE)
diff --git a/tutorials/11_elm-building-web-apps.md b/tutorials/11_elm-building-web-apps.md
index 722a5e8..255fefc 100644
--- a/tutorials/11_elm-building-web-apps.md
+++ b/tutorials/11_elm-building-web-apps.md
@@ -4,7 +4,7 @@
 
 [Webpack](https://webpack.js.org) is a module bundler for JavaScript applications. It builds a dependency graph of source modules and creates static assets. It uses different loaders for different file types, e.g., to convert new EcmaScript syntax into the one supported by browsers or to convert Sass to CSS. It can also minify those assets.
 
-Besides other loaders, there is also [elm-webpack-laoder](https://github.com/elm-community/elm-webpack-loader). If you require an Elm module from JavaScript code, it will use `elm make` under the hood to build it.
+Besides other loaders, there is also [elm-webpack-laoder](https://github.com/elm-community/elm-webpack-loader). If we require an Elm module from JavaScript code, it will use `elm make` under the hood to build it.
 
 Here's an example of configuration:
 
@@ -82,7 +82,7 @@ The flags can be one of the following types:
 - Records
 - `Json.Decode.Value`
 
-If you use anything else than `Json.Decode.Value` and provide an incorrect type, you get an error on the JavaScript side. Therefore it is safer to use `Json.Decode.Value`, define a decoder and handle possible errors on the Elm side when the decoding fails.
+If we use anything else than `Json.Decode.Value` and provide an incorrect type, we get an error on the JavaScript side. Therefore it is safer to use `Json.Decode.Value`, define a decoder and handle possible errors on the Elm side when the decoding fails.
 
 ### Ports
 
@@ -160,7 +160,7 @@ subscriptions model =
 
 ```
 
-On JavaScript side, you can send a message to the Elm app using the port.
+On JavaScript side, we can send a message to the Elm app using the port.
 
 ```js
 var program = require('src/Todos.elm');
@@ -338,9 +338,13 @@ route =
 ```
 
 
-## Further Reading
+## Materials
 
 - [elm-webpack-boilerplate](https://github.com/MI-AFP/elm-webpack-boilerplate)
+- [Examples - Web Application](https://github.com/MI-AFP/elm-examples/tree/master/webapp)
+
+## Further Reading
+
 - [Webpack Concepts](https://webpack.js.org/concepts)
 - [Web Apps · An Introduction to Elm](https://guide.elm-lang.org/webapps/)
 - [Elm Europe 2017 - Richard Feldman - Scaling Elm Apps](https://www.youtube.com/watch?v=DoA4Txr4GUs)
diff --git a/tutorials/12_elm-real-world-use-cases.md b/tutorials/12_elm-real-world-use-cases.md
index 06578c5..0fdad35 100644
--- a/tutorials/12_elm-real-world-use-cases.md
+++ b/tutorials/12_elm-real-world-use-cases.md
@@ -285,8 +285,8 @@ The other option is to [use ports](https://stackoverflow.com/a/52569683/2492795)
 
 ## Materials
 
-- [Complex Form Example](https://github.com/MI-AFP/elm-examples/tree/master/form)
-- [SVG Clock Example](https://github.com/MI-AFP/elm-examples/tree/master/clock)
+- [Examples - Complex Form](https://github.com/MI-AFP/elm-examples/tree/master/form)
+- [Examples - SVG Clock](https://github.com/MI-AFP/elm-examples/tree/master/clock)
 
 ## Further Reading
 

From 418a746d006d308b384fbf629cabbe8a5946bbcc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marek=20Such=C3=A1nek?=
 <MarekSuchanek@users.noreply.github.com>
Date: Sun, 19 May 2019 20:41:13 +0200
Subject: [PATCH 21/26] Create project-guide.md

---
 project-guide.md | 155 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 155 insertions(+)
 create mode 100644 project-guide.md

diff --git a/project-guide.md b/project-guide.md
new file mode 100644
index 0000000..8bfa6d4
--- /dev/null
+++ b/project-guide.md
@@ -0,0 +1,155 @@
+# Open-Source Project Guide
+
+This guide is part of [MI-AFP](https://github.com/MI-AFP) course of functional programming but brings and summarizes broader ideas what to consider when developing an open-source project, i.e., not necessarily in Haskell or Elm. We try to cover all important aspects and use references to existing posts and guides with more complete descriptions and explanations. If you find anything wrong or missing, feel free to contribute in open-source matter :wink:
+
+## Think Before Coding
+
+When you have ideas or some assignment what to program, you can easily create project and start coding right away. That might go well for some smaller project but sometimes even for tiny utility script you might end up shortly in "no idea" zone.  Usually, it is better if you think first about what you want to accomplish, how it can be done, and then setup some productive enviroment for work itself.
+
+### Requirements and expectations
+
+At first, do a mindmap (it is really helpful tool for creativity) or a list of things that your project should do in terms of functionality and its behaviour and look. In software engineering, there are functional and non-functional requirements. Functional are trivital, just list what the app should do, e.g., communicate with GitHub API to list labels of given repository.
+
+On the other hand, non-functional requirements might be more complicated to summarize. They cover many areas and some can be, for instance, it will be in form of web application, it will use relational database, it will have internationalization, and so on. In general, for requirements, you should think about [FURPS](https://en.wikipedia.org/wiki/FURPS):
+
+* Functionality - Capability (Size & Generality of Feature Set), Reusability (Compatibility, Interoperability, Portability), Security (Safety & Exploitability)
+* Usability (UX) - Human Factors, Aesthetics, Consistency, Documentation, Responsiveness
+* Reliability - Availability (Failure Frequency (Robustness/Durability/Resilience), Failure Extent & Time-Length (Recoverability/Survivability)), Predictability (Stability), Accuracy (Frequency/Severity of Error)
+* Performance - Speed, Efficiency, Resource Consumption (power, ram, cache, etc.), Throughput, Capacity, Scalability
+* Supportability (Serviceability, Maintainability, Sustainability, Repair Speed) - Testability, Flexibility (Modifiability, Configurability, Adaptability, Extensibility, Modularity), Installability, Localizability
+
+Also, you need to consider your own expectations:
+
+* What do you want to learn
+* Are you going to work in team or alone
+* Do you want to publish it or is it just private work
+* etc.
+
+### Do some research
+
+Hmm, you have requirements... so you can start to work. Well you can, but maybe it is good idea to now take your list of requirements and do a bit of reasearch what solutions already exist. Not only that you might find out that you would totally "reivent the wheel" and the software you want to develop is already here and you would just waste your precious time, but you might get inspired and learn from other's mistakes.
+
+1. Find (for example using Google) similar existing solutions if there are any
+2. Take a look at each and write down what your like and dislike and how much it fulfils your requirements
+3. If some fulfils its completely and you like it, you don't need this project probably
+4. Adjust your requirements based on research and/or make summary list what to avoid in your app (what you didn't like in the existing solutions)
+
+### Language, framework, libraries
+
+Before you start, you need to consider what you will use. What programming language(s) are you going to code in, what framework will you use and what external libraries. That will also highly affect tools, the architecture, and overall structure of your project. These technologies are filtered mostly by:
+
+* non-functional requirements (such as type of application, speed, accessibility, etc.),
+* what are you able to work in (or able/keen to learn it),
+* what are you allowed to used (licenses or internall restrictions).
+
+If there are still more options remaining, do the research how is the specific technology widespread and how it suits your task. A bigger and more active community around the technology means better for your project since there will be people to answer your questions eventually. Important last word about this, sometimes it is healthy to get our of your comfort zone and try something new that you are not totally familiar with, spend time to learn and try it (if you can)...
+
+### Setup productive environment
+
+Finally you know what are you going to code and what technologies will be used. That is sufficient to easily setup the environment for you to code efficiently:
+
+* [IDE](https://en.wikipedia.org/wiki/Integrated_development_environment) - the central point where you will work, there are again many options based on the technologies you want to use - [IntelliJ IDEA](https://www.jetbrains.com/idea/), [VS Code](https://code.visualstudio.com), [Visual Studio](https://visualstudio.microsoft.com/cs/), [PyCharm](https://www.jetbrains.com/pycharm/), [KDevelop](https://www.kdevelop.org), [NetBeans](https://netbeans.org), [Eclipse](https://www.eclipse.org/ide/), etc.
+* Plugins for technologies - IDE usually can be enhanced with plugins specialized for your programming language(s) and framework(s), usually it consists of syntax highliting, linter, auto completion, preconfigured action, or code snippets
+* VCS (see below) - ideally integrated within IDE
+* Build & test automatization - it is nice to be able to build, run, or test the application without leaving IDE and ideally with single action
+
+Don't forget, that this is highly subjective and depends really on you what you prefer. Some people are really happy with [Vim](https://www.vim.org) and its plugins. Some prefer other simpler editors with UI similar to [Notepad++](https://notepad-plus-plus.org/). But most of programmers like full-fledged IDE providing all what they need easily.
+
+## VCS
+
+Important part of a productive environment (and not just for team, even if you are the only developer) is something called Version Control System. As the name is well-descriptive, it allows you to keep track of changes of your work and in the most tools not just in single line but in branches that can be merged afterwards. It allows you also to go back when needed, check who made what changes and when, tag some specific revisions and many more.
+
+### Git vs. SVN
+
+The most famous version control systems these days are [Git](https://git-scm.com) and [SVN (subversion)](https://subversion.apache.org). Frequently, you can stick with rule that SVN is more suitable for larger and binary files (although there is Git LFS) or when good integration for specific tool is supplied (for example, Enterprise Architect). The core difference is in approach that SVN is centralized and you need to lock part that you want to change, this is where Git will require you resolve merge conflicts. Merging and branches in SVN are more complicated than in Git (this many be subjective).
+
+For more see: https://www.perforce.com/blog/vcs/git-vs-svn-what-difference
+
+### GitHub, GitLab, and others
+
+Of course, you can use Git only locally or deploy your own basic Git server to have backups and you will have your work versioned and backuped. But to gain the most of it, using public web-based hosting services for Git is essential. There are more but for the widely used, we can enumerate: [GitHub](https://github.com), [GitLab](https://about.gitlab.com), and [BitBucket](https://bitbucket.org). The main advantage is in public sharing of open-source project for free and easily opening them to contributions.
+
+Aside from the basic Git functionality, related features to support the software development process are supplied. One of the key features are issues for reporting bugs, sharing ideas, and discussing related stuff. Others are Pull Requests (or Merge Requests) with reviews that allow to control contributions from externals into the project as well as merge of internal branches of multiple developers. Moreover, many functions for project management (e.g., kanban boards, labels, assignments, and time tracking) and documentation (wiki pages, web-based editors, documentation sites integrations, etc.) are available.
+
+Another important advantage is that there are more services that can be integrated with these hostings such as CI, code analytics, deployment environments, project management systems, etc. As a disadvantage one can see providing own work publically or to some company. For that, there are private repositories (sometimes paid) or you can create own deployment of GitLab on your server or for organisation and then share the work publically but under full control.
+
+### Commits and branches
+
+Git allows you to develop in branches and make units of change called commits. A very good practice is to setup guidelines for you, your team, and/or external contributors how to split work into branches and how to compose commit messages. There is so-called [Gitflow Workflow](https://cs.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow) that describes naming and branching of code in universal and nice way. Relating branches and Pull Requests to certain issues seems to be useful for tracking.
+
+Important also is to have **atomic commits** so one commit is only one change of your code. That helps you when going through the changes in time and cherrypicking some of them or alternating them. A good description of commit is vital as well. There is always a short message but then you can include a more elaborate description if needed. But it should be always clear from the message what the commit changed in the project and even when you don't know the previous or following messages. Messages such as "Bugfix app", "Web improvement", "Another enhancement", "Trying again", are really bad!
+
+## Documentation
+
+Imagine your have a great piece of software that can help a lot of people, it is somewhere but noone knows what it is and how to use it. To help with that, you need to provide a documentation. Of course, you should always use "standard" way of installation for given programming language and platform as well as follow conventions how to use the app, but even dummy user should be able to get the information somewhere.
+
+Your documentation should always cover:
+
+* What is your project about
+* How to install and use the application (as easy as possible)
+* Configuration details and more options ("advanced stuff")
+* API (if library or service)
+* How to contribute (if opensource)
+
+For documentation, you can write your own, you can try to fit in single README file (for smaller projects) or use some service such as [GitHub Pages](https://pages.github.com), [ReadTheDocs](https://readthedocs.org), or [GitBook](https://www.gitbook.com) (there are many more). There are more views on your project - user, administrator (for example in case of web application), and developer. You should provide documentation for all of them with some expectations about their knowledge and experience. For developers, standard documentation directly in the code can be very useful.
+
+## Quality
+
+Quality of your code (as well as other parts of your project including documentation, communication, and quality assurance itself) is important for others and you too. Maintaining code that is well-writen using standard consistent conventions, is properly tested (i.e. works as it should), and is easy to read and handle, is a way easier. You should invest the time to assure quality of your project and it will definitely pay back.
+
+### Testing
+
+When talking about quality of code, the first that comes to mind of most people is testing. Of course, you should properly test your software with unit and integration tests. For the selected programming language(s) and framework(s) there should be some existing testing frameworks and guidelines how to write tests, how to make mocks, spies, and other tricks in testing. Often, people measure "coverage" which percentage of statements covered by your tests. It can be useful to check whether changes in your code increase or decrease the coverage.
+
+But be careful, 100 % coverage does not mean that your code is working correctly. You can get such coverage easily with stupid tests that will be passed even by totally bugged implementation. When writing tests you should follow:
+
+* All main parts/units are tested (separately, unit tests)
+* Communication between units is tested (integration tests)
+* There are also "negative" tests, not only positive - i.e. don't test only that things work when they should work but also that they don't work if the shouldn't
+* If external services (for example some REST API) is used, never test with live version - use mocks or records of the communication
+
+Interesting testing approach that is lately often used since more and more web applications are being developed is called [end-to-end tests](https://www.tutorialspoint.com/software_testing_dictionary/end_to_end_testing.htm). It tests whole application as user would use it. In case of CLI, it tries to use the app using the CLI and checks the outputs. In case of web application, it uses real (or "headless") browser and clicks or fills some forms in it and again checks how the page behaves. It takes some time to setup such tests and start writing the cases, but again - it pays off in bigger projects since usually the tests are well-reusable.
+
+### Code Quality
+
+By code quality we mean things covered by static code analysis. Tests use your app running (i.e. dynamic) but static analysis just checks the programming code without any execution. There are many [tools](https://en.wikipedia.org/wiki/List_of_tools_for_static_code_analysis) for that and they mainly cover:
+
+* Conformity with conventions and rules for writing code (naming variables, indentation, structuration of files, ...)
+* Repetitions in code (i.e. violations against DRY principle)
+* Using vulnarable code and libraries or deprecated constructs
+* Not handling exceptions correctly
+* Incorrect working with types
+* etc.
+
+Moreover, some tools can be integrated with GitHub or GitLab and check all your pushed commits easily.
+
+### Reviews
+
+Programming alone has a few serious risks especially when you get lazy:
+
+* skipping the documentation or making it useless
+* writing code in a way that only you (at least you should!) understand it
+* incorporate nasty bugs
+* making dummy tests or none at all
+
+To avoid that, you need some people to do reviews for you and do the review for others (for example, contributors to your project or team members). Moreover, pair programming is also a good practice of [extreme programming](https://en.wikipedia.org/wiki/Extreme_programming). Try to be in positive mood both when writing review and being reviewed, in both cases you can learn a lot from others who has different experience in software development.
+
+## Continuous Integration, Inspection, and Delivery
+
+As already being said few times, there are services that can be easily integrated with GitHub or GitLab in order to do something with your project automatically when you push commits, create pull request, release new version, or do some other action. The "something" can be actually anything and you can write such "[CI tool](https://en.wikipedia.org/wiki/Continuous_integration)" even by yourself.
+
+* Continuous Integration - This term is used usually when your software is built (all parts are integrated), and tested with automatic tests or at least attempt to execute it is done. The result is that at that moment your code is (at least somehow) working. It is nice to see in your commits history which were working and which were not. For this, you can use [Travis CI](travis-ci.org), [Semaphore CI](https://semaphoreci.com), AppVeyor, and many others.
+* Continuous Inspection - Services that does static inspection of your code, they can verify dependencies of your project, evaluate coverage, and others. One of the examples is [SonarQube](https://www.sonarqube.org), but again there are many similar services.
+* Continuous Delivery - If your code passed the build and test phases, it can be deployed somewhere. The deployment can have many realizations, from actual deployment on some web hosting or app server (realized, for example, by service like [Heroku](https://www.heroku.com) or [AWS](https://aws.amazon.com)), though publishing new documentation on [ReadTheDocs](https://readthedocs.org), to uploading installation packages to some registry. All depends what you need, want, and how you will set it up.
+
+## License
+
+When you want to publish something, in our case usually programming code, you are required to state under what terms is your work published, can be used, edited, or distributed. There are many licenses for open-source and you should not write your own, try to find existing and suitable first. Very good site that can help you is [choosealicense.com](https://choosealicense.com). More complete one is located at [opensource.org/licenses](https://opensource.org/licenses).
+
+Also, if you create some graphics, you should consider Creative Commons license that is usually well-suitable for things like diagrams, images, textures, or posters. When your project is build from separated modules, those modules can be even licensed under different terms. For example, your library can be published under MIT and GUI app wrapping the library under GPL. Sometimes such licensing might be good, but having small app divided and licensed with many different licenses might cause headache to anyone who would like to use it.
+
+On the other hand, as you usually use libraries and other projects made by different people than you are (or even yours!), you need to take into account the licenses of such included and used software, graphics, and anything. If someone states that you cannot use their work in conditions you are using, then you need to find another solution. Problems are also with so-called "Share-Alike", i.e., you need to license your code under the same license (for instance, GPL works like that). That limits your options when picking a correct license...
+
+## Contributions
+
+If you develop open-source project, you need to open for contributions of other people. Sometimes this requires a time to review new code, teach people, and have a lot of patience with them. You can take advantage of it, and if you want, ask active contributors to help you with the project maintaining. That is how world of open-source works and as everything it has advantages and disadvantages. It is always up to you, what do you want to do with your own project... Good luck!

From 3588824ab5328a02037208eab0964bdf23c2c12e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marek=20Such=C3=A1nek?= <marek.suchanek@fit.cvut.cz>
Date: Thu, 6 Jun 2019 15:43:22 +0200
Subject: [PATCH 22/26] Monad transformers added

---
 tutorials/97_monadtrans.md                    | 411 ++++++++++++++++++
 .../{99_bonus.md => 99_exts-deptypes.md}      |   0
 2 files changed, 411 insertions(+)
 create mode 100644 tutorials/97_monadtrans.md
 rename tutorials/{99_bonus.md => 99_exts-deptypes.md} (100%)

diff --git a/tutorials/97_monadtrans.md b/tutorials/97_monadtrans.md
new file mode 100644
index 0000000..7be133d
--- /dev/null
+++ b/tutorials/97_monadtrans.md
@@ -0,0 +1,411 @@
+# More on Monad Transformers
+
+In Haskell and in functional programming in general, a monad transformer is a type constructor which takes a monad as an argument and returns a monad as a result. Basically said, it is combination of monads in "layers".
+
+Monad transformers can be pretty useful and make code both efficient and readable when used properly. They can be used to compose features encapsulated by monads – such as state, exception handling, I/O, logging, and others – in a modular way. Typically, a monad transformer is created by generalising an existing monad and applying the resulting monad transformer to the `Identity` or `IO` monad yields a monad which is equivalent to the original monad (ignoring any necessary boxing and unboxing).
+
+## Definition
+
+Monad transformer is a wrapper type that has:
+
+1. a type constructor `t` of kind `(* -> *) -> * -> *` (needs a monad `m` a type)
+2. defined monad operations `return` and `>>=` (bind) compliant in mo nadic laws for `t m` iff `m` is a monad
+3. an operation `lift` of type `m a -> t m a` that allows to access the inner monad `m` and fullfils:
+  * `lift . return = return`
+  * `lift (m >>= k) = (lift m) >>= (lift . k)` 
+
+## MonadT, MaybeT and EitherT
+
+When using monad transformers in Haskell, package [transformers](http://hackage.haskell.org/package/transformers) provide them for basic monads such as `Maybe`, `List`, `Reader`, `Writer`, or `State`. Be careful, others are separately in different packages such as `Either` in [either](https://hackage.haskell.org/package/either). It is quite common to use `T` as suffix after monad name to name its transformer.
+
+### Maybe with IO
+
+As was already said, monad transformers are used as wrapper types to combine monads with other common features provided by different monads, for example, `IO` with actions like `putStrLn` or `getLine`. Why would someone need such a combination? Why not use those monads in a normal way?
+
+```haskell
+main :: IO
+main = do
+  maybeUserName <- readUserName
+  case maybeUserName of
+    Nothing -> print “Invalid user name!”
+    Just (uName) -> do
+      maybeEmail <- readEmail
+      case maybeEmail of
+        Nothing -> print “Invalid email!”
+        Just (email) -> do
+          maybePassword <- readPassword
+          Case maybePassword of
+            Nothing -> print “Invalid Password”
+            Just password -> login uName email password
+
+readUserName :: IO (Maybe String)
+readUserName = do
+  str <- getLIne
+  if length str > 5
+    then return $ Just str
+    else return Nothing
+
+readEmail :: IO (Maybe String)
+...
+
+readPassword :: IO (Maybe String)
+...
+
+login :: String -> String -> String -> IO ()
+...
+```
+
+By using monad transformer `MaybeT IO` that wraps `IO` actions the code can get much more readable and efficient. It is also better in terms of extensibility and modularity when you want to replace `IO`, for example.
+
+```haskell
+newtype MaybeT m a = MaybeT { runMaybeT :: m (Maybe a) }
+
+instance (Monad m) => Monad (MaybeT m) where
+    return = lift . return
+    x >>= f = MaybeT $ do
+        v <- runMaybeT x
+        case v of
+            Nothing -> return Nothing
+            Just y  -> runMaybeT (f y)
+```
+
+It is just a newtype that inserts maybe into some monad. Function `return` is then just lifted for this monad transformer and bind `>>=` works naturally for `Maybe` type, returns `Nothing` if `Nothing` is wrapped and evaluates with value from `Just` otherwise.
+
+```haskell
+readUserName :: MaybeT IO String
+readUserName = MaybeT $ do
+  str <- getLine
+  if length str > 5
+    then return $ Just str
+    else return Nothing
+```
+
+The code is then pretty readable and understandable on the first sight, no more bothersome nested `if`s or `case`s. It is also better for maintenance obviously. Similarly it works for `EitherT` where it is important that in the inner monad (such as `IO`) is only the type of `Right` values and not `Left`s.
+
+```haskell
+newtype EitherT e m a = EitherT { runEitherT :: m (Either e a) }
+
+instance Monad m => Monad (EitherT e m) where
+  return a = EitherT $ return (Right a)
+  m >>= k  = EitherT $ do
+    a <- runEitherT m
+    case a of
+      Left  l -> return (Left l)
+      Right r -> runEitherT (k r)
+```
+
+## More Layers of Monads
+
+Monad transformers are as shown again monads, that means that you can wrap monad transfomers in monad transformers!
+
+```haskell
+type Env = (Maybe String, Maybe String, Maybe String)
+
+readUserName :: MaybeT (ReaderT Env IO) String
+readUserName = MaybeT $ do
+  (maybeOldUser, _, _) <- ask
+  case maybeOldUser of
+    Just str -> return str
+    Nothing -> do
+      -- lift allows normal IO functions from inside ReaderT Env IO!
+      input <- lift getLine
+      if length input > 5
+        then return (Just input)
+        else return Nothing
+```
+
+But as you can see that to get into inner layers more lifts are needed... In such cases, some helper functions and naming your transformer is quite handy.
+
+```haskell
+type TripleMonad a = MaybeT (ReaderT Env IO) a
+
+performReader :: ReaderT Env IO a -> TripleMonad a
+performReader = lift
+
+performIO :: IO a -> TripleMonad a
+performIO = lift . lift
+
+readUserName :: TripleMonad String
+readUserName = do
+  (maybeOldUser, _, _) <- performReader ask
+  case maybeOldUser of
+    Just str -> return str
+    Nothing -> do
+      input <- performIO getLine
+      if length input > 5
+        then return (Just input)
+        else return Nothing
+```
+
+## Other Way for Transformers
+
+As the other way around, there are some typeclasses which allow you to make certain assumptions about the monad stack below inside transformers. For instance, you often don’t care what the exact stack is, but you just need IO to exist somewhere in the layers because you want to do IO actions. For this purpose, there is typeclass `MonadIO` (also from [transformers](https://hackage.haskell.org/package/transformers) package).
+
+```haskell
+class (Monad m) => MonadIO m where
+  liftIO :: IO a -> m a
+```
+
+If you create your own monad transformer, you can/should make it instance of `MonadIO` in order to allow anyone to use it in generic way to perform IO actions using standard `liftIO` function.
+
+```haskell
+type TripleMonad a = MaybeT (ReaderT Env IO) a
+
+performReader :: ReaderT Env IO a -> TripleMonad a
+performReader = lift
+
+performIO :: IO a -> TripleMonad a
+performIO = lift . lift
+
+instance MonadIO (TripleMonad a) where
+  liftIO = performIO
+
+-- This generic function can be now used with our TripleMonad
+debugFunc :: (MonadIO m) => String -> m a
+debugFunc input = do
+  liftIO $ putStrLn "Interpreting Input: " ++ input
+  liftIO $ putStrLn "Cool huh?!"
+```
+
+## Example from DS Wizard
+
+We can show some real use case from larger Haskell application - [Data Stewardship Wizard (server)](https://github.com/ds-wizard/dsw-server). Monad transformers are used, for instance, to have a nice and modular application context:
+
+```haskell
+module Model.Context.AppContext where
+
+import Control.Applicative (Applicative)
+import Control.Monad.IO.Class (MonadIO)
+import Control.Monad.Logger (LoggingT, MonadLogger)
+import Control.Monad.Reader (MonadReader, ReaderT)
+import qualified Data.UUID as U
+import Database.Persist.MongoDB (ConnectionPool)
+import Network.AMQP (Channel)
+import Network.HTTP.Client (Manager)
+
+import Api.Resource.User.UserDTO
+import Model.Config.AppConfig
+import Model.Config.BuildInfoConfig
+
+data AppContext = AppContext
+  { _appContextAppConfig :: AppConfig
+  , _appContextBuildInfoConfig :: BuildInfoConfig
+  , _appContextPool :: ConnectionPool
+  , _appContextMsgChannel :: Maybe Channel
+  , _appContextHttpClientManager :: Manager
+  , _appContextTraceUuid :: U.UUID
+  , _appContextCurrentUser :: Maybe UserDTO
+  }
+
+newtype AppContextM a = AppContextM
+  { runAppContextM :: ReaderT AppContext (LoggingT IO) a
+  } deriving (Applicative, Functor, Monad, MonadIO, MonadReader AppContext, MonadLogger)
+```
+
+Thanks to its default behaviour, instances of typeclasses can be easily derived (notice mainly `MonadIO`). This `AppContextM` is used across whole web application for every endpoint or service and carries all necessary resources and information including database connection, configurations, logged user, message queue connection, and others. The best thing is that when needed, it is easy to add something new to the `AppContext` type (e.g. monitoring service connection) and it won't break anything!
+
+Now see that you can use `IO`, `MonadReader`, and `MonadLogger` easily in the service:
+
+```haskell
+    
+module Service.User.UserService where
+
+import Control.Lens ((&), (.~), (^.))
+import Control.Monad.Reader (asks, liftIO)
+import Crypto.PasswordStore
+import Data.ByteString.Char8 as BS
+import Data.Maybe (fromMaybe)
+import Data.Time
+import qualified Data.UUID as U
+
+import Api.Resource.ActionKey.ActionKeyDTO
+import Api.Resource.User.UserChangeDTO
+import Api.Resource.User.UserCreateDTO
+import Api.Resource.User.UserDTO
+import Api.Resource.User.UserPasswordDTO
+import Api.Resource.User.UserProfileChangeDTO
+import Api.Resource.User.UserStateDTO
+import Database.DAO.User.UserDAO
+import LensesConfig
+import Localization
+import Messaging.Out.Topic.UserTopic
+import Model.ActionKey.ActionKey
+import Model.Config.AppConfig
+import Model.Context.AppContext
+import Model.Error.Error
+import Model.Error.ErrorHelpers
+import Model.User.User
+import Service.ActionKey.ActionKeyService
+import Service.Common
+import Service.Mail.Mailer
+import Service.User.UserMapper
+import Service.User.UserValidation
+import Util.Uuid
+
+getUsers :: AppContextM (Either AppError [UserDTO])
+getUsers = heFindUsers $ \users -> return . Right $ toDTO <$> users
+
+createUserByAdmin :: UserCreateDTO -> AppContextM (Either AppError UserDTO)
+createUserByAdmin reqDto = do
+  uUuid <- liftIO generateUuid
+  createUserByAdminWithUuid reqDto uUuid
+
+createUserByAdminWithUuid :: UserCreateDTO -> U.UUID -> AppContextM (Either AppError UserDTO)
+createUserByAdminWithUuid reqDto uUuid = do
+  uPasswordHash <- generatePasswordHash (reqDto ^. password)
+  dswConfig <- asks _appContextAppConfig
+  let uRole = fromMaybe (dswConfig ^. roles . defaultRole) (reqDto ^. role)
+  let uPermissions = getPermissionForRole dswConfig uRole
+  createUser reqDto uUuid uPasswordHash uRole uPermissions
+
+registrateUser :: UserCreateDTO -> AppContextM (Either AppError UserDTO)
+registrateUser reqDto =
+  heCheckIfRegistrationIsEnabled $ do
+    uUuid <- liftIO generateUuid
+    uPasswordHash <- generatePasswordHash (reqDto ^. password)
+    dswConfig <- asks _appContextAppConfig
+    let uRole = dswConfig ^. roles . defaultRole
+    let uPermissions = getPermissionForRole dswConfig uRole
+    createUser reqDto uUuid uPasswordHash uRole uPermissions
+
+createUser :: UserCreateDTO -> U.UUID -> String -> Role -> [Permission] -> AppContextM (Either AppError UserDTO)
+createUser reqDto uUuid uPasswordHash uRole uPermissions =
+  heValidateUserEmailUniqueness (reqDto ^. email) $ do
+    now <- liftIO getCurrentTime
+    let user = fromUserCreateDTO reqDto uUuid uPasswordHash uRole uPermissions now now
+    insertUser user
+    heCreateActionKey uUuid RegistrationActionKey $ \actionKey -> do
+      publishToUserCreatedTopic user
+      emailResult <- sendRegistrationConfirmationMail (toDTO user) (actionKey ^. hash)
+      case emailResult of
+        Left errMessage -> return . Left $ GeneralServerError _ERROR_SERVICE_USER__ACTIVATION_EMAIL_NOT_SENT
+        _ -> do
+          sendAnalyticsEmailIfEnabled user
+          return . Right $ toDTO user
+  where
+    sendAnalyticsEmailIfEnabled user = do
+      dswConfig <- asks _appContextAppConfig
+      if dswConfig ^. analytics . enabled
+        then sendRegistrationCreatedAnalyticsMail (toDTO user)
+        else return $ Right ()
+
+getUserById :: String -> AppContextM (Either AppError UserDTO)
+getUserById userUuid = heFindUserById userUuid $ \user -> return . Right $ toDTO user
+
+modifyUser :: String -> UserChangeDTO -> AppContextM (Either AppError UserDTO)
+modifyUser userUuid reqDto =
+  heFindUserById userUuid $ \user ->
+    heValidateUserChangedEmailUniqueness (reqDto ^. email) (user ^. email) $ do
+      dswConfig <- asks _appContextAppConfig
+      updatedUser <- updateUserTimestamp $ fromUserChangeDTO reqDto user (getPermissions dswConfig reqDto user)
+      updateUserById updatedUser
+      return . Right . toDTO $ updatedUser
+  where
+    getPermissions dswConfig reqDto oldUser =
+      if (reqDto ^. role) /= (oldUser ^. role)
+        then getPermissionForRole dswConfig (reqDto ^. role)
+        else oldUser ^. permissions
+
+modifyProfile :: String -> UserProfileChangeDTO -> AppContextM (Either AppError UserDTO)
+modifyProfile userUuid reqDto =
+  heFindUserById userUuid $ \user ->
+    heValidateUserChangedEmailUniqueness (reqDto ^. email) (user ^. email) $ do
+      updatedUser <- updateUserTimestamp $ fromUserProfileChangeDTO reqDto user
+      updateUserById updatedUser
+      return . Right . toDTO $ updatedUser
+
+changeUserPasswordByAdmin :: String -> UserPasswordDTO -> AppContextM (Maybe AppError)
+changeUserPasswordByAdmin userUuid reqDto =
+  hmFindUserById userUuid $ \user -> do
+    passwordHash <- generatePasswordHash (reqDto ^. password)
+    now <- liftIO getCurrentTime
+    updateUserPasswordById userUuid passwordHash now
+    return Nothing
+
+changeCurrentUserPassword :: String -> UserPasswordDTO -> AppContextM (Maybe AppError)
+changeCurrentUserPassword userUuid reqDto =
+  hmFindUserById userUuid $ \user -> do
+    passwordHash <- generatePasswordHash (reqDto ^. password)
+    now <- liftIO getCurrentTime
+    updateUserPasswordById userUuid passwordHash now
+    return Nothing
+
+changeUserPasswordByHash :: String -> Maybe String -> UserPasswordDTO -> AppContextM (Maybe AppError)
+changeUserPasswordByHash userUuid maybeHash userPasswordDto =
+  validateHash maybeHash $ \akHash ->
+    hmFindUserById userUuid $ \user ->
+      hmGetActionKeyByHash akHash $ \actionKey -> do
+        passwordHash <- generatePasswordHash (userPasswordDto ^. password)
+        now <- liftIO getCurrentTime
+        updateUserPasswordById userUuid passwordHash now
+        deleteActionKey (actionKey ^. hash)
+        return Nothing
+  where
+    validateHash maybeHash callback =
+      case maybeHash of
+        Just akHash -> callback akHash
+        Nothing ->
+          return . Just . createErrorWithErrorMessage $ _ERROR_SERVICE_USER__REQUIRED_ADMIN_ROLE_OR_HASH_IN_QUERY_PARAMS
+
+resetUserPassword :: ActionKeyDTO -> AppContextM (Maybe AppError)
+resetUserPassword reqDto =
+  hmFindUserByEmail (reqDto ^. email) $ \user ->
+    hmCreateActionKey (user ^. uuid) ForgottenPasswordActionKey $ \actionKey -> do
+      emailResult <- sendResetPasswordMail (toDTO user) (actionKey ^. hash)
+      case emailResult of
+        Left errMessage -> return . Just $ GeneralServerError _ERROR_SERVICE_USER__RECOVERY_EMAIL_NOT_SENT
+        _ -> return Nothing
+
+changeUserState :: String -> Maybe String -> UserStateDTO -> AppContextM (Maybe AppError)
+changeUserState userUuid maybeHash userStateDto =
+  validateHash maybeHash $ \akHash ->
+    hmFindUserById userUuid $ \user ->
+      hmGetActionKeyByHash akHash $ \actionKey -> do
+        updatedUser <- updateUserTimestamp $ user & active .~ (userStateDto ^. active)
+        updateUserById updatedUser
+        deleteActionKey (actionKey ^. hash)
+  where
+    validateHash maybeHash callback =
+      case maybeHash of
+        Just akHash -> callback akHash
+        Nothing -> return . Just . createErrorWithErrorMessage $ _ERROR_SERVICE_USER__REQUIRED_HASH_IN_QUERY_PARAMS
+
+deleteUser :: String -> AppContextM (Maybe AppError)
+deleteUser userUuid =
+  hmFindUserById userUuid $ \user -> do
+    deleteUserById userUuid
+    return Nothing
+
+-- --------------------------------
+-- PRIVATE
+-- --------------------------------
+getPermissionForRole :: AppConfig -> Role -> [Permission]
+getPermissionForRole config role =
+  case role of
+    "ADMIN" -> config ^. roles ^. admin
+    "DATASTEWARD" -> config ^. roles ^. dataSteward
+    "RESEARCHER" -> config ^. roles ^. researcher
+    _ -> []
+
+generatePasswordHash :: String -> AppContextM String
+generatePasswordHash password = liftIO $ BS.unpack <$> makePassword (BS.pack password) 17
+
+updateUserTimestamp :: User -> AppContextM User
+updateUserTimestamp user = do
+  now <- liftIO getCurrentTime
+  return $ user & updatedAt .~ Just now
+
+heCheckIfRegistrationIsEnabled = heCheckIfFeatureIsEnabled "Registration" (general . registrationEnabled)
+´´´
+
+## References
+
+* [Real World Haskell - Monad Transformers](http://book.realworldhaskell.org/read/monad-transformers.html)
+* [Wikibooks - Haskell/Monad Transformers](https://en.wikibooks.org/wiki/Haskell/Monad_transformers)
+* [Wikipedia - Monad Transformer](https://en.wikipedia.org/wiki/Monad_transformer)
+* [Monday Morning Haskell - Monads 6](https://mmhaskell.com/monads-6) = source of most of the examples
+* [A Gentle Introduction to Monad Transformers](https://github.com/kqr/gists/blob/master/articles/gentle-introduction-monad-transformers.md)
+* [A Gentle Introduction to Monad Transformers](https://github.com/kqr/gists/blob/master/articles/gentle-introduction-monad-transformers.md)
+* [Monad Transformers aren’t hard!](https://medium.com/@alexander.zaidel/monad-transformers-arent-hard-23387c7ef4a6)
+* [Haskell Wiki - Monad Transformers Explained](https://wiki.haskell.org/Monad_Transformers_Explained)
+
diff --git a/tutorials/99_bonus.md b/tutorials/99_exts-deptypes.md
similarity index 100%
rename from tutorials/99_bonus.md
rename to tutorials/99_exts-deptypes.md

From 1c5fc6faefb0f116034beacf527ed0b3678a640e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marek=20Such=C3=A1nek?= <marek.suchanek@fit.cvut.cz>
Date: Thu, 6 Jun 2019 15:43:38 +0200
Subject: [PATCH 23/26] Init TH bonus tutorial

---
 tutorials/98_template-haskell.md | 73 ++++++++++++++++++++++++++++++++
 1 file changed, 73 insertions(+)
 create mode 100644 tutorials/98_template-haskell.md

diff --git a/tutorials/98_template-haskell.md b/tutorials/98_template-haskell.md
new file mode 100644
index 0000000..ecf050a
--- /dev/null
+++ b/tutorials/98_template-haskell.md
@@ -0,0 +1,73 @@
+# Template Haskell
+
+Template Haskell is an experimental language extension to the Haskell programming language implemented in the Glasgow Haskell Compiler (version 6 and later). In early incarnations it was also known as Template Meta-Haskell. It allows **compile-time metaprogramming** and **generative programming** by means of manipulating abstract syntax trees and 'splicing' results back into a program. The abstract syntax is represented using ordinary Haskell data types and the manipulations are performed using ordinary Haskell functions.
+
+## Why Bother?
+
+With Template Haskell (TH) you can write code that generates code (i.e. metaprogramming). Sometimes it is considered as bad and result of failing to address some problem in a normal programming way. On the other hand, in some situations it can really simplify your work when you need to really generate amount of similar and complex code from simpler specification. There are some typical use cases of Template Haskell:
+
+* **Deriving of type class instances** - You know keyword `deriving` and we said that you can use it for basic typeclasses such as `Show`, `Read`, or `Ord`. Well, there are ways how to derive also othes. One is using [GHC.Generics](https://wiki.haskell.org/GHC.Generics) but that might slow down the compilation significantly. The other is TH and that way is used for example by [aeson](http://hackage.haskell.org/package/aeson) library when deriving instances for transformation from and to JSON.
+* **Domain Specific Languages (DSLs)** - DSLs are trendy, nice, and cool way how to code things without actually writing the code itself but using different syntax in special quotes. They are integrated into systems built in Haskell. Examples of such DLSs are the language for model declaration used in [persistent](http://hackage.haskell.org/package/persistent), and various other mini-languages used in the [yesod](http://hackage.haskell.org/package/yesod) web framework that we have already shown.
+* **Compile-time construction of values of refined types** - It simply turns invalid inputs into compilation failures.
+* **Compile-time loading and processing of data from external files** - This is very useful sometimes to avoid loading resources on the beginning of every run of the application. Even though it involves running IO during compilation, it’s a relatively innocent use case of that dangerous feature.
+
+You should always reconsider using Template Haskell if there is no easier way because it is considered as dark magic (with many black boxes), might slow down the compilation and can introduce hard-to-debug problems.
+
+## Q Monad and Splicing
+
+The core of TH is the `Q` monad (short for “quotation”) that hosts all functions provided by TH:
+
+* Generating new unique names that cannot be captured.
+* Retrieving information about a thing by its name. Usually we want to know about functions and types, but there are also ways to learn about a module, get collection of instances of a particular type class, etc.
+* Putting and getting some custom state that is then shared by all TH code in the same module.
+* Running IO during compilation, so we can e.g. read something from a file.
+
+Everything needed for basic TH is in [template-haskell](http://hackage.haskell.org/package/template-haskell) package, including the definition of the `Q` monad and other types and typeclasses that we will mention afterwards.
+
+```haskell
+newtype Q a = Q { unQ :: forall m. Quasi m => m a }
+
+runQ :: Quasi m => Q a -> m a
+runQ (Q m) = m
+
+instance Monad Q where
+  Q m >>= k  = Q (m >>= \x -> unQ (k x))
+  (>>) = (*>)
+  fail       = Fail.fail
+
+instance Fail.MonadFail Q where
+  fail s     = report True s >> Q (Fail.fail "Q monad failure")
+
+instance Functor Q where
+  fmap f (Q x) = Q (fmap f x)
+
+instance Applicative Q where
+  pure x = Q (pure x)
+  Q f <*> Q x = Q (f <*> x)
+  Q m *> Q n = Q (m *> n)
+```
+
+What is the `Q a` good for? - To use `a` in a Haskell program somehow. It can be anything, but we want to insert something into the Haskell code and it can be one of the following:
+
+* **Declaration** ([Dec](https://hackage.haskell.org/package/template-haskell/docs/Language-Haskell-TH.html#t:Dec)) = top-level things like function and data type definitions
+* **Expression** ([Exp](https://hackage.haskell.org/package/template-haskell/docs/Language-Haskell-TH.html#t:Exp)) = some expression such as `if` statement, `5 + 3`, or literal `"Hello"`
+* **Typed expression** ([TExp](https://hackage.haskell.org/package/template-haskell/docs/Language-Haskell-TH.html#t:TExp)) = identical to **Expression** but also defines a type of the expression "inside"
+* **Type** ([Type](https://hackage.haskell.org/package/template-haskell/docs/Language-Haskell-TH.html#t:Type)) = type of any kind, for example, `Integer`, `Maybe`, `Int -> Double`, or `Either String`, including type constraints and wildcards such as `Num a => a`
+* **Pattern** ([Pat](https://hackage.haskell.org/package/template-haskell/docs/Language-Haskell-TH.html#t:Pat)) = pattern for matching in function, or `case`, `where`, and `let in`
+
+Using those you can construct on meta-level anything that is possible to write in Haskell as a code.
+
+## All the Quotations
+
+## Possibilities and Limitations
+
+## References
+
+* [Haskell Wiki - A practical Template Haskell Tutorial](https://wiki.haskell.org/A_practical_Template_Haskell_Tutorial)
+* [Template Haskell tutorial (Mark Karpov)](https://markkarpov.com/tutorial/th.html)
+* [Wikipedia - Template Haskell](https://en.wikipedia.org/wiki/Template_Haskell)
+* [Template Haskell Is Not Scary](https://www.parsonsmatt.org/2015/11/15/template_haskell.html)
+* [24 Days of GHC Extensions: Template Haskell](https://ocharles.org.uk/guest-posts/2014-12-22-template-haskell.html)
+* [Syntax of Template Haskell and Quasiquotes](https://riptutorial.com/haskell/example/18471/syntax-of-template-haskell-and-quasiquotes)
+* [Intro to Template Haskell](https://typeclasses.com/news/2018-10-intro-template-haskell)
+* [Template Haskell 101](https://www.schoolofhaskell.com/user/marcin/template-haskell-101)

From a6e1f48e0083937fc45fccc81b327c87bdc87f38 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marek=20Such=C3=A1nek?= <marek.suchanek@fit.cvut.cz>
Date: Thu, 6 Jun 2019 15:47:51 +0200
Subject: [PATCH 24/26] Fix code quotes

---
 tutorials/97_monadtrans.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tutorials/97_monadtrans.md b/tutorials/97_monadtrans.md
index 7be133d..1061889 100644
--- a/tutorials/97_monadtrans.md
+++ b/tutorials/97_monadtrans.md
@@ -396,7 +396,7 @@ updateUserTimestamp user = do
   return $ user & updatedAt .~ Just now
 
 heCheckIfRegistrationIsEnabled = heCheckIfFeatureIsEnabled "Registration" (general . registrationEnabled)
-´´´
+```
 
 ## References
 

From 2eca1344f18b906322ff6701a9e86a81a55169ac Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marek=20Such=C3=A1nek?= <marek.suchanek@fit.cvut.cz>
Date: Fri, 7 Jun 2019 13:14:19 +0200
Subject: [PATCH 25/26] Template Haskell bonus tut

---
 tutorials/98_template-haskell.md | 83 +++++++++++++++++++++++++++++++-
 1 file changed, 82 insertions(+), 1 deletion(-)

diff --git a/tutorials/98_template-haskell.md b/tutorials/98_template-haskell.md
index ecf050a..7fa44fd 100644
--- a/tutorials/98_template-haskell.md
+++ b/tutorials/98_template-haskell.md
@@ -55,12 +55,93 @@ What is the `Q a` good for? - To use `a` in a Haskell program somehow. It can be
 * **Type** ([Type](https://hackage.haskell.org/package/template-haskell/docs/Language-Haskell-TH.html#t:Type)) = type of any kind, for example, `Integer`, `Maybe`, `Int -> Double`, or `Either String`, including type constraints and wildcards such as `Num a => a`
 * **Pattern** ([Pat](https://hackage.haskell.org/package/template-haskell/docs/Language-Haskell-TH.html#t:Pat)) = pattern for matching in function, or `case`, `where`, and `let in`
 
-Using those you can construct on meta-level anything that is possible to write in Haskell as a code.
+Using those you can construct on meta-level anything that is possible to write in Haskell as a code (including Template Haskell). For example, this is how you can write in TH Haskell lambda expression `\x -> x + 1`:
+
+```haskell
+lambdaXplus1 :: Q Exp
+lambdaXplus1 = do
+  x <- newName "x" -- unique variable name
+  return $ LamE    -- lambda expression
+    [VarP x]       -- pattern matching on 'x'
+    (InfixE (Just (VarE x)) (VarE '(+)) (Just (LitE (IntegerL 1))))
+```
+
+Such TH expression can be then used in Haskell:
+
+```
+GHCi> :set -XTemplateHaskell
+GHCi> $(lambdaXplus1) 3
+4
+GHCi> $lambdaXplus1 3
+4
+GHCi> let f = (* 2) . $myFunc
+GHCi> f 10
+22
+```
+
+This is called **splicing** and the expression immediately following the `$` is called **splice**. If splice is parametric, you have to use brackets (e.g. `$(mySplice arg1 arg2) 7`), otherwise you may omit them as we did in the example above. Splice is ten evaluated to its Haskell form.
+
+A splice can be in four places in the code:
+
+* expression
+* pattern
+* type
+* top-level declaration
+
+The top-level declaration splices can omit `$` since there is no ambiguity (like with the `($)` operator). Well known use of this is with lenses.
+
+```haskell
+makeLens ''MyType
+-- is the same as:
+$(makeLens ''MyType)
+```
 
 ## All the Quotations
 
+Doing the meta-programming in the way as shown above is not very handy and may lead to uncompilable code. Luckily, there are quotes (different for various types of code that can be generated):
+
+* **Declaration** = `[d| ... |]` of type `Q [Dec]`
+* **Expression** = `[e| ... |]` of type `Q Exp`
+* **Typed expression** = `[|| ... ||]` of type `Q (TExp a)`
+* **Type** = `[t| ... |]` of type `Q Type`
+* **Pattern** = `[p| ... |]` of type `Q Pat`
+
+In this way, the `Q`'d expression above can be rewritten easily as:
+
+```haskell
+lambdaXplus1 :: Q Exp
+lambdaXplus1 = [| \x -> x + 1 |]
+
+lambdasXplus2 :: Q Exp
+lambdasXplus2 = [| $lambdaXplus1 . $lambdaXplus1 |
+```
+
+If you want to work with typed expression so the compiler can ensure that the phantom type always corresponds to what is inside, you must state the specific type:
+
+```haskell
+lambdaXplus1 :: Q (TExp (Integer -> Integer))
+lambdaXplus1 = [|| \x -> x + 1 ||]
+```
+
+If you want to use typed expression in other expression you must do doubled splicing `$$`. Normal splices cannot be used in quotations for typed expressions and vice versa. Why? Of course, you must know the type in typed. For the other way, you may use `unType :: TExp a -> Exp` that gets rid of the type.
+
+## Quasi and runQ
+
+If you want to play with `Q` monad in GHCi (and apps as well) you might need `runQ` of type `Quasi m => Q a -> m a`. It is because you want to work in `IO` monad and `IO` monad is one of instances of the `Quasi` typeclass. `Quasi` is the type class for monads that provide all the capabilities for meta-programming we have mentioned in the beginning when we introduced `Q`.
+
+```
+GHCi> runQ [e| Just x |]
+AppE (ConE GHC.Base.Just) (UnboundVarE x)
+GHCi> runQ [p| Just x |]
+ConP GHC.Base.Just [VarP x_0]
+GHCi> runQ [| Just x |]
+AppE (ConE GHC.Base.Just) (UnboundVarE x)
+```
+
 ## Possibilities and Limitations
 
+There are many more options to do with Template Haskell especially when it comes to names (like with `makeLens ''MyType` or defining variables). You can, for example, then also reifying things using `reify :: Name -> Q Info`, `reifyInstances :: Name -> [Type] -> Q [InstanceDec]`, and others. But there are also some limitiations that you might encounter and have to deal with, for example, inside a splice one can only use functions that are already compiled and sometimes order of definition matters in TH (which is not the case for Haskell).
+
 ## References
 
 * [Haskell Wiki - A practical Template Haskell Tutorial](https://wiki.haskell.org/A_practical_Template_Haskell_Tutorial)

From 9d8367831dfba0155278dae13fcc64a2cbe0a5c1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marek=20Such=C3=A1nek?= <marek.suchanek@fit.cvut.cz>
Date: Fri, 7 Jun 2019 13:19:05 +0200
Subject: [PATCH 26/26] Images for project guide

---
 project-guide.md | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/project-guide.md b/project-guide.md
index 8bfa6d4..bdbe6cd 100644
--- a/project-guide.md
+++ b/project-guide.md
@@ -63,6 +63,8 @@ Important part of a productive environment (and not just for team, even if you a
 
 The most famous version control systems these days are [Git](https://git-scm.com) and [SVN (subversion)](https://subversion.apache.org). Frequently, you can stick with rule that SVN is more suitable for larger and binary files (although there is Git LFS) or when good integration for specific tool is supplied (for example, Enterprise Architect). The core difference is in approach that SVN is centralized and you need to lock part that you want to change, this is where Git will require you resolve merge conflicts. Merging and branches in SVN are more complicated than in Git (this many be subjective).
 
+![Git vs. Subversion (git-tower.com)](https://www.git-tower.com/learn/content/01-git/01-ebook/en/02-desktop-gui/07-appendix/02-from-subversion-to-git/centralized-vs-distributed.png)
+
 For more see: https://www.perforce.com/blog/vcs/git-vs-svn-what-difference
 
 ### GitHub, GitLab, and others
@@ -79,6 +81,8 @@ Git allows you to develop in branches and make units of change called commits. A
 
 Important also is to have **atomic commits** so one commit is only one change of your code. That helps you when going through the changes in time and cherrypicking some of them or alternating them. A good description of commit is vital as well. There is always a short message but then you can include a more elaborate description if needed. But it should be always clear from the message what the commit changed in the project and even when you don't know the previous or following messages. Messages such as "Bugfix app", "Web improvement", "Another enhancement", "Trying again", are really bad!
 
+![Git Flow (Atlassian)](https://wac-cdn.atlassian.com/dam/jcr:61ccc620-5249-4338-be66-94d563f2843c/05%20(2).svg?cdnVersion=lf)
+
 ## Documentation
 
 Imagine your have a great piece of software that can help a lot of people, it is somewhere but noone knows what it is and how to use it. To help with that, you need to provide a documentation. Of course, you should always use "standard" way of installation for given programming language and platform as well as follow conventions how to use the app, but even dummy user should be able to get the information somewhere.
@@ -142,6 +146,8 @@ As already being said few times, there are services that can be easily integrate
 * Continuous Inspection - Services that does static inspection of your code, they can verify dependencies of your project, evaluate coverage, and others. One of the examples is [SonarQube](https://www.sonarqube.org), but again there are many similar services.
 * Continuous Delivery - If your code passed the build and test phases, it can be deployed somewhere. The deployment can have many realizations, from actual deployment on some web hosting or app server (realized, for example, by service like [Heroku](https://www.heroku.com) or [AWS](https://aws.amazon.com)), though publishing new documentation on [ReadTheDocs](https://readthedocs.org), to uploading installation packages to some registry. All depends what you need, want, and how you will set it up.
 
+![CI and CD (dzone.com)](https://www.edureka.co/blog/content/ver.1531719070/uploads/2018/07/Asset-33-1.png)
+
 ## License
 
 When you want to publish something, in our case usually programming code, you are required to state under what terms is your work published, can be used, edited, or distributed. There are many licenses for open-source and you should not write your own, try to find existing and suitable first. Very good site that can help you is [choosealicense.com](https://choosealicense.com). More complete one is located at [opensource.org/licenses](https://opensource.org/licenses).