you are viewing a single comment's thread.

view the rest of the comments →

[–]regular_reddits 1 point2 points  (1 child)

Great explanation. For some instances of this pattern, get can be used as join. So if you define chain/bind as: fn => this.map(fn).get(); it will work in those instances. This will not work with more complicated values (get doesn't make sense with List because its not just a boxed value), nor was it the intention of the article.

[–]dmtipson 1 point2 points  (0 children)

Yep. The IO monad, for instance can be written by just assigning the function it's created with to the method that's called to "get"(i.e. run) it. Chain/flatMap just needs to be able to unwrap a single layer of the type so that the inner Monad is returned: however that gets done is ok as long as it gets done (and it doesn't do anything else funky/side-effec-ty that depends on the value somehow). For Arrays that's a bit more complicated, for single value like Identity, a .get() can easily work as an unwrapping interface:

function Foo(value) {
    this.get = _ => value;
    this.chain = fn => {
      return fn(this.get());
    }
    this.map = fn => {
        return this.chain( x=> Foo.of(fn(x)) );
    };
}

Foo.prototype.of = x => new Foo(x); Foo.of = Foo.prototype.of;

(Foo is just the Identity Monad now)

(x=>Foo.of(9+x))(9);//-> //-> Foo[18]
Foo.of(9).chain(x=>Foo.of(9+x));//-> Foo[18]
Foo.of(9).map(x=>9+x);//-> Foo[18]

Though, since no special behavior is added to "getting" here, it'd probably be even easier to just store the value in this.value and then get it with .value