{"id":13607063,"url":"https://github.com/soupi/haskell-study-plan","last_synced_at":"2025-04-04T07:04:31.587Z","repository":{"id":45004557,"uuid":"150746773","full_name":"soupi/haskell-study-plan","owner":"soupi","description":"An opinionated list of resources for learning Haskell","archived":false,"fork":false,"pushed_at":"2022-03-26T16:26:40.000Z","size":140,"stargazers_count":897,"open_issues_count":0,"forks_count":54,"subscribers_count":48,"default_branch":"master","last_synced_at":"2025-03-28T06:03:27.656Z","etag":null,"topics":["beginners-guide","guide","haskell","haskell-tutorial","learning","tutorial"],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"cc0-1.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/soupi.png","metadata":{"files":{"readme":"README.org","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-09-28T13:43:47.000Z","updated_at":"2025-03-24T04:43:13.000Z","dependencies_parsed_at":"2022-08-28T03:11:01.375Z","dependency_job_id":null,"html_url":"https://github.com/soupi/haskell-study-plan","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/soupi%2Fhaskell-study-plan","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/soupi%2Fhaskell-study-plan/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/soupi%2Fhaskell-study-plan/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/soupi%2Fhaskell-study-plan/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/soupi","download_url":"https://codeload.github.com/soupi/haskell-study-plan/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247135141,"owners_count":20889420,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["beginners-guide","guide","haskell","haskell-tutorial","learning","tutorial"],"created_at":"2024-08-01T19:01:15.227Z","updated_at":"2025-04-04T07:04:31.569Z","avatar_url":"https://github.com/soupi.png","language":null,"readme":"* Haskell Study Plan\n\n| You might also be interested in my project-oriented online book: [[https://lhbg-book.link][Learn Haskell by building a static blog generator]] |\n\n** About This Guide\nThis guide is an opinionated list of resources for learning Haskell.\n\nIt is aimed at more experienced programmers that would like a denser Haskell tutorial.\n\nIf you prefer a gentler introduction, try one of these resources:\n\n- [[https://www.seas.upenn.edu/~cis194/spring13/lectures.html][cis194 course (2013)]] or [[https://haskell-via-sokoban.nomeata.de/][Haskell via Sokoban]]\n- [[https://en.wikibooks.org/wiki/Haskell][Haskell Wikibook]]\n- [[http://haskellbook.com/][Haskell Programming From First Principles]]\n- [[http://www.cs.nott.ac.uk/~pszgmh/pih.html][Programming in Haskell]]\n\nIf you prefer videos:\n\n- [[https://www.youtube.com/playlist?list=PLe7Ei6viL6jGp1Rfu0dil1JH1SHk9bgDV][Haskell for Imperative Programmers]]\n- [[https://github.com/haskell-beginners-2022/course-plan][Haskell Beginners 2022 course]]\n\nAnd/or one of these resources to get started quickly:\n\n- [[https://kowainik.github.io/projects/learn4haskell][Kowainik's Learn4Haskell]]\n- [[https://typeclasses.com/beginner-crash-course][Typeclasses' Beginner crash course]]\n\n** Table of Contents                                                  :TOC_3:\n- [[#haskell-study-plan][Haskell Study Plan]]\n  - [[#about-this-guide][About This Guide]]\n  - [[#beginning][Beginning]]\n  - [[#more-basics-drill-down][More Basics Drill Down]]\n  - [[#tools][Tools]]\n  - [[#useful-packages][Useful Packages]]\n  - [[#exercises][Exercises]]\n    - [[#lists][Lists]]\n    - [[#sort-a-list][Sort a List]]\n    - [[#dict][Dict]]\n    - [[#ppm][PPM]]\n    - [[#rpn-calculator][RPN Calculator]]\n  - [[#lambda-calculus][Lambda Calculus]]\n    - [[#overview][Overview]]\n    - [[#exercises-1][Exercises]]\n  - [[#kinds][Kinds]]\n    - [[#overview-1][Overview]]\n    - [[#exercise][Exercise]]\n  - [[#what-is-io][What is IO?]]\n    - [[#overview-2][Overview]]\n    - [[#do-notation][Do notation]]\n    - [[#exercises-2][Exercises]]\n  - [[#type-classes][Type classes]]\n    - [[#overview-3][Overview]]\n    - [[#more-material][More Material]]\n    - [[#exercise-1][Exercise]]\n  - [[#monoids-functors-applicative-monads-and-more][Monoids, Functors, Applicative, Monads and More]]\n    - [[#overview-4][Overview]]\n    - [[#instances][Instances]]\n    - [[#exercises-3][Exercises]]\n    - [[#bonus-counterexamples-of-type-classes][Bonus: Counterexamples of Type Classes]]\n    - [[#more][More]]\n  - [[#error-handling][Error Handling]]\n    - [[#using-either-for-errors][Using Either for errors]]\n    - [[#exceptions][Exceptions]]\n    - [[#exercises-4][Exercises]]\n  - [[#laziness][Laziness]]\n  - [[#debugging][Debugging]]\n  - [[#performance][Performance]]\n    - [[#resources][Resources]]\n    - [[#data-structures][Data Structures]]\n  - [[#monad-transformers][Monad Transformers]]\n    - [[#overview-5][Overview]]\n    - [[#exercises-5][Exercises]]\n  - [[#ghc-language-extensions][GHC Language Extensions]]\n  - [[#functional-patterns][Functional Patterns]]\n    - [[#effectful-outer-layer-uneffectful-core][Effectful outer layer, Uneffectful core]]\n    - [[#compose-smaller-things-to-bigger-things][Compose Smaller Things to Bigger Things]]\n    - [[#type-classes-patterns][Type Classes Patterns]]\n    - [[#parse-dont-validate][Parse, Don't Validate]]\n    - [[#more-1][More]]\n  - [[#more-2][More]]\n    - [[#hands-on-tutorials][Hands-on tutorials]]\n    - [[#project-ideas][Project ideas]]\n    - [[#some-advanced-topics][Some Advanced Topics]]\n    - [[#references][References]]\n    - [[#news-aggregators][News Aggregators]]\n    - [[#simple-example-programs][Simple Example Programs]]\n    - [[#a-few-cool-open-source-applications][A Few Cool Open-Source Applications]]\n\n** Beginning\n1. [[https://www.haskell.org/downloads][Install Haskell]]\n2. [[https://gilmi.me/blog/post/2021/08/14/hs-core-tools][Learn about the core tools]]\n3. [[https://soupi.github.io/rfc/reading_simple_haskell][Reading Simple Haskell]]\n4. [[https://soupi.github.io/rfc/writing_simple_haskell][Writing Simple Haskell]]\n5. [[https://en.wikibooks.org/wiki/Haskell/Indentation][Indentation]]\n6. [[https://www.seas.upenn.edu/~cis194/spring13/lectures/01-intro.html][Haskell intro (cis194)]]\n7. [[http://www.scs.stanford.edu/16wi-cs240h/slides/basics.html][Haskell Basics (cs240h)]]\n8. [[https://gilmi.me/blog/post/2020/10/01/substitution-and-equational-reasoning][Substitution and Equational Reasoning]]\n9. [[https://github.com/Gabriel439/slides/blob/master/bigtechday/slides.md][Haskell and proving things]]\n   - Read until \"Everything is a Monoid\" (right after \"Chaining proofs\")\n\nThe basics are important, each resource here brings it's own view on it which will help solidify this material.\nIf there are exercises to do, do them!\n\nKey ideas:\n\n- In Haskell we use a different computation model\n  - Instead of \"telling the machine what to do in order to change the state of the machine\"\n    we \"transform data until we have the result we want\"\n- Referential Transparency enables equational reasoning\n- Types help prevent errors and help model programs\n** More Basics Drill Down\n- Wikibook\n  - [[https://en.wikibooks.org/wiki/Haskell/Recursion][Recursion]]\n  - [[https://en.wikibooks.org/wiki/Haskell/Lists_and_tuples][Lists and tuples]]\n  - [[https://en.wikibooks.org/wiki/Haskell/Type_basics][Type basics]]\n  - [[https://en.wikibooks.org/wiki/Haskell/More_on_datatypes#Named_Fields_(Record_Syntax)][Records]]\n  - [[https://en.wikibooks.org/wiki/Haskell/Higher-order_functions][Higher Order Functions]]\n  - [[https://en.wikibooks.org/wiki/Haskell/Modules][Modules]] and [[https://en.wikibooks.org/wiki/Haskell/Standalone_programs][Standalone Programs]]\n** Tools\n- [[https://www.haskell.org/hoogle/][Hoogle]]\n- [[https://github.com/ndmitchell/ghcid#readme][GHCid]]\n- Editor Integration\n  - [[https://marketplace.visualstudio.com/items?itemName=haskell.haskell][VSCode / VSCodium]] (* Recommended. Just install the `haskell` extension in vscode/vscodium.)\n  - [[https://github.com/soupi/minimal-haskell-emacs][Emacs]]\n    - [[https://github.com/soupi/minimal-haskell-emacs/tree/evil][+ vim bindings]]\n  - [[https://www.reddit.com/r/haskell/comments/9bxbwp/which_ide_are_you_using_for_hakell/][More Options]]\n- [[https://www.ahri.net/practical-haskell-programs-from-scratch/][Practical Haskell programs from scratch - a quick and easy guide]]\n- [[https://sakshamsharma.com/2018/03/haskell-proj-struct/][Structuring your first Haskell project with Stack]]\n** Useful Packages\nHere are a few useful packages you might want to use when building software with Haskell:\n\n- [[https://hackage.haskell.org/package/base][base]] - Haskell standard library. Contains large collection of useful libraries ranging from data structures to parsing combinators and debugging utilities.\n- [[https://hackage.haskell.org/package/containers][containers]] - Contains efficient general-purpose implementations of various immutable container types including sets, maps, sequences, trees, and graphs.\n- [[http://hackage.haskell.org/package/vector][vector]] - Efficient arrays.\n- [[https://hackage.haskell.org/package/text][text]] - An efficient unicode text type. It is much more efficient than the built in ~String~ type.\n- [[https://hackage.haskell.org/package/bytestring][bytestring]] - An efficient vector of byte type.\n- [[http://hackage.haskell.org/package/async][async]] - API for running IO operations asynchronously.\n- [[http://hackage.haskell.org/package/network][network]] - Low-level networking interface.\n- [[http://hackage.haskell.org/package/random][random]] - random number library.\n\nBook (paid): [[https://leanpub.com/haskell-stdlibs/][Haskell (Almost) Standard Libraries]] by Alejandro Serrano Mena\n\n[[https://hackage.haskell.org/][And more]].\n** Exercises\n*** Lists\n- [[https://wiki.haskell.org/99_questions/1_to_10][1-10 Haskell Problems]]\n- [[https://wiki.haskell.org/99_questions/11_to_20][11-20 Haskell Problems]]\n*** Sort a List\nSort a list of ints by inserting all its elements into a binary search tree.\n\n1. Define a data type of a binary search tree\n2. Write the type signatures of the functions relevant to the task (sort, insertElementToTree, listToTree, flatten, display, etc.)\n3. Implement these functions\n\nThink of scenarios and test your functions.\n*** Dict\nCompress and decompress a file using dict compression.\n\nDict compression takes text, splits it by words, and creates two things:\n1. A mapping from each word in the text to a number\n2. the original text where each word is replaced by it's map's number\n\nYour task is to create an application that can either compress or decompress a text file.\n\nThere are two commands: compress and decompress, they both get a text file.\n\n- To compress: ~\u003e dict compress file.txt~\n- To decompress: ~\u003e dict decompress file.txt~\n\nFor the compress command, the output should be the compressed items ((1) and (2)).\nFor the decompress command, the output should be the original text.\n\n*Note*: You can use the functions ~read~ and ~show~ to convert from/to some types and ~String~.\n*** PPM\nCreate a program that will output a [[https://en.wikipedia.org/wiki/Netpbm_format#PPM_example][PPM file]].\n\n1. The size of each \"pixel\" should be controlled by a parameter\n2. Your input should be a list of list of colors\n3. If a row is not long enough fill the rest of it with the color white\n4. *Bonus*: Choose a pallete of 8 or 16 basic colors and read a file containing numbers from 0 to 7 (or 15)\n   separated by spaces and newlines, and output it's image\n*** RPN Calculator\nCreate a program that calculates an arithmetic expression written in [[https://en.wikipedia.org/wiki/Reverse_Polish_notation][reverse polish notation]].\n\nImplement the following operations:\n\nliteral integers, +, -, *, /, negate\n\nExample execution:\n\n#+BEGIN_SRC\n$ rpn-calc 5 7 2 negate + *\n25\n#+END_SRC\n** Lambda Calculus\n*** Overview\nThe lambda calculus is a minimalistic language that is in the core of functional programming.\n\nIt presents a minimalistic framework to learn about many common features in functional languages.\n\nWhile this section isn't strictly necessary, and you can skip it, it does provide some\ninsight about the core of Haskell.\n\n- [[http://www.inf.fu-berlin.de/lehre/WS03/alpi/lambda.pdf][A tutorial on the lambda calculus]]\n- [[https://gitlab.cecs.anu.edu.au/pages/2019-S1/courses/comp1100/lectures/lambda.pdf][Slides on the lambda calculus]]\n- [[https://en.wikipedia.org/wiki/Lambda_calculus][Wikipedia article on the Lambda Calculus]]\n\n*** Exercises\n\n1. Reduce the following expressions to normal form using pen and paper\n   1. ~λx. x~\n   2. ~(λx. x) y~\n   3. ~(λx. x x) (λy. y)~\n   4. ~(λw. λx. λz. x w z) a (λb. λc. c b) (λd. d)~\n2. Use eta conversion on the following expression\n   1. ~λx. f x~\n   2. ~λf. λy. (λx. f x) y~\n3. Write the expression ~2 + 3~ in the lambda calculus and evaluate it using pen and paper\n4. Write the expression ~factorial 5~ in the lambda calculus and evaluate it using pen and paper\n\nUse this [[http://cdparks.github.io/lambda-machine/][Lambda Machine]] to check your answers\n\n** Kinds\n*** Overview\nEvery expression has a concrete type.\n\nKinds are the types of types.\n\nThis is a simplified view of how kinds are represented in GHC:\n\n#+BEGIN_SRC haskell\ndata Kind\n  = Type -- can also be written as: *\n  | KArr Kind Kind -- KArr in Haskell this is written as: -\u003e\n#+END_SRC\n\nThink of ~Type~ being the kind of concrete (or inhabited) types, and ~KArr~ is a function from ~Kind~ to ~Kind~.\n\nIf a type is parametarized (when defining the ADT you pass it parameters)\nthen in order for it to be concrete you have to supply it with all the types it expects to get.\n\nExample:\n\n#+BEGIN_SRC haskell\n\ndata Bool\n  = True\n  | False\n\ndata Maybe a\n  = Just a\n  | Nothing\n\n#+END_SRC\n\n~Bool~ is not parametarized so it is a concrete type (which means it's kind is ~Type~)\nand has the Values ~True~ and ~False~.\n\n~Maybe~ is not a concrete type, it need to be supplied with a type for ~a~. (It has the kind ~Type -\u003e Type~).\n\n~Maybe Bool~ is a concrete type because all of the paramters for ~Maybe~ have been supplied.\n\nAn expression can only have a type with the kind ~Type~.\n\nExamples:\n\n| Value     | Type                   | Kind                           | Comments                             |\n|-----------+------------------------+--------------------------------+--------------------------------------|\n| True      | Bool                   | Type  (also written ~*~)       | a value                              |\n| 'c'       | Char                   | Type                           |                                      |\n| \"Hello\"   | String                 | Type                           |                                      |\n| not True  | Bool                   | Type                           | function application                 |\n| Just True | Maybe Bool             | Type                           |                                      |\n| [\"Hello\"] | [String]               | Type                           |                                      |\n| Nothing   | Maybe a                | Type                           | polymorphic                          |\n| id        | a -\u003e a                 | Type                           | a function                           |\n| map       | (a -\u003e b) -\u003e [a] -\u003e [b] | Type                           |                                      |\n| map not   | [Bool] -\u003e [Bool]       | Type                           | partially applied function           |\n| getLine   | IO String              | Type                           |                                      |\n| putStrLn  | String -\u003e IO ()        | Type                           |                                      |\n|           | Void                   | Type                           | a concrete types with no values      |\n|           | Maybe                  | Type -\u003e Type                   | isn't fully supplied with parameters |\n|           | IO                     | Type -\u003e Type                   |                                      |\n|           | Either                 | Type -\u003e Type -\u003e Type           |                                      |\n|           | Either a               | Type -\u003e Type                   | partially supplied with parameters   |\n|           | Free                   | (Type -\u003e Type) -\u003e Type -\u003e Type | the first argument is of higher kind |\n\n\nYou can use ghci to query the kind of a type using ~:kind~\n\nWhy do we care about Kinds? It let us generalize things and create abstractions.\n\nLet's take a look at a data type that uses higher kinds:\n\n#+BEGIN_SRC haskell\ndata Rec f a\n  = Rec a (f (Rec f a))\n#+END_SRC\n\n- This data type has two type parameters, ~f~ and ~a~.\nFrom their use in the right side of the ~=~ we can see that ~a~ has the kind ~Type~ because\nit is placed as a field without type arguments. We can also see that ~f~ has kind ~Type -\u003e Type~\nbecause it is placed as a field with one type argument (which in this case, is the same data type we defined).\nThis makes ~Rec~ kind to be ~(Type -\u003e Type) -\u003e Type -\u003e Type~.\n\nWhy is this data type interesting? Let's try to plug some types and see.\nWe need some ~a~ which as kind ~Type~ so let's just choose ~Int~ for now, and let's use ~Maybe~ for ~f~.\nLet's look at some values of our new type ~Rec Maybe Int~.\n\n- ~x1 = Rec 1 Nothing~\n- ~x2 = Rec 1 (Just (Rec 2 Nothing))~\n- ~x3 = Rec 1 (Just (Rec 2 (Just (Rec 3 Nothing))))~\n\nSee a pattern here? it seems like this is an encoding of a non-empty list:\n\n- You always have at least one value\n- ~Nothing~ is similar to ~Nil~\n- ~Just~ is similar to ~Cons~\n\nLet's take a look at another example with this type:\n\n#+BEGIN_SRC haskell\ndata Identity a\n  = Identity a\n#+END_SRC\n\n~Identity~ basically just holds a value of type ~a~. Nothing interesting here.\n\nLet's try to plug it in ~Rec~ (and get ~Rec Identity Int~) and see what kind of value we can have:\n\n- ~y1 = Rec 1 (Identity (Rec 2 (Identity (Rec 3 (Identity ...)))))~\n- ~y2 = Rec 0 y2~\n\nAs you can see we basically need to keep providing new values with no way of bailing out.\nSo we got an infinite list of values (or a stream).\n\nWe can write all kinds of generic algorithms on this data type and reuse them\nfor different scenarios and needs simply by pluging in a different ~f~!\n\nWe'll see more of those after we talk about type classes.\n\nThere is more to Haskell's kinds system, and a really good article about it is linked later on the tutorial.\n\nAnd by the way, the real name of ~Rec~ is [[https://hackage.haskell.org/package/free-5.1/docs/Control-Comonad-Cofree.html][Cofree]].\n\n*** Exercise\nTry to plug into our ~Rec~ a different type of kind ~Type -\u003e Type~ that you know and see what happens!\n** What is IO?\n*** Overview\nIt is a parametarized type constructor (it has the kind ~Type -\u003e Type~).\n\n~IO a~ represents a description of a program (or subroutine) that when executed\nwill produce some value of type ~a~ and may do some I/O effects while at it.\n\nEvaluating an ~IO a~ is pure - the evaluation will always reduce to the same *description of a program*.\n\nIn an executable, you need to define ~main :: IO ()~ - a description of a program to run. The Haskell runtime will execute this.\n\n\nYou can combine subroutine descriptions to create bigger subroutine descriptions:\n\n1. ~pure :: a -\u003e IO a~\n\n   Produces a value without doing any I/O.\n\n   - Example: ~pure True~\n\n   Which has the type ~IO Bool~, will not do any I/O and when executed will produce a value of type ~Bool~, specifically ~True~.\n\n2. ~fmap :: (a -\u003e b) -\u003e IO a -\u003e IO b~\n\n   Similar to ~map~ on lists, it will apply a function on the parameter of ~IO~.\n\n   - Example: ~fmap not (pure True)~\n\n   Which has the type ~IO Bool~ will not do any I/O and when executed will produce a value of type ~Bool~ by first applying the function ~not~ on the result of ~pure True~,\n   and so will produce the value ~False~.\n\n3. ~(\u003e\u003e) :: IO a -\u003e IO b -\u003e IO b~\n   \n   Run this first thing, discard the result, and then run the second thing.\n\n   - Example:\n     #+BEGIN_SRC haskell\n     putStrLn \"Hello\" \u003e\u003e putStrLn \"World\"\n     #+END_SRC\n\n   Which has the type ~IO ()~, when executed, will print the string ~Hello~ and then will print the string ~World~\n   and will produce a value of type ~()~, specifically ~()~ (in this case the value has the same name as the type).\n\n4. ~(\u003e\u003e=) :: IO a -\u003e (a -\u003e IO b) -\u003e IO b~\n\n   Run this first thing, take its result, pass it to the function which is the second argument, and then execute that.\n\n   - Example: ~getLine \u003e\u003e= putStrLn~\n\n   Which has the type ~IO ()~ will read a ~String~ from the user, apply that String to ~putStrLn~ and then execute it,\n   thus printing the same string it got from the user.\n   Then it will produce a value of type ~()~, specifically ~()~.\n\n   Note: You can implement ~(\u003e\u003e)~ using ~(\u003e\u003e=)~ like this:\n\n     #+BEGIN_SRC haskell\n     (\u003e\u003e) prog1 prog2 = prog1 \u003e\u003e= \\_ -\u003e prog2\n     #+END_SRC\n\n5. ~join :: IO (IO a) -\u003e IO a~\n\n  Takes a description of a program that produces a description of a program that produces a value of type ~a~\n  and converts it to a descrption of a program that will produce a value of type ~a~ by executing the first, and then executing the result.\n\n  - Example: ~join (fmap putStrLn getLine)~\n\n  Which is the same as ~getLine \u003e\u003e= putStrLn~.\n  As you can see we can implement ~\u003e\u003e=~ using ~fmap~ and ~join~\n\n    #+BEGIN_SRC haskell\n    (\u003e\u003e=) prog func = join (fmap func prog)\n    #+END_SRC\n\nThere are many more functions and combinators that return ~IO a~. You can view some of them in the module [[http://hackage.haskell.org/package/base-4.11.1.0/docs/System-IO.html#t:IO][System.IO]].\n*** Do notation\n\ndo notation is syntactic sugar around ~\u003e\u003e~ and ~\u003e\u003e=~.\n\nExample:\n\n#+BEGIN_SRC haskell\nmain = do\n  putStrLn \"Tell me your name.\"\n  let greet name = \"Hello, \" ++ name ++ \"!\"\n  name \u003c- getLine\n  putStrLn (greet name)\n#+END_SRC\n\nWill be desugared to:\n\n#+BEGIN_SRC haskell\nmain =\n  putStrLn \"Tell me your name.\" \u003e\u003e\n    let\n      greet name = \"Hello, \" ++ name ++ \"!\"\n    in\n      getLine \u003e\u003e= \\name -\u003e\n        putStrLn (greet name)\n#+END_SRC\n\n1. A regular line that does not create a binding will be sequenced to the next using ~\u003e\u003e~\n2. A new definition can be created using ~let~, it will be translated to ~let \u003cdefinition\u003e in \u003crest of the lines in the do\u003e~\n3. A line that creates a binding with ~\u003c-~ will use ~\u003e\u003e=~ to pass the result and the lambda (~\\name -\u003e~) is used to bind the variable to the result\n4. The last line will remain the same - no desugar needed\n\nThis is basically CPS (continuation passing style).\n\n| code                    | operator | type of the left side | type of the right side | comments                                                                                    |\n|-------------------------+----------+-----------------------+------------------------+---------------------------------------------------------------------------------------------|\n| let gretting = \"hello\"  | ~=~      | String                | String                 | ~=~ means both side are interchangeable (they both mean exactly the same thing)             |\n| let mygetline = getLine | ~=~      | IO String             | IO String              | Here we just create a new name that is identical to ~getLine~. We are not running anything  |\n| name \u003c- getLine         | ~\u003c-~     | String                | IO String              | ~\u003c-~ is syntactic sugar for ~\u003e\u003e=~ where we bind the *result* of the computation to the name |\n\nIO's API fits a pattern that can be seen in more types in Haskell, which is why the type signatures\nof the functions presented here are more general. We'll discuss that later.\n*** Exercises\n- Implement a number guessing game\n  - Generate a random number between 1 and 100, the user should try to guess what it is.\n    - If the user guess is too high, say it's too high.\n    - If the user guess is too low, say it's too low.\n    - Hint: you can use [[https://hackage.haskell.org/package/random-1.1/docs/System-Random.html#v:randomRIO][randomRIO]] to generate a random number\n  - Bonus: Remember the amount of times the user guesses and print that at the end of the game.\n    - Hint: In pure functional programming we use recursion to emulate state\n  - Bonus: Remember the user's guesses and tell them if they already tried that guess.\n- Implement a [[https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop][REPL]] interface to your [[#rpn-calculator][RPN Calculator]]\n  - Create an interactive interface that lets the user repeatedly write calculations\n    and return the evaluations for them\n** Type classes\n*** Overview\nWe use type classes to describe groups of types that all behave in a similar way and refer to them generically.\n\nA good type class will have operations on the type and laws attached to it - similar to abstract algebra.\n\nLaws cannot be enforced by the compiler - a good convention in Haskell is not to define lawless type classes and not implement unlawful instances.\n\nWe define a type class like this:\n\n#+BEGIN_SRC haskell\nclass Eq (a :: *) where\n  (==) :: a -\u003e a -\u003e Bool\n#+END_SRC\n\nWe define a class of types that can implement the operation ~(==)~.\n\nWe implement an instance of a type class for a given type like this:\n\n#+BEGIN_SRC haskell\n-- In this case we place `Bool` in place of `a` everywhere\ninstance Eq Bool where\n  (==) b1 b2 = case (b1, b2) of\n    (True, True) -\u003e True\n    (False, False) -\u003e True\n    _ -\u003e False\n#+END_SRC\n\nNow we can implement polymorphic functions that will work on a subset of all types - all types that fill the constraint - have instances of a type class.\n\n#+BEGIN_SRC haskell\n(/=) :: Eq a =\u003e a -\u003e a -\u003e Bool\n(/=) x y = not (x == y)\n#+END_SRC\n\nclass instances should be defined in the same place as the type class definition or at the same place as the type definitions.\nFailing to do that may cause [[https://wiki.haskell.org/Orphan_instance][Orphan Instances]].\n\n\n| Abstraction             | definition                          | different substitutions                                     | comments                                                                        |\n|-------------------------+-------------------------------------+-------------------------------------------------------------+---------------------------------------------------------------------------------|\n| No polymorphism         | func1 ::          Int -\u003e Int -\u003e Int | none                                                        | we know exactly which types are used and can do all kinds of operations on them |\n| Parametric polymorphism | func2 ::            a -\u003e   a -\u003e   a | ~a~ can be any type                                         | We don't know which type ~a~ is and can't do any type related operations on it  |\n| Type classes (ad-hoc)   | func3 :: Ord a =\u003e   a -\u003e   a -\u003e   a | ~a~ can be any type that can be ordered (Bool, Int, String) | anything to the left of ~=\u003e~ is a constraint on the type                        |\n\n*** More Material\n\n- [[https://www.youtube.com/watch?v=6COvD8oynmI][Adventure with Types in Haskell - SPJ]]\n- [[https://en.wikibooks.org/wiki/Haskell/Classes_and_types][Haskell Wikibook Chapter on Classes and Types]]\n- [[https://en.wikibooks.org/wiki/Haskell/Type_basics_II][Numbers type classes]]\n\n*** Exercise\n- Read about a few common type classes:\n  - Show\n  - Read\n  - Eq\n  - Ord\n  - Num\n  - Integral\n  - Floating\n- Go back to [[#sort-a-list][Sort a List]] exercise and change it to work on more types than just ~Int~\n\nNote: We can create instances for higher kinded types (for example: ~Type -\u003e Type~). We will see some of those next.\n** Monoids, Functors, Applicative, Monads and More\n*** Overview\nKey idea:\n\n*These are abstract algebraic structures*\n\nThey define operations and laws on them such as identity and associativity.\n\nMany patterns fit these structures, making them useful as abstractions!\n\nType classes you should care about (at the moment):\n\n- Semigroup\n- Monoid\n- Functor\n- Applicative\n- Monad\n\n- Foldable\n- Traversable\n\nRead about them in the [[https://wiki.haskell.org/Typeclassopedia][typeclassopedia]] in this order.\n\nAfter that: read [[http://dev.stephendiehl.com/hask/#monads][The monads section in wiwik]] to meet some useful monad instances.\n\n- [[https://github.com/Gabriel439/slides/blob/master/bigtechday/slides.md][Haskell and proving things]]\n    - Read from \"Everything is a Monoid\" (right after \"Chaining proofs\") or from the beginning if you want to review it again\n\n*** Instances\nMake sure to meet:\n\n- Maybe\n- Either\n- List\n- ~-\u003e~ (Functions)\n- IO\n- Reader\n- State\n- Writer\n\nAnd understand why and how they work!\n*** Exercises\n- Implement some instances to a few types you like.\n- Implement ~Functor~, ~Foldable~ and ~Traversable~ instances for the ~Tree~ data type you defined at [[#sort-a-list][Sort a list]] and revised in [[#type-classes][Type Classes]]\n- Implement a ~Foldable~ instance for the ~Rec~ data type we defined in the section on Kinds.\n  - Test your solution by using ~Sum~, ~Product~, ~Any~ or ~All~ from ~Data.Monoid~.\n- Implement a ~Functor~ instance for the ~Rec~ data type we defined in the section on Kinds.\n  - Test your solution by mapping and then folding\n*** Bonus: [[https://blog.functorial.com/posts/2015-12-06-Counterexamples.html][Counterexamples of Type Classes]]\n*** More\n- [[https://en.wikibooks.org/wiki/Haskell][Haskell wikibook section on Monads]]\n** Error Handling\n*** Using Either for errors\nThere are quite a few ways to indicate and handle errors in Haskell.\nWe are going to look at one solution: using the type [[https://hackage.haskell.org/package/base-4.12.0.0/docs/Data-Either.html][Either]]. Either is defined like this:\n\n#+BEGIN_SRC haskell\ndata Either a b\n  = Left a\n  | Right b\n#+END_SRC\n\nSimply put, a value of type ~Either a b~ can contain either a value of type ~a~, or a value of type ~b~.\nWell can tell them apart from the contructor used.\n\n#+BEGIN_SRC haskell\nLeft True :: Either Bool b\nRight 'a' :: Either a Char\n#+END_SRC\n\nUsing this type, we can represent computations that may fail by using ~Either~ with one type to represent error values\nand the other type to represent the values we want if the computation succeeds.\n\nFor example, let's say that we want to parse a ~String~ as a decimal digit to an ~Int~. We have two possible failures:\n\n1. The string contains more than one character\n1. The string is empty\n2. The character is not one of 0,1,2,3,4,5,6,7,8,9\n\nWe can represent this as a type\n\n#+BEGIN_SRC haskell\ndata ParseDigitError\n  = EmptyString\n  | StringIsTooLong\n  | NotADigit Char\n  deriving Show\n#+END_SRC\n\nAnd our function can have the type\n\n#+BEGIN_SRC haskell\nparseDigit :: String -\u003e Either ParseDigitError Integer\n#+END_SRC\n\nNow when we check our string we can return ~Left~ on error and ~Right~ on successful parsing.\n\n\n#+BEGIN_SRC haskell\nparseDigit :: String -\u003e Either ParseDigitError Integer\nparseDigit str = case str of\n  -- empty string\n  [] -\u003e Left EmptyString\n  -- more than one character\n  _ : _ : _ -\u003e Left StringIsTooLong\n  [c] -\u003e\n    if elem c \"0123456789\"\n      then Right (read [c])\n      else Left (NotADigit c)\n#+END_SRC\n\n~Either a~ is also an instance of ~Functor~, ~Applicative~, and ~Monad~, so we have some combinators to work with\nif we want to combine these kind of computations.\n\nFor example, we can use our function to parse an integer by trying to\nparse each character (using ~traverse~) and then use a function to sum them all together\nby applying it to the ~Int~ value using ~fmap~.\n\n#+BEGIN_SRC haskell\nparseInteger :: String -\u003e Either ParseDigitError Integer\nparseInteger str = do\n  if null str\n    then Left EmptyString\n    else\n  -- We use (:[]) first because each element of a `String` is a `Char` and our functions works on `String`.\n  -- This also means that in this case only NotADigit error can be return, which is still fine.\n      let\n        digits = traverse (parseDigit . (:[])) str\n      in\n        fmap\n          ( foldr (+) 0\n          . zipWith (\\e n -\u003e 10 ^ e * n) [0..]\n          . reverse\n          )\n          digits\n#+END_SRC\n\nTry it!\n\n\nNote that since ~Either~ has kind ~Type -\u003e Type -\u003e Type~ and ~Functor~, ~Applicative~ and ~Monad~\nexpect something of kind ~Type -\u003e Type~, we can only create instances for ~Either a~ and not ~Either~.\n\nThis means that when we use, for example, ~\u003c*\u003e~ which has the type\n\n#+BEGIN_SRC haskell\n(\u003c*\u003e) :: Applicative f =\u003e f (a -\u003e b) -\u003e f a -\u003e f b\n#+END_SRC\n\nwe replace ~f~ with ~Either a~ and not ~Either~:\n\n#+BEGIN_SRC haskell\n-- We'll use `e` for the left type of the either instead of `a` here because `a` is already taken\n(\u003c*\u003e) :: Either e (a -\u003e b) -\u003e Either e a -\u003e Either e b\n#+END_SRC\n\nThis means that ~e~ must be the same. If you want, for example, to use two different error types,\ntwo approaches you can use are:\n\n1. Replace them with one big ADT that contain both errors\n2. Make one ADT that combines both types just like ~Either~ does with ~a~ and ~b~\n   and use the function ~first~ from [[https://hackage.haskell.org/package/base-4.12.0.0/docs/Data-Bifunctor.html][Data.Bifunctor]] to convert from one error type to the other.\n   (~first~ is like ~fmap~ but for the first type variable in ~Either~)\n\n*** Exceptions\n- [[https://www.oreilly.com/library/view/parallel-and-concurrent/9781449335939/ch08.html#sec_exceptions][Exceptions]]\n*** Exercises\n- Revise your [[#rpn-calculator][RPN Calculator]] to use ~Either~ to terminate early due to errors.\n** Laziness\n- [[https://apfelmus.nfshost.com/articles/lazy-eval.html][The Incomplete Guide to Lazy Evaulation (In Haskell)]]\n- [[http://blog.ezyang.com/2011/04/the-haskell-heap/][The Haskell Heap]]\n- [[https://www.oreilly.com/library/view/parallel-and-concurrent/9781449335939/ch02.html#sec_par-eval-whnf][Lazy Evaluation and Weak Head Normal Form]]\n- [[https://two-wrongs.com/how-laziness-works][How laziness works - a tour through Haskell IRs]]\n** Debugging\n- [[https://en.wikibooks.org/wiki/Haskell/Debugging][Using Traces]]\n** Performance\nHaskell can be fast and have a low memory foot-print in many scenarios even when you use immutable data structures and uneffectful code.\n\nIt is a good idea to keep your code idiomatic and measure before you decide to use mutation and other fancier methods. You may not need it!\n*** Resources\n**** General\n- [[https://en.wikibooks.org/wiki/Haskell/Performance_introduction][Introduction]]\n- [[https://www.slideshare.net/tibbe/highperformance-haskell][High Performance Haskell]]\n- [[https://www.scs.stanford.edu/16wi-cs240h/slides/perf.html][Performance (cs240h)]]\n**** Profiling\n- [[https://stackoverflow.com/questions/32123475/profiling-builds-with-stack][Profiling Builds with Stack]]\n- [[http://book.realworldhaskell.org/read/profiling-and-optimization.html][Profiling and Optimization]]\n- [[https://slides.com/sumith1896/space-leaks-in-haskell][Space Leaks in Haskell]] and [[http://neilmitchell.blogspot.com/2015/09/detecting-space-leaks.html][Detecting Space Leaks]]\n- [[https://github.com/mpickering/eventlog2html][eventlog2html]]\n**** Case Studies\n- [[https://chrisdone.com/posts/fast-haskell-c-parsing-xml/][Fast Haskell: Competing with C at parsing XML]]\n- [[https://markkarpov.com/post/migrating-text-metrics.html][Migrating text metrics to pure Haskell]]\n- [[https://two-wrongs.com/on-competing-with-c-using-haskell.html][On Competing With C Using Haskell]]\n- [[https://github.com/ChrisPenner/wc][wc - Counting Words With Haskell]]\n- [[https://www.joachim-breitner.de/blog/758-Winter_is_coming_even_more_quickly][Winter is coming even more quickly]]\n*** Data Structures\n\nThe choice of a data structure is determined by the properties of your data and the algorithms used.\n\nSingle-linked lists are a fairly ubiquious data structure in Haskell.\nDue to their simplicity and syntactic sugar, they're used all over the place - often when they're not a good choice.\n\nLists are good for:\n\n1. You only need to add or take the beginning of the list (consing), which is O(1)\n2. You use map, filter, zip and folds, which are O(N) anyway and are subject to operation fusion (aka. ~map f . map g = map (f . g)~\n3. Your list is really small and is not expected to grow\n4. Your list is infinite\n\nLists are not good if:\n\n1. You use ~lookup~ - use ~Map~\n2. You want the elements to be unique - use ~Set~\n3. You expect the list to have at least one argument, use ~NonEmpty~\n4. You use append or concat, use ~DList~ or ~Seq~\n5. You use sort with non-unique values, use ~Seq~\n\n- [[http://dev.stephendiehl.com/hask/#data-structures][More Information]]\n** Monad Transformers\n*** Overview\nFunctors and applicative interfaces [[https://hackage.haskell.org/package/transformers-0.3.0.0/docs/Data-Functor-Compose.html][can be composed easily]], but monads cannot.\n\nMonad transformers are a way to compose the capabilities of multiple type's monadic interface to one type.\n\n- [[http://slides.com/fp-ctd/lecture-7#][Haskell ITMO course at CTD - Lecture 7]]\n- [[https://two-wrongs.com/a-gentle-introduction-to-monad-transformers][A Gentle Introduction to Monad Transformers]]\n- [[https://www.schoolofhaskell.com/user/commercial/content/monad-transformers][School of Haskell - Monad Transformers]]\n- [[https://blog.jle.im/entry/mtl-is-not-a-monad-transformer-library.html][mtl is Not a Monad Transformer Library]]\n*** Exercises\n- To your [[#rpn-calculator][RPN Calculator]] REPL:\n  - Use ~Either~ to terminate an evaluation of an expression early when encountering errors\n  - Add the ~Reader~ interface to thread through the evaluation the build-in operations\n  - Add the ability for the user to define new words (with the syntax: ~: \u003cword\u003e \u003cexpressions\u003e~)\n** GHC Language Extensions\nHaskell is a standartized programming language. The last standard is [[https://www.haskell.org/onlinereport/haskell2010/][Haskell 2010]].\nGHC, the most popular Haskell compiler, contains more features than what's available in Haskell 2010.\nTo use those features, we must tell the compiler that we want to use them.\nWe do this by invoking a compiler flag or adding a ~LANGUAGE~ pragma at the top of the source file.\n\n- [[https://impurepics.com/posts/2019-08-01-haskell-extensions.html][Haskell Extensions in Pictures]]\n- [[https://limperg.de/ghc-extensions/][A Guide to GHC's Extensions]]\n** Functional Patterns\n*** Effectful outer layer, Uneffectful core\nCode that does no effects is easier to test, debug and reason about.\n\nKeeping most of our program's logic uneffectful makes it more flexible.\n\nBut programs still need to interact with the outside world.\n\nFor that, we can create an outer layer that is responsible for interacting with\nthe user and dispatching the right logic functions.\n\nNotice this pattern in these [[http://www.haskellforall.com/2015/10/basic-haskell-examples.html][Basic Haskell Examples]].\n*** Compose Smaller Things to Bigger Things\n- [[https://wiki.haskell.org/Combinator_pattern][Combinator Pattern]]\n*** Type Classes Patterns\nType Classes such as ~Monoid~, ~Functor~, ~Applicative~ and ~Monad~ can be thought of as patterns.\nThey are all around us and are at the core API of many libraries.\n\nYou can find them when doing web development, streaming, IO, concurrency,\nparsing, error handling, testing, build systems and more. \n\nExamples:\n\n- [[https://kseo.github.io/posts/2014-01-16-applicative-parsing.html][Applicative Parsing]]\n- [[https://hackage.haskell.org/package/lucid-2.9.10/docs/Lucid.html][Lucid - a DSL for writing HTML]]\n- [[https://www.oreilly.com/library/view/parallel-and-concurrent/9781449335939/ch10.html][Software Transactional Memory]]\n*** Parse, Don't Validate\n- [[https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/][Parse, don't validate]]\n*** More\n- [[https://www.fpcomplete.com/blog/2017/06/readert-design-pattern/][The ReaderT Design Pattern]]\n- [[https://www.reddit.com/r/haskell/comments/5r271m/haskell_design_patterns/][Discussion on Reddit]]\n- [[https://gumroad.com/l/CLyzT][William Yao - Abstractions in Context (book)]]\n- [[https://algebradriven.design][Algebra-Driven Design (book)]]\n** More\n*** Hands-on tutorials\n- [[https://marcosampellegrini.com/simple-haskell-book][The Simple Haskell Handbook - build a continuous integration server from scratch (book)]]\n- [[https://blog.jle.im/entry/streaming-huffman-compression-in-haskell-part-1-trees][Streaming Huffman Compression in Haskell]]\n- [[https://github.com/soupi/learn-haskell-blog-generator][Learn Haskell by building a blog generator]]\n- [[https://lokathor.gitbooks.io/using-haskell/content/][OpenGL Using Haskell]]\n- [[https://gilmi.me/blog/post/2016/10/14/lisp-to-js][Compiling Lisp to JavasScript from scratch in 350 LOC]]\n- [[https://wespiser.com/writings/wyas/home.html][Write you a Scheme, version 2]]\n- [[https://gilmi.me/blog/post/2020/12/05/scotty-bulletin-board][Building a bulletin board website using scotty and friends]]\n*** Project ideas\n- Morse code encoder/decoder\n- A file reader\n- Over the network rock-paper-scissors game\n- An RPN calculator\n- A markdown (subset) to HTML converter\n- A [[https://gemini.circumlunar.space][gemini]] server\n- Cookie clicker\n- A chat server and client\n- A picture album website\n- A pastebin clone\n- A tetris game\n- A discord bot\n*** Some Advanced Topics\nThese may not be as useful for your everyday programming tasks, but it's nice to know they exist when you need them\n\n- [[https://en.wikibooks.org/wiki/Haskell/FFI][Foreign Function Interface]]\n- [[https://chrisdone.com/posts/data-typeable][Generic Programming]]\n- [[https://markkarpov.com/tutorial/th.html][Meta Programming with Template Haskell]]\n- [[https://lexi-lambda.github.io/blog/2021/03/25/an-introduction-to-typeclass-metaprogramming][An introduction to typeclass metaprogramming]]\n- [[https://diogocastro.com/blog/2018/10/17/haskells-kind-system-a-primer/][Haskell's kind system - a primer]] and [[https://www.parsonsmatt.org/2017/04/26/basic_type_level_programming_in_haskell.html][Basic Type Level Programming]]\n- [[https://blog.sumtypeofway.com/an-introduction-to-recursion-schemes/][Recursion Schemes]]\n- [[https://skillsmatter.com/skillscasts/4251-lenses-compositional-data-access-and-manipulation][Lenses]]\n*** References\n- [[https://haskell.fpcomplete.com/tutorial/operators][Operators Glossary]]\n- [[http://dev.stephendiehl.com/hask/][What I Wish I Knew Learning Haskell]]\n*** News Aggregators\n- [[https://haskellweekly.news/][Haskell Weekly News]]\n- [[https://haskell.pl-a.net/][Haskell Planetarium]]\n*** Simple Example Programs\n- [[https://anardil.net/tag/coreutils.html][Unix core utilities in Haskell]]\n- [[https://gist.github.com/soupi/199a16be6e2071c3b724][Simple File Reader]]\n- [[https://gitlab.com/gilmi/sdl2-snake][Snake Game]]\n- [[https://gitlab.com/gilmi/sod-cmus][Simplified Web Interface to cmus]]\n- [[https://gitlab.com/gilmi/imgs][Image Server]]\n- [[https://gitlab.com/gilmi/sharelinks][Minimalistic website for link sharing]]\n- [[https://github.com/jackoe/discourse-tui][A terminal UI for discourse]]\n- [[https://github.com/alpacaaa/quad-ci][Continuous Integration system]]\n*** A Few Cool Open-Source Applications\nHere are a few cool open source applications written in Haskell that might accept contributions if you're interested.\n\n- [[https://github.com/aurapm/aura/][Aura]] - A package manager for Arch Linux and its AUR.\n- [[https://gitlab.com/gilmi/bulletin-app][bulletin-app]] - A bulletin board website app built with haskell and scotty.\n- [[https://github.com/google/codeworld][CodeWorld]] - CodeWorld is an educational environment using Haskell.\n- [[https://lettier.github.io/gifcurry/][gifcurry]] - Your open source video to GIF maker built with Haskell.\n- [[https://giml-lang.org][Giml]] - A functional programming language built live on stream.\n- [[https://github.com/therewillbecode/haskell-poker][Haskell-Poker]] - A poker site built with Haskell.\n- [[http://hledger.org/][hledger]] -  Friendly, robust, plain text accounting.\n- [[https://owickstrom.github.io/komposition][Komposition]] - The video editor built for screencasters.\n- [[https://github.com/matterhorn-chat/matterhorn][Matterhorn]] - A terminal client for the Mattermost chat system.\n- [[https://github.com/lettier/movie-monad][Movie-Monad]] - A free and simple to use video player made with Haskell.\n- [[https://neuron.zettel.page/][neuron]] - A future-proof command-line app for managing your plain-text Zettelkasten notes.\n- [[https://gilmi.me/nyx][nyx-game]] - A short bullet-hell game made with Haskell.\n- [[https://github.com/jaspervdj/patat][patat]] - Terminal-based presentations using Pandoc.\n- [[https://github.com/begriffs/postgrest][postgrest]] - REST API for any Postgres database.\n- [[https://github.com/purescript/purescript][PureScript]] - A strongly-typed language that compiles to Javascript.\n- [[https://github.com/agentm/project-m36][Project:m36]] - A relational algebra engine as inspired by the writings of Chris Date.\n- [[https://taskell.app/][Taskell]] - Command-line Kanban board/task management.\n- [[https://github.com/cdepillabout/termonad][termonad]] - A terminal emulator configurable in Haskell.\n- [[https://github.com/tidalcycles/Tidal][Tidal]] - Language for live coding of pattern.\n","funding_links":[],"categories":["Others"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsoupi%2Fhaskell-study-plan","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsoupi%2Fhaskell-study-plan","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsoupi%2Fhaskell-study-plan/lists"}