Some Implementation in Swift.
Functor
Let $C$ be a constructor which takes a variable as parameter.
$C$ is a Functor if $C$ has the following ability.
For example, we can write such a function functor
or map
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| class Box<T> {
var content: T
init(content: T) {
self.content = content
}
func functor<U>(_ relation: (T) -> U) -> Box<U> {
return Box<U>(content: relation(self.content))
}
}
func functor<T, U>(box: Box<T>, relation: (T) -> U) -> Box<U> {
return Box(content: relation(box.content))
}
let a = Box(content: 1)
let b = functor(box: a, relation: { $0 + 100 }).content
b // 101
|
And we can chain functors like this.
1
2
3
| let addup: (Int)->Int = { $0 + 1 }
let c = a.functor(addup).functor(addup).content
c // 3
|
We can also do it like Haskell
1
2
3
4
5
6
7
8
9
10
| precedencegroup chainopts {
associativity: left
}
infix operator <^>: chainopts
func <^><T, U>(a: Box<T>, f: (T) -> U) -> Box<U> {
return a.functor(f)
}
let d = a <^> addup <^> addup
d.content // 3
|
Monad
$C$ is a Monad if $C$ has the following ability. This is also called as flatmap
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| class Box<T> {
var content: T
init(content: T) {
self.content = content
}
func monad<U>(_ relation: (T) -> Box<U>) -> Box<U> {
return relation(self.content)
}
}
func monad<T, U>(box: Box<T>, relation: (T) -> Box<U>) -> Box<U> {
return relation(box.content)
}
let e = monad(box: a, relation: { Box(content: $0 + 1000) } ).content
e // 1001
let addupAndWrap: (Int)->Box<Int> = { Box(content: $0 + 1000) }
let f = a.monad(addupAndWrap).monad(addupAndWrap).content
f // 2001
|
Haskell-like version.
1
2
3
4
5
6
| infix operator >>-: chainopts
func >>-<T, U>(a: Box<T>, f: (T) -> Box<U>) -> Box<U> {
return a.monad(f)
}
let g = a >>- addupAndWrap >>- addupAndWrap
g.content // 2001
|
Applicative
$C$ is a Applicative if $C$ has the following ability.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| class Box<T> {
var content: T
init(content: T) {
self.content = content
}
func apply<U>(_ relation: Box<(T) -> U>) -> Box<U> {
return Box<U>(content: relation.content(self.content))
}
}
func apply<T, U>(box: Box<T>, relation: Box<(T) -> U>) -> Box<U> {
return Box(content: relation.content(box.content))
}
let h = apply(box: a, relation: Box(content: {$0 + 10000} )).content
h // 10001
let anBoxContainsAddup: Box<(Int)->Int> = Box(content: {$0 + 10000} )
let i = a.apply(anBoxContainsAddup).apply(anBoxContainsAddup).content
i // 20001
|
Haskell-like version.
1
2
3
4
5
6
| infix operator <*>: chainopts
func <*><T, U>(a: Box<T>, f: Box<(T) -> U>) -> Box<U> {
return a.apply(f)
}
let j = a <*> anBoxContainsAddup <*> anBoxContainsAddup
j.content // 20001
|