can be created via type constructors ["fantasy"] #:: Array String #[["fantasy"], ["land"#]] #:: Array (Array String) Type Signature Notation in Fantasyland
is an infix type constructor of a method a #~> b () stands for no argument () #-> a #=> expresses constraints on type variables Semigroup a #=> a #-> a Type Signature Notation in Fantasyland
#:: a #-> List a #-> List a Nil: [] #// Nil #:: List a }) List.prototype.concat = function(that) { return this.cata({ Cons: (head, tail) #=> List.Cons(head, tail.concat(that)), Nil: () #=> that }) } List.Cons(1, List.Nil).concat(List.Cons(2, List.Nil)) #// = List.Cons(1, List.Cons(2, List.Nil)) Linked List as an Instance of Semigroup
a website providing several ways for users to sign up, e.g. email/password and social login. • An user creating two accounts accidentally wants to merge them now. • An user account can be an instance of Semigroup!
checked by compilers, so there’s no need for unit tests. • First, Any, Sum and other types we used here can be provided by libraries. • Functional programming languages, like PureScript, already providing these common types in the language.
Boolean equals should satisfy following laws: Reflexivity: a.equals(a) ##=== true Commutativity: a.equals(b) ##=== b.equals(a) Transitivity: if a.equals(b) and b.equals(c) then a.equals(c)
#=> Array m #-> m foldArray = array #=> array.reduce((a, b) #=> a.concat(b), []) foldArray(["A", "B", "C"]) #// = "ABC" foldArray([Sum(1), Sum(2)]) #// = Sum(3) In this sense, we could fold other types by… foldList #:: Monoid m #=> List m #-> m foldTree #:: Monoid m #=> Tree m #-> m if they can be reduced.
+ 1 [1].map(inc) #// = [2] Promise.resolve(1).then(inc) #// = Promise.resolve(2) Observable.of(1).map(inc) #// = Observable.of(2) They are similar … as usual, there is an abstraction over them already!
Promise Int Observable.of(1) #:: Observable Int 1 2 [2] #:: Array Int Promise.resolve(2) #:: Promise Int Observable.of(2) #:: Observable Int map(x #=> x + 1) Notice that the types of Promise and Observable are overly simplified here. We should also consider error handling in their types.
over unary type constructors… Functor f #=> f a #~> (a #-> b) #-> f b We know (#->) is a binary type constructor, so (#->) r is an unary type constructor… ((#->) r a) #~> (a #-> b) #-> ((#->) r b) (r #-> a) #~> (a #-> b) #-> (r #-> b)