Notebook for PureScript by Example
https://leanpub.com/purescript/read#leanpub-auto-functions-and-records
Chapter 2 Getting Started
|
|
Chapter 3 Functions and Records
Simple Types (3.3)
Built-in types
- Number
- String
- Boolean
- integers
- characters
- arrays
- records
- functions
|
|
Fuction
|
|
Quantified Types (3.4)
|
|
forall means universally quantified type
Notes On Indentation (3.5)
PureScript code is indentation-sensitive
Defining Our Types (3.6)
|
|
Type Constructors and Kinds (3.7)
List is an example of a type constructor.
Values do not have the type List directly, but rather List a for some type a. That is, List takes a type argument a and constructs a new type List a.
values are distinguished by their types, types are distinguished by their kinds
|
|
Curried Functions (3.11)
Functions in PureScript take exactly one argument.
Querying the Address Book (3.12)
|
|
Note that, just like for top-level declarations, it was not necessary to specify a type signature for filterEntry. However, doing so is recommended as a form of documentation.
Infix Function Application (3.13)
head $ filter filterEntry book
is equals
head (filter filterEntry book)
($) is just an alias for a regular function called apply
|
|
Function Composition (3.14)
- <<< backwards composition
- >>> forwards composition
|
|
Chapter 4 Recursion, Maps And Folds
- purescript-maybe, which defines the Maybe type constructor
- purescript-arrays, which defines functions for working with arrays
- purescript-strings, which defines functions for working with Javascript strings
- purescript-foldable-traversable, which defines functions for folding arrays and other data structures
- purescript-console, which defines functions for printing to the console
Recursion on Array (4.4)
- The null function returns true on an empty array
|
|
Infix Operators (4.6)
|
|
Flattening Arrays (4.8)
|
|
Do Notation (4.10)
map and bind allow us to write so-called monad comprehensions
|
|
Guards (4.11)
|
|
That is, if guard is passed an expression which evaluates to true, then it returns an array with a single element. If the expression evaluates to false, then its result is empty.
Folds (4.12)
|
|
Tail Recursion (4.13)
purescript-free and purescript-tailrec packages.
|
|
Notice that the recursive call to fact is the last thing that happens in this function - it is in tail position.
Prefer Folds to Explicit Recursion
Chapter 5 Pattern Matching
- purescript-globals, which provides access to some common JavaScript values and functions.
- purescript-math, which provides access to the JavaScript Math module.
Simple Pattern Matching (5.3)
|
|
- Number, String, Char and Boolean literals
- Wildcard patterns, indicated with an underscore (_), which match any argument, and which do not bind any names.
Guards (5.5)
|
|
Array Patterns (5.6)
|
|
Record Patterns and Row Polymorphism (5.7)
|
|
Notice: what is the type variable r here?
We can read the new type signature of showPerson as “takes any record with first and last fields which are Strings and any other fields, and returns a String”.
This function is polymorphic in the row r of record fields, hence the name row polymorphism.
Nested Patterns (5.8)
|
|
Named Patterns (5.9)
|
|
Case Expressions (5.10)
|
|
Algebraic Data Types (5.12)
Algebraic Data Types (or ADTs)
|
|
Using ADTs (5.13)
|
|
Newtypes (5.15)
There is an important special case of algebraic data types (ADT), called newtypes
Newtypes must define exactly one constructor, and that constructor must take exactly one argument.
a newtype gives a new name to an existing type. In fact, the values of a newtype have the same runtime representation as the underlying type. This gives an extra layer of type safety.
|
|
Newtypes will become important, since they allow us to attach different behavior to a type without changing its representation at runtime.
Chapter 6 Type Classes
Show Me (6.3)
|
|
We can annotate the expression with a type, using the :: operator, so that PSCi can choose the correct type class instance:
|
|
Common Type Classes (6.4)
|
|
|
|
Functor Law
- identity law: map id xs = xs
- composition law: map g (map f xs) = map (g <<< f) xs
Type Annotations (6.5)
|
|
Instance Dependencies (6.7)
|
|
Multi Parameter Type Classes (6.8)
|
|
Functional Dependencies (6.9)
|
|
Nullary Type Classes (6.10)
|
|
Note that there is no instance defined for the Partial type class! Doing so would defeat its purpose: attempting to use the head function directly will result in a type error:
|
|
|
|
Note that the Partial constraint appears inside the parentheses on the left of the function arrow, but not in the outer forall. That is, unsafePartial is a function from partial values to regular values.
Chapter 7 Applicative Validation
lift Arbitrary Functions (7.4)
|
|
Maybe implement apply class
|
|
|
|
Applicative type class (7.5)
|
|
More Effects (7.7)
|
|
Applicative Validation (7.9)
|
|
purescript-validation
The Data.AddressBook.Validation module uses the V (Array String) applicative functor to validate the data structures
|
|
Traversable Functors (7.11)
|
|
|
|
|
|
Traversable functors capture the idea of traversing a data structure, collecting a set of effectful computations, and combining their effects. In fact, sequence and traverse are equally important to the definition of Traversable - each can be implemented in terms of each other
List implements
|
|
Applicative Functors for Parallelism (7.12)
|
|
This computation would start computing values asynchronously using computation1 and computation2. When both results have been computed, they would be combined into a single result using the function f.
Chapter 8 The Eff Monad
Monads and Do Notation (8.3)
|
|
In general, every line of a do notation block will contain a computation of type m a for some type a and our monad m
The monad m must be the same on every line
the types a can differ (i.e. individual computations can have different result types)
|
|
Monad type class (8.4)
|
|
syntax suger
all of the following statement are same
|
|
8.5 Monad Laws
|
|
Right identity
It tells us that we can eliminate a call to pure if it is the last expression in a do notation block:
|
|
The right-identity law says that this is equivalent to just expr.
Left identity
we can eliminate a call to pure if it is the first expression in a do notation block:
|
|
This code is equivalent to next, after the name x has been replaced with the expression y.
Associativity
It tells us how to deal with nested do notation blocks
|
|
8.6 Folding With Monads
foldM generalizes the foldl function that we met earlier to a monadic context.
Intuitively, foldM performs a fold over a list in some context supporting some set of side-effects.
|
|
Example:
|
|
8.7 Monads and Applicatives
Every instance of the Monad type class is also an instance of the Applicative type class
|
|
a monad has to combine its side-effects in sequence.
8.8 Native Effects
The Eff monad is defined in the Prelude, in the Control.Monad.Eff module. It is used to manage so-called native side-effects.
8.9 Side-Effects and Purity
The answer is that PureScript does not aim to eliminate side-effects. It aims to represent side-effects in such a way that pure computations can be distinguished from computations with side-effects in the type system. In this sense, the language is still pure.
main is required to be a computation in the Eff monad
8.10 The Eff Monad
Simple example.
This program uses do notation to combine two types of native effects provided by the Javascript runtime: random number generation and console IO.
|
|
8.11 Extensible Effects
|
|
main is a computation with side-effects, which can be run in any environment which supports random number generation and console IO, and any other types of side effect, and which returns a value of type Unit