Skip to content

Instantly share code, notes, and snippets.

@azz
Last active October 14, 2017 02:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save azz/cebf30ac0d98f48ed0d14c650b5ea759 to your computer and use it in GitHub Desktop.
Save azz/cebf30ac0d98f48ed0d14c650b5ea759 to your computer and use it in GitHub Desktop.
protocol Functor { fmap; }

const nothing = Symbol("nothing");

class Maybe implements Functor {
    /*private*/ constructor(value) { this._value = value; }

    static just(value) { return new Maybe(value) }
    static nothing() { return new Maybe(nothing) }

    fmap<B>(fn) {
        return this._value === nothing
            ? this
            : Maybe.just(fn(this._value));
    }
}

Pseudo-TypeScript version:

protocol Functor<A> {
  fmap<B>(fn: (a: A) => B): Functor<B>;
  //                        ^ not quite, shouldn't be widened, should be, e.g. Maybe<B>
}

const nothing = Symbol("nothing");
type Just<A> = A;
type Nothing = typeof nothing;

class Maybe<A> implements Functor<Just<A> | Nothing> {
    private constructor(private value: Just<A> | Nothing) { }

    static just<A>(value: A) { return new Maybe(value) }
    static nothing<A>() { return new Maybe<A>(nothing) }

    fmap<B>(fn: (a: A) => B) {
        return this.value === nothing
            ? this
            : Maybe.just(fn(this.value as A));
    }
}

Lets try Applicative.

-- Haskell
instance Applicative Maybe where  
    pure = Just  
    Nothing <*> _ = Nothing  
    (Just f) <*> something = fmap f something
// JS
protocol Applicative extends Functor { static pure; ap; }

const nothing = Symbol("nothing");

class Maybe implements Applicative {
  static pure(value) { return Maybe.just(value) }
  ap(mb) {
    if (this._value === nothing) return this;
    return mb[Functor.fmap](this._value);
  }
  
  // just, nothing, fmap elided
}

Bring forth the Monad!

-- Haskell
instance Monad Maybe where  
    return x = Just x  
    Nothing >>= f = Nothing  
    Just x >>= f  = f x  
    fail _ = Nothing  
protocol Monad extends Applicative {
  bind;
  join(mb) { return this[Monad.bind](() => mb); }
  static fail(msg) { throw new Error(msg); }
}

class Maybe implements Monad {
  bind(fn) {
    if (this._value === nothing) return this;
    return fn(this._value);
  }

  static fail() { return Maybe.nothing() }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment