├── README.rst ├── appendix ├── language-attrs.rst └── languages.rst ├── concepts ├── algebra.rst ├── category-theory.rst ├── functions.hs ├── type-theory.rst └── why-haskell.rst ├── language ├── 000-composition.rst ├── 001-data-flow.rst ├── 01-expressions-and-equations.rst ├── 03-transform-and-combine.rst ├── 031-evaluating-expressions.rst ├── 04-functions.rst ├── 05-polymorphic-data-and-functions.rst ├── 10-recursion-and-corecursion.rst ├── 11-fold-and-unfold.rst ├── 12-composing-functions.rst ├── 13-functors.rst ├── 14-composing-functors.rst ├── 15-applicatives.rst ├── 16-arrows.rst ├── 17-monads.rst ├── 19-types.rst ├── 20-typeclasses.rst ├── 21-record-types.rst ├── 22-type-families-gadt.rst ├── 23-types-kinds.rst ├── 24-dependent-types.rst ├── 40-modules.rst ├── 50-composition-ladder.rst └── function-rep.hs ├── libs ├── concurrency.rst ├── containers.rst ├── errors-and-exceptions.rst ├── pipes.rst ├── template-haskell.rst └── transformers │ ├── transformers.hs │ └── transformers.rst ├── preface.rst └── tools └── optimization.rst /README.rst: -------------------------------------------------------------------------------- 1 | Concise Haskell 2 | =============== 3 | 4 | THIS IS A WORK IN PROGRESS. 5 | 6 | Table of Contents 7 | ----------------- 8 | 9 | * `Preface `_ 10 | 11 | Haskell Language 12 | ~~~~~~~~~~~~~~~~ 13 | 14 | * Why Haskell 15 | * Denotational Composition 16 | * Data Flow Model 17 | 18 | Basics 19 | ^^^^^^ 20 | 21 | * Expressions and Equations 22 | * Transform and Combine 23 | * Evaluating Expressions 24 | 25 | Functions 26 | ^^^^^^^^^ 27 | 28 | * Functions 29 | * Recursion 30 | * Unary and Binary 31 | * Recursive Folds 32 | * Composing Functions 33 | 34 | Functors 35 | ^^^^^^^^ 36 | 37 | * Functors 38 | * Composing Functors 39 | * Applicatives 40 | * Arrows 41 | * Monads 42 | 43 | Type System 44 | ^^^^^^^^^^^ 45 | 46 | * Polymorphic Data & Functions 47 | * Typeclasses 48 | * Record Types 49 | * Type Families and GADT 50 | * Kinds 51 | 52 | Modules and Packages 53 | ~~~~~~~~~~~~~~~~~~~~ 54 | 55 | * Modules 56 | * Packages 57 | 58 | Data Structures and Libraries 59 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 60 | 61 | * Basic Data Structures 62 | * Container Abstractions 63 | * Advanced Data Structures 64 | * Generics 65 | 66 | .. Performance 67 | ~~~~~~~~~~~ 68 | 69 | * Inside Haskell 70 | 71 | Theory 72 | ~~~~~~ 73 | 74 | * `Algebra `_ 75 | * Category Theory 76 | * Type Theory 77 | 78 | Appendix 79 | ~~~~~~~~ 80 | 81 | * Syntax Cheat Sheet 82 | * Packages 83 | * Glossary 84 | * Learning Resources 85 | * Programming Languages 86 | 87 | Contributions 88 | ------------- 89 | 90 | Contributions are welcome! You can also contribute by raising issues including 91 | specific questions or areas which are difficult or mind twisting to understand 92 | in Haskell. This will help us improve the coverage of those areas or addressing 93 | those questions in a better way with graphics, examples or better explanation. 94 | -------------------------------------------------------------------------------- /appendix/language-attrs.rst: -------------------------------------------------------------------------------- 1 | Terminology 2 | ~~~~~~~~~~~ 3 | 4 | +------------------------+----------------------------------------------------+ 5 | | DRY | Don't repeat yourself | 6 | +------------------------+----------------------------------------------------+ 7 | | PL | Programming language | 8 | +------------------------+----------------------------------------------------+ 9 | 10 | High Level Programming 11 | ---------------------- 12 | 13 | +------------+--------------------------------------------+-------------+ 14 | | data input | slice, dice, transform, combine | data output | 15 | | +--------------------------------------------+ | 16 | | | High Level Programming Language | | 17 | +------------+--------------------------------------------+-------------+ 18 | 19 | Product Building Phases 20 | ----------------------- 21 | 22 | +--------------------+--------------------------------------------+ 23 | | Short term | Long term | 24 | +====================+============================================+ 25 | | Survival | Scalable Growth | 26 | +--------------------+--------------------------------------------+ 27 | | Prototype | Mature Product | 28 | +--------------------+--------------------------------------------+ 29 | | Quick & dirty | Complex, Scalable, Performant, Sustainable | 30 | +--------------------+--------------------------------------------+ 31 | | Build with clay | Build with blocks | 32 | +--------------------+--------------------------------------------+ 33 | 34 | Basic Language Features 35 | ----------------------- 36 | 37 | +--------------------------------------------------------------------------------+ 38 | | The key is providing a feature without compromising on other features. | 39 | +--------------------------------------------------------------------------------+ 40 | 41 | +-----------+--------------------------------------------------------------+-----------------+ 42 | | | Development (maintenance) | Deployment | 43 | +===========+============================================+=================+=================+ 44 | | PL | DRY | Safe | Efficient | 45 | | +------------+-------------------------------+-----------------+ | 46 | | Feature | Expressive | Composable | Correct | | 47 | +-----------+------------+-------------------------------+-----------------+-----------------+ 48 | | Tasks | Build, Understand & Change | Test | Performance | 49 | +-----------+-------------------------+------------------+-----------------+ | 50 | | Execution | Total Time & Resources | Clock time | Quality | | 51 | +-----------+-------------------------+------------------+-----------------+-----------------+ 52 | | Cost | Total building cost | Opportunity cost | Sustenance cost | Deployment cost | 53 | +-----------+-------------------------+------------------+-----------------+-----------------+ 54 | 55 | Scalability 56 | ~~~~~~~~~~~ 57 | 58 | * Parallel 59 | * Distributed 60 | -------------------------------------------------------------------------------- /appendix/languages.rst: -------------------------------------------------------------------------------- 1 | Functionality Features 2 | ---------------------- 3 | 4 | This needs a lot of work. The judgement here is subjective and may not be 5 | accurate. The parameters need to be defined more specifically and need to 6 | provide more details on specific features and other reasons. 7 | 8 | Statically Typed 9 | ~~~~~~~~~~~~~~~~ 10 | 11 | +----------+----------------------+------------------------+------------------+ 12 | | Language | Expressive | Composable | Correct | 13 | +==========+======================+========================+==================+ 14 | | Haskell | Excellent (lazy) | Excellent (lazy, pure) | Safe | 15 | +----------+----------------------+------------------------+------------------+ 16 | | Rust | ? | Good? | Safe | 17 | +----------+----------------------+------------------------+------------------+ 18 | | Swift | Good | Depends | Safe | 19 | | | | (OO + Functional) | | 20 | +----------+----------------------+------------------------+------------------+ 21 | | Scala | Good | Depends | Safe | 22 | | | | (OO + Functional) | | 23 | +----------+----------------------+------------------------+------------------+ 24 | | C | Poor | Poor | Unsafe | 25 | +----------+----------------------+------------------------+------------------+ 26 | | C++ | Average | Poor | Unsafe | 27 | +----------+----------------------+------------------------+------------------+ 28 | | Go | Average? | Poor | Safe | 29 | +----------+----------------------+------------------------+------------------+ 30 | | Java | Average | Poor | Safe | 31 | +----------+----------------------+------------------------+------------------+ 32 | 33 | Dynamically Typed 34 | ~~~~~~~~~~~~~~~~~ 35 | 36 | +----------+----------------------+------------------------+------------------+ 37 | | Language | Expressive | Composable | Correct | 38 | +==========+======================+========================+==================+ 39 | | Clojure | | Good | Safe | 40 | +----------+----------------------+------------------------+------------------+ 41 | | Erlang | | Good | Safe | 42 | +----------+----------------------+------------------------+------------------+ 43 | | Python | | Poor | Safe | 44 | +----------+----------------------+------------------------+------------------+ 45 | 46 | Performance Features 47 | -------------------- 48 | 49 | * Concurrency, parallelism and distributed computing features are a combination 50 | of language features and libraries. 51 | * Composable concurrency and parallelism? 52 | 53 | +----------+------------+------------+---------------------+------------------+ 54 | | Language | Efficient | Concurrent | Parallel | Distributed | 55 | +==========+============+============+=====================+==================+ 56 | | Haskell | Fast | base | parallel | | 57 | | | | stm | DPH | cloud-haskell | 58 | | | | async | | courier | 59 | | | | haxl | | hdph | 60 | | | | hactor | | transient | 61 | | | | future | | | 62 | | | | promise | | | 63 | +----------+------------+------------+---------------------+------------------+ 64 | | Rust | Very Fast | Threads | | | 65 | +----------+------------+------------+---------------------+------------------+ 66 | | Swift | Very Fast | GCD | | | 67 | +----------+------------+------------+---------------------+------------------+ 68 | | Scala | Fast | threading | Parallel Collections| Akka | 69 | | | | Futures | | | 70 | | | | Actors | | | 71 | | | | STM | | | 72 | | | | Akka | | | 73 | +----------+------------+------------+---------------------+------------------+ 74 | | C | Very Fast | | | | 75 | +----------+------------+------------+---------------------+------------------+ 76 | | C++ | Very Fast | | | | 77 | +----------+------------+------------+---------------------+------------------+ 78 | | Go | Fast | Goroutines | | | 79 | +----------+------------+------------+---------------------+------------------+ 80 | | Java | Fast | threading | | | 81 | | | | Futures | | | 82 | | | | ForkJoin | | | 83 | +----------+------------+------------+---------------------+------------------+ 84 | 85 | Misc Notes 86 | ---------- 87 | 88 | * Portability 89 | 90 | * Haskell - Native, JVM, interoperates with C/R/Java/Python/Rust 91 | 92 | * Swift: compile time ARC, unsafe (unmanaged memory) is possible. 93 | 94 | * live coding playgrounds 95 | * REPL 96 | * JIT in dev 97 | * ABI compatible with C 98 | * Rust: Ownership and borrowing for shared memory and concurrency 99 | 100 | * unsafe (unmanaged memory) is possible. 101 | -------------------------------------------------------------------------------- /concepts/algebra.rst: -------------------------------------------------------------------------------- 1 | Algebra 2 | ======= 3 | 4 | .. contents:: Table of Contents 5 | :depth: 1 6 | 7 | Terminology 8 | ----------- 9 | 10 | +-------------------+---------------------------------------------------------+ 11 | | Dual | An opposite and complementary concept. | 12 | +-------------------+---------------------------------------------------------+ 13 | | Cartesian product | For sets A and B, the Cartesian product A × B is the | 14 | | | set of all ordered pairs (a, b) where a ∈ A and b ∈ B. | 15 | +-------------------+---------------------------------------------------------+ 16 | | Relation | A mapping from elements of one set to another | 17 | +-------------------+---------------------------------------------------------+ 18 | | Function | A relation where one source maps to only one target | 19 | +-------------------+---------------------------------------------------------+ 20 | | Partial function | A function that is not defined for some values | 21 | | | of its parameters | 22 | +-------------------+---------------------------------------------------------+ 23 | | Total function | A function which is defined for all values | 24 | | | of its parameters. | 25 | +-------------------+---------------------------------------------------------+ 26 | | Homomorphism | A homomorphism is a structure-preserving map between | 27 | | | two algebraic structures of the same type. | 28 | | | Literally meaning, having same shape. | 29 | +-------------------+---------------------------------------------------------+ 30 | 31 | Classes 32 | ------- 33 | 34 | +-------------------+---------------------------------------------------------+ 35 | | Class | | 36 | +-------------------+---------------------------------------------------------+ 37 | | Proper class | | 38 | +-------------------+---------------------------------------------------------+ 39 | 40 | Sets 41 | ---- 42 | 43 | +----------------------------------------------------------+----------------------------------------------------------+-------------------+ 44 | | Structure | Definition | Example | 45 | +==========================================================+==========================================================+===================+ 46 | | `Set `_ | A collection of distinct objects. | {1, 2, 3, 4, ...} | 47 | +----------------------------------------------------------+----------------------------------------------------------+-------------------+ 48 | 49 | In Haskell, data types correspond to the sets in mathematics. For example the 50 | type `Int` represents the following set of values:: 51 | 52 | {..., -3, -2, -1, 0, 1, 2, 3, ...} 53 | 54 | Composite Sets 55 | -------------- 56 | 57 | Larger composite sets can be created by combining primitive sets. Two very 58 | useful combining operations are `cartesian product` or simply `product`, and 59 | `coproduct` or `sum`. 60 | 61 | Algebraic data types (ADT) in Haskell are defined as products or sums of 62 | primitive or basic data types. 63 | 64 | Cartesian Product 65 | ~~~~~~~~~~~~~~~~~ 66 | 67 | Given two sets `A` and `B`, `A × B` is the cartesian product. It represents all 68 | tuples `(a,b)` where `a` is from set `A` and `b` is from set `B`. If `A` has 69 | `m` elements and `B` has `n` elements then `A × B` will have `m × n` elements. 70 | 71 | In Haskell a product of two types (a type represents a set) can be represented 72 | as a two tuple, the following two forms are equivalent: 73 | 74 | +-------------------------------+---------------------------------------------+ 75 | | ``data (a, b) = (a, b)`` | ``data Product = Product Int Int`` | 76 | +-------------------------------+---------------------------------------------+ 77 | 78 | A cartesian product `Int × Int` i.e. `(Int, Int)` type can have values like:: 79 | 80 | (0,0) 81 | (0,1) 82 | (0,-1) 83 | (1,0) 84 | (1,-1) 85 | ... 86 | 87 | Coproduct or Sum 88 | ~~~~~~~~~~~~~~~~ 89 | 90 | A coproduct or sum is the disjoint union of two sets. An element of the 91 | disjoint union of `a` and `b` is either an element of `a` or an element of `b`. 92 | If the two sets overlap, the disjoint union contains two copies of the 93 | overlapping elements. Coproduct is a concept from category theory and is a 94 | dual of product. It is also called a sum. 95 | 96 | The Haskell data type `Either` is a coproduct of data types `a` and `b`:: 97 | 98 | data Either a b = Left a | Right b 99 | 100 | You can think of an element of a disjoint union as being tagged with an 101 | identifier that specifies its originating set. Therefore, it is also called a 102 | `tagged union`, `Left` and `Right` being the tags. 103 | 104 | A coproduct represents a choice or disjunction in contrast to product which 105 | represents a combination or conjunction. 106 | 107 | Mappings Between Sets 108 | --------------------- 109 | 110 | (Binary) Relations 111 | ~~~~~~~~~~~~~~~~~~ 112 | 113 | A relation `maps` elements of one set to another set. A `binary relation` 114 | between two sets is represented by a set of pairs of related elements of the 115 | two sets. In other words, a relation from set `X` to set `Y` is a subset of 116 | their Cartesian product `X × Y`. `X` is called the `domain` of the relation and 117 | `Y` is called `codomain` or `range`. Relations are also known as 118 | `correspondences`. 119 | 120 | An example of a relation is `greater than` between two sets of natural numbers. 121 | This relation maps each element in one set to every element in the other set. 122 | 123 | `Functions `_ 124 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 125 | 126 | A function is a binary relation where the first value of every tuple is unique 127 | through the set. That is, one element in the domain maps to at most one element 128 | in the range. 129 | 130 | A function `f` that maps values from a set `X` to another set `Y` is denoted as 131 | `f: X → Y`. `X` is called the domain and `Y` the codomain of `f`. 132 | 133 | .. |invalid| image:: https://github.com/harendra-kumar/concise-haskell-diagrams/blob/master/algebra/invalid.png 134 | .. |total| image:: https://github.com/harendra-kumar/concise-haskell-diagrams/blob/master/algebra/total.png 135 | .. |partial| image:: https://github.com/harendra-kumar/concise-haskell-diagrams/blob/master/algebra/partial.png 136 | 137 | +------------+------------------------------------------+---------------------------+ 138 | | Type | Property | Examples | 139 | +============+==========================================+===========================+ 140 | | Valid | f(X) maps to only one element in Y | |invalid| | 141 | +------------+------------------------------------------+-------------+-------------+ 142 | | Total | f(X) is defined for all elements in X | |total| | |partial| | 143 | +------------+------------------------------------------+-------------+-------------+ 144 | | Injective | one-to-one i.e. f(x1) /= f(x2) | | | 145 | +------------+------------------------------------------+-------------+-------------+ 146 | | Surjective | onto i.e. each element in Y is mapped to | | | 147 | +------------+------------------------------------------+-------------+-------------+ 148 | | bijective | Injective & surjective i.e. | | | 149 | | | one-to-one from whole X to whole Y | | | 150 | +------------+------------------------------------------+-------------+-------------+ 151 | 152 | Relations are a generalization of functions. For example, `greater than` is a 153 | relation but not a valid function because it can map one element in a domain to 154 | more than one element in codomain. 155 | 156 | Types of Functions 157 | ------------------ 158 | 159 | Unary Operation 160 | ~~~~~~~~~~~~~~~ 161 | 162 | A unary operation transforms a type into another type or in other words it maps 163 | the values from one set (type) to values in another set (type). 164 | 165 | +-------------------------------+---------------------------------------------+ 166 | | Math Notation | Haskell Type | 167 | +-------------------------------+---------------------------------------------+ 168 | | f: X → Y | f :: x -> y | 169 | +-------------------------------+---------------------------------------------+ 170 | 171 | Binary Operation 172 | ~~~~~~~~~~~~~~~~ 173 | 174 | A binary operation combines two objects of potentially different types into a 175 | third object of potentially different type. In other words, it maps the 176 | cartesian product of two sets (types) to a target set (type). In Haskell a 177 | binary functions are implemented by currying that is applying one argument at a 178 | time. 179 | 180 | +-------------------------------+---------------------------------------------+ 181 | | Math Notation | Haskell Type | 182 | +-------------------------------+---------------------------------------------+ 183 | | :: | :: | 184 | | | | 185 | | f: X → Y → Z | f :: (x, y) -> z | 186 | | | f :: x -> y -> z | 187 | | | f :: x -> (y -> z) | 188 | +-------------------------------+---------------------------------------------+ 189 | 190 | N-ary Operations 191 | ~~~~~~~~~~~~~~~~ 192 | 193 | An N-ary operation combines `n` objects of potentiall different types into one 194 | object of potentially different type or in other words it maps the product of n 195 | sets (types) into a target set. In Haskell, n-ary operations are implemented by 196 | currying i.e. applying one argument at a time. 197 | 198 | Algebraic Structures 199 | -------------------- 200 | 201 | An algebraic structure is a set (called `carrier set` or underlying set) with 202 | one or more operations defined on it that satisfies a list of axioms. Some 203 | examples of algebraic structures of programming importance are semigroups and 204 | monoids. 205 | 206 | In Haskell, a set is represented by a `type` and operations are `functions` on 207 | the type. 208 | 209 | Algebraic Composition 210 | --------------------- 211 | 212 | Composing objects (Magma) 213 | ~~~~~~~~~~~~~~~~~~~~~~~~~ 214 | 215 | `Magma` is a family of algebraic structures that allow us to combine multiple 216 | objects in a set using binary functions. The most basic structure, magma, is 217 | incrementally specialized to derive more restrictive and sophisticated 218 | structures. 219 | 220 | +----------------------------------------------------------+----------------------------------------------------------+-------------------------------------+ 221 | | Structure | Definition | Example | 222 | +==========================================================+==========================================================+=====================================+ 223 | | `Magma `_ | A set with a single binary operation (closed, M × M → M) | {1, 2, 3, ...} | 224 | | | | | 225 | | | | ``x1 + x2 = x3`` | 226 | +----------------------------------------------------------+----------------------------------------------------------+-------------------------------------+ 227 | | `Semigroup `_ | A magma with a binary operation that is associative | ``(x1 + x2) + x3 = x1 + (x2 + x3)`` | 228 | +----------------------------------------------------------+----------------------------------------------------------+-------------------------------------+ 229 | | `Monoid `_ | A semigroup with an identity element | {0, 1, 2, 3, ...} | 230 | | | | | 231 | | | | ``x + 0 = x = 0 + x`` | 232 | +----------------------------------------------------------+----------------------------------------------------------+-------------------------------------+ 233 | | `Group | A monoid with an invertible operation | | 234 | | `_ | | | 235 | | | | ``x * y = id = y * x`` | 236 | +----------------------------------------------------------+----------------------------------------------------------+-------------------------------------+ 237 | 238 | Haskell Typeclasses 239 | ~~~~~~~~~~~~~~~~~~~ 240 | 241 | +-----------------------------------------------------------------------------+ 242 | | Algebraic structures to compose multiple objects using a binary function | 243 | +-------------------------------------+---------------------------------------+ 244 | | Combine | Fold | 245 | +=====================================+=======================================+ 246 | | Semigroup | Monoid | 247 | +-------------------------------------+---------------------------------------+ 248 | 249 | Monoid 250 | ~~~~~~ 251 | 252 | A `Monoid` is the most commonly used structure because it is simple enough to 253 | not be too restrictive and sophisticated enough to be quite useful. 254 | 255 | A simple example of a Monoid in Haskell is a two tuple e.g. (a, b). For example 256 | 257 | * `(Int, Int)` is a monoid under addition (+) with 0 as the identity. 258 | * `(Int, Int)` is a monoid under multiplication (*) with 1 as the identity. 259 | 260 | Global and local identities:: 261 | 262 | ∃x∀y x.y=y.x=y 263 | ∀y∃x x.y=y.x=y 264 | 265 | Summary 266 | ------- 267 | 268 | +-------------------+----------------+-------------------------------+--------------------+ 269 | | Algebraic Concept | Notation | Corresponding Haskell Concept | Notation | 270 | +===================+================+===============================+====================+ 271 | | Set | `X` | Type | `x` | 272 | +-------------------+----------------+-------------------------------+--------------------+ 273 | | Cartesian Product | `X × Y` | Tuple | `(x, y)` | 274 | +-------------------+----------------+-------------------------------+--------------------+ 275 | | Coproduct or Sum | `X + Y` | Either | `Left x` or | 276 | | | | | `Right y` | 277 | +-------------------+----------------+-------------------------------+--------------------+ 278 | | Unary operation | `f: X → Y` | Single argument function | `f :: x -> y` | 279 | +-------------------+----------------+-------------------------------+--------------------+ 280 | | Binary Operation | `f: X × Y → X` | Uncurried form | `f :: (x, y) -> x` | 281 | | | +-------------------------------+--------------------+ 282 | | | | Curried form | `f :: x -> y -> x` | 283 | +-------------------+----------------+-------------------------------+--------------------+ 284 | -------------------------------------------------------------------------------- /concepts/category-theory.rst: -------------------------------------------------------------------------------- 1 | Categorical Composition 2 | ======================= 3 | 4 | Terminology 5 | ----------- 6 | 7 | +------------------+----------------------------------------------------------+ 8 | | hom-set | | 9 | +------------------+----------------------------------------------------------+ 10 | | 2-category | A category with "morphisms between morphisms"; that | 11 | | | is, where each hom-set itself carries the structure of a | 12 | | | category. | 13 | +------------------+----------------------------------------------------------+ 14 | | Product category | The product of two categories C and D, denoted C × D and | 15 | | | called a product category, is a straightforward extension| 16 | | | of the concept of the Cartesian product of two sets | 17 | +------------------+----------------------------------------------------------+ 18 | | Coproduct | | 19 | +------------------+----------------------------------------------------------+ 20 | | Bi-functor | A functor whose domain is a product category | 21 | +------------------+----------------------------------------------------------+ 22 | | Profunctor | Generalizes functors the way relations generalize | 23 | | | functions. | 24 | +------------------+----------------------------------------------------------+ 25 | | Kleisli category | A category naturally associated to any monad T. | 26 | +------------------+----------------------------------------------------------+ 27 | | Monoidal Category| A monoidal category is a category equipped with a | 28 | | | tensor product and a unit object. | 29 | | | Monoidal categories can be used to define the concept | 30 | | | of a monoid object and an associated action on the | 31 | | | objects of the category | 32 | +------------------+----------------------------------------------------------+ 33 | | Catamorphism | the unique homomorphism from an initial algebra into | 34 | | | some other algebra. | 35 | | | catamorphisms provide generalizations of folds of lists | 36 | | | to arbitrary algebraic data types | 37 | +------------------+----------------------------------------------------------+ 38 | | Anamorphism | The categorical dual of catamorphism. Generalizes unfolds| 39 | +------------------+----------------------------------------------------------+ 40 | | F-Algebra | | 41 | +------------------+----------------------------------------------------------+ 42 | 43 | * comma category 44 | * limits and colimits 45 | * adjunctions 46 | 47 | * tensorial strength - natural transformation preserving certain structure of 48 | the functor is the strength of the functor. 49 | 50 | Layman description 51 | ------------------ 52 | 53 | The key point is that there is a correspondence (which 54 | implies difference as well) between parallel worlds. And we derive an 55 | operation in a world from an operation in another one by just 56 | defining a transformation because there is a correspondence. This 57 | allows reuse. 58 | 59 | Illustrate category theory with an example of the number system. How we can 60 | apply a solution from one field to another by abstracting it. How relationships 61 | among different objects/concepts are important and the specific details of the 62 | objects are just noise. 63 | 64 | Morphisms and Galois Connections 65 | -------------------------------- 66 | 67 | Morphisms are exact one to one correspondence whereas Galois Connections 68 | are correspondence of one object to multiple in another world. Both are 69 | relations or correspondences only the rules of correspondence are 70 | different. Or in other words a Galois Connections defines an object 71 | which is an approximate or reduction of multiple objects in another 72 | world. 73 | 74 | Definition by relations 75 | ----------------------- 76 | 77 | In category theory an object is uniquely defined by its relations with other 78 | objects. There is nothing absolute, everything is relative. So you do not need 79 | a reference frame. Things are always in relation to other things and those 80 | relations define what they are. This true about everything and can be applied 81 | to things in everyday life and anything in the universe. 82 | 83 | That is one of the reasons why we unnderstand concepts better when we think 84 | about their duals. We think of a concept in relation to its dual. For example 85 | we understand 0 and infinity better when we think about them both as duals of 86 | each other rather than when we only think about one and not the other. 87 | 88 | Objects are immaterial 89 | ---------------------- 90 | 91 | In categories we have nothing to do with the objects per se they are opaque to 92 | us. Objects are only the endpoints of functions. We are only operating on the 93 | functions more generally known as morphisms in category theory. 94 | 95 | Universal Construction 96 | ~~~~~~~~~~~~~~~~~~~~~~ 97 | 98 | There is a common construction in category theory called the universal 99 | construction for defining objects in terms of their relationships. It is 100 | universal because the objects do not matter. The construction holds for any 101 | object. As long as the relationships are the same we have the same 102 | construction. Its a generalized construction irrespective of what our objects 103 | are. It is an abstraction, meaning the objects do not matter we have an 104 | abstract concept defined just by the relationships among objects. 105 | 106 | For example a product type for sets is defined as: 107 | 108 | data (a, b) = (a, b) 109 | 110 | The relationships or morphisms or functions between the constituent sets a and 111 | b and the product (a,b) are: 112 | 113 | fst (a, b) = a 114 | snd (a, b) = b 115 | 116 | Now, if any opaque object satisfies the same relationships then we have a 117 | generalized product construction. Does not matter what the objects are if they 118 | satisfy fst and snd type of relationships we have a product of the two objects. 119 | 120 | A product of two objects a and b is the object c equipped with two projections 121 | such that for any other object c’ equipped with two projections there is a 122 | unique morphism m from c’ to c that factorizes those projections. 123 | 124 | coproduct is the dual of product. 125 | 126 | A coproduct of two objects a and b is the object c equipped with two injections 127 | such that for any other object c’ equipped with two injections there is a 128 | unique morphism m from c to c’ that factorizes those injections. 129 | 130 | A product behaves like multiplication, with the terminal object playing the 131 | role of one; whereas coproduct behaves more like the sum, with the initial 132 | object playing the role of zero. In particular, for finite sets, the size of 133 | the product is the product of the sizes of individual sets, and the size of the 134 | coproduct is the sum of the sizes. 135 | 136 | ------ 137 | 138 | left :: a -> Either a b is the dual of the projection fst :: (a,b) -> a 139 | 140 | Category 141 | -------- 142 | 143 | A category C consists of objects (denoted as ``a``, ``b`` etc.) and morphisms 144 | (aka arrows, denoted as ``f``, ``g`` etc.) and a binary operation called 145 | ``composition`` of morphisms (denoted as ``f . g`` and read as `f after g`). 146 | 147 | * small category: objects and morphisms are sets and not proper classes 148 | * large category: objects and morphisms are proper classes 149 | 150 | A category is not closed under the binary operation unlike algebraic 151 | structures. 152 | 153 | +-----------------------------+-------------------------------------------+---------------------+ 154 | | Category Structure | Definition | Corresponding | 155 | | | | algebraic structure | 156 | +=============================+===========================================+=====================+ 157 | | Semicategory (Semigroupoid) | Composition is associative | Semigroup | 158 | | | | | 159 | | | ``f . (g . h) = (f . g) . h`` | | 160 | +-----------------------------+-------------------------------------------+---------------------+ 161 | | (Small) category | Composition has identity | Monoid | 162 | | | | | 163 | | | ``f . id = f = id . f`` | | 164 | +-----------------------------+-------------------------------------------+---------------------+ 165 | | Groupoid | Every morphism is invertible or the | | 166 | | | category can be viewed as having an | Group | 167 | | | associated unary operation called | | 168 | | | ``inverse`` | | 169 | +-----------------------------+-------------------------------------------+---------------------+ 170 | 171 | A Category is any Semigroupoid for which the Yoneda lemma holds. 172 | 173 | Examples 174 | -------- 175 | 176 | +---------+--------------------------------+---------------+ 177 | | Category| Objects | Morphisms | 178 | +=========+================================+===============+ 179 | | Set | sets | functions | 180 | +---------+--------------------------------+---------------+ 181 | | Cat | small categories | functors | 182 | +---------+--------------------------------+---------------+ 183 | | Hask | types | functions | 184 | +---------+--------------------------------+---------------+ 185 | 186 | Morphisms 187 | ~~~~~~~~~ 188 | 189 | Morphisms are more general than functions. For example a morphism could be a 190 | relation (e.g. a "greater than" relationship) rather than a function. 191 | 192 | +--------------+--------------+------------------+----------------------------+ 193 | | Morphism | Function Eq. | Rule | Description | 194 | +==============+==============+==================+============================+ 195 | | Monomorphism | Injective | f . g1 /= f . g2 | Maps one to one | 196 | | (f) | | +----------------------------+ 197 | | | | | Unique right inverse exists| 198 | +--------------+--------------+------------------+----------------------------+ 199 | | Epimorphism | Surjective | g1 . f /= g2 . f | Produces unique results | 200 | | (f) | | | when mapped | 201 | | | | +----------------------------+ 202 | | | | | Unique left inverse exists | 203 | +--------------+--------------+------------------+----------------------------+ 204 | | Bimorphism | Bijective | Epi + Mono | Both left and right | 205 | | | | | inverse are unique | 206 | +--------------+--------------+------------------+----------------------------+ 207 | | Isomorphism | | f . g = idY | f: X -> Y, g: Y -> X | 208 | | (f & g) | | | | 209 | | | | g . f = idX | f and g are isomorphisms | 210 | | | | | and inverses | 211 | +--------------+--------------+------------------+----------------------------+ 212 | | Endomprhism | | f: X → X | | 213 | | (f) | | | | 214 | +--------------+--------------+------------------+----------------------------+ 215 | | Automorphism | | Endo + Iso | | 216 | +--------------+--------------+------------------+----------------------------+ 217 | 218 | Inverses 219 | ~~~~~~~~ 220 | 221 | When an operation maps more than one values to a single value an inverse will 222 | not be unique. In case of functions this means inverse will not be a valid 223 | function. 224 | 225 | * retraction: left inverse 226 | * section: right inverse 227 | 228 | Special morphisms 229 | ----------------- 230 | 231 | +------------------------+----------------------------------------------------+ 232 | | Functor | A morphism from one (small) category to another | 233 | +------------------------+----------------------------------------------------+ 234 | | Natural Transformation | A morphism from a functor to another functor | 235 | +------------------------+----------------------------------------------------+ 236 | 237 | Functors 238 | -------- 239 | 240 | * Endofunctor - a functor from a category to itself 241 | 242 | Products and Coproducts 243 | ----------------------- 244 | 245 | A product behaves like multiplication, with the terminal object playing the 246 | role of one; whereas coproduct behaves more like the sum, with the initial 247 | object playing the role of zero. In particular, for finite sets, the size of 248 | the product is the product of the sizes of individual sets, and the size of the 249 | coproduct is the sum of the sizes. 250 | 251 | Product 252 | ~~~~~~~ 253 | 254 | In Haskell a product of two types can be represented as:: 255 | 256 | data (a, b) = (a, b) 257 | 258 | Product is "AND" or conjunction - it has two elements - say, `x` from `a` AND 259 | `y` from `b`. 260 | 261 | Coproduct or Sum 262 | ~~~~~~~~~~~~~~~~ 263 | 264 | The dual of product is coproduct. A coproduct represents a choice. It can be 265 | represented by the `Either` data type in Haskell:: 266 | 267 | data Either a b = Left a | Right b 268 | 269 | Coproduct is "OR" or disjunction - it has one element which is - either `x` 270 | from `a` OR `y` from `b`. 271 | 272 | Hakell Typeclasses 273 | ------------------ 274 | 275 | +-----------------------------------------------------------------------------+ 276 | | Categorical structures to compose multiple functions using a binary | 277 | | operation called composition. | 278 | +-------------------------------------+---------------------------------------+ 279 | | Combine | Fold | 280 | +=====================================+=======================================+ 281 | | Semigroupoid | Category | 282 | +-------------------------------------+---------------------------------------+ 283 | 284 | Hask - Category of Haskell Types 285 | -------------------------------- 286 | 287 | Haskell types and (monomorphic) functions form a category which is called `Hask`. 288 | 289 | +-----------------------------------------------------------------------------+ 290 | | Category Hask | 291 | +=====================+=======================================================+ 292 | | Objects | types | 293 | +---------------------+-------------------------------------------------------+ 294 | | Morphisms | functions | 295 | +---------------------+-------------------------------------------------------+ 296 | | combining operation | function composition | 297 | +---------------------+-------------------------------------------------------+ 298 | 299 | Functors in Hask 300 | ~~~~~~~~~~~~~~~~ 301 | 302 | In Haskell a functor maps functions from category Hask to Hask. Therefore every 303 | instance of a functor in Hask is an endofunctor. 304 | 305 | For example, list type `[]` is a `Functor` type because it provides `map` which 306 | is a function to map any function from type `a` to type `[a]`. For example, 307 | `Int` and `[Int]` are two types in Hask, `map succ [1,2,3]` maps the function 308 | `succ` which works on `Int` to work on `[Int]`. 309 | 310 | Natural Transformations 311 | ~~~~~~~~~~~~~~~~~~~~~~~ 312 | 313 | An `Applicative` functor in Haskell provides two natural transformations i.e. 314 | `pure` and `<*>` to transform the functor. 315 | 316 | Monoidal Category of Endofunctors 317 | --------------------------------- 318 | 319 | * objects - functors 320 | * morphism - natural transformation 321 | * combine and fold - natural transformations 322 | * combining operation - tensor 323 | 324 | In category theory, preservation of monoidal structure is related to tensorial 325 | strength, so an applicative functor is also known as a strong lax monoidal 326 | functor. However, in Hask, every functor has canonical strength with respect to 327 | the product, so this property doesn't add anything to the definition. 328 | 329 | 330 | For example an applicative is a functor with two natural transformations to 331 | preserve the monoidal structure. 332 | 333 | Notions of Computation 334 | ---------------------- 335 | 336 | Computation involves combining or folding functions or computations together. 337 | The most convenient and powerful way to fold is using a monoid. 338 | 339 | +-----------------------------------------------------------------------------+ 340 | | Each one of the three well-known notions of computations in Haskell are a | 341 | | monoid in a monoidal category. | 342 | +-------------+--------------+------------------------------------------------+ 343 | | Structure | Monoidal | Description | 344 | | | category | | 345 | +=============+==============+================================================+ 346 | | Applicative | Endofunctors | lax monoidal functors with a compatible | 347 | | | | strength. | 348 | | | | Monoids in a monoidal category of endofunctors | 349 | | | | using Day convolution as a tensor. | 350 | +-------------+--------------+------------------------------------------------+ 351 | | Arrows | Profunctors | Strong monoids in a monoidal category of | 352 | | | | profunctors. | 353 | +-------------+--------------+------------------------------------------------+ 354 | | Monad | Endofunctors | Monoids in a monoidal category of endofunctors | 355 | | | | using composition as a tensor. | 356 | +-------------+--------------+------------------------------------------------+ 357 | 358 | The main difference between monads and applicative functors is that the latter 359 | does not allow effects to depend on previous values, i.e. they are fixed 360 | beforehand. 361 | 362 | * A normal function could be wrapped in a (applicative) type and applied 363 | to values wrapped in the same type. This is another way of composing 364 | which is a transformation on normal function application to the peculiar 365 | world of the type. 366 | * An applicative allows you to compose functor applications, monoidal functor 367 | * A monad allows you to compose by chaining or collecting and using the results 368 | in a certain way. A do block in Monad allows you to chain conveniently. In 369 | monad you first compose the actions and then run them using an input. 370 | 371 | Applicative, Monad, Arrows all provide facilities to compose computations and 372 | that is why the corresponding modules are in `Control.*` namespace. On the 373 | other hand a Functor allows transformation of a type and its operations to 374 | another and is therefore under `Data.*` namespace. 375 | 376 | References 377 | ---------- 378 | 379 | * https://bartoszmilewski.com/2014/10/28/category-theory-for-programmers-the-preface/ 380 | * https://stackoverflow.com/questions/43572970/is-coproduct-the-same-as-sum-types 381 | * https://stackoverflow.com/questions/14249955/why-isnt-there-a-simple-syntax-for-coproduct-types-in-haskell 382 | -------------------------------------------------------------------------------- /concepts/functions.hs: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env stack 2 | {- stack runghc 3 | --package base 4 | --package diagrams-lib 5 | --package diagrams-svg 6 | --package diagrams-rasterific 7 | -- 8 | -hide-all-packages 9 | -} 10 | 11 | {-# LANGUAGE NoMonomorphismRestriction #-} 12 | 13 | import System.Environment 14 | import Diagrams.Prelude 15 | --import Diagrams.Backend.SVG.CmdLine 16 | import Diagrams.Backend.Rasterific.CmdLine 17 | 18 | --main = mainWith [("functions", invalid === (partial ||| strutX 1 ||| total))] 19 | main = mainWith 20 | [ ("invalid", invalid) 21 | , ("partial", partial) 22 | , ("total" , total) 23 | , ("structure", structure) -- algebraic structure 24 | ] 25 | 26 | namedText :: String -> Diagram B 27 | namedText x = text x # named x 28 | 29 | dom :: [String] -> Diagram B 30 | dom xs = ellipse 0.92 <> (vsep 1.3 (map namedText xs) # scale 0.25 # centerY) 31 | 32 | domain, codomain :: [String] -> Diagram B 33 | domain xs = label "Domain" === dom xs 34 | codomain xs = (label "Codomain" ||| strutX 0.52) === dom xs 35 | 36 | label :: String -> Diagram B 37 | label x = 38 | strutY 0.25 39 | === 40 | text x # scale 0.2 41 | === 42 | strutY 0.25 43 | 44 | func :: String -> Diagram B -> Diagram B -> [(String, String)] -> Diagram B 45 | func l d c a = frame 0.2 $ 46 | foldr (uncurry connect) (hsep 1 [d, c]) a 47 | # centerX 48 | === label l 49 | 50 | invalid :: Diagram B 51 | invalid = func "Invalid" 52 | (domain ["a", "b", "c"]) 53 | (codomain ["1", "2", "3"]) 54 | [("a", "1"), ("b", "2"), ("b", "3")] 55 | 56 | partial :: Diagram B 57 | partial = func "Partial" 58 | (dom ["a", "b", "c"]) 59 | (dom ["1", "2", ""]) 60 | [("a", "1"), ("b", "2")] 61 | 62 | 63 | total :: Diagram B 64 | total = func "Total" 65 | (dom ["a", "b", "c"]) 66 | (dom ["1", "2", "3"]) 67 | [("a", "1"), ("b", "2"), ("c", "3")] 68 | 69 | structure :: Diagram B 70 | structure = circle 1 <> text "Type" # scale 0.25 <> circle 2 71 | -------------------------------------------------------------------------------- /concepts/type-theory.rst: -------------------------------------------------------------------------------- 1 | Terminology 2 | ----------- 3 | 4 | .. _Curry-Howard Correspondence: https://en.wikipedia.org/wiki/Curry%E2%80%93Howard_correspondence 5 | 6 | +---------------------------------+-----------------------------------------------------------------+ 7 | | Proposition | A statement which can be true or false e.g. A -> B; if A then B.| 8 | +---------------------------------+-----------------------------------------------------------------+ 9 | | Conjunction | logical AND | 10 | +---------------------------------+-----------------------------------------------------------------+ 11 | | Disjunction | logical OR | 12 | +---------------------------------+-----------------------------------------------------------------+ 13 | | Top (T) | A tautology, always true | 14 | +---------------------------------+-----------------------------------------------------------------+ 15 | | Bottom (_|_ or F) | A contradiction, always false | 16 | +---------------------------------+-----------------------------------------------------------------+ 17 | | Theorem | A set of propositions representing a true statement | 18 | +---------------------------------+-----------------------------------------------------------------+ 19 | | Type | Denotes certain rules that a value should conform to | 20 | +---------------------------------+-----------------------------------------------------------------+ 21 | | Inhabited | A type is inhabited if a value of that type exists | 22 | +---------------------------------+-----------------------------------------------------------------+ 23 | | Isomorphic | A is isomorphic to B when B represents A in just another form | 24 | | | and vice versa, in other words they can morph into each other. | 25 | | | Isomorphic objects are equivalent. | 26 | +---------------------------------+-----------------------------------------------------------------+ 27 | | `Curry-Howard Correspondence`_ | If a type is inhabited it proves a theorem | 28 | +---------------------------------+-----------------------------------------------------------------+ 29 | | Universal Quantification | forall `a`: the proposition is true for all values of a | 30 | +---------------------------------+-----------------------------------------------------------------+ 31 | | Existential Quantification | exists `a`: the proposition is true for some values of a | 32 | +---------------------------------+-----------------------------------------------------------------+ 33 | | Lambda Calculus | a formal system in mathematical logic for | 34 | | | expressing computation based on function abstraction and | 35 | | | application using variable binding and substitution. | 36 | +---------------------------------+-----------------------------------------------------------------+ 37 | | Introduction rule | When a constructor is used on the RHS to construct, | 38 | | | it is called an `introduction rule` in type theory. | 39 | +---------------------------------+-----------------------------------------------------------------+ 40 | | Elimination rule | When a constructor is used on the LHS to pattern | 41 | | | match or destruct a data structure, it is called | 42 | | | an `elimination rule` in type theory. | 43 | +---------------------------------+-----------------------------------------------------------------+ 44 | 45 | Curry-Howard Isomorphism 46 | ------------------------ 47 | 48 | +---------------------------------------+ 49 | | Type ~ Rules (Propositions) ~ Theorem | 50 | +---------------------------------------+ 51 | | Inhabited Type ~ Proof of the theorem | 52 | +---------------------------------------+ 53 | 54 | +-------------------------------------------------+ 55 | | Example: | 56 | +------+-----------------------+------------------+ 57 | | Type | Rules | Inhabited values | 58 | +======+=======================+==================+ 59 | | A | * A is a number | | 60 | | | * A is greater than 0 | | 61 | | | * A is less than 0 | None | 62 | +------+-----------------------+------------------+ 63 | | B | * B is a number | 1, 2, 3, 4 | 64 | | | * B is greater than 0 | | 65 | | | * B is less than 5 | | 66 | +------+-----------------------+------------------+ 67 | 68 | Curry-Howard Correspondence 69 | --------------------------- 70 | 71 | +-------------+---+-------------+ 72 | | Mathematics | | Programming | 73 | +=============+===+=============+ 74 | | Formulas | ~ | Types | 75 | +-------------+---+-------------+ 76 | | Proofs | ~ | Programs | 77 | +-------------+---+-------------+ 78 | 79 | Formulas & Types 80 | ~~~~~~~~~~~~~~~~ 81 | 82 | +----------------------------+-----------------------------------+ 83 | | Logic (Formulas) | Programming (Types) | 84 | +============================+===================================+ 85 | | universal Quantification | generalised product type (Π type) | 86 | +----------------------------+-----------------------------------+ 87 | | existential Quantification | generalised sum type (Σ type) | 88 | +----------------------------+-----------------------------------+ 89 | | implication | function type | 90 | +----------------------------+-----------------------------------+ 91 | | Conjunction | product type | 92 | +----------------------------+-----------------------------------+ 93 | | Disjunction | sum type | 94 | +----------------------------+-----------------------------------+ 95 | | true formula | unit type | 96 | +----------------------------+-----------------------------------+ 97 | | false formula | bottom type | 98 | +----------------------------+-----------------------------------+ 99 | 100 | Proofs & Programs 101 | ~~~~~~~~~~~~~~~~~ 102 | 103 | +------------------------------+-----------------------------+ 104 | | Natural Deduction (Proofs) | Lambda Calculus (Programs) | 105 | +==============================+=============================+ 106 | | axiom | variable | 107 | +------------------------------+-----------------------------+ 108 | | introduction rule | constructor (Abstraction) | 109 | +------------------------------+-----------------------------+ 110 | | elimination rule | destructor (Apply) | 111 | +------------------------------+-----------------------------+ 112 | | normal deduction | normal form | 113 | +------------------------------+-----------------------------+ 114 | | normalisation of deductions | weak normalisation | 115 | +------------------------------+-----------------------------+ 116 | | provability | type inhabitation problem | 117 | +------------------------------+-----------------------------+ 118 | | intuitionistic tautology | inhabited type | 119 | +------------------------------+-----------------------------+ 120 | 121 | Haskell Type system logical connectives 122 | --------------------------------------- 123 | 124 | Note, there is nothing precise in it , this is just to get a rough intuition 125 | about the type system. The Haskell type-system provides the following logical 126 | connectives that make a functionally complete system: 127 | Composition: 128 | Sum = OR 129 | Product = AND 130 | Transformation 131 | function application = -> 132 | Bottom = _|_ 133 | 134 | Note that the Haskell sum type is a tagged union and not really a coproduct of 135 | independent types unless we are using GADTs. 136 | 137 | We can recover NOT from implication and bottom: NOT = A -> Bottom. 138 | We need only one of AND and OR and both of the rest to make a functionally 139 | complete system i.e. {NOT, AND} or {NOT, OR}. 140 | 141 | When we define a data type `A` then we know that type `A` exists i.e. there is 142 | a way to construct it. If we have a function signature or inferred call A -> B 143 | -> C -> D, it means A AND B AND C -> D. Which says if types a, b and c exist 144 | then type d is valid. All such logic equations implied by the types used 145 | eveywhere in the program taken together must be satisfiable for the program to 146 | be accepted by the compiler. Otherwise the program gets rejected meaning the 147 | types are inconsistent. 148 | 149 | References 150 | ---------- 151 | 152 | * http://www.haskellforall.com/2017/02/the-curry-howard-correspondence-between.html 153 | * https://en.wikibooks.org/wiki/Haskell/The_Curry%E2%80%93Howard_isomorphism 154 | * https://en.wikipedia.org/wiki/Duality_(mathematics) 155 | * https://en.wikipedia.org/wiki/Functional_completeness 156 | * https://en.wikipedia.org/wiki/Curry%E2%80%93Howard_correspondence 157 | * https://en.wikipedia.org/wiki/Combinatory_logic 158 | * https://stackoverflow.com/questions/44034591/is-haskells-type-system-isomorphic-to-an-inconsistent-logic-system-if-so-what 159 | * https://en.wikipedia.org/wiki/SKI_combinator_calculus 160 | -------------------------------------------------------------------------------- /concepts/why-haskell.rst: -------------------------------------------------------------------------------- 1 | Why Haskell? 2 | ------------ 3 | 4 | +-----------------------+-----------------------------------------------------+ 5 | | High level feature | Low level enabler of high level feature | 6 | +=====+=================+=====================================================+ 7 | | DRY | Expressive | Polymorphism (higher order functions, typeclasses), | 8 | | | | Incremental abstraction ladder (low to high), Lazy | 9 | | +-----------------+-----------------------------------------------------+ 10 | | | Composable | Denotational (Functional, Pure), lazy, | 11 | | | | Composable concurrency | 12 | +-----+-----------------+-----------------------------------------------------+ 13 | | Reasoning | Sequential reasoning (purity), equational reasoning | 14 | | | (denotational semantics) | 15 | +-----------------------+-----------------------------------------------------+ 16 | | Correct | Strong Static typing, purity enables better testing | 17 | +-----------------------+-----------------------------------------------------+ 18 | | Efficient | Compiled, Interesting compiler optimizations | 19 | | | possible due to purity | 20 | +-----------------------+-----------------------------------------------------+ 21 | 22 | Programming in other languages is like playing Jenga whereas programming in 23 | Haskell is like playing Lego. 24 | 25 | What is unique about Haskell? 26 | ----------------------------- 27 | 28 | The first level debate is about Functional vs Object Oriented Programming (OOP) 29 | languages. The proof of functional being a very important programming paradigm 30 | is in the trends in traditional programming languages racing towards 31 | introducing more and more functional features. Objective C has been replaced by 32 | Swift and Java is being replaced by Scala both of which are designed to have 33 | very strong functional features. Even traditional imperative languages like 34 | Java and C++ too are introducing functional features. Even python has 35 | introduced several functional features. If functional is not equal or better 36 | than OOP why would OOP languages even bother about introducing it? In my 37 | opinion, functional is going to dominate the OOP paradigm in coming future. 38 | 39 | The second level debate is on static typing or dynamic typing (e.g. Haskell vs 40 | Clojure). Dynamic typing relies on actually executing all code paths to find 41 | all bugs while static typing finds them right away at compile time. In any 42 | reasonably sized project you would want the static typing paradigm otherwise 43 | the cost of testing and fixing problems later would just become enormous and 44 | unmanageable. All serious large scale programming languages are statically 45 | typed e.g. Swift, Scala, OCaml, F#, Java, C++. 46 | 47 | Assuming these debates are settled we can argue about what does Haskell bring 48 | to the table differentiating it from other statically typed functional 49 | languages like F#, OCaml, Scala or Swift for example. All these languages are 50 | quite similar and have roots in OCaml the strict cousin of Haskell from the ML 51 | family. Scala and Swift ride on the legacy of Objective C and JVM ecosystem 52 | compatibility respectively. They have a hybrid OOP and functional paradigm 53 | which confuses programmers and leaves a big scope of messing up your code 54 | because of a confused design. On the other hand only functional languages have 55 | a clean design providing only one (functional) way of thinking and designing. 56 | 57 | Haskell has a clean design - no obligation of supporting a legacy. However, it 58 | can support the JVM if you want to integrate with existing Java code. Other 59 | than using a single functional only paradigm Haskell also has two unique design 60 | features viz. purity and laziness. The immense value that purity brings to the 61 | table is the power of sequential and equational reasoning which no other 62 | language provides. This is something that is not easily appreciated easily but 63 | is the most important aspect of Haskell. This is what brings order to the 64 | chaos. It makes each and every part of the program to look like a sequential 65 | flow rather than a mess of cyclic dependencies in which you spend most of your 66 | time as a programmer to find out where a particular value is being changed. Or 67 | to sort out the mess of entangled control flow and trying to make sense out of 68 | it. Adele Goldberg aptly said, "In Smalltalk, everything happens somewhere 69 | else." Haskell enforces does not allow you to have that mess to begin with by 70 | design. The whole program is a directed acyclic graph except localized 71 | recursion. Haskell builds a beautiful waterfall of data flow instead of a mess 72 | of entangled wires. A Haskell program is just a series of transforms on data, 73 | the data is handed over from one function to another. It does not hide data 74 | under the carpet where someone sneakily comes and changes and you have no clue 75 | who did it. 76 | 77 | I was a fan of object oriented programming until I encountered the better 78 | functional programming paradigm. OOP tried to improve upon the existing free 79 | for all in C but did not solve the problem completely. In OOP, the fundamental 80 | problem of cyclic data flow dependencies across objects remains. To make any 81 | program scalable to understand by an ordinary programmer it needs to be 82 | sequential in data flow. If you have to jump from one place to another and keep 83 | a huge context in mind then it will make an ordinary head spin. There may be a 84 | few extra ordinarily gifted minds which can make sense out of the chaos but an 85 | average programmer will find it difficult to wade through it. 86 | 87 | Think about refactoring an OOP program. Since it has state embedded in objects 88 | and complex interactions, refactoring a complex program will be a nightmare. 89 | However in Haskell, data is separated from code that works on it. It is much 90 | easier to refactor both independently and because we have pure functions just 91 | transforming data. 92 | 93 | Edsger Dijkstra: “Object-oriented programming is an exceptionally bad idea 94 | which could only have originated in California.” 95 | 96 | Re-use is a myth in OO programming while it is a reality in Haskell because of 97 | separation of data and code. 98 | 99 | To appreciate the importance of sequential reasoning of human mind think about 100 | understanding a piece of code sprinkled with gotos all over. Why was goto 101 | discouraged in C in the first place? Why did we invent control flow structures? 102 | Haskell just takes it to the next level and removes gotos in your design. 103 | 104 | To solve this problem in a fundamental, language enforced manner Haskell 105 | provides sequential and equational reasoning possible because of its pure 106 | functional model. 107 | 108 | Expressive Power: Abstractions & DSLs 109 | ------------------------------------- 110 | 111 | Expressive power is directly related to ability to reuse. Haskell has very 112 | powerful abstraction tools allowing maximum reuse. 113 | 114 | * Low level abstraction facilities 115 | 116 | * parametric polymorphism 117 | * higher order functions 118 | * ad-hoc polymorphism 119 | * Examples of some high level abstraction tools 120 | 121 | * Functors 122 | * Applicatives 123 | * Monads 124 | * Haskell provides an incremental abstraction ladder where you can keep 125 | building higher level abstractions on top of lower level. You can create high 126 | level domain specific langauges to suit your application. 127 | 128 | Composability 129 | ------------- 130 | 131 | * Another way to reuse 132 | * TBD 133 | 134 | Correctness 135 | ----------- 136 | 137 | * Strong static typing 138 | * Automatic memory management 139 | * Equational reasoning due to purity 140 | * Easier testing due to purity (quickcheck) 141 | 142 | Concurrency 143 | ----------- 144 | 145 | See the concurrency chapter 146 | 147 | Parallelism 148 | ----------- 149 | 150 | See the concurrency chapter 151 | 152 | Reasoning 153 | --------- 154 | 155 | * Sequential reasoning 156 | * Human mind naturally thinks sequentially 157 | * The amount of memory is limited 158 | * Abstractions allow you to forget and reduce the scope 159 | * provable, pure abstractions are key 160 | * Pure transformations allow you to think sequentially, purely in terms of data and 161 | transformations on it. 162 | * In OOP everything is mingled, you have hidden state in objects, you need to 163 | keep that in mind to understand how the operations behave. In pure functional the 164 | state is always explicit. 165 | * OOP is messed easily, its not easy to mess pure functional, at least the 166 | purity cannot be compromised. 167 | * Dependencies across objects could be real hell and cyclic making your head 168 | spin. Some languages have sorted out dependencies across packages but as long 169 | as impurity exists dependencies across units within a package will remain 170 | cyclic creating problems in understanding. 171 | 172 | References 173 | ---------- 174 | 175 | * https://www.fpcomplete.com/blog/2016/11/comparative-concurrency-with-haskell 176 | * https://www.microsoft.com/en-us/research/publication/beautiful-concurrency/ 177 | * https://www.fpcomplete.com/blog/2016/11/mastering-time-to-market-haskell 178 | * https://www.fpcomplete.com/blog/2016/11/comparison-scala-and-haskell 179 | 180 | * http://raganwald.com/2010/12/01/oop-practiced-backwards-is-poo.html 181 | * http://blog.jot.fm/2010/08/26/ten-things-i-hate-about-object-oriented-programming/comment-page-2/ 182 | * http://www.yegor256.com/2016/08/15/what-is-wrong-object-oriented-programming.html 183 | 184 | * http://www.youscience.com/what-is-sequential-reasoning-and-why-does-it-matter/ 185 | * http://www.erasmatazz.com/library/the-mind/history-of-thinking/033d91601d1f41bdbb9d/verbal-reasoning.html 186 | 187 | * https://www.snoyman.com/blog/2017/12/what-makes-haskell-unique 188 | -------------------------------------------------------------------------------- /language/001-data-flow.rst: -------------------------------------------------------------------------------- 1 | Flow Based Programming 2 | ====================== 3 | 4 | .. need a good quote 5 | 6 | .. contents:: Table of Contents 7 | :depth: 1 8 | 9 | .. sectnum:: 10 | 11 | Operational Composition 12 | ----------------------- 13 | 14 | The previous chapter discussed purely denotational details of composition in 15 | Haskell. This chapter discusses the details of `operational composition`. 16 | Operational details include how data flows in the program, and how data flows 17 | are composed rather than how the processing logic is composed. 18 | 19 | Logic vs Data Flow 20 | ~~~~~~~~~~~~~~~~~~ 21 | 22 | `Logic` and `data flow` are the two fundamental dimensions of any program. For 23 | scaling a program, logic must follow data flow or vice versa. If these two are 24 | orthogonal to each other we will not be able to scale the program. 25 | 26 | Example 27 | ~~~~~~~ 28 | 29 | We have to write the input data to a file and compute its length. There are 30 | multiple ways of doing that: 31 | 32 | 1) accumulate all the data into a memory, write it to file, compute its length 33 | 2) Create an explicit loop, which writes data block by block in each iteration 34 | and keeps accumulating the length. 35 | 3) Use a streaming abstraction like pipe, let the data flow thorugh the pipes 36 | and each pipe does different things to data like writing to a file or computing 37 | its length. 38 | 39 | Structuring Data Flow 40 | --------------------- 41 | 42 | There are two ways to structure your program. 43 | 44 | Logic driven data 45 | ~~~~~~~~~~~~~~~~~ 46 | 47 | LazyIO says, I the program logic, will decide in what order the data will be 48 | accessed, give it to me when I demand it. Which means the data can be accessed 49 | in any random order, over any span of time, placing no limits on what needs to 50 | remain in-memory at a given time. This is a data pull model and the root of all 51 | evils due to lazyIO. Random access of data is always expensive. 52 | 53 | Also, in this model the whole data has to be available before we can process it 54 | since we may demand any part of the data at any time. This will be problematic 55 | when the data is being produced dynamically and we do not even know how much it 56 | is. 57 | 58 | Data driven logic 59 | ~~~~~~~~~~~~~~~~~ 60 | 61 | In contrast the pipe model says, you the program, will receive the data in a 62 | predefined order and you will have to structure your logic based on that. This 63 | is a data push model. The pipes are not allowed to buffer random amounts of 64 | data, they will process a chunk and let it go. Then they will move on to the 65 | next chunk. Thus there is bound at how much data is bufferred in the system. 66 | 67 | Data access is serial in this case which is cheap. Pipes observe the data 68 | flowing through them and make observations or perform transformations. 69 | 70 | The `logic drives data` model is more like the whole village dipping in the 71 | pool while `data drives logic` is like a pipeline based supply system and 72 | everyone drinks from the tap. 73 | 74 | Composing Data Flow: Streaming 75 | ------------------------------ 76 | 77 | Functions are low level pipes: Pipes are very similar to functions but at a 78 | higher level of abstraction. Like functions they also take an input and produce 79 | an output. They encapsulate some closely related logic that operates on the 80 | data flowing through them. 81 | 82 | Pipes are like fatter functions isolating a related piece of logic within a 83 | boundary. They reduce the footprint or hold-up boundaries of data. 84 | 85 | Lazy evaluation in general allows you unbounded data footprint, resulting in 86 | space leaks. There is no guarantee upto what point data will be held. Pipes 87 | chop your program into pieces which introduces fences beyond which data will 88 | not be held up, thus avoiding space leaks. 89 | 90 | The way functions allow us to compose the logic elegantly, the same way pipes 91 | allow us to compose bundles of closely related data flow logic elegantly. These 92 | pieces are structured according to the data flow. Or in other words they allow 93 | us to compose smaller special purpose programs together to create bigger 94 | programs which are structured according to the data flow. 95 | 96 | Higher order pipes: The way we have higher order functions we can have higher 97 | order pipes. Basically each pipe is a tee, it observes the data flowing 98 | through, accumulates its observations and passes it onto another pipe which is 99 | a higher order pipe. All higher order pipes are connected together to create a 100 | higher order logic and process all those observations further. 101 | 102 | Lazy evaluation as fine grained data flow programming 103 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 104 | 105 | Functions are low level pipes. 106 | 107 | Infinite data structures are like the indefinite data producers. Lazy 108 | evaluation composes multiple functions together and a data element passes 109 | through those functions like data passes through pipes. The usual design model 110 | is to let the data pass through all stages quickly and then get garbage 111 | collected and not hold up the data. If you hold up it turns into a space leak. 112 | 113 | Each function is a pipe connected to another function, another pipe. Lazy 114 | evaluation drives the data through this big chain of pipes. The pipes get 115 | activated when we want to draw something from the remote end. This is literally 116 | data driven programming. 117 | 118 | We need a picture here with functions/closures connected to each other and how 119 | data flows through them. How the whole evaluation machinery is cranked to 120 | generate output from input. 121 | 122 | Haskell lazy evaluation is fundamentally data driven or flow based programming, 123 | or in other words stream based programming. 124 | 125 | Stream fusion basically fuses multiple stages of lazy evaluation into one 126 | big imperative like loop instead of chain invocation of each stage. Same way we 127 | represent loops by pipes. 128 | 129 | Within a high level pipe we can use strict evaluation rather than lazy 130 | evaluation and fuse that whole logic together to make it more efficient. 131 | 132 | Can we automatically make everything strict rather than lazy depending on 133 | feasibility? 134 | 135 | Consumer and Producer Model 136 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 137 | 138 | Consume | Produce | what | 139 | N | N | Not a pipe | 140 | N | Y | Contra-effect (Source) | 141 | Y | N | effect (sink) | 142 | Y | Y | pipe | 143 | 144 | Analogies 145 | ~~~~~~~~~ 146 | 147 | * Water pipelines 148 | * Electronic circuit networks 149 | * Unix pipes 150 | 151 | Imperative Design Patterns 152 | -------------------------- 153 | 154 | Programmer drives everything 155 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 156 | 157 | In imperative languages the programmer is free to interleave logic and data the 158 | way he wants. This is totally non-composable obviously. You depend on the 159 | programmer discipline. 160 | 161 | "for" loops translate into composed pipes 162 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 163 | 164 | From the imperative land you can think about pipes as a translation of your 165 | "for" loops. For example the snippet I gave you can be implemented as a for 166 | loop in imperative languages. The for loop will read a chunk of data, write the 167 | chunk to a file, add the length of the chunk to a length variable. When the 168 | loop is done you will have written it out to the output file and you will have 169 | the length. 170 | 171 | In haskell you will use two pipes instead. The first one will write the data to 172 | the output file and the second one will compute the length. 173 | 174 | Push vs pull 175 | ------------ 176 | 177 | * push based: strict evaluation (left fold) 178 | * pull based: lazy evaluation (right fold) 179 | -------------------------------------------------------------------------------- /language/11-fold-and-unfold.rst: -------------------------------------------------------------------------------- 1 | Fold and Unfold 2 | =============== 3 | 4 | .. contents:: Table of Contents 5 | :depth: 1 6 | 7 | .. sectnum:: 8 | 9 | Recursive Algebraic Data Types 10 | ------------------------------ 11 | 12 | Lists 13 | ~~~~~ 14 | 15 | Lists are a result of pure combining of data without logic. 16 | 17 | +----------+----------------------------------+-------------------------------+ 18 | | Type | Values | Description | 19 | +==========+==========+==========+============+===============================+ 20 | | [a] | [] | 1 : [] | 1 : 2 : [] | List of Int | 21 | | | | | | Explicit constructor syntax | 22 | | +----------+----------+------------+-------------------------------+ 23 | | | [] | [1] | [1,2] | Sugared syntax | 24 | | +----------+----------+------------+-------------------------------+ 25 | | | [] | ['a'] | ['a','b'] | List of chars (String) | 26 | | +----------+----------+------------+-------------------------------+ 27 | | | "" | "a" | "ab" | String literals | 28 | +----------+----------+----------+------------+-------------------------------+ 29 | 30 | :: 31 | 32 | data [] a = [] | : a (List a) -- Recursive 33 | 34 | Note that Haskell's built-in list is not really a special syntax it is a user 35 | defined data type, '[]' is the empty list constructor and ':' is the Cons 36 | constructor. Though there is a syntactic sugar to specify lists in a more 37 | convenient way [1, 2] is equivalent to 1 : 2 : []. 38 | 39 | * List comprehensions 40 | * See prelude for list functions 41 | 42 | Recursive Binary Folding 43 | ------------------------ 44 | 45 | For combining arbitrary number of objects of the same type we can use a binary 46 | product composition function recursively. 47 | 48 | Combining Data 49 | ~~~~~~~~~~~~~~ 50 | 51 | Combining data requires assistance of a function because combining operation is 52 | after all a dynamic transformation. To combine data we require imposition of a 53 | certain abstract static structure on the data and an associated function to 54 | assist combining that structure. 55 | 56 | A binary operation can express a generalized n-ary operation. 57 | 58 | Composing a set of values into a single value 59 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 60 | 61 | Assume that we have a collection of values of the same type, for example a list 62 | of integers [1, 2, 3, 4, 5]. If we have a binary operation `f :: a -> a -> a` 63 | 64 | Composing Two or More Values 65 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 66 | 67 | When we have a collection of two or more values we can just use the binary 68 | operation to compose them. 69 | 70 | Folding 71 | ~~~~~~~ 72 | 73 | Composition or fold combines multiple things of the same type resulting in a 74 | single final value. The binary operation we need to fold must have: 75 | 76 | f :: a -> a -> a -- dissolves a into a 77 | f :: a -> b -> a -- dissolves b into a 78 | f :: a -> b -> b -- dissolves a into b 79 | 80 | What happens if we do not have the identity element? 81 | 82 | 5+0 = 5 83 | 5*1 = 5 84 | 85 | We differentiate composition into two basic forms i.e. combine & fold. 86 | Combining allows you to combine two values using a binary operation. Combining 87 | can be used repeatedly on two or more values to arrive at a single final value. 88 | We define folding as a more general form of combining which uses an identity 89 | element to allow the same binary operation to combine 0 or more elements 90 | together. 91 | 92 | Concrete data objects are commonly composed using algebraic structures (magma 93 | family) whereas functions are composed using categorical structures: 94 | 95 | * Composing data - Magma (semigroup, monoid) 96 | * Composing functions - Category (semigroupoid, category) 97 | 98 | Folding or Sum Composition 99 | ~~~~~~~~~~~~~~~~~~~~~~~~~~ 100 | 101 | A special and interesting case of composition occurs when all the objects to be 102 | combined are of the same type. Just like a sum type represents many choices, 103 | here the many objects of the same type represent different choices from the 104 | same type. We combine them all into an output type. We call such a composition 105 | a fold or sum. 106 | 107 | :: 108 | A, A, A, ... 109 | 110 | Using a binary product composition constructor or function we can fold any 111 | number of objects of the same type recursively. For recursion we necessarily 112 | need the output of the transformation to be the same as one of its inputs so 113 | that we can feed back the output into the input. 114 | 115 | C :: A -> B -> B 116 | 117 | Semigroup Composition (Non-Empty Containers) 118 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 119 | 120 | When the objects being combined are of different types the only way to compose 121 | is using a funciton or constructor. But when the objects being combined are of 122 | the same type we have a convenient special case of general composition. We can 123 | now use a binary composition function to combine arbitrary number of objects. 124 | 125 | Enables folding of two or more objects of the same type. 126 | A semigroup can combine two or more objects using a binary operation. A 127 | semigroup is a non-empty container since there is no way to represent an empty 128 | value. A semigroup can be made a Monoid by using Option as a wrapper around it. 129 | 130 | Monoidal Composition (Possibly Empty Containers) 131 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 132 | 133 | When the type has an identity we can have a more general composition where we 134 | can combine 0 to n number of objects in the same way. 135 | 136 | :: 137 | 138 | mempty :: a 139 | mappend :: a -> a -> a 140 | you can fold t a : t a -> a 141 | 142 | Generalized: 143 | initial :: b 144 | combine :: a -> b -> b 145 | you can fold t a : t a -> b 146 | 147 | folds are general as they fold many elements into a potentially different type. 148 | A monoid type folds into itself, that's why it is a MONO-id, it is mono and it 149 | has an id! 150 | 151 | Enables folding of 0 or more objects of the same type. 152 | A monoid adds the concept of empty to the semigroup. It is a convenience over 153 | semigroup with a built-in representation of the absence of a value (mempty). 154 | That is we do not need an Option wrapper for that. 155 | 156 | Some types have an in-built representation of mempty and therefore a semigroup 157 | + Option will not work for them e.g. integers with sum operation have 0 as an 158 | empty value. They are natural monoids. 159 | 160 | A monoid is useful where the concept of empty or absence of a value is 161 | important. Just like Maybe. For example as a sink where we want to start empty 162 | and collect 0 or more objects. A stream may yield 0 or more objects, collecting 163 | and folding a stream requires a monoid unless we have an initial object to fold 164 | with. A monoid is therefore useful in more cases because it can be used where a 165 | semigroup can be used unless we specifically want to preclude the empty state. 166 | However lesser types will have a Monoid instance compared to semigroup. 167 | 168 | The same code that requires two objects to combine can work with just one 169 | object by supplying the other one as empty. This simplifies code over 170 | semigroup. 171 | 172 | * Semigroup | Data that can be combined | minimum two objects, enables operations on containers of objects 173 | 174 | * Monoid 175 | 176 | * Foldable 177 | 178 | Basic Folds 179 | ----------- 180 | 181 | fold: 182 | 183 | Given a list container ``[1,2,3,4,5]``. There are two ways to compute the sum 184 | of its elements:: 185 | 186 | sum s (x : xs) = x + sum s xs -- 1 + (2 + (3 + (4 + 5))) right associative 187 | sum s (x : xs) = sum (s + x) xs -- (((1 + 2) + 3) + 4) + 5 left associative 188 | 189 | The right associative version is called the right fold and the left associative 190 | version is called the left fold. Note in foldr the fold operation is at the top 191 | level of the expression and recursion occurs as part of it. In foldl recursive 192 | call is at the top level of the expression and the fold operation occurs as 193 | part of it. 194 | 195 | Now, the behavior of these operations depends on the evaluation strategy. When 196 | the operation (+) is strict the right fold puts the whole structure on the 197 | stack and unravels it in the end, whereas the left fold does not use the stack 198 | at all. Note that when the container being folded is strict (a memory buffer 199 | for example) we have already consumed space in the container and the left fold 200 | does not require more space, on the other hand when the container is lazy it is 201 | not using any space but we need that space at the end when folding so they both 202 | are equivalent in that sense. They are just duals of each other. 203 | 204 | On the other hand when the operation is lazy in the second argument, the right 205 | fold can keep yielding the next element from the container whereas the left 206 | fold keeps building a lazy structure until the whole container is consumed, 207 | consuming space proportional to the container size. Note that in this example 208 | we are using the (+) operation which is trivially strict. However a folding 209 | operation can be a whole pipeline of lazy operations. 210 | 211 | To conclude, when consuming a structure (strict or lazy) using a pipeline of 212 | lazy evaluation right fold is most efficient. For consuming a structure (strict 213 | or lazy) using strict evaluation, left fold is most efficient. Combining a 214 | strict operation on a large structure with a right fold or a lazy operation on 215 | a large structure with a left fold may not be a good idea, it may not scale. 216 | When we need to do that dividing up the structure in chunks and then folding is 217 | a good strategy. 218 | 219 | Right = yield or distribute 220 | Left = accumulate 221 | 222 | Lazy right fold = scalable/transform - consumer pulls lazily from it - infinite structures ok 223 | Strict left fold = scalable/transform - producer can push to it - infinite structures ok 224 | Strict right fold = not scalable/buffer whole - yield the whole thing strictly - structure must be finite -- consumes the whole structure strictly, accumulating it on the stack. 225 | Lazy left fold = not scalable/buffer whole - accumulate a lazy structure - structure must be finite -- builds a lazy structure 226 | 227 | A lazy left fold can be used to reverse a list without looking at the elements 228 | of the list. We will be using memory only for the spine of the list and not for 229 | the lazy elements of the list. It can basically accumulates any structure 230 | into a lazy structure. 231 | 232 | A strict left fold can be used to sum the elements of a list. It basically 233 | accumulates any structure into a strict value. 234 | 235 | A lazy right fold can be used as a pipeline to join a lazy computation with 236 | another lazy computation, passing one element at a time from the source to the 237 | consumer. It basically distributes any structure as a lazy value. 238 | 239 | A strict right fold distributes any structure as a strict value. For example it 240 | can be used to convert a lazy structure into a strict array. For example it can 241 | be used to serialize a lazy structure in memory. 242 | 243 | Strict right fold and lazy left fold can use compact regions automatically to 244 | scale. They should be used for serializations and conversions rather than as 245 | part of a lazy transformation pipeline. They buffer the whole thing. 246 | 247 | Note that IO monad is strict. So to finally consume the output or input it is 248 | inevitable to face the combination of strict evaluation and lazy structures. 249 | However if the IO does not need to accumulate we can have a full lazy pipeline, 250 | consuming one input and producing one output at a time (or chunks). However if 251 | we use IO monad in them middle of a computation it cannot scale unless we use a 252 | limited buffer. 253 | 254 | 255 | foldr: 256 | 257 | The following equations hold for a list:: 258 | 259 | foldr (:) [] xs == xs 260 | map f = foldr ((:) . f) [] 261 | 262 | A lazy right fold can be equated with a pull style operation where the consumer 263 | keeps pulling the next element from the container on-demand. 264 | 265 | 266 | foldl: 267 | 268 | Note that the ``identity`` is folded with the first element, therefore the 269 | following reverses the list:: 270 | 271 | reverse xs = foldl (flip (:)) [] 272 | 273 | A strict left fold is a push style mechanism where the producer keeps pushing 274 | the next element to the consumer. 275 | 276 | Mnemonics: 277 | 278 | fold: remember "fuze it" - first argument is the fold function (fu), the second 279 | is zero (ze), and ``it`` refers to the container we are folding. 280 | 281 | fuze it : fold (fu)unction ze(ro) it 282 | 283 | Argument order: The fold function in foldr takes the element first whereas in 284 | foldl it takes the list first which is in accordance with their behavior of 285 | reducing the element first or the list first. 286 | 287 | foldl makes sense in general for left-associative operators, and foldr makes 288 | sense for right-associative operators. Left-associative operators must have 289 | the type (a -> b -> a) i.e. result type is same as left argument e.g. ``(m >>= 290 | f1) >>= f2``, while right-associative operators must have type (a -> b -> b) 291 | i.e. result type is the same as the right argument e.g. ``1 : (2 : [])``. 292 | 293 | +-----------------------------------------------------------------------------+ 294 | | Folds | 295 | +----------------------+------------------------------------------------------+ 296 | | fold a container of | fold :: Monoid m => t m -> m | 297 | | monoids | | 298 | +----------------------+------------------------------------------------------+ 299 | | map elements to | foldMap :: Monoid m => (a -> m) -> t a -> m | 300 | | monoids then fold | | 301 | +----------------------+------------------------------------------------------+ 302 | | Right fold | foldr :: (a -> b -> b) -> b -> t a -> b | 303 | +----------------------+------------------------------------------------------+ 304 | | Left fold | foldl :: (b -> a -> b) -> b -> t a -> b | 305 | +----------------------+------------------------------------------------------+ 306 | | fold a nonempty | foldr1/foldl1 :: (a -> a -> a) -> t a -> a | 307 | | container | | 308 | +----------------------+------------------------------------------------------+ 309 | 310 | Construction Using Folds 311 | ~~~~~~~~~~~~~~~~~~~~~~~~ 312 | 313 | When we fold using a constructor: 314 | 315 | * A list is just a binary recursive composition of the same type using a 316 | constructor. 317 | * A tree is a binary recursive composition of two different types 318 | using a constructor. 319 | 320 | Foldable 321 | -------- 322 | 323 | Foldable -- values folded as pure data (does not require functor instance) 324 | 325 | Typeclass Functions 326 | ~~~~~~~~~~~~~~~~~~~ 327 | 328 | :: 329 | 330 | fold $ map Sum [1,2,3] 331 | foldMap Sum [1,2,3] 332 | 333 | +--------+------+--------+------+---------+---------+-----+---------+ 334 | | toList | null | length | elem | maximum | minimum | sum | product | 335 | +--------+------+--------+------+---------+---------+-----+---------+ 336 | 337 | Other Functions 338 | ~~~~~~~~~~~~~~~ 339 | 340 | +---------+-----------+-----+----+-----+-----+-----------+-----------+ 341 | | concat | concatMap | and | or | any | all | maximumBy | minimumBy | 342 | +---------+-----------+-----+----+-----+-----+-----------+-----------+ 343 | 344 | +---------+-----------+ 345 | | notElem | find | 346 | +---------+-----------+ 347 | 348 | Unfolds 349 | ------- 350 | 351 | * https://hackage.haskell.org/package/unfoldable 352 | 353 | unfolds are enumerations? 354 | 355 | Comonoid 356 | ~~~~~~~~ 357 | 358 | A comonoid in a monoidal category is a monoid in the dual category, what is 359 | the problem? 360 | 361 | The dual of Monoid. The way a Monoid (e.g. writer) accumulates a comonoid 362 | duplicates. Like a monoid has mempty a comonoid would have a "mfull". A monoid 363 | keeps adding stuff to empty. A comonoid would keep distributing stuff from 364 | "mfull". For example a copy constructor of an object in C++ duplicates itself, 365 | it is a comonoid. 366 | 367 | See how Comonoid relates to a Comonad the way a Monoid relates to a Monad. 368 | 369 | People confuse a comonoid with reader monad. Comonoid relates to distributive 370 | the same way monoid relates to traversable. Every Distributive Functor is 371 | actually Representable. Representable endofunctors over the category of Haskell 372 | types are isomorphic to the reader monad. 373 | 374 | References 375 | ---------- 376 | 377 | * https://en.wikipedia.org/wiki/Fold_(higher-order_function) 378 | * https://groups.google.com/forum/#!topic/elm-discuss/ehsV6-YveFA fold function argument order 379 | * http://www.cs.nott.ac.uk/~pszgmh/fold.pdf A tutorial on the universality and 380 | expressiveness of fold 381 | * http://eprints.eemcs.utwente.nl/7281/01/db-utwente-40501F46.pdf Functional Programming with Bananas, Lenses, Envelopes and Barbed Wire 382 | * https://wiki.haskell.org/Attribute_grammar Traversal & folds using attribute grammar 383 | 384 | Streaming folds 385 | ~~~~~~~~~~~~~~~ 386 | 387 | * http://squing.blogspot.in/2008/11/beautiful-folding.html 388 | * http://conal.net/blog/posts/another-lovely-example-of-type-class-morphisms 389 | * http://conal.net/blog/posts/more-beautiful-fold-zipping 390 | * http://www.haskellforall.com/2013/08/composable-streaming-folds.html 391 | * https://www.schoolofhaskell.com/user/edwardk/cellular-automata/part-2 392 | 393 | Category theory 394 | ~~~~~~~~~~~~~~~ 395 | 396 | * https://wiki.haskell.org/Catamorphisms 397 | * https://www.schoolofhaskell.com/user/edwardk/recursion-schemes/catamorphisms 398 | * https://ulissesaraujo.wordpress.com/2007/12/19/catamorphisms-in-haskell/ 399 | 400 | Comonoids 401 | ~~~~~~~~~ 402 | 403 | * https://stackoverflow.com/questions/23855070/what-does-a-nontrivial-comonoid-look-like 404 | * https://stackoverflow.com/questions/15418075/the-reader-monad/15419213#15419213 405 | 406 | Packages 407 | -------- 408 | 409 | * http://hackage.haskell.org/package/monad-supply-0.3/docs/Control-Monad-Supply.html 410 | * http://hackage.haskell.org/package/monoid-subclasses-0.1/docs/Data-Monoid-Factorial.html 411 | * http://hackage.haskell.org/package/monoid-subclasses 412 | -------------------------------------------------------------------------------- /language/16-arrows.rst: -------------------------------------------------------------------------------- 1 | Arrows 2 | ====== 3 | 4 | +-----------------------------------------------------------------------------+ 5 | | Arrows | 6 | +-----------------------------------------------------------------------------+ 7 | | Composing unary transformations in a functor context | 8 | +---------------------------------+-------------------------+-----------------+ 9 | | | Values | Functions | 10 | +=================================+=========================+=================+ 11 | | Lift | arr | 12 | | +-------------------------------------------+ 13 | | | ArrowChoice | 14 | | | | 15 | +---------------------------------+-------------------------+-----------------+ 16 | | Product | ArrowApply | | 17 | +----------------+----------------+-------------------------+-----------------+ 18 | | Sum | Semigroup | ArrowPlus (<+>) | . | 19 | | +----------------+-------------------------+-----------------+ 20 | | | Monoid | ArrowZero (zeroArrow) | id | 21 | +----------------+----------------+-------------------------+-----------------+ 22 | 23 | * Arrows (category composition) (binary composition) 24 | They are equivalents of binary functions that can be composed, they are 25 | profunctors. 26 | 27 | We can think of arrows as computations, too. The Arrow class we have de- fined 28 | is clearly analogous to the usual Monad class — we have a way of creating a 29 | pure computation without effects (arr/return), and a way of sequencing 30 | computations ((>>>)/(>>=)). ``But whereas monadic computations are parameterised 31 | over the type of their output, but not their input, arrow computations are 32 | parameterised over both.`` The way monadic programs take input cannot be varied 33 | by varying the monad, but arrow programs, in contrast, can take their input in 34 | many different ways depending on the particular arrow used. The stream function 35 | example above illustrates an arrow which takes its input in a different way, as 36 | a stream of values rather than a single value, so this is an example of a kind 37 | of computation which cannot be represented as a monad. 38 | 39 | .. 40 | Notice that a monad type is ``m a`` where a is the output type and an arrow 41 | type is ``c a b`` where ``a`` is the input type and ``b`` is the output type. 42 | Another way to put it is that a monad puts a value in a context whereas an 43 | arrow puts a function in a context. 44 | 45 | Arrows thus offer a competing way to represent computations in Haskell. But 46 | their purpose is not to replace monads, it is to bring the benefits of a shared 47 | interface, discussed above, to a wider class of computations than monads can 48 | accomodate. And in practice, this often means computations that represent 49 | processes. 50 | 51 | In the case of monads, the second argument of (>>=) is a Haskell function, 52 | which permits the user of this interface to use all of Haskell to map the 53 | result of the first computation to the computation to be performed next. Every 54 | time we sequence two monadic computations, we have an opportunity to run 55 | arbitrary Haskell code in between them. But in the case of arrows, in contrast, 56 | the second argument of (>>>) is just an arrow, an element of an abstract 57 | datatype, and the only things we can do in that arrow are things that the 58 | abstract data type interface provides. Certainly, the arr combinator enables 59 | us to have the output of the first arrow passed to a Haskell function — but 60 | this function is a pure function, with the type b -> c, which thus has no 61 | opportunity to perform further effects. If we want the effects of the second 62 | arrow to depend on the output of the first, then we must construct it using 63 | operations other than arr and (>>>). 64 | 65 | Idioms are oblivious, arrows are meticulous, monads are promiscuous 66 | ------------------------------------------------------------------- 67 | 68 | We revisit the connection between three notions of computation: Moggi’s monads, 69 | Hughes’s arrows and McBride and Paterson’s idioms (also called applicative 70 | functors). We show that idioms are equivalent to arrows that satisfy the type 71 | isomorphism A ❀ B ' 1 ❀ (A → B) and that monads are equivalent to arrows that 72 | satisfy the type isomorphism A ❀ B ' A → (1 ❀ B). Further, idioms embed into 73 | arrows and arrows embed into monads 74 | 75 | Arrows vs Profunctors 76 | --------------------- 77 | 78 | An Arrow is just a Strong Category. Purescript deprecated the arrow package in 79 | favor of profunctors package. 80 | * https://github.com/purescript-deprecated/purescript-arrows 81 | 82 | * https://stackoverflow.com/questions/38169453/whats-the-relationship-between-profunctors-and-arrows 83 | * https://www.reddit.com/r/haskell/comments/4fkkzo/when_does_one_consider_using_arrows/?st=j7a7kiim&sh=0fb14070 84 | * https://cdsmith.wordpress.com/2011/07/30/arrow-category-applicative-part-i/ 85 | * https://cdsmith.wordpress.com/2011/08/13/arrow-category-applicative-part-iia/ 86 | * https://stackoverflow.com/questions/24668313/arrows-are-exactly-equivalent-to-applicative-functors 87 | * https://elvishjerricco.github.io/2017/03/10/profunctors-arrows-and-static-analysis.html 88 | * http://blog.sigfpe.com/2011/07/profunctors-in-haskell.html 89 | * http://www-kb.is.s.u-tokyo.ac.jp/~asada/papers/fromComptoComp.pdf 90 | Categorifying Computations into Components via Arrows as Profunctors 91 | 92 | * https://stackoverflow.com/questions/17668452/can-someone-explain-to-me-why-the-app-function-of-arrowapply-makes-them-as-power/17673690#17673690 93 | 94 | You can use Applicative to get the generality, and you can use Monads to get 95 | the interface-functionality, so you could argue that theoretically we don't 96 | need them, but some people like the notation for arrows because it's like do 97 | notation, and you can indeed use Arrow to implement parsers that have a static 98 | component, thus apply compile-time optimisations. I believe you can do that 99 | with Applicative, but it was done with Arrow first. 100 | 101 | A note about Applicative being "less powerful": 102 | The paper points out that Applicative is more general than Monad, but you could 103 | make Applicative functors have the same abilities by providing a function run 104 | :: Applicative f => f (f b) -> f b that lets you run a produced computation, or 105 | use :: Applicative f => f (a -> f b) -> f a -> f b that allows you to promote a 106 | produced computation to a computation. If we define join = run and unit = (<$>) 107 | we get the two functions that make one theoretical basis for Monads, and if we 108 | define (>>=) = flip (use.pure) and return = unit we get the other one that's 109 | used in Haskell. There isn't an ApplicativeRun class, simply because if you can 110 | make that, you can make a monad, and the type signatures are almost identical. 111 | The only reason we have ArrowApply instead of reusing Monad is that the types 112 | aren't identical; ~> is abstracted (generalised) into the interface in 113 | ArrowApply but function application -> is used directly in Monad. This 114 | distinction is what makes programming with Arrows feel different in many ways 115 | to programming in monads, despite the equivalence of ArrowApply and Monad. 116 | 117 | 118 | * http://haskell.cs.yale.edu/wp-content/uploads/2012/06/FromJFP.pdf Yampa 119 | arrows 120 | * http://homepages.inf.ed.ac.uk/wadler/papers/arrows-and-idioms/arrows-and-idioms.pdf 121 | Idioms are oblivious, arrows are meticulous, monads are promiscuous 122 | 123 | Use Cases 124 | ---------- 125 | 126 | A good use case of arrows is stream processing, signal processing, circuit 127 | diagrams. 128 | 129 | References 130 | ---------- 131 | 132 | * https://softwareengineering.stackexchange.com/questions/114681/what-is-the-purpose-of-arrows 133 | * http://www.cse.chalmers.se/~rjmh/afp-arrows.pdf 134 | * https://en.wikibooks.org/wiki/Haskell/Understanding_arrows 135 | * https://en.wikibooks.org/wiki/Haskell/Arrow_tutorial 136 | -------------------------------------------------------------------------------- /language/20-typeclasses.rst: -------------------------------------------------------------------------------- 1 | Type Classes 2 | ============ 3 | 4 | Terminology 5 | ----------- 6 | 7 | * Dictionary 8 | * Superclass 9 | 10 | A Bare Type 11 | ----------- 12 | 13 | Any type creates an indirection or a context in which the value is to be 14 | interpreted. It says you cannot directly operate on me, you will have to use my 15 | way of doing things. A value wrapped in a type cannot be operated directly or 16 | accidentally. No existing function will operate on a newly born type. We have 17 | to define type specific operations for it. 18 | 19 | A bare type is pure data definition isolated from the world. We need to connect 20 | it to the world by defining operations on it. 21 | 22 | Adding it to typeclasses 23 | ~~~~~~~~~~~~~~~~~~~~~~~~ 24 | 25 | Standard operations are bundled in typeclasses. Typeclasses are also a way of 26 | advertising (via constraints) that this type supports these operations and you 27 | can use those operations. So the new type can fit into a lot of existing 28 | infrastructure automatically - existing hihger level typeclasses can use it, 29 | existing operations can use it. Some typeclass operations can be automatically 30 | defined using deriving. 31 | 32 | Defining Operations 33 | ~~~~~~~~~~~~~~~~~~~ 34 | 35 | We can also define operations on a type without making it a member of 36 | typeclasses. 37 | 38 | 39 | TBD - picture of a bare type, then with operations, typeclass oeprations 40 | 41 | Deriving 42 | -------- 43 | 44 | GeneralizedNewTypeDeriving - how do you know what all instances can be derived 45 | automatically by GHC? 46 | 47 | Typeclass Definition 48 | -------------------- 49 | 50 | +-----------------------------------------------------------------------------+ 51 | | Typeclass definition | 52 | +=============================================================================+ 53 | | :: | 54 | | | 55 | | class Default a where | 56 | | def :: a | 57 | +-----------------------------------------------------------------------------+ 58 | | The type variable `a` represents any member type of the type class. | 59 | +-----------------------------------------------------------------------------+ 60 | | `def` is like any other function, the type signature of `def` is | 61 | | polymorphic and determined by the typeclass. The effective signature of | 62 | | `def` is equivalent to: | 63 | +-----------------------------------------------------------------------------+ 64 | | :: | 65 | | | 66 | | def :: Default a => a | 67 | +-----------------------------------------------------------------------------+ 68 | 69 | Instances 70 | --------- 71 | 72 | Unlike functions with polymorphic parameters, which provide a single definition 73 | for a whole set of types (known as `parametric polymorphism`), typeclasses 74 | allow the function definition to be dependent on the type. Each type can have 75 | its own definition of the polymorphic functions defined by a type class, this 76 | is called `ad-hoc polymorphism`. 77 | 78 | An instance of a typeclass provides the definition of the typeclass functions 79 | corresponding to a particular type. 80 | 81 | +-----------------------------------------------------------------------------+ 82 | | Typeclass instance | 83 | +=============================================================================+ 84 | | :: | 85 | | | 86 | | instance Default Int where | 87 | | def = 0 | 88 | | | 89 | | instance Default String where | 90 | | def = "" | 91 | +-----------------------------------------------------------------------------+ 92 | 93 | Resolving Instances 94 | ------------------- 95 | 96 | When the function `def` is called, its definition is provided by one of the 97 | instances of `Default`. The definition is uniquely determined by the actual 98 | signature of the function inferred at the call site:: 99 | 100 | def :: Default a => a 101 | 102 | def :: Int -- 0 103 | def :: String -- "" 104 | def :: Char -- Doesn't compile, no instance for "Default Char" 105 | 106 | +-----------------------------------------------------------------------------+ 107 | | Ambiguity check: | 108 | | To determine the typeclass instance, we must be able to fully resolve the | 109 | | signature of `def` at the call site. This will result in an error: | 110 | +-----------------------------------------------------------------------------+ 111 | | :: | 112 | | | 113 | | class Default a where | 114 | | def :: Int | 115 | +-----------------------------------------------------------------------------+ 116 | | Here, type `a` and therefore the specific instance of the class, cannot be | 117 | | determined by a call to `def` e.g. | 118 | +-----------------------------------------------------------------------------+ 119 | | :: | 120 | | | 121 | | def :: Default a => Int | 122 | | | 123 | | def :: Int -- 'a' cannot be determined here so compiler cannot determine | 124 | | -- which instance to use | 125 | +-----------------------------------------------------------------------------+ 126 | 127 | Typeclass Definition - Again 128 | ---------------------------- 129 | 130 | +-----------------------------------------------------------------------------+ 131 | | Put a constraint to restrict the types that can be a member of the class | 132 | +-----------------------------------------------------------------------------+ 133 | | :: | 134 | | | 135 | | class Num a => Default a where | 136 | | def :: a | 137 | +-----------------------------------------------------------------------------+ 138 | | The signature of `def` is now equivalent to: | 139 | +-----------------------------------------------------------------------------+ 140 | | :: | 141 | | | 142 | | def :: (Num a, Default a) => a | 143 | +-----------------------------------------------------------------------------+ 144 | | A typeclass can provide a default implementation of a function | 145 | +-----------------------------------------------------------------------------+ 146 | | :: | 147 | | | 148 | | class Num a => Default a where | 149 | | def :: a | 150 | | def = 0 -- default implementation | 151 | | | 152 | | instance Default Int -- Will use the default implementation of def | 153 | +-----------------------------------------------------------------------------+ 154 | | One class function can be defined in terms of another class function | 155 | +-----------------------------------------------------------------------------+ 156 | | :: | 157 | | | 158 | | class Num a => Default a where | 159 | | def1 :: a | 160 | | def2 :: a | 161 | | def1 = def2 - 1 | 162 | | def2 = def1 + 1 | 163 | +-----------------------------------------------------------------------------+ 164 | | If we define def1 then def2 will have a default implementation and vice | 165 | | versa. | 166 | +-----------------------------------------------------------------------------+ 167 | | :: | 168 | | | 169 | | instance Default Int where | 170 | | def1 = 0 -- def2 is automatically defined to 1 | 171 | +-----------------------------------------------------------------------------+ 172 | 173 | -XConstrainedClassMethods 174 | ~~~~~~~~~~~~~~~~~~~~~~~~~ 175 | 176 | Allow class methods to constrain class type variables:: 177 | 178 | class Seq s a where 179 | fromList :: [a] -> s a 180 | elem :: Eq a => a -> s a -> Bool 181 | 182 | Typeclass Instances - Again 183 | --------------------------- 184 | 185 | default instance 186 | ~~~~~~~~~~~~~~~~ 187 | 188 | Wildcard instance that applies when a specific instance does not:: 189 | 190 | instance C a where 191 | op = ... -- Default 192 | 193 | -XTypeSynonymInstances 194 | ~~~~~~~~~~~~~~~~~~~~~~ 195 | :: 196 | 197 | type Point a = (a,a) 198 | instance C (Point a) where ... 199 | 200 | -XFlexibleInstances 201 | ~~~~~~~~~~~~~~~~~~~ 202 | :: 203 | 204 | instance C (Maybe Int) where ... -- allows arbitrary nested types 205 | 206 | -XFlexibleContexts 207 | ~~~~~~~~~~~~~~~~~~ 208 | :: 209 | 210 | instance (C t1 ... tn) => ... 211 | 212 | Type Family Application in Instance 213 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 214 | 215 | Is illegal. But there is a workaround for a single instance:: 216 | 217 | type family Fam t 218 | instance (Fam Int ~ famint) => C famint 219 | 220 | * https://ghc.haskell.org/trac/ghc/ticket/3485 221 | 222 | Constraints are a good way to restrict the polymorphism. In fact we can even 223 | make a class which represents a single type. 224 | 225 | :: 226 | 227 | type Module = R ("a" := Int, "b" := String) 228 | 229 | class (a ~ Module) => Default a where 230 | def :: ("b" := String) -> a 231 | 232 | instance (x ~ R ("a" := Int, "b" := String)) => Default x where 233 | def t = R (#a := 0 :: "a" := Int) :*: R t 234 | 235 | Multi-parameter Typeclasses 236 | --------------------------- 237 | 238 | Functional Dependencies 239 | ~~~~~~~~~~~~~~~~~~~~~~~ 240 | 241 | :: 242 | 243 | class MonadBase b m => MonadBaseControl b m | m -> b where 244 | 245 | We can read ``m -> b`` as ``m determines b``. The part after ``|`` is a 246 | functional dependency which says ``m`` uniquely determines ``b`` i.e. for the 247 | same ``m`` there cannot be more than one ``b``. In other words, ``b`` is a 248 | function of ``m`` i.e. ``f m = b`` for some f. 249 | 250 | -XAllowAmbiguousTypes can be useful with functional dependencies. 251 | 252 | Infix Constructor syntax 253 | ~~~~~~~~~~~~~~~~~~~~~~~~ 254 | 255 | :: 256 | 257 | class a :=: b where ... 258 | 259 | 260 | Multi-parameter Typeclass Instances 261 | ----------------------------------- 262 | 263 | Instance declarations 264 | --------------------- 265 | 266 | :: 267 | 268 | instance => where ... 269 | instance (assertion1, ..., assertionn) => class type1 ... typem where ... 270 | 271 | instance => C (T a1 ... an) : Haskell98 272 | instance => C (T1 a1 ... an) (T2 b1 ... bn) : Multiparameter 273 | 274 | Examples: 275 | 276 | Overlapping & Incoherent Instances 277 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 278 | 279 | Try `Int Bool` or `Int [Int]` in the folowing:: 280 | 281 | instance {-# OVERLAPPABLE #-} context1 => C Int b where ... -- (A) 282 | instance {-# OVERLAPPABLE #-} context2 => C a Bool where ... -- (B) 283 | instance {-# OVERLAPPABLE #-} context3 => C a [b] where ... -- (C) 284 | instance {-# OVERLAPPING #-} context4 => C Int [Int] where ... -- (D) 285 | 286 | * More specific instance is chosen when possible 287 | * When ambiguous, errors out unless ``-XIncoherentInstances`` is used 288 | 289 | UndecidableInstances 290 | ~~~~~~~~~~~~~~~~~~~~ 291 | 292 | Instance termination rules 293 | ^^^^^^^^^^^^^^^^^^^^^^^^^^ 294 | 295 | Paterson: 296 | - occurrence of `t` in constraint <= occurrence of `t` in head 297 | - length of constraint < length of head 298 | - no type functions allowed in constraint 299 | 300 | These are not okay:: 301 | 302 | -- Context assertion no smaller than head 303 | instance C a => C a where ... 304 | -- (C b b) has more occurrences of b than the head 305 | instance C b b => Foo [b] where ... 306 | 307 | Type variables present in the context but not in the head `may` cause 308 | typechecker loop:: 309 | 310 | class D a 311 | class F a b | a->b 312 | instance F [a] [[a]] 313 | instance (D c, F a c) => D [a] -- 'c' is not mentioned in the head 314 | 315 | Coverage: 316 | For each functional dependency, ⟨tvs⟩left -> ⟨tvs⟩right, of the class, every 317 | type variable in S(⟨tvs⟩right) must appear in S(⟨tvs⟩left), where S is the 318 | substitution mapping each type variable in the class declaration to the 319 | corresponding type in the instance head. 320 | 321 | -XUndecidableInstances 322 | ^^^^^^^^^^^^^^^^^^^^^^ 323 | 324 | Allows class synonym:: 325 | 326 | class (C1 a, C2 a, C3 a) => C a where { } 327 | instance (C1 a, C2 a, C3 a) => C a where { } 328 | f :: C a => ... 329 | 330 | Relaxes the paterson conditions described above. 331 | 332 | Deriving Instances 333 | ------------------ 334 | 335 | * You can’t use deriving to define instances of a data type with existentially 336 | quantified data constructors. 337 | 338 | +------------------------------+----------------------------------------------+ 339 | | -XDeriveFunctor | deriving Functor | 340 | +------------------------------+----------------------------------------------+ 341 | | -XDeriveFoldable | deriving Foldable | 342 | +------------------------------+----------------------------------------------+ 343 | | -XDeriveTraversable | deriving Traversable | 344 | +------------------------------+----------------------------------------------+ 345 | | -XDeriveDataTypeable | deriving (Typeable, Data) | 346 | +------------------------------+----------------------------------------------+ 347 | | -XGeneralizedNewtypeDeriving | Everything that the underlying type supports?| 348 | +------------------------------+----------------------------------------------+ 349 | 350 | * http://cs.brynmawr.edu/~rae/talks/2013/hiw-roles.pdf GeneralizedNewtypeDeriving is now type-safe 351 | 352 | Associated Types 353 | ---------------- 354 | 355 | When the types in the type signatures of class functions cannot be mapped to 356 | the member type directly we can use type functions to map them to the desired 357 | types. Such type functions are called associated types. 358 | 359 | Data types 360 | 361 | :: 362 | 363 | class GMapKey k where 364 | data GMap k :: * -> * 365 | 366 | empty :: GMap k v 367 | lookup :: k -> GMap k v -> Maybe v 368 | insert :: k -> v -> GMap k v -> GMap k v 369 | 370 | instance GMapKey Int where 371 | data GMap Int v = GMapInt (Data.IntMap.IntMap v) 372 | 373 | empty = GMapInt Data.IntMap.empty 374 | lookup k (GMapInt m) = Data.IntMap.lookup k m 375 | insert k v (GMapInt m) = GMapInt (Data.IntMap.insert k v m) 376 | 377 | instance GMapKey () where 378 | data GMap () v = GMapUnit (Maybe v) 379 | 380 | empty = GMapUnit Nothing 381 | lookup () (GMapUnit v) = v 382 | insert () v (GMapUnit _) = GMapUnit $ Just v 383 | 384 | Are the associated type functions available outside the typeclass instance? 385 | Are they available where the instance is used? Yes they are available outside 386 | the type class, not restricted to the typeclass. 387 | 388 | Type synonyms 389 | 390 | Examples: Variable argument function 391 | ------------------------------------ 392 | 393 | We can overload a function based on its signature. 394 | 395 | class Signature a where 396 | func :: a 397 | 398 | instance Signature (String -> String) 399 | where func s1 = s1 400 | 401 | instance Signature (String -> String -> String) 402 | where func s1 s2 = s1 ++ s2 403 | 404 | Problem 405 | ------- 406 | 407 | 408 | class AddMod a where 409 | addmod :: a 410 | 411 | addmod :: x -> z 412 | addmod :: x -> y -> z 413 | 414 | How do we fix return type z in the signature in the class and represent the 415 | arguments using a variable? Is it even possible? 416 | 417 | Can we create a constraint to specify that the return type of a function is 418 | fixed but arguments can be anything, any number? 419 | 420 | * http://okmij.org/ftp/Haskell/polyvariadic.html#polyvar-fn 421 | * http://chris-taylor.github.io/blog/2013/03/01/how-haskell-printf-works/ 422 | 423 | References 424 | ---------- 425 | 426 | * https://wiki.haskell.org/Typeclassopedia 427 | * https://ocharles.org.uk/blog/guest-posts/2014-12-15-deriving.html 428 | * http://stackoverflow.com/questions/8546335/ambiguous-type-variable-a0-in-the-constraints 429 | * https://stackoverflow.com/questions/12645254/ghc-code-generation-for-type-class-function-calls 430 | -------------------------------------------------------------------------------- /language/21-record-types.rst: -------------------------------------------------------------------------------- 1 | Record Types 2 | ============ 3 | 4 | .. contents:: Table of Contents 5 | :depth: 1 6 | 7 | Terminology 8 | ----------- 9 | 10 | +------------------------+----------------------------------------------------+ 11 | | Record | A record is a product type with named fields | 12 | +------------------------+----------------------------------------------------+ 13 | | | :: | 14 | | | | 15 | | | data R = | 16 | | | R { | 17 | | | x :: String | 18 | | | , y :: Int | 19 | | | } deriving (Show) | 20 | | | | 21 | +------------------------+----------------------------------------------------+ 22 | | Field Labels | The names of the fields e.g. `x` and `y` are | 23 | | | called field labels | 24 | +------------------------+----------------------------------------------------+ 25 | | Selector functions | The field names also act as a function that takes | 26 | | | the record as argument and returns the field value.| 27 | | | e.g. `x r` will return the value of field `x` i.e. | 28 | | | a `String` type. | 29 | +------------------------+----------------------------------------------------+ 30 | 31 | Record Syntax 32 | ------------- 33 | 34 | +-----------------------------------------------------------------------------+ 35 | | `-XNoTraditionalRecordSyntax` (7.4.1) -- to disable the record syntax | 36 | +=============================================================================+ 37 | | .. class :: center | 38 | | | 39 | | Records | 40 | +----------------------+------------------------------------------------------+ 41 | | :: | :: | 42 | | | | 43 | | data R = | data R where | 44 | | R { | R :: { | 45 | | x :: String | x :: String | 46 | | , y :: Int | , y :: Int | 47 | | } deriving (Show) | } -> R | 48 | | | deriving (Show) | 49 | +----------------------+------------------------------------------------------+ 50 | | Selector functions to extract a field from a record data structure are | 51 | | automatically generated for each record field:: | 52 | | | 53 | | x :: R -> String | 54 | | y :: R -> Int | 55 | +-----------------------------------------------------------------------------+ 56 | | Until the brain gets trained, it is pretty confusing that the types of the | 57 | | selector functions are different from what they seem to be from the code: | 58 | +-----------------------------------+-----------------------------------------+ 59 | | :: | :: | 60 | | | | 61 | | data R = | -- | 62 | | R { | | 63 | | x :: String | x :: R -> String | 64 | | , y :: Int | y :: R -> Int | 65 | | } | | 66 | +-----------------------------------+-----------------------------------------+ 67 | | `-XDuplicateRecordFields` (8.0.1) allows using identical fields in different| 68 | | records even in the same module. Selector functions and updates are | 69 | | disambiguated using the type of the field or the record. | 70 | +-----------------------------------------------------------------------------+ 71 | | :: | 72 | | | 73 | | data S = | 74 | | S { | 75 | | x :: String | 76 | | , z :: Int | 77 | | } deriving (Show) | 78 | +-----------------------------------------------------------------------------+ 79 | | Exporting and importing selector functions: | 80 | +-----------------------------------------------------------------------------+ 81 | | :: | 82 | | | 83 | | Module M (y) where ... -- only when y is unambiguous field | 84 | | Module M (R(x)) where ... -- even when x is ambiguous field | 85 | | | 86 | | import M (y) -- only when y is unambiguous field | 87 | | import M (R(x)) -- even when x is ambiguous field | 88 | +-----------------------------------------------------------------------------+ 89 | 90 | Construction And Pattern Matching 91 | --------------------------------- 92 | 93 | +-----------------------------------------------------------------------------+ 94 | | Construction and pattern matching | 95 | +=============================================================================+ 96 | | Record constructor brackets {} have a higher precedence than function | 97 | | application. | 98 | +-----------------------------------------------------------------------------+ 99 | | `-XDisambiguateRecordFields` allows using record fields x and y unqualified | 100 | | even if they clash with field names in other records and even when the | 101 | | record is defined in a module which is imported qualified. | 102 | +-----------------------------------------------------------------------------+ 103 | | Note that selector functions are symbols but field names are literals i.e. | 104 | | you cannot say x = y and then use x in place of y as a field name. x will | 105 | | refer to the selector function, when used as a field name it will refer to | 106 | | field named "x" rather than "y". | 107 | +-----------------------------------------------------------------------------+ 108 | | **Construction** | 109 | +----------------------------+------------------------------------------------+ 110 | | ``show (R "a" 1)`` | ``show R { y = 1, x = "a" } | 111 | | | -- Note precedence of {}`` | 112 | +----------------------------+------------------------------------------------+ 113 | | ``r = R "a" 1`` | ``r = R { y = 1, x = "a" }`` | 114 | +----------------------------+------------------------------------------------+ 115 | | `-XRecordWildCards` | ``let {x = "a"; y = 2} in R {..} | 116 | | | -- R {x = x, y = y}`` | 117 | +----------------------------+------------------------------------------------+ 118 | | **Pattern matching** | 119 | +----------------------------+------------------------------------------------+ 120 | | ``f (R _ _) = ...`` | ``f R {} = ... | 121 | | | -- Note precedence of {}`` | 122 | +----------------------------+------------------------------------------------+ 123 | | ``f (R "a" 1) = ...`` | ``f R {x = "a", y = 1} = ...`` | 124 | +----------------------------+------------------------------------------------+ 125 | | ``f (R a b) = ...`` | ``f (R {x = a, y = b}) = a ++ show b`` | 126 | +----------------------------+------------------------------------------------+ 127 | | `-XNamedFieldPuns` | ``f (R {x, y}) = ... | 128 | | | -- f (R {x = x, y = y})`` | 129 | | +------------------------------------------------+ 130 | | | ``f (R {x, y = b}) = ... | 131 | | | -- f (R {x = x, y = b})`` | 132 | | +------------------------------------------------+ 133 | | | ``f (R {M.x, M.y}) = ... -- M is module | 134 | | | qualifier`` | 135 | +----------------------------+------------------------------------------------+ 136 | | `-XRecordWildCards` | ``f (R {..}) = ... | 137 | | | -- f (R {x = x, y = y})`` | 138 | | ``..`` expands to missing +------------------------------------------------+ 139 | | `in-scope` record fields | ``f (R {x = "a", ..}) = ... | 140 | | | -- f (R {x = "a", y = y})`` | 141 | | +------------------------------------------------+ 142 | | | ``import R(y)`` | 143 | | | | 144 | | | ``f (R {..}) = ... | 145 | | | -- f (R {y = y})`` | 146 | +----------------------------+------------------------------------------------+ 147 | 148 | Access and Update 149 | ----------------- 150 | 151 | +-----------------------------------------------------------------------------+ 152 | | Access and update | 153 | +=============================================================================+ 154 | | **Accessing field 'x' using its selector function** | 155 | +----------------------------------+------------------------------------------+ 156 | | ``x R {x = "a", y = 1}`` | ``x r`` | 157 | +----------------------------------+------------------------------------------+ 158 | | When using `-XDuplicateRecordFields` disambiguate selectors: | 159 | +-----------------------------------------------------------------------------+ 160 | | By inferred or explicit type of the selector function (e.g. ``x``). | 161 | +-----------------------+-------------------+---------------------------------+ 162 | | ``v = x :: S -> Int`` | ``v :: S -> Int`` | ``f :: (S -> Int) -> _`` | 163 | | | | | 164 | | | ``v = x`` | ``f x`` | 165 | +-----------------------+-------------------+---------------------------------+ 166 | | By explicit but not inferred type of the record being accessed (e.g. ``s``).| 167 | +-----------------------+-----------------------------------------------------+ 168 | | ``ok s = x (s :: S)`` | ``bad :: S -> Int`` | 169 | | | | 170 | | | ``bad s = x s -- Ambiguous`` | 171 | +-----------------------+-----------------------------------------------------+ 172 | | If only one of the conflicting selectors is imported by a module then it | 173 | | can be used unambiguously. | 174 | +-----------------------------------------------------------------------------+ 175 | | **Updating one or more fields** | 176 | +----------------------------------+------------------------------------------+ 177 | | ``R {x = "a", y = 1} {x = "b"}`` | ``r { x = "b", y = 2}`` | 178 | +----------------------------------+------------------------------------------+ 179 | | ``..`` expands to missing | ``f (R {x = "a", ..}) = R{x = "b", ..}`` | 180 | | `in-scope` record fields | | 181 | +----------------------------------+------------------------------------------+ 182 | | When using `-XDuplicateRecordFields`, disambiguate duplicate fields: | 183 | +-----------------------------------------------------------------------------+ 184 | | By field names: | 185 | +-----------------------------------------------------------------------------+ 186 | | ``s {z = 5} -- field z occurs only in record type S`` | 187 | +-----------------------------------------------------------------------------+ 188 | | By the inferred or explicit type of the update application | 189 | | (e.g. ``s {x = 5}``). | 190 | +------------------------+-------------------+--------------------------------+ 191 | | ``v = s {x = 5} :: S`` | ``v :: S -> S`` | ``f :: S -> _`` | 192 | | | | | 193 | | | ``v = s {x = 5}`` | ``f (s {x = 5})`` | 194 | +------------------------+-------------------+--------------------------------+ 195 | | By the explicit but not inferred type of the record being updated | 196 | | (e.g. ``s``). | 197 | +-----------------------------+-----------------------------------------------+ 198 | | ``ok s = (s :: S) {x = 5}`` | ``bad :: S`` | 199 | | | | 200 | | | ``bad s = s {x = 5} -- Ambiguous`` | 201 | +-----------------------------+-----------------------------------------------+ 202 | 203 | Conventions and Coding Patterns 204 | ------------------------------- 205 | 206 | Default Value Pattern 207 | --------------------- 208 | 209 | We can define default values for all fields of a record and then override them 210 | to customize:: 211 | 212 | data Record = Record 213 | { a :: Int 214 | , b :: String 215 | } 216 | r = def $ Record {a = 10, b = "hello"} 217 | 218 | * see data-default-class package 219 | * We can construct and modify a record even without the constructor if we have 220 | a default record. We just use the default record as a starting value and 221 | override the fields. This pattern is used quite often. Some libraries do not 222 | export the record constructor to force using teh default value as a starting 223 | value and to control what fields can be modified. 224 | 225 | Anonymous Records 226 | ----------------- 227 | 228 | Extensible Records 229 | ------------------ 230 | 231 | Named function arguments 232 | ------------------------ 233 | 234 | Records can be used as a means to name the function arguments. We can pass a 235 | record argument instead of individual arguments. 236 | 237 | The application of defaults to a record can be used to pass named function 238 | arguments. We pass arguments bundled in a record instead of individually: 239 | 240 | func (def $ Record {a = 10, b = "hello"}) 241 | 242 | Using anonymous records we can have true named function arguments without the 243 | boilerplate of def and Record. 244 | 245 | Mandatory and optional arguments 246 | -------------------------------- 247 | 248 | Using rawr we can implement mandatory and optional arguments too. We provide 249 | defaults only for optional arguments. That way we will have to pass the other 250 | arguments if the function signature requires it. For example:: 251 | 252 | func :: R ("a" := Int, "b" := String) -> IO () 253 | func (P (_ := a :: "a" := Int, _ := b :: "b" := String)) = 254 | putStrLn $ show a ++ b 255 | def :: ("b" := String) -> R ("a" := Int, "b" := String) 256 | def t = (R (#a := 0) :*: R t) 257 | main = func (def (#b := "hello")) 258 | 259 | In this example the argument "a" is optional and "b" is mandatory. 260 | 261 | Use the keyword-arg example in examples dir. 262 | 263 | GHC Internals 264 | ------------- 265 | 266 | * GHC.OverloadedLabels 267 | * GHC.Records 268 | -------------------------------------------------------------------------------- /language/24-dependent-types.rst: -------------------------------------------------------------------------------- 1 | Dependent Type Programming 2 | -------------------------- 3 | 4 | A natural number datatype:: 5 | 6 | data Nat where 7 | Zero :: Nat 8 | Succ :: Nat → Nat 9 | 10 | can automatically be used at the type level to indicate the 11 | length of a vector represented by a GADT. 12 | 13 | :: 14 | 15 | data Vec :: ∗ → Nat → ∗ where 16 | VNil ::Vec a ’Zero 17 | VCons :: a → Vec a n → Vec a (’Succ n) 18 | 19 | (The single quotes in front of the data constructor names indicate 20 | that they were promoted from the expression language.) 21 | 22 | Furthermore, type families can express functions on this typelevel data, such 23 | as one that computes whether one natural number is less than another.:: 24 | 25 | type family (m ::Nat) :< (n ::Nat) ::Bool 26 | type instance m :< ’Zero = ’False 27 | type instance ’Zero :<(’Succ n) = ’True 28 | type instance (’Succ m):<(’Succ n) = m : argApply (map snd p) n 25 | 26 | funcbox :: [String] -> Int -> Diagram B 27 | funcbox params n = (strokeLocTrail $ tr `at` p2 (0, 0)) <> plabels 28 | where tr = (closeTrail . trailFromVertices) (map p2 pts) 29 | pts = [(0,0), (0, -1), (1, -1), (1, 0)] ++ argPts 30 | plabels :: Diagram B 31 | plabels = atPoints (map p2 argTips) (map ((scale 0.1) . topLeftText) (reverse params)) 32 | argTips :: [(Double, Double)] 33 | argTips = map snd $ filter (even . fst) (zip [1..] argPts) 34 | argPts = take (2 * n + 1) 35 | $ zip (map ((* (base / 2)) . toFrac) lst) 36 | (map (\x -> if odd x then (- height) else 0.0) lst) 37 | where lst = reverse [1..2 * m] 38 | (base, height) = triangleProps m 39 | m = length params 40 | 41 | toFrac = fromRational . toRational 42 | 43 | -- the triangle used to represent one argument 44 | -- (base, height) 45 | triangleProps m = (base, (base / 2) * sqrt 3) 46 | where base = 1 / (toFrac m) 47 | 48 | argApply :: [String] -> Int -> Diagram B 49 | argApply args n = 50 | (triangle base # reflectY <> text (args !! (m - n)) # scale 0.1) 51 | # moveTo (p2 ((toFrac (m - n) * base + base / 2), 0)) 52 | where (base, _) = triangleProps m 53 | m = length args 54 | -------------------------------------------------------------------------------- /libs/concurrency.rst: -------------------------------------------------------------------------------- 1 | Basic Concurrency 2 | ----------------- 3 | 4 | GHC Options 5 | ----------- 6 | 7 | -threaded 8 | 9 | For real parallelism: 10 | 11 | Concurrency 12 | ----------- 13 | 14 | * Composable concurrency (purity) 15 | * Tools: threadscope 16 | 17 | Creating Threads 18 | ---------------- 19 | 20 | * Control.Concurrent (base package) 21 | 22 | :: 23 | 24 | forkIO :: IO () -> IO ThreadId 25 | killThread :: ThreadId -> IO () 26 | throwTo :: Exception e => ThreadId -> e -> IO () 27 | 28 | async 29 | ~~~~~ 30 | 31 | The main additional functionality it provides is the ability to wait for the 32 | return value of a thread 33 | 34 | data Async a | represents an asynchronous IO action that will return a value of 35 | type a, or die with an exception.:: 36 | 37 | async :: IO a -> IO (Async a) 38 | withAsync :: IO a -> (Async a -> IO b) -> IO b 39 | 40 | wait :: Async a -> IO a 41 | waitAny :: [Async a] -> IO (Async a, a) 42 | poll :: Async a -> IO (Maybe (Either SomeException a)) 43 | cancel :: Async a -> IO () 44 | 45 | race :: IO a -> IO b -> IO (Either a b) 46 | concurrently :: IO a -> IO b -> IO (a, b) 47 | mapConcurrently :: Traversable t => (a -> IO b) -> t a -> IO (t b) 48 | 49 | newtype Concurrently a 50 | 51 | A value of type Concurrently a is an IO operation that can be composed with 52 | other Concurrently values, using the Applicative and Alternative instances. 53 | 54 | Calling runConcurrently on a value of type Concurrently a will execute the IO 55 | operations it contains concurrently, before delivering the result of type a. 56 | 57 | Data Sharing/Communication/Synchronization 58 | ------------------------------------------ 59 | 60 | Synchronization Needs: 61 | 62 | * Transactional read and modification of shared data (raced) 63 | * Serialized read and modification with blocking wait (ordered) 64 | * Send and receive data (one at a time or FIFO Channels) 65 | * Binary Semaphore 66 | * Quantity Semaphore 67 | 68 | Facilities: 69 | 70 | * MVar (fairness, single-wakeup, performance) 71 | * stm (Composable atomicity, Composable blocking, robust error handling) 72 | 73 | * Asynchronous exceptions 74 | * Completely safe to interrupt threads because of purity 75 | 76 | +--------------+------------------------------------+-------------------------+ 77 | | data IORef a | * mutable variable | new, read, write | 78 | | | * CPU can reorder reads/writes | | 79 | +--------------+------------------------------------+-------------------------+ 80 | | | * reads and writes are serialized | atomicModify | 81 | | | * Acts as a barrier to reordering | | 82 | +--------------+------------------------------------+-------------------------+ 83 | | data MVar a | * mutable variable with explicit | new, take, put | 84 | | | synch | | 85 | | | * Fair, single-wakeup, lazy, | | 86 | | | ordered | | 87 | +--------------+------------------------------------+-------------------------+ 88 | | data Chan a | * Unbounded FIFO channel | new, dup, read, write | 89 | | | * implemented with MVars | | 90 | +--------------+------------------------------------+-------------------------+ 91 | | data QSem | * Quantity Semaphore: aqcuired and | new, wait, signal | 92 | | | | | 93 | | data QSemN | released in units of one | | 94 | +--------------+------------------------------------+-------------------------+ 95 | 96 | MVars 97 | ----- 98 | 99 | * As synchronized mutable variables :: 100 | 101 | A <- take, modify (B waits), put 102 | B <- take, modify (A waits), put 103 | 104 | * As a binary semaphore MVar (), with takeMVar and putMVar as wait and signal. :: 105 | 106 | A <- take, do something (B waits), put 107 | B <- take, do something (A waits), put 108 | 109 | * As channels, with takeMVar and putMVar as receive and send, and :: 110 | 111 | A puts -> B takes 112 | A puts -> B takes 113 | ... 114 | A blocks if full 115 | B blocks if empty 116 | 117 | they are very simple and susceptible to race conditions, deadlocks or uncaught 118 | exceptions. STM is more sophisticated and easier to get right than MVars. 119 | Unless you need low level control and control over performance overhead use 120 | STM. 121 | 122 | Fairness: No thread can be blocked indefinitely on an MVar unless another 123 | thread holds that MVar indefinitely. 124 | 125 | Laziness: MVars are lazy; if you place an expensive unevaluated thunk inside an 126 | MVar, it will be evaluated by the thread that consumes it, not the thread that 127 | produced it. 128 | 129 | Memory Ordering: MVar operations are always observed to take place in the order 130 | they are written in the program 131 | 132 | stm 133 | --- 134 | 135 | STM: A monad supporting atomic memory transactions. Provides Alternative and 136 | MonadPlus instances as well. 137 | 138 | Either the whole transaction happens or nothing. TVars can be read and modified 139 | inside the atomically blocks to communicate across threads:: 140 | 141 | atomically :: STM a -> IO a 142 | 143 | Retry execution of the current memory transaction because it has seen values in 144 | TVars which mean that it should not continue (e.g. the TVars represent a shared 145 | buffer that is now empty). The implementation may block the thread until one of 146 | the TVars that it has read from has been udpated:: 147 | 148 | retry :: STM a 149 | 150 | +-----------------+--------------------------------+--------------------------+ 151 | | data TVar a | Mutable variable in STM | new, read, write | 152 | +-----------------+--------------------------------+--------------------------+ 153 | | data TMVar a | Mutable variable with synch in | new, take, put | 154 | | | STM | | 155 | +-----------------+--------------------------------+--------------------------+ 156 | | data TChan a | Unbounded FIFO channel | new, dup, clone, peek, | 157 | | | | read, write | 158 | +-----------------+--------------------------------+--------------------------+ 159 | | data TQueue a | Unbounded FIFO (Faster, | new, peek, read, write | 160 | | | no dup or clone | | 161 | +-----------------+--------------------------------+--------------------------+ 162 | | data TBQueue a | Bounded FIFO | new, peek, read, write | 163 | +-----------------+--------------------------------+--------------------------+ 164 | | data TSem a | Quantity semaphore: acquired | new, wait, signal | 165 | | | and released in units of one. | | 166 | | | No fairness. | | 167 | +-----------------+--------------------------------+--------------------------+ 168 | | data TArray i e | Mutable array with MArray | | 169 | | | interface in STM | | 170 | +-----------------+--------------------------------+--------------------------+ 171 | 172 | parallel 173 | -------- 174 | 175 | * Purity 176 | * Determinism 177 | 178 | * Program does the same thing but faster 179 | * No trade-off with correctness 180 | * No race conditions or deadlocks 181 | 182 | * basic pure parallelism: sparks & strategies 183 | 184 | * Control.Parallel.Strategies 185 | * Eval monad (rpar/rseq) 186 | 187 | * deterministic parallelism 188 | * minimal control over the evaluation order 189 | * Strategies 190 | 191 | * Adding parallelism over pure (lazy) data structures 192 | * Composability: combine Strategies into larger ones 193 | * modular: (e `using` s) parallelism separate from algorithm 194 | * myList `using` parList rdeepseq 195 | * Lazy evaluation is the magic ingredient that bestows 196 | modularity, and thus forms the basis of Strategies. Programmer aware of: 197 | 198 | * Evaluation order (rpar requires lazy computation) 199 | * garbage collection (result of rpar must not be discarded) 200 | 201 | * The Par monad (does not require laziness) 202 | * parallel 203 | * accelerate (GPU programming) 204 | 205 | sparks:: 206 | 207 | par :: a -> b -> b 208 | a `par` b is exactly equivalent semantically to b. 209 | 210 | Eval monad:: 211 | 212 | runEval :: Eval a -> a 213 | 214 | myStrat :: Strategy (a,b) 215 | myStrat (a,b) = do { a' <- rpar a; b' <- rseq b; return (a',b') } 216 | myStrat (a,b) = (,) <$> rpar a <*> rseq b 217 | 218 | Deterministic, modular, and compositional parallelism strategies:: 219 | 220 | type Strategy a = a -> Eval a 221 | using :: a -> Strategy a -> a 222 | withStrategy :: Strategy a -> a -> a 223 | dot :: Strategy a -> Strategy a -> Strategy a -- compose 224 | 225 | Strategies: r0/rseq/rdeepseq/rpar/rparWith 226 | Startegies for traversable/lists/tuples 227 | Strategic function application 228 | 229 | Distributed 230 | ----------- 231 | 232 | * transient 233 | * cloud-haskell 234 | 235 | References 236 | ---------- 237 | 238 | * http://community.haskell.org/~simonmar/ 239 | * https://www.microsoft.com/en-us/research/wp-content/uploads/1996/01/concurrent-haskell.pdf Concurrent Haskell - Paper 240 | * http://simonmar.github.io/bib/papers/stm.pdf Composable Memory Transactions 241 | * https://www.microsoft.com/en-us/research/publication/beautiful-concurrency/ STM 242 | * https://www.microsoft.com/en-us/research/publication/tackling-awkward-squad-monadic-inputoutput-concurrency-exceptions-foreign-language-calls-haskell/?from=http%3A%2F%2Fresearch.microsoft.com%2Fen-us%2Fum%2Fpeople%2Fsimonpj%2Fpapers%2Fmarktoberdorf%2F Tackling the Awkward Squad 243 | * https://www.fpcomplete.com/blog/2016/11/comparative-concurrency-with-haskell 244 | * http://chimera.labs.oreilly.com/books/1230000000929 Parallel and Concurrent Programming in Haskell By Simon Marlow 245 | 246 | * https://github.com/atemerev/skynet 1 million thread benchmark 247 | * http://benchmarksgame.alioth.debian.org/u64q/performance.php?test=threadring thread ring benchmark 248 | 249 | * https://pdfs.semanticscholar.org/f23d/5d8989a3c7fab493e53374b6b85ffa5d57d5.pdf The Essence of Multitasking 250 | * https://www.cs.indiana.edu/hyplan/dfried/ts.ps Trampolined style 251 | -------------------------------------------------------------------------------- /libs/containers.rst: -------------------------------------------------------------------------------- 1 | Folds, Traversals and Optics 2 | ============================ 3 | 4 | The common operations that you perform on containers are folds and traversals. 5 | 6 | base | distributive | mono-traversable | lens | lens-action 7 | 8 | * the ``foldl`` and ``folds`` packages 9 | * https://hackage.haskell.org/package/unfoldable 10 | 11 | lens 12 | ---- 13 | 14 | * http://hackage.haskell.org/package/lens-tutorial-1.0.2 15 | 16 | Lenses allow you to magnify and view a small part of a big structure. They 17 | allow you to traverse or fold all or a part of any data structure not just 18 | containers like lists but even monomorphic type data structures. Lenses can be 19 | composed to create more sophisticated traversal or fold mechanisms. 20 | 21 | There are two types of lens combinators, the ones that work on pure data 22 | structures and the ones that work in the State monad. 23 | 24 | Lens: 25 | * Source object: s 26 | * The part inside the source that we are focusing on: a 27 | 28 | A lens encodes enough information so that we can generically adapt it to view, 29 | set, over functions. A lens is just a type synonum of a function. 30 | 31 | Lens is a function specific to source. If you provide it a way to transform a 32 | type into a functor, it will give you a way to transform the source into the 33 | same functor. It does not matter which functor. The functor provides another 34 | level of abstraction for the transformation so that it can work for pure 35 | transformations as well as side effects. For pure values we can put them 36 | Identity functor to make this work and then take them out. 37 | 38 | type Lens s a = Functor f => (a -> f a) -> (s -> f s) 39 | 40 | The functor can be provided by the adapter functions like `over`. 41 | 42 | over :: Lens s a -> (a -> a) -> (s -> s). We can read that as: Given a lens 43 | focusing on an a inside of an s, and a function from a to a, and an s, I can 44 | give you back a modified s from applying the function to the focus point of the 45 | lens. 46 | 47 | over is a generic function, you just give it a lens and corresponding value 48 | transfomer it will provide you the source transfomer: 49 | over: Lens s a -> Transformer a -> Transformer s 50 | 51 | over is a higher rank function. It is like a broker or adapter fitting multiple 52 | compatible things together. 53 | 54 | view :: Lens s a -> s -> a. We can read this as: Given a lens that focuses on 55 | an a inside of an s, and an s, I can give you an a. 56 | 57 | view ln s = getConst $ ln Const s 58 | 59 | -------- 60 | 61 | type Lens' s a = Functor f => (a -> f a) -> s -> f s 62 | type Lens s t a b = Functor f => (a -> f b) -> s -> f t 63 | -- you can change the type of the focus and the type of the source as well as a 64 | result of an update. 65 | -- Setter also has similar type except that f is Settable instead of a Functor 66 | 67 | Notice that Lens or Setter is a generalization of a Functor: 68 | * fmap transforms (a -> b) -> (f a -> f b) 69 | * Lens transforms (a -> f b) -> ( s -> f t) 70 | 71 | * sets or setting takes a fmap like function 72 | * The Setter mapped is merely "sets fmap" 73 | * "over mapped" is just "fmap" 74 | 75 | Types:: 76 | 77 | s (contains) a 78 | | | changes to 79 | v v 80 | t (contains) b 81 | 82 | +----------------+------------------------------------------------------------+ 83 | | instrument | is also a | 84 | +================+============================================================+ 85 | | iso | lens, prism (invertible i.e. s t a b | a b s t) | 86 | +----------------+------------------------------------------------------------+ 87 | | prism | (getter b t) | traversal s t a b | 88 | | (dual of lens?)| | 89 | +----------------+------------------------------------------------------------+ 90 | | lens | getter, traversal | 91 | +----------------+------------------------------------------------------------+ 92 | | getter | fold, action | 93 | +----------------+------------------------------------------------------------+ 94 | | traversal | setter, fold | 95 | +----------------+------------------------------------------------------------+ 96 | 97 | * lens is a traversal AND a getter 98 | * prism is a traversal OR a reverse getter 99 | 100 | :: 101 | 102 | Iso -> Prism -- (re) --> review (reverse getter) 103 | | | 104 | v v 105 | Lens -> Traversal -> Setter 106 | | | 107 | v v 108 | Getter -> Fold 109 | | | 110 | v v 111 | Action -> MonadicFold 112 | 113 | Put the above diagram in a tree form. 114 | Provide links to hackage docs. 115 | 116 | Types:: 117 | 118 | type Iso s t a b = forall p f. (Profunctor p, Functor f) => p a (f b) -> p s (f t) 119 | type Prism s t a b = forall p f. (Choice p, Applicative f) => p a (f b) -> p s (f t) 120 | type Lens s t a b = forall f. Functor f => (a -> f b) -> s -> f t 121 | 122 | Prism examples 123 | 124 | +------------------------------------+--------------------------------+ 125 | | ``Left "hello" & _Left %~ length`` | ``Left 5`` | 126 | +------------------------------------+--------------------------------+ 127 | | ``re _Left :: Contravariant f => LensLike' f a (Either a c)`` | 128 | +------------------------------------+--------------------------------+ 129 | | ``5^.re _Left`` | ``Left 5`` -- contravariant | 130 | +------------------------------------+--------------------------------+ 131 | 132 | Operators 133 | ~~~~~~~~~ 134 | 135 | * ('<&>') = 'flip' 'fmap' 136 | * flip argument order of composite functions 137 | * fab ?? a = fmap ($ a) fab 138 | 139 | * Lens combinators are left associative 140 | (10,20) & _2 +~ 1 & _1 -~ 1 141 | ((((10,20) & _2) +~ 1) & _1) -~ 1 142 | 143 | * Lens combinators compose in the opposite direction to "." 144 | 145 | * TODO: verify and add more operators from 146 | https://hackage.haskell.org/package/lens-4.15/docs/Control-Lens-Lens.html 147 | 148 | +-----------------------------------------------------------+ 149 | | view/fold operations (^ prefix) | 150 | +=======================================+===================+ 151 | | view (a) | ``^.`` | 152 | +---------------------------------------+-------------------+ 153 | | iview ((i, a)) | ``^@.`` | 154 | +---------------------------------------+-------------------+ 155 | | safe retrieval (Maybe a) | ``^?`` | 156 | +---------------------------------------+-------------------+ 157 | | unsafe retrieval (a) | ``^?!`` | 158 | +---------------------------------------+-------------------+ 159 | | toListOf ([a]) | ``^..`` | 160 | +---------------------------------------+-------------------+ 161 | | Actions & Monadic folds (^@ for indexed versions) | 162 | +---------------------------------------+-------------------+ 163 | | action | ``^! ^@!`` | 164 | +---------------------------------------+-------------------+ 165 | | MonadicFold collect all results | ``^!! ^@!!`` | 166 | +---------------------------------------+-------------------+ 167 | | MonadicFold collect leftmost result | ``^!? ^@!?`` | 168 | +---------------------------------------+-------------------+ 169 | 170 | +-----------------------------------------------------------------------------+ 171 | | Set or traversal ops (~ or = suffix, optional < or << prefix) | 172 | +=============================================================================+ 173 | | Suffixes ~ or = indicate set or traversal ops | 174 | +-----------+-------------------+--------------------------+------------------+ 175 | | Suffix ~ | set pure | ``(10,20) & _2 +~ 1`` | ``(10,21)`` | 176 | +-----------+-------------------+--------------------------+------------------+ 177 | | Suffix = | set state monad | ``execState (do _2 += 1) | ``(10,21)`` | 178 | | | | (10,20)`` | | 179 | +-----------+-------------------+--------------------------+------------------+ 180 | | < or << prefixes are used to return the new or old value respectively | 181 | +-----------+-------------------+--------------------------+------------------+ 182 | | Prefix < | return the result | ``(10,20) & _2 <+~ 1`` | ``(21,(10,21))`` | 183 | +-----------+-------------------+--------------------------+------------------+ 184 | | Prefix << | return the old | | 185 | | | value | | 186 | +-----------+-------------------+---------------------------------------------+ 187 | 188 | +-------------------------------------------+ 189 | | Set or traversal operations | 190 | +===================+=======================+ 191 | | Opt Prefixes: < <<| Suffixes: ~ = | 192 | +-------------------+-----------------------+ 193 | | set | ``.`` | 194 | +-------------------+-----------------------+ 195 | | over | ``%`` | 196 | +-------------------+-----------------------+ 197 | +-------------------+-----------------------+ 198 | | Opt Prefix: < | Suffixes: ~ = | 199 | +-------------------+-----------------------+ 200 | | iover | ``%@`` | 201 | +-------------------+-----------------------+ 202 | | Math | ``+ - * // ^ ^^ **`` | 203 | +-------------------+-----------------------+ 204 | | Logic | ``|| &&`` | 205 | +-------------------+-----------------------+ 206 | | Monoid | ``<>`` | 207 | +-------------------+-----------------------+ 208 | | Bits | ``.|. .&.`` | 209 | +-------------------+-----------------------+ 210 | | FilePath | `` <.>`` | 211 | +-------------------+-----------------------+ 212 | +-------------------+-----------------------+ 213 | | | Suffixes: ~ = | 214 | +-------------------+-----------------------+ 215 | | iset | ``.@`` | 216 | +-------------------+-----------------------+ 217 | | traverseOf | ``%%`` | 218 | +-------------------+-----------------------+ 219 | | Indexed traverse | ``%%@`` | 220 | +-------------------+-----------------------+ 221 | 222 | mono-traversable 223 | ~~~~~~~~~~~~~~~~ 224 | 225 | References 226 | ---------- 227 | 228 | * http://blog.jakubarnold.cz/2014/07/30/foldable-and-traversable.html 229 | * http://lens.github.io/tutorial.html 230 | * http://blog.jakubarnold.cz/2014/07/14/lens-tutorial-introduction-part-1.html 231 | * http://blog.jakuba.net/2014/08/06/lens-tutorial-stab-traversal-part-2.html 232 | * https://artyom.me/lens-over-tea-4 233 | * https://patternsinfp.wordpress.com/2011/01/31/lenses-are-the-coalgebras-for-the-costate-comonad/ 234 | * https://arxiv.org/pdf/1103.2841.pdf Functor is to Lens as Applicative is to Biplate Introducing Multiplate 235 | -------------------------------------------------------------------------------- /libs/errors-and-exceptions.rst: -------------------------------------------------------------------------------- 1 | Overview 2 | -------- 3 | 4 | Two tracks, normal and exception. An exception just short circuits the 5 | execution and makes the control flow jump directly to the exception handler. 6 | 7 | Checked vs Unchecked Exceptions 8 | ------------------------------- 9 | 10 | Checked errors are explicitly typed in the signature. Unchecked errors are more 11 | of an independently mechanism that is implicitly attached to a function and you 12 | never know, it may or may not be there, the type system does not help in 13 | knowing the presence of errors, you need to know about them and deal with them. 14 | Any function which is in IO monad or which has a MonadThrow constraint can 15 | throw many different type of errors. The onus is on the programmer to find out 16 | about them all and deal with them if she wants to. 17 | 18 | Maybe/Either/ExceptT approach is superior to throw/catch mechanism as it can 19 | tell you specifically which exceptions can occur (checked) in a given function 20 | and looking at the function signature you can tell that the function can fail. 21 | 22 | throw/catch mechanism is primarily for runtime system to throw exceptions 23 | without having to express that in the type signature of the function. That way 24 | this is not a preferrable mechanism for programmer controlled error cases. Such 25 | exceptions by the runtime system can be thrown in pure code (e.g. DivideByZero 26 | or in IO code when some IO error occurs). 27 | 28 | The programmer should always consider the possiblity that any function that 29 | returns an IO type or a monad transformer that can be instantiated using the IO 30 | monad (or using MonadThrow) may throw an exception of any type. 31 | 32 | Handling Errors in Pure Code 33 | ---------------------------- 34 | 35 | There are two fundamental ways to represent error conditions. 36 | 37 | +--------+---------+------------------------------------+ 38 | | Maybe | Nothing | Error (only indication) | 39 | | +---------+------------------------------------+ 40 | | | Just | Return value | 41 | +--------+---------+------------------------------------+ 42 | | Either | Left | Error value | 43 | | +---------+------------------------------------+ 44 | | | Right | Return value | 45 | +--------+---------+------------------------------------+ 46 | 47 | Maybe is used when you only one error case it only tells whether there is an 48 | error or no error. When you want to distinguish between error cases use Either. 49 | 50 | These allow the programmer to explicitly and fully control the error handling. 51 | In addition to these ``throw`` is another way to express an exception 52 | condition. 53 | 54 | Maybe and Either as Monads 55 | -------------------------- 56 | 57 | We can also use Maybe and Either as monads to short circuit computations in a 58 | do block. TBD provide examples. 59 | 60 | +-------------+---------------------------------------------------------------+ 61 | | Monad | Operations | 62 | +=============+===============================================================+ 63 | | Maybe | Nothing value short circuits the sequence. | 64 | +-------------+---------------------------------------------------------------+ 65 | | Either | Left value short circuits the sequence. | 66 | +-------------+---------------------------------------------------------------+ 67 | | Except | throwE, catchE | 68 | +-------------+---------------------------------------------------------------+ 69 | | | runExcept :: Except e a -> Either e a | 70 | +-------------+---------------------------------------------------------------+ 71 | 72 | Maybe, Either and Except provide short circuiting behavior very much like the 73 | "return" statements in the imperative languages. 74 | 75 | Handling Errors in IO code: Exceptions 76 | -------------------------------------- 77 | 78 | +--------------+--------------------------------------------------------------+ 79 | | Synchronous | internal exception events generated from within a piece of | 80 | | | code | 81 | +--------------+--------------------------------------------------------------+ 82 | | Asynchronous | external exception events generated from outside a piece of | 83 | | | code. For example, `threadKill`. | 84 | +--------------+--------------------------------------------------------------+ 85 | 86 | Synchronous exceptions are internal or inherent to the code being executed, 87 | they come from within the code being run under an exception handler. The 88 | programmer runs a piece code under an exception handler and if the code throws 89 | an expcetion it is caught by that handler. Therefore synchronous expcetions do 90 | not interrupt the flow of code arbitrarily. 91 | 92 | On the other hand asynchronous exceptions are not inherent to the code being 93 | run they come from outside, they are caused by external factors beyond the 94 | control of the currently running code, for example some other thread may use 95 | threadKill to kill the current thread. Such exceptions can arrive at any point 96 | of time in the code flow. For example we may have opened a file handle and 97 | reading from the file and the exception arrives even before we cloe the file 98 | handle. Therefore asynchronous exceptions can interfere with the code flow. 99 | They are beyond the control of the currently running code. 100 | 101 | Data: Representing an Exception 102 | ------------------------------- 103 | 104 | An exception is represented by a user defined algebraic data type. You can 105 | encode arbitrary information available at the exception site in the exception 106 | and throw it. At the catch site this information can be used by the handler. 107 | 108 | An exception data type is dynamically typed i.e. an instance of ``Typeable``. 109 | Every exception must be an instance of ``Exception`` typeclass implementing 110 | ``fromException`` and ``toException``. Use these to convert a generic exception 111 | (``SomeException``) to a specific type and vice-versa. These functions have a 112 | default implementation. 113 | 114 | ``Exception`` typeclass also provides a ``displayException`` function to show 115 | the exception in a human-friendly manner when it is caught, also ``Show`` is a 116 | superclass of ``Exception`` so each exception is required to have a ``Show`` 117 | instance as well. Example? 118 | 119 | Control.Exception in base 120 | 121 | :: 122 | 123 | SomeException (Exception) 124 | IOException 125 | ArithException 126 | ... 127 | SomeAsyncException 128 | AsyncException 129 | NonTermination 130 | NestedAtomically 131 | ... 132 | 133 | Control (Throw and Catch) 134 | ------------------------- 135 | 136 | Control.Exception in base 137 | 138 | There are two control tracks in a program, normal and exceptional. Normally 139 | your run on the regular track but if an error condition is detected we 140 | ``throw`` the train onto the exception track. ``catch`` defines what the 141 | exception track is and automatically puts it on the exception track when an 142 | exception occurs. ``try`` runs the train and tells you finally which track you 143 | are on, normal or exception. Then you can decide how what to do on that track. 144 | 145 | Masking Asynchronous exceptions 146 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 147 | 148 | Asynchronous exceptions can arrive at any time without notice. To perform 149 | certain operations safely we may have to block async exceptions from occuring 150 | until we are ready to handle to them. 151 | 152 | +-------------------+---------------------------------------------------------+ 153 | | ``mask`` | mask/restore async exceptions | 154 | +-------------------+---------------------------------------------------------+ 155 | | ``interruptible`` | Allow asynchronous exceptions to be raised even inside | 156 | | | mask. | 157 | +-------------------+---------------------------------------------------------+ 158 | 159 | Handle IO Exceptions (synchronous) 160 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 161 | 162 | ``try`` is simpler to use, it is just like calling a function that returns an 163 | ``Either`` value. If you are interested in only synchronous exceptions this is 164 | the simplest option. However, it is inherently unsafe for handling 165 | asynchronous exceptions as exception handling is actually performed outside the 166 | try block where there is no exception handler installed; if asynchronous 167 | exceptions arrive at that time we will have no handler installed. 168 | 169 | It just transforms a function to return an Either, collecting any IO exceptions 170 | in the ``Left`` case and return value in the ``Right`` case. 171 | 172 | +------------------------------+---------------------------+ 173 | | ``try `` | ``IO (Either e a)`` | 174 | +------------------------------+---------------------------+ 175 | 176 | Handle IO Exceptions (synchronous and asynchronous) 177 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 178 | 179 | ``catch`` is safe for asynchronous exceptions as it safely installs the handler 180 | and only then runs the IO action guaranteeing that any exception arriving 181 | during the execution will be caught. 182 | 183 | +------------------------------+---------------------------+ 184 | | ``catch `` | ``IO a`` | 185 | +------------------------------+---------------------------+ 186 | 187 | Automatic resource cleanup: ``finally``, ``bracket`` or ``onException``. 188 | 189 | Unhandled Exceptions 190 | ~~~~~~~~~~~~~~~~~~~~ 191 | 192 | Unhandled exceptions are caught by the runtime system, it prints the exception 193 | and terminates the thread. When there are multiple threads only the thread that 194 | received the exception is terminated. 195 | 196 | Throw IO Exceptions 197 | ~~~~~~~~~~~~~~~~~~~ 198 | 199 | Mechanisms used to indicate an error e.g. ``error`` and ``throw`` are untyped 200 | and therefore can be used in an expression of any type without a type error. 201 | 202 | Exceptions may be thrown from purely functional code, but may only be caught 203 | within the 'IO' monad. 204 | 205 | +---------------------------------------+--------------+----------------------+ 206 | | Exception e | Sync/Async | Pure/IO | 207 | +---------------------------------------+--------------+----------------------+ 208 | | ``throw :: Exception e => e -> a`` | synchronous | pure/IO | 209 | +---------------------------------------+ +----------------------+ 210 | | ``throwIO :: e -> IO a`` | | IO | 211 | +---------------------------------------+ | | 212 | | ``ioError :: IOError -> IO a`` | | | 213 | +---------------------------------------+--------------+ | 214 | | ``throwTo :: ThreadId -> e -> IO ()`` | asynchronous | | 215 | +---------------------------------------+--------------+----------------------+ 216 | 217 | Exceptions in Pure Expressions 218 | ------------------------------ 219 | 220 | ``evaluate`` evaluates and uncovers exceptions from a pure expression. Notice 221 | that it returns a result in the IO monad so that we can handle the exceptions 222 | using the exception catching mechanisms in the IO monad:: 223 | 224 | evaluate :: a -> IO a 225 | 226 | Laziness and Exceptions 227 | ~~~~~~~~~~~~~~~~~~~~~~~ 228 | 229 | Laziness can make exceptions manifest when the expression is evaluated: 230 | 231 | :: 232 | 233 | main = do 234 | -- throw (ExitFailure 5) 235 | x <- return $ toInteger $ div 1 0 236 | putStrLn "hello" 237 | y <- return (x + 2) 238 | putStrLn "hello" 239 | putStrLn $ show y -- div-by-zero exception is thrown here 240 | 241 | Some Standard Exception APIs 242 | ---------------------------- 243 | 244 | Wildcard/untyped exceptions 245 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 246 | 247 | These can be used in any code pure, IO or any other monad. The type is ``a`` 248 | 249 | +-----------------------------------------------------------------------------+ 250 | | error - the wildcard exception | 251 | +======================+======================================================+ 252 | | error :: String -> a | error is completely untyped, and can be called from | 253 | | | anywhere. Throws an exception with a message. | 254 | +----------------------+-------------+----------------------------------------+ 255 | 256 | IO Code 257 | ~~~~~~~ 258 | 259 | These can be used only in IO code. The type is ``IO a`` 260 | 261 | IO Exit Codes 262 | ^^^^^^^^^^^^^ 263 | 264 | :: 265 | 266 | Module System.Exit 267 | exitFailure -- throws exception of type ExitCode 268 | exitSuccess 269 | exitWith 270 | die :: String -> IO a - like error but in IO. 271 | 272 | IO Errors 273 | ^^^^^^^^^ 274 | 275 | * System.IO.Error 276 | * type IOError = IOException 277 | 278 | Monadic Error Handling 279 | ---------------------- 280 | 281 | MonadFail 282 | ~~~~~~~~~ 283 | 284 | +------------------+-------------+--------------------------------------------+ 285 | | Aborting monadic | fail | | 286 | | computations | (MonadFail) | | 287 | +------------------+-------------+--------------------------------------------+ 288 | 289 | Transformers 290 | ~~~~~~~~~~~~ 291 | 292 | Equivalents of Maybe and Either for monadic code. They are purely synchronous 293 | in nature and are completely independent of the IO exceptions and 294 | try/catch/throw. 295 | 296 | +-------------+----------------------+------------+---------------------------+ 297 | | Transformer | Equivalent pure type | mtl Class | Operations | 298 | +=============+======================+============+===========================+ 299 | | MaybeT | Maybe | | | 300 | +-------------+----------------------+------------+---------------------------+ 301 | | EitherT | Either | | | 302 | +-------------+----------------------+------------+---------------------------+ 303 | | ExceptT | Either | MonadError | throwError, catchError | 304 | +-------------+----------------------+------------+---------------------------+ 305 | 306 | MaybeT, EitherT and ExceptT provide short circuiting behavior very much like 307 | the "return" statements in the imperative languages. TODO - Explain this with 308 | examples of parallels between the two paradigms. 309 | 310 | Extensible Exceptions 311 | ~~~~~~~~~~~~~~~~~~~~~ 312 | 313 | Extension of try/catch/throw for any monad, not just IO. 314 | 315 | These can be used in any monad implementing ``MonadThrow``. The type is ``m a`` 316 | 317 | See monad transformers chapter. 318 | 319 | MonadThrow errors can be conveniently cast into Maybe and Either. You don't 320 | need a ``try`` you can just interpret it as an ``Either`` value:: 321 | 322 | instance MonadThrow Maybe where 323 | throwM _ = Nothing 324 | 325 | :: 326 | 327 | Prelude Path Control.Monad.Catch> f = throwM (InvalidAbsDir "x") :: MonadThrow m => m Int 328 | Prelude Path Control.Monad.Catch> f :: Maybe Int 329 | Nothing 330 | 331 | CallStack, Source location 332 | -------------------------- 333 | 334 | Which exception mechanism to use? 335 | --------------------------------- 336 | 337 | One good thing about the throw/catch mechanism is that we can catch any and all 338 | types of exceptions we can define our own exception types anywhere. All of 339 | these percolate up and get collected by a catching mechanism. However in case 340 | of ExceptT we fix the type of errors by parameterizing the ExceptT with a given 341 | type. If someone wants to define a different type the the exceptT error type 342 | has to be a made a sum type and the new error has to be added to it. In 343 | contrast throw is more modular as we can always define and throw new types of 344 | exceptions. 345 | 346 | The disadvantage of throw/catch is that there can be indeterminate types of 347 | errors that can be thrown and we cannot be sure whether we caught them all or 348 | there is something lurking under that will come under a catchall case. 349 | 350 | Checked Errors 351 | ~~~~~~~~~~~~~~ 352 | 353 | * Pure 354 | 355 | * Maybe 356 | * Either 357 | 358 | * Monadic 359 | 360 | * MaybeT 361 | * ExceptT (it is in fact EitherT) 362 | 363 | Unchecked Exceptions 364 | ~~~~~~~~~~~~~~~~~~~~ 365 | 366 | * Pure 367 | 368 | * throw 369 | * evaluate and then try/catch 370 | 371 | * Monadic (IO/runtime exceptions) 372 | 373 | * throw/throwIO 374 | * try (in absence of async exceptions) 375 | * throwTo (async throw) 376 | * mask (mask async exceptions) 377 | * catch (for sync/async exceptions) 378 | 379 | * Monadic (extensible/monad transformers) 380 | 381 | * MonadMask/MonadCatch/MonadThrow 382 | * throwM 383 | * try 384 | * mask 385 | * catch 386 | 387 | Design Pattern 388 | ~~~~~~~~~~~~~~ 389 | 390 | Simple rule: Use checked errors where the whole program is in your control and 391 | therefore you can always modify the error type to add more cases when you want. 392 | Use unchecked errors where the pieces of code you are throwing the errors from 393 | is independent of where the errors may be caught. 394 | 395 | The unchecked exception mechanism allows you to define a new exception anywhere 396 | and throw it. The good thing about it is that it makes the code modular, the 397 | bad thing about it is that the onus is on the catcher to catch and interpret 398 | all errors, there is always a possibility that the catcher might miss some. So 399 | the modularity does not come without a cost. 400 | 401 | The unchecked mechanism is useful when you really don't care about those errors 402 | in most cases but sometimes you may you leave the decision on the user, so you 403 | do not want the inconvenience of handling it always. The user has a choice to 404 | use a catchall for catching all such errors and put them in just one basket or 405 | even let the runtime system deal with them. When you always care and want to 406 | user to explicitly know about the errors then use a checked mechanism. 407 | 408 | Example 409 | ~~~~~~~ 410 | 411 | Consider a case where you are designing an API for creating a user in a 412 | database. When creating a user you may find that a user with the same name 413 | already exists. But there are many other kind of errors that can occur e.g. the 414 | database connection failed or your thread got killed or some other kind of IO 415 | error happened beacuse of which your requrest to the database failed. 416 | 417 | There are multiple ways you can design this API. For example:: 418 | 419 | createUser :: UserRecord -> IO () 420 | 421 | The case when a user already exists is also conveyed via throwIO. In this case 422 | the signature does not convey any error condition and the user of this API has 423 | to know the presence of errors and use ``try`` to catch the exceptions. This 424 | includes the important case of the user already existing which is really not an 425 | exceptional condition it is an inherent part of the API and we would always 426 | want the user to handle it unconditionally. It is not a good idea to leave it 427 | to the user. However, all other error conditions are in a different category 428 | they are not part of the inherent business logic for this API, they are just 429 | other possibilities always lurking around and can happen for this API or for 430 | others as well. 431 | 432 | Consider another possibility of the API design:: 433 | 434 | createUser :: MonadThrow m => UserRecord -> m () 435 | 436 | This is equivalent to the previous one except that the monad is generalized and 437 | the signature reminds the user that it can throw an exception which is implicit 438 | in case of IO. But that's not an improvement. 439 | 440 | Now consider this one:: 441 | 442 | createUser :: UserRecord -> m (Maybe ()) 443 | 444 | This API captures the API's inherent error in the signature and leaves the 445 | general, really exceptional conditions to the unchecked exception mechanism. 446 | This is the one you should go with. 447 | 448 | References 449 | ---------- 450 | 451 | * http://hackage.haskell.org/package/exceptions 452 | * http://hackage.haskell.org/package/safe-exceptions 453 | * https://hackage.haskell.org/package/safe-exceptions-checked-0.1.0/docs/Control-Exception-Safe-Checked.html 454 | * http://hackage.haskell.org/package/resourcet 455 | 456 | * https://github.com/fpco/safe-exceptions#readme 457 | * https://haskell-lang.org/tutorial/exception-safety 458 | * https://www.schoolofhaskell.com/user/commercial/content/exceptions-best-practices 459 | * https://www.schoolofhaskell.com/user/snoyberg/general-haskell/exceptions/catching-all-exceptions 460 | * https://www.schoolofhaskell.com/user/snoyberg/general-haskell/exceptions/exceptions-and-monad-transformers 461 | * https://www.yesodweb.com/blog/2014/05/exceptions-cont-monads 462 | * https://www.well-typed.com/blog/2015/07/checked-exceptions/ 463 | -------------------------------------------------------------------------------- /libs/pipes.rst: -------------------------------------------------------------------------------- 1 | Pipes 2 | ----- 3 | 4 | Bidirectional Streaming Component 5 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 6 | 7 | A ``Proxy`` is the most general `open` component, with four openings: 8 | 9 | 10 | :: 11 | 12 | Proxy a' a b' b m r 13 | 14 | Upstream | Downstream 15 | +---------+ 16 | | | 17 | a' <== <== b' -- Information flowing upstream 18 | | | 19 | a ==> ==> b -- Information flowing downstream 20 | | | | 21 | +----|----+ 22 | v 23 | r 24 | 25 | Specialized Components 26 | ~~~~~~~~~~~~~~~~~~~~~~ 27 | 28 | Some openings of Proxy can be closed by using ``()`` on the input end or ``X`` 29 | (i.e. ``Void``) on the output end, to create more specialized components. In 30 | the following text we will only be talking about downstream components: 31 | 32 | +------------+-----------------+----------------+-----------------------------+ 33 | | Downstream | Proxy X () () b | Producer b m r | ``a ==> ==> |`` | 34 | | Components +-----------------+----------------+-----------------------------+ 35 | | | Proxy () a () b | Pipe a b m r | ``a ==> ==> b`` | 36 | | +-----------------+----------------+-----------------------------+ 37 | | | Proxy () a () X | Consumer a m r | ``| ==> ==> b`` | 38 | +------------+-----------------+----------------+-----------------------------+ 39 | 40 | Consuming and Producing Actions 41 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 42 | 43 | We will call a component with at least one opening, an `open` component. An 44 | `open` component with an ``output`` end can ``yield`` and one with an ``input`` 45 | end can ``await``: 46 | 47 | +----------+-------------------+ 48 | | Producer | yield | 49 | +----------+-------------------+ 50 | | Pipe | yield, await | 51 | +----------+-------------------+ 52 | | Consumer | await | 53 | +----------+-------------------+ 54 | 55 | Composing Components 56 | ~~~~~~~~~~~~~~~~~~~~ 57 | 58 | +--------------------+------------+-------------------------------------------+ 59 | | Component1 | Combinator | Component2 | 60 | +====================+============+===========================================+ 61 | | A producing | ``for`` | action consuming the output and producing | 62 | | component | | some component | 63 | +--------------------+------------+-------------------------------------------+ 64 | | A producing | ``~>`` | action consuming the output and producing | 65 | | action | | some component | 66 | +--------------------+------------+-------------------------------------------+ 67 | | Any component | ``>~`` | A consuming component | 68 | +--------------------+------------+-------------------------------------------+ 69 | | A producing | ``>->`` | A consuming component | 70 | | component | | | 71 | +--------------------+------------+-------------------------------------------+ 72 | 73 | * ``cat``: a pipe that produces whatever it receives. 74 | 75 | A Closed Component 76 | ~~~~~~~~~~~~~~~~~~ 77 | 78 | When a composition closes all the openings, it produces a `closed` component 79 | called an ``Effect``. Ultimately our goal is to compose components to produce 80 | an ``Effect``. 81 | 82 | +----------+-----+----------+---+-------------+ 83 | | Producer | >-> | Consumer | = | Effect | 84 | +----------+-----+----------+---+-------------+ 85 | 86 | An ``Effect`` can be run using ``runEffect`` to produce a monadic action in 87 | monad `m`:: 88 | 89 | runEffect :: Monad m => Effect m r -> m r 90 | 91 | ListT 92 | ~~~~~ 93 | 94 | :: 95 | 96 | -- a Producer can be converted into a ListT (Select) 97 | -- and vice-versa (enumerate) 98 | newtype ListT m a = Select { enumerate :: Producer a m () } 99 | 100 | References 101 | ---------- 102 | 103 | * https://www.schoolofhaskell.com/school/to-infinity-and-beyond/pick-of-the-week/coroutines-for-streaming 104 | * http://blog.functorial.com/posts/2015-07-31-Stackless-PureScript.html 105 | * https://themonadreader.files.wordpress.com/2011/10/issue19.pdf Coroutine Pipelines 106 | * http://spivey.oriel.ox.ac.uk/wiki2/images/a/a1/Copipes.pdf Faster Coroutine Pipelines 107 | -------------------------------------------------------------------------------- /libs/transformers/transformers.hs: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env stack 2 | {- stack runghc 3 | --package base 4 | --package diagrams-lib 5 | --package diagrams-svg 6 | --package diagrams-rasterific 7 | -- 8 | -hide-all-packages 9 | -} 10 | 11 | {-# LANGUAGE NoMonomorphismRestriction #-} 12 | {-# LANGUAGE FlexibleContexts #-} 13 | 14 | import System.Environment 15 | import Diagrams.Prelude 16 | import Diagrams.Backend.Rasterific.CmdLine 17 | import Data.Maybe (fromMaybe) 18 | import Control.Arrow (second) 19 | 20 | main = mainWith $ map (second (frame 0.2)) 21 | [ ("monad" , monad "m") 22 | , ("transformer" , transformer) 23 | , ("transformer-stack2" , transformerStack2) 24 | , ("transformer-lift" , transformerLift) 25 | , ("transformer-lift2" , transformerLift2) 26 | , ("transformer-base2" , transformerBase2) 27 | , ("transformer-base-lift2" , transformerBaseLift2) 28 | , ("transformer-io-lift2" , transformerIOLift2) 29 | ] 30 | 31 | monadLift :: String -> Diagram B 32 | monadLift label = 33 | monad label <> arrowAt (p2 (0, -1)) unitY 34 | 35 | addLift :: String -> String -> Point V2 Double -> Double -> Diagram B 36 | addLift n1 n2 p len = 37 | arrowAt p (unitY # scale len) 38 | <> alignedText (-0.15) 1 ("lift " ++ n1) 39 | # rotate (1/4 @@ turn) 40 | # scale (len/4) 41 | # moveTo p 42 | # moveOriginBy (V2 0.2 0) 43 | <> (origin ~~ p2 (1, 0) 44 | ||| alignedText 0 0.5 ("MonadTrans " ++ n2) # scale 0.1 45 | ||| strutX 0.75) 46 | # moveTo (p + p2 (0, len)) 47 | 48 | addBaseLift :: String -> String -> String -> Point V2 Double -> Double -> Angle Double -> Diagram B 49 | addBaseLift tclass lift to p len ang = 50 | (arrowAt p (unitY # scale len) 51 | <> alignedText (-0.15) 1 (lift) 52 | # rotate (1/4 @@ turn) 53 | # scale (len/8) 54 | # moveTo p 55 | # moveOriginBy (V2 0.2 0)) # rotate ang 56 | <> (origin ~~ p2 (1, 0) 57 | ||| alignedText 0 0.5 (tclass ++ to) # scale 0.1 58 | ||| strutX 0.8) 59 | # moveTo (p + p2 (0, len)) 60 | 61 | transformerLift :: Diagram B 62 | transformerLift = 63 | transformer 64 | <> addLift "m" "t" (p2 (0, 1/2)) (1/2) 65 | 66 | transformerBaseLiftCommon :: String -> String -> String -> Diagram B 67 | transformerBaseLiftCommon tclass var lift = 68 | transformerBase2 69 | <> addBaseLift tclass' lift "t2" (p2 (0, 1/3)) (1/3) (-1/16 @@ turn) 70 | <> addBaseLift tclass' lift "t1" (p2 (0, 1/3)) (2/3) (1/16 @@ turn) 71 | <> (origin ~~ p2 (1, 0) 72 | ||| alignedText 0 0.5 (tclass' ++ var) # scale 0.1 73 | ||| strutX 0.8) 74 | # moveTo (p2 (0, 1/3)) 75 | where tclass' = tclass ++ " " 76 | 77 | transformerBaseLift2 :: Diagram B 78 | transformerBaseLift2 = transformerBaseLiftCommon "MonadBase b" "b" "liftBase b" 79 | 80 | transformerIOLift2 :: Diagram B 81 | transformerIOLift2 = transformerBaseLiftCommon "MonadIO" "IO" "liftIO" 82 | 83 | transformerLift2 :: Diagram B 84 | transformerLift2 = 85 | transformerStack2 86 | <> addLift "m" "t2" (p2 (0, 1/3)) (1/3) 87 | <> addLift "t2" "t1" (p2 (0, 2/3)) (1/3) 88 | 89 | transformerBase2 :: Diagram B 90 | transformerBase2 = 91 | monad "t1" 92 | <> monad "t2" # scale (2 / 3) 93 | <> monad "b" # scale (1 / 3) 94 | 95 | transformerStack2 :: Diagram B 96 | transformerStack2 = 97 | monad "t1" 98 | <> monad "t2" # scale (2 / 3) 99 | <> monad "m" # scale (1 / 3) 100 | 101 | transformer :: Diagram B 102 | transformer = 103 | monad "t" 104 | <> monad "m" # scale (1 / 2) 105 | 106 | monad :: String -> Diagram B 107 | monad label = 108 | arc xDir (1 / 2 @@ turn) # named label 109 | <> mkLabel unitX 110 | <> mkLabel unit_X 111 | where 112 | mkLabel :: V2 Double -> Diagram B 113 | mkLabel l = text label # scale 0.2 # moveOriginBy l 114 | -------------------------------------------------------------------------------- /preface.rst: -------------------------------------------------------------------------------- 1 | About this book 2 | --------------- 3 | 4 | The goal of the book is to systematically explain GHC Haskell from a 5 | programmer's perspective so that he/she can easily find all the details 6 | required for using the language at one place. It is not the goal of this book 7 | to describe the theory behind the implementation or the language. It explains 8 | concepts or theory only where it is important for the effective use of the 9 | language for practical programming. 10 | 11 | .. 12 | This is intended to be an open source, live and evolving book. I intend to keep 13 | uploading new material as it becomes ready. I will try to keep things in order 14 | but sometimes it may be out of order. I expect to keep improving the text over 15 | time. I also expect the readers to help me out in improving it by providing 16 | feedback and contributions in content. 17 | 18 | How you learn? 19 | -------------- 20 | 21 | The big picture vs tiny details. 22 | 23 | In my experience, there are two phases in learning a programming language. In 24 | the beginner phase you learn in bits and pieces and mostly by example or by 25 | looking at code. As you keep learning you keep putting things together and 26 | building a bigger picture. Many times you have your aha moments when you put 27 | the pieces of puzzle together yourself and figure out a pattern or high level 28 | concept. This I call bottom up learning and this is usually the way to begin. 29 | 30 | When you reach an intermediate stage you need to build a consistent big picture 31 | to have a deeper understanding and reach the expert stage. Big picture should 32 | be a consistent beautiful model that you can abstract and derive things from 33 | first principles and therefore remember more effectively. The intermediate 34 | learning material should help build and understand that model. I call this top 35 | down learning. 36 | 37 | Bottom up and top down can happen simultaneously or one after other but both 38 | need to happen nevertheless and finally the learner must have a consistent 39 | model in his head. 40 | 41 | In this text we are presenting Haskell from the top down perspective assuming 42 | you have learnt the basics. 43 | 44 | Building Intuition 45 | ------------------ 46 | 47 | This text goes from the first principles to higher level abstractions 48 | incrementally, building higher level stuff on lower level stuff. Each chapter 49 | is self contained and has a comprehensive reference for everything related to 50 | that concept. In addition to systematically building new concepts on top of 51 | the previous concepts we also try to discuss dual concepts alongside each 52 | other for a better and deeper understanding. We want to create a deeper 53 | understanding of the concepts and inculcate intuition about abstractions and 54 | how they are built in the first place so that the reader can easily apply the 55 | same process to novel situations. It is important to learn how to learn 56 | Haskell! 57 | 58 | When I started learning Haskell I dived into things as I encountered them. In 59 | the absence of a good comprehensive reference it led to grokking code, reading 60 | papers, struggling with category theory. I got completely bogged down with 61 | stuff that I did not need for using the language, leading to big diversions, 62 | wasting a lot of time. However, if I had access to a good reference where all 63 | the related concepts are condensed together and shown in relation to each other 64 | I could have learnt the big picture faster and then looked at details when I 65 | needed. What I felt lacking is what this book tries to present. Everything at 66 | one place with a top down big picture. Fully self-contained, including full 67 | Haskell and GHC language reference so that the reader does not need to keep 68 | searching for missing stuff at different places. 69 | 70 | Haskell is overwhelming, there is a lot to imbibe. However, it is overwhelming 71 | because the boon of Haskell is also the curse of Haskell. It has systematic 72 | building blocks and you can use permutations or combinations of those building 73 | blocks and as combinations multiply they grow rapidly. However, if we know the 74 | building blocks, correspondences, duals etc. systematically we can just 75 | abstract out most of stuff and derive it rather than remembering everything in 76 | an ad-hoc manner. That is the approach we are taking in this book. 77 | 78 | For example if we use applicatives, arrows and monads, their duals, free/cofree 79 | versions it easily becomes tens of concepts to learn but in fact they are all 80 | manifestations of some sort of transformation and composition and if we know 81 | how they relate to the basic concepts and to each other they are easy to 82 | follow and remember. 83 | 84 | One important aspect to building a deeper understanding is knowing the big 85 | picture and how things relate to each other. For example how recursion, folds, 86 | lists, monoids are related? When we know the precise relationships it is easier 87 | to understand them better and remember them. 88 | 89 | GHC Haskell reference 90 | --------------------- 91 | 92 | One of the goals of this text is to be a concise but comprehensive reference to 93 | GHC Haskell including all GHC extensions. This is different from the GHC manual 94 | in conciseness and presentation. The GHC manual only describes the GHC specific 95 | language extensions. They are described mostly from the GHC developer's 96 | perspective and in the sequence they were developed rather than in a holistic 97 | view of the language which makes it hard to find relevant material and build a 98 | consistent picture quickly. 99 | 100 | The goal of this text is to build one holistic view of all available language 101 | features, starting from Haskell basics to GHC extensions, present all related 102 | concepts at one place so as to provide the full consistent picture. We want to 103 | provide maximum information in minimum space using a cheat sheet like format to 104 | keep it concise. 105 | 106 | It focuses purely on language and not other things in the Haskell ecosystem for 107 | example operational features of the compiler or build tools etc. 108 | 109 | This is written from a programmer's perspective who wants to learn the language 110 | quickly and needs a handy reference to be able to search useful stuff quickly 111 | when he needs it. It tries to present the minimal concepts which are relevant 112 | to a user of the language and avoids explaining detailed rationale, theoretical 113 | underpinnings, background or pedagogic material unless when necessary. 114 | Essential concepts are separated from deeper treatments where necessary. The 115 | descriptions of concepts are not formal or rigorous in any sense, they are only 116 | for an intuitive understanding of the concepts. 117 | 118 | Forward and Reverse Reading Styles 119 | ---------------------------------- 120 | 121 | This book has been written in a dependency order, that is the most fundamental 122 | concepts are introduced first and those building upon those are introduced 123 | later, in that sequence, wherever possible. When you start to learn Haskell the 124 | natural reading style is read the book from start to end. However, that is not 125 | how it works practically. While learning Haskell and being an expert at the 126 | language, you would still want to be able to read existing code written by 127 | others and understand it, which may not be possible unless you know all the 128 | features, concepts, syntax used in that piece of code. This creates difficulty 129 | until you have read and understood a lot of concepts. To overcome this problem 130 | this books introduces a reverse index as well. When you encounter a particular 131 | syntax, concept or feature you can look it up in the index, which has a small 132 | description as well as reference to full explanation of the concept in the 133 | book. That way with the help of this book working as a dictionary you can 134 | deciper any Haskell code even if you are not yet an expert in Haskell. This 135 | helps you learn Haskell on the job. 136 | 137 | Note on Jargon 138 | -------------- 139 | 140 | Haskell has several dimensions and layers of abstraction and beautiful 141 | mathematical concepts that fit together elegantly. However, to think about the 142 | concepts systematically it is important to get familiarised with the vocabulary 143 | and know the precise meanings of the terms involved. 144 | 145 | This text tries to avoid jargon where possible but many terms that allow you to 146 | express concepts in a concise and clear manner are necessary. We define the 147 | terminology succinctly in each chapter. Sometimes terms are included just so 148 | that the reader is able to understand other material on the topic, e.g. the GHC 149 | manual. 150 | -------------------------------------------------------------------------------- /tools/optimization.rst: -------------------------------------------------------------------------------- 1 | Optimization 2 | ------------ 3 | 4 | Three powerful and interrelated optimizations that require programmer awareness 5 | are: 6 | 7 | * INLINING 8 | * SPECIALIZATION 9 | * Rewrite-rules 10 | 11 | Another powerful optimization is strictness(UNPACK, Bang patterns). 12 | These four optimizations can make or break performance. Other than these most 13 | other optimizations are mostly simple choices enabled or disabled. 14 | 15 | One option that you can use to gain some performance for free is to use the 16 | llvm backend. 17 | 18 | What options each level enables? 19 | 20 | * https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/flags.html#optimisation-levels 21 | 22 | Inlining 23 | -------- 24 | 25 | What Happens in Inlining? 26 | ------------------------- 27 | 28 | Also called unfolding. The compiler pass that performs inlining is called the 29 | "simplifier". 30 | 31 | GHC guarantees to inline precisely the code that you wrote, no more and no 32 | less. It does this by capturing a copy of the definition of the function to use 33 | for inlining (we call this the “inline-RHS”), which it leaves untouched, while 34 | optimising the ordinarily RHS as usual. For externally-visible functions the 35 | inline-RHS (not the optimised RHS) is recorded in the interface file. 36 | 37 | What gets inlined? 38 | ------------------ 39 | 40 | GHC only inlines the function if: 41 | 42 | * there is some reason (no matter how slight) to suppose that it is useful to 43 | do so. 44 | * it is fully applied 45 | 46 | * Mutually recursive functions: GHC ensures that inlining cannot go on forever: 47 | every mutually-recursive group is cut by one or more loop breakers that is 48 | never inlined. GHC tries not to select a function with an INLINE pragma as a 49 | loop breaker, but when there is no choice even an INLINE function can be 50 | selected, in which case the INLINE pragma is ignored. 51 | 52 | * Recursive functions: For a self-recursive function, the loop breaker can only 53 | be the function itself, so an INLINE pragma is always ignored. 54 | 55 | How to inline? 56 | -------------- 57 | 58 | INLINE and INLINABLE/INLINEABLE pragmas retain a copy of the original RHS for 59 | inlining purposes, and persists it in the interface file, regardless of the 60 | size of the RHS. 61 | 62 | Unlike INLINE, it is OK to use an INLINABLE pragma on a recursive function. The 63 | principal reason do to so to allow later use of SPECIALISE. If you mark 64 | function f as INLINABLE, then you can subsequently SPECIALISE it in another 65 | module because the definition is available in the interface file. 66 | 67 | A function not marked INLINE or INLINABLE can also be inlined by GHC depending 68 | on its size, inlining threshold etc. However, by annotating f as INLINABLE, you 69 | ensure that f‘s original RHS is inlined, rather than whatever random optimised 70 | version of f GHC’s optimiser has produced. 71 | 72 | At the definition site: An INLINE pragma for a function can be put anywhere its 73 | type signature could be put. 74 | 75 | * {-# INLINE f #-} - “please inline me wherever I am used” 76 | * {-# NOINLINE f #-} - noinline can be useful to move infrequently called code 77 | out of the way which can speedup the instruction caching and fetching. 78 | 79 | At the call site: 80 | 81 | * {-# INLINABLE f #-} - “feel free to inline me at the call site, my definition 82 | is available in the interface file". The decision at the call site will be 83 | affected by the inlining threshold, optimisation level etc. 84 | 85 | * inline (f x) - “please inline this call”. To guarantee a try to inline, the 86 | function has to be INLINABLE so that its definition is exported via the 87 | interface file. 88 | 89 | INLINE is equivalent to INLINABLE + "inline" at all the call sites. 90 | 91 | Phase Control 92 | ~~~~~~~~~~~~~ 93 | 94 | Phase 0 is the last phase. 95 | 96 | “INLINE[k] f” means: do not inline f until phase k, but from phase k onwards be 97 | very keen to inline it. 98 | “INLINE[~k] f” means: be very keen to inline f until phase k, but from phase k 99 | onwards do not inline it. 100 | “NOINLINE[k] f” means: do not inline f until phase k, but from phase k onwards 101 | be willing to inline it (as if there was no pragma). 102 | “NOINLINE[~k] f” means: be willing to inline f until phase k, but from phase k 103 | onwards do not inline it. 104 | 105 | Compiler Options 106 | ~~~~~~~~~~~~~~~~ 107 | 108 | :: 109 | 110 | -fexpose-all-unfoldings - equivalent to marking everything INLINABLE 111 | -fignore-interface-pragmas - Do not use the interface pragmas available in 112 | other modules. 113 | -fomit-interface-pragmas - Do not generate any interface pragmas for consumers 114 | to use. equivalent to marking everyhting NOINLINE, 115 | NOSPECIALIZE. 116 | 117 | -funfolding-creation-threshold=⟨n⟩ 118 | -funfolding-dict-discount=⟨n⟩ 119 | -funfolding-fun-discount=⟨n⟩ 120 | -funfolding-keeness-factor=⟨n⟩ 121 | -funfolding-use-threshold=⟨n⟩ 122 | 123 | -fmax-inline-alloc-size=⟨n⟩ 124 | -fmax-inline-memcpy-insn=⟨n⟩ 125 | -fmax-inline-memset-insns=⟨n⟩ 126 | -fno-pre-inlining 127 | 128 | -fsimplifier-phases=⟨n⟩ 129 | -fmax-simplifier-iterations=⟨n⟩ 130 | 131 | -fstatic-argument-transformation 132 | 133 | -ddump-inlinings (use with -dverbose-core2core for detailed output) 134 | -ddump-simpl 135 | -ddump-simpl-iterations 136 | -ddump-simpl-stats 137 | 138 | It is not clear what all is exposed by default when no INLINE pragams are 139 | specified. Are small functions still liable to be inlined? Are class operations 140 | still liable to be inlined? 141 | 142 | Specialization 143 | -------------- 144 | 145 | Definition side options: 146 | 147 | +---------------------------+-------------------------------------------------+ 148 | | SPECIALISE | Specialise this globally at the given type | 149 | +---------------------------+-------------------------------------------------+ 150 | | INLINABLE | Can be specialised at the callsite | 151 | +---------------------------+-------------------------------------------------+ 152 | 153 | Use side options: 154 | 155 | +---------------------------+-------------------------------------------------+ 156 | | SPECIALISE | Specialise this at the given type in this module| 157 | +---------------------------+-------------------------------------------------+ 158 | | -fspecialise | Specialise all calls to locally defined | 159 | | | functions in this module | 160 | +---------------------------+-------------------------------------------------+ 161 | | -fcross-module-specialise | Specialise calls to imported functions marked | 162 | | | INLINABLE at the definition. Needs -fspecialise | 163 | +---------------------------+-------------------------------------------------+ 164 | | -fspecialise-aggressively | Specialise regardless of size, local or | 165 | | | imported functions marked INLINABLE | 166 | +---------------------------+-------------------------------------------------+ 167 | 168 | :: 169 | 170 | -fspec-constr 171 | -fspec-constr-keen 172 | -fspec-constr-count=⟨n⟩ 173 | -fspec-constr-threshold=⟨n⟩ 174 | 175 | -fliberate-case 176 | Default:off but enabled with -O2. 177 | Turn on the liberate-case transformation. This unrolls recursive function once 178 | in its own RHS, to avoid repeated case analysis of free variables. It’s a bit 179 | like the call-pattern specialiser (-fspec-constr) but for free variables rather 180 | than arguments. 181 | -fliberate-case-threshold=⟨n⟩ 182 | 183 | -Wmissed-specialisations 184 | -Wall-missed-specialisations 185 | -ddump-spec 186 | 187 | Specialization is not possible with polymorphic recursion. 188 | 189 | * https://stackoverflow.com/questions/18341146/specialization-of-polymorphic-functions 190 | 191 | Rewrite Rules 192 | ------------- 193 | 194 | Rewrite rules can interact with the inliner (also called simplifier). 195 | 196 | :: 197 | 198 | -fenable-rewrite-rules 199 | -fno-enable-rewrite-rules -- note that GHC builtin rules still fire. 200 | However rules in GHC.Base or any other libraries are disabled. 201 | 202 | -ddump-simpl-stats 203 | -ddump-rule-firings 204 | -ddump-rule-rewrites 205 | -ddump-rules 206 | -frule-check 207 | -Winline-rule-shadowing 208 | 209 | Strictness 210 | ---------- 211 | 212 | using a bang pattern in a function argument does not seem to have exactly the 213 | same effect as using $! when calling the function. Using bang pattern in 214 | argument seems to be more efficient. Also, if we use both together the effect 215 | is much adverse. Need more research on this. 216 | 217 | :: 218 | 219 | -fstrictness 220 | -fstrictness-before=⟨n⟩ 221 | 222 | -funbox-small-strict-fields 223 | -funbox-strict-fields 224 | 225 | -ffun-to-thunk 226 | -fmax-worker-args=⟨n⟩ 227 | -fno-state-hack 228 | -fpedantic-bottoms 229 | 230 | -flate-dmd-anal 231 | Default:off 232 | Run demand analysis again, at the end of the simplification pipeline. We found 233 | some opportunities for discovering strictness that were not visible earlier; 234 | and optimisations like -fspec-constr can create functions with unused arguments 235 | which are eliminated by late demand analysis. Improvements are modest, but so 236 | is the cost. See notes on the Trac wiki page. 237 | 238 | -ddump-stranal 239 | -ddump-str-signatures 240 | -ddump-worker-wrapper 241 | 242 | Batching, CSE 243 | ------------- 244 | 245 | :: 246 | 247 | -fcse 248 | -fstg-cse 249 | -fcmm-elim-common-blocks 250 | -fcmm-sink 251 | 252 | -ffloat-in 253 | -ffull-laziness 254 | 255 | -ddump-cse 256 | 257 | Concurrency, Parallelism 258 | ------------------------- 259 | 260 | :: 261 | 262 | -feager-blackholing 263 | -fomit-yields 264 | 265 | Code generation 266 | --------------- 267 | 268 | :: 269 | 270 | -fregs-graph 271 | -fregs-iterative 272 | -fvectorise 273 | -fvectorisation-avoidance 274 | 275 | -fllvm 276 | 277 | General diagnostics 278 | ------------------- 279 | 280 | :: 281 | 282 | * -dppr-debug - works in conjunction with other options 283 | * -dverbose-core2core - works in conjunction with other options (-ddump-inlinings) 284 | * -dshow-passes 285 | * -ddump-core-stats 286 | * -ddump-simpl-stats 287 | * -dverbose-stg2stg 288 | * -dstg-stats 289 | --------------------------------------------------------------------------------