'lang sweet.js';
// @flow

export class Maybe<T> {

  // $FlowFixMe: computed properties still not supported in flow
  static ['fantasy-land/of'](v: T): Maybe<T> {
    return Maybe.of(v);
  }

  static of(v: T): Maybe<T> {
    return new Just(v);
  }

  // $FlowFixMe: computed properties still not supported in flow
  static ['fantasy-land/empty'](): Maybe<T> {
    return Maybe.empty();
  }

  static empty(): Maybe<T> {
    return new Nothing;
  }
  
  // $FlowFixMe: computed properties still not supported in flow
  static ['fantasy-land/zero'](): Maybe<T> {
    return Maybe.zero();
  }

  static zero(): Maybe<T> {
    return new Nothing;
  }

  // $FlowFixMe: computed properties still not supported in flow
  ['fantasy-land/map']<V>(f: T => V): Maybe<V> {
    return this.map(f);
  }

  map<V>(f: T => V): Maybe<V> {
    throw new Error();
  }

  // $FlowFixMe: computed properties still not supported in flow
  ['fantasy-land/ap']<V>(other: Maybe<T => V>): Maybe<V> {
    return this.ap(other);
  }

  ap<V>(other: Maybe<T => V>): Maybe<V> {
    throw new Error();
  }

  // $FlowFixMe: computed properties still not supported in flow
  ['fantasy-land/chain']<V>(f: T => Maybe<V>): Maybe<V> {
    return this.chain(f);
  }

  chain<V>(f: T => Maybe<V>): Maybe<V> {
    throw new Error();
  }
}

export class Nothing<T> extends Maybe<T> {
  map<V>(f: T => V): Maybe<V> {
    return Maybe.empty();
  }

  ap<V>(other: Maybe<T => V>): Maybe<V> {
    return Maybe.empty();
  }

  chain<V>(f: T => Maybe<V>): Maybe<V> {
    return Maybe.empty();
  }
}

export class Just<T> extends Maybe<T> {
  value: T;

  constructor(v: T) {
    super();
    this.value = v;
  }

  map<V>(f: T => V): Maybe<V> {
    return new Just(f(this.value));
  }

  ap<V>(other: Maybe<T => V>): Maybe<V> {
    if (other instanceof Just) {
      return Maybe.of(other.value(this.value));
    }
    return Maybe.empty();
  }

  chain<V>(f: T => Maybe<V>): Maybe<V> {
    return f(this.value);
  }
}
@@ -444,18 +444,16 @@
 ng;%0A  %7D%0A
-  
 %0A  // $F
@@ -634,32 +634,188 @@
 w Nothing;%0A  %7D%0A%0A
+  static isJust(v: Maybe%3C*%3E): boolean %7B%0A    return v instanceof Just;%0A  %7D%0A%0A  static isNothing(v: Maybe%3C*%3E): boolean %7B%0A    return v instanceof Nothing;%0A  %7D%0A%0A
   // $FlowFixMe:
@@ -2115,16 +2115,17 @@
 is.value);%0A  %7D%0A%7D
+%0A

Add isJust/isNothing to Maybe