├── .gitignore ├── lhbg-v0.pdf ├── assets ├── pdf.png ├── cover.png ├── book-logo.png └── book-logo-transparent.png ├── book.toml ├── src ├── 05-glue.md ├── 03-html_printer.md ├── 06-errors_and_files │ ├── 05-summary.md │ ├── 02-except.md │ ├── 03-exceptions.md │ └── 01-either.md ├── 03-html │ ├── 08-exercises.md │ ├── 03-edsls.md │ ├── 09-summary.md │ ├── 05-modules.md │ ├── 07-internal_modules.md │ ├── 01-html_content.md │ ├── 06-escaping_characters.md │ ├── 02-type_signatures.md │ └── 04-safer_construction.md ├── SUMMARY.md ├── 10-recap.md ├── 04-markup.md ├── 11-next.md ├── 02-hello.md ├── 01-about.md ├── 12-faq.md ├── 04-markup │ ├── 03-displaying_results.md │ └── 01-data_type.md ├── 06-errors_and_files.md ├── 09-documentation.md ├── 08-testing.md └── 05-glue │ └── 01-markup_to_html.md ├── .github └── workflows │ └── gh-pages.yml └── readme.md /.gitignore: -------------------------------------------------------------------------------- 1 | .stack-work/ 2 | *~ 3 | book 4 | output/ 5 | -------------------------------------------------------------------------------- /lhbg-v0.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soupi/learn-haskell-blog-generator/HEAD/lhbg-v0.pdf -------------------------------------------------------------------------------- /assets/pdf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soupi/learn-haskell-blog-generator/HEAD/assets/pdf.png -------------------------------------------------------------------------------- /assets/cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soupi/learn-haskell-blog-generator/HEAD/assets/cover.png -------------------------------------------------------------------------------- /assets/book-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soupi/learn-haskell-blog-generator/HEAD/assets/book-logo.png -------------------------------------------------------------------------------- /assets/book-logo-transparent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soupi/learn-haskell-blog-generator/HEAD/assets/book-logo-transparent.png -------------------------------------------------------------------------------- /book.toml: -------------------------------------------------------------------------------- 1 | [book] 2 | title = "Learn Haskell by building a blog generator" 3 | description = "A project-oriented online book about Haskell" 4 | authors = ["Gil Mizrahi"] 5 | language = "en" 6 | src = "src" 7 | 8 | [output.html] 9 | git-repository-url = "https://github.com/soupi/learn-haskell-blog-generator" 10 | git-repository-icon = "fa-github" 11 | default-theme = "light" 12 | -------------------------------------------------------------------------------- /src/05-glue.md: -------------------------------------------------------------------------------- 1 | # Gluing things together 2 | 3 | In this chapter, we are going to glue the pieces we built together 4 | and build an actual blog generator. We will: 5 | 6 | 1. Read markup text from a file 7 | 2. Parse the text to a `Document` 8 | 3. Convert the result to our `Html` EDSL 9 | 4. Generate HTML code 10 | 5. Write it to a file 11 | 12 | While doing so, we will learn: 13 | 14 | - How to work with IO 15 | - How to import external libraries to process whole directories and create a simple command-line interface 16 | -------------------------------------------------------------------------------- /src/03-html_printer.md: -------------------------------------------------------------------------------- 1 | # Building an HTML printer library 2 | 3 | In this part, we'll explore a few basic building blocks in Haskell, 4 | including functions, types, and modules, while building a small HTML printer library 5 | with which we will later construct HTML pages from our markup blog posts. 6 | 7 | If you're not familiar with HTML and would like a quick tutorial before diving in, MDN's 8 | [Getting started with HTML](https://developer.mozilla.org/en-US/docs/Learn/HTML/Introduction_to_HTML/Getting_started) 9 | is a good overview of the subject. 10 | -------------------------------------------------------------------------------- /.github/workflows/gh-pages.yml: -------------------------------------------------------------------------------- 1 | name: github pages 2 | 3 | on: 4 | push: 5 | branches: 6 | - book 7 | pull_request: 8 | 9 | jobs: 10 | deploy: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v2 14 | 15 | - name: Setup mdBook 16 | shell: bash 17 | run: | 18 | wget https://gilmi.me/static/misc/mymdbook2 19 | chmod +x mymdbook2 20 | ./mymdbook2 build 21 | cp assets/book-logo.png book/ 22 | cp assets/book-logo-transparent.png book/ 23 | cp assets/pdf.png book/ 24 | cp lhbg-v0.pdf book/ 25 | echo "learn-haskell.blog" > book/CNAME 26 | 27 | - name: Deploy 28 | uses: peaceiris/actions-gh-pages@v3 29 | if: github.ref == 'refs/heads/book' 30 | with: 31 | github_token: ${{ secrets.GITHUB_TOKEN }} 32 | publish_dir: ./book 33 | -------------------------------------------------------------------------------- /src/06-errors_and_files/05-summary.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | This was quite a section. Let's recount the things we've learned. 4 | 5 | We discussed several ways to handle errors in Haskell: 6 | 7 | 1. Encoding errors as a data type and using the `Either` type to encode "a value or an error". 8 | Useful approach for uneffectful code 9 | 2. Using `ExceptT` when we want to combine the approach in (1) on top of an existing 10 | type with monadic capabilities 11 | 3. Using exceptions for IO code 12 | 13 | We've also learned a few new abstractions and techniques: 14 | 15 | 1. The `Traversable` type class, for data structures that can be traversed from left to right, 16 | such as linked lists, binary trees and `Map`s. 17 | Pretty useful when combined with another applicative functor type like `Either` or `IO` 18 | 2. The `Monad` type class extends the `Applicative` type class with the `join :: m (m a) -> m a` 19 | function. We learned that `Either` implements this type class interface, and so does `IO` 20 | 3. The `MonadTrans` type class for *monad transformers* for types that take other monads as inputs 21 | and provide a monadic interface (`>>=`, do notation, etc.) while combining both their capabilities. 22 | We saw how to stack an `Either`-like monad transformer, `ExceptT`, on top of `IO` 23 | 24 | We are almost done – only a couple more things left to do with this project. Let's go! 25 | 26 | > You can view the git commit of 27 | > [the changes we've made](https://github.com/soupi/learn-haskell-blog-generator/commit/a08d148d981fa00cb7025f1b651d7b75084dd1ae) 28 | > and the [code up until now](https://github.com/soupi/learn-haskell-blog-generator/tree/a08d148d981fa00cb7025f1b651d7b75084dd1ae). 29 | -------------------------------------------------------------------------------- /src/03-html/08-exercises.md: -------------------------------------------------------------------------------- 1 | # Exercises 2 | 3 | We need a few more features for our HTML library to be useful for 4 | our blog software. Add the following features to our `Html.Internal` module 5 | and expose them from `Html`. 6 | 7 | ## 1. Unordered lists 8 | 9 | These lists have the form: 10 | 11 | ```html 12 | 17 | ``` 18 | 19 | We want in our library a new function: 20 | ```hs 21 | ul_ :: [Structure] -> Structure 22 | ``` 23 | 24 | So that users can write this: 25 | 26 | ```hs 27 | ul_ 28 | [ p_ "item 1" 29 | , p_ "item 2" 30 | , p_ "item 3" 31 | ] 32 | ``` 33 | 34 | and get this: 35 | 36 | ```html 37 | 42 | ``` 43 | 44 | ## 2. Ordered lists 45 | 46 | Very similar to unordered lists, but instead of `