Maybe

Container

Let’s create a normal container first.

1
2
3
4
5
6
7
8
9
10
11
class Container {
constructor(x) {
this._value = x
}
// use the of to create the container
static of(x) {
return new Container(x)
}
}
Container.of(2) // Container { _value: 2 }
Container.of({ name: "jack" }) // Container { _value: { name: 'jack' } }

But we should not directly manipulate the data in the container. We need a function to do this.

1
2
3
4
5
6
// Container.prototype.map :: (a -> b) -> Container a -> Container b
Container.prototype.map = function (f) {
return Container.of(f(this._value))
}
let six = Container.of(2).map((x) => x * 3) // Container { _value: 6 }
six.map((x) => x.toString()).map((x) => "number: " + x + "!") // Container { _value: 'number: 6!' }

After passing the values in the Container to the map function, we can let them manipulate it; after the operation is completed, in order to prevent accidents, put them back into the Container they belong to. The result is that we can call the map continuously, running any function we want to run.
And the Functor is a container type that implements the map function and adheres to certain rules.

Maybe

In Haskell, the Maybe type is defined as follow:

1
data Maybe a = Just a | Nothing

Maybe will check if its value is empty before calling the passed function. So let’s create a simple one.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Maybe {
constructor(x) {
this._value = x
}
static of(x) {
return new Maybe(x)
}
isNothing() {
return this._value === null || this._value === undefined
}
// map :: (a -> b) -> Maybe a -> Maybe b
map(f) {
return this.isNothing() ? Maybe.of(null) : Maybe.of(f(this._value))
}
}
Maybe.of("hello world").map(match(/o/gi)) // Maybe { _value: [ 'o', 'o' ] }
Maybe.of({ name: "jack" })
.map($.prop("age"))
.map((x) => x + 10) // Maybe { _value: null }

Error handling

There is a class called Either in scala that represents the value of one of two possible types. Instances of Either are either an instance of Left or Right.
Now we need to create the Left and the Right.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Left {
constructor(x) {
this._value = x
}
static of(x) {
return new Left(x)
}
// do nothing
map(f) {
return this
}
}
class Right {
constructor(x) {
this._value = x
}
static of(x) {
return new Right(x)
}
map(f) {
return Right.of(f(this._value))
}
}
Left.of(2).map((x) => x + 2) // Left { _value: 2 }
Right.of(2).map((x) => x + 2) //Right { _value: 4 }

Use it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// getChange :: a -> b -> Either(String, Number)
let getChange = curry((a, b) => {
if (a < b) return Left.of("You need to give more money.")
return Right.of(a - b)
})
getChange(10, 8) // Right { _value: 'Get the change: 2' }
getChange(10, 15) // Left { _value: 'You need to give more money.' }

// eigher :: (a -> c) -> (b -> c) -> Either a b -> c
var either = curry((f, g, e) => {
switch (e.constructor) {
case Left:
return f(e._value)
case Right:
return g(e._value)
}
})
// faild :: a -> a
var faild = (x) => x
// success :: a -> b
var success = (x) => {
return "get change: " + x
}
// foo :: a -> a -> c
var foo = $.compose(either(faild, success), getChange)

foo(0, 2) // You need to give more money.
foo(4, 2) // get change: 2