ruxo
6/16/2016 - 5:07 PM

FP lib

FP lib

export interface Func<A,B> { (x:A): B }
export interface Action<T> { (): T }

export function identity<T>(x:T) { return x }

export abstract class Maybe<T> {
  data: T
  abstract get(): T
  abstract map<R>(f: Func<T,R>): Maybe<R>
  abstract chain<R>(f: Func<T, Maybe<R>>): Maybe<R>
  abstract perform(fsome: Func<T,void>, fnone?: Action<void>): void
  abstract isNone(): boolean
  abstract isSome(): boolean
}
export class SomeType<T> extends Maybe<T> {
  constructor(value: T){
    super()
    this.data = value
  }
  map<R>(f: (x:T) => R): Maybe<R> { return Some(f(this.data)) }
  chain<R>(f: (x:T) => Maybe<R>): Maybe<R> { return f(this.data) }
  get(default_func?: () => T): T { return this.data }
  ap(opt) { return opt.map(this.data) }
  perform(fsome: Func<T,void>, fnone?: Action<void>): void { this.map<any>(fsome) }
  isNone() { return false }
  isSome() { return true }
}
export class NoneType<T> extends Maybe<T> {
  map<R>(f): Maybe<R> { return this as any }
  chain<R>(f): Maybe<R> { return this as any }
  get(default_func?: () => T): T { return default_func? default_func() : undefined }
  ap(opt) { return this }
  perform(fsome: Func<T,void>, fnone?: Action<void>): void { if (fnone) fnone() }
  isNone() { return true }
  isSome() { return false }
}
const noneAny = new NoneType<any>()

export function Some<T>(data: T): SomeType<T> { return new SomeType<T>(data) }
export function None<T>(): NoneType<T> { return noneAny }
export function maybe<T>(data: T) : Maybe<T> { return (data === undefined || data === null)? None<T>() : Some(data) }
export function head<T>(data: T[]) : Maybe<T> { return maybe((data.length > 0)? data[0] : undefined) }

export const sequence = (...fs) => (x = undefined) => fs.reduce((value, f) => f(value), x)

export function presence<T>(data): Maybe<T> { return maybe(data).chain(d => d.length == 0? None<T>() : Some(d)) }

export abstract class Either<R,W> {
  abstract map<U,V>(fright?: Func<R,U>, fleft?: Func<W,V>): Either<U,V>
  abstract chain<U,V>(fright?: Func<R,Either<U,V>>, fleft?: Func<W,Either<U,V>>): Either<U,V>
  abstract get<T>(fright?: Func<R,T>, fleft?: Func<W,T>): T
  abstract ap(either): any
}
export class RightType<R,W> extends Either<R,W> {
  constructor(private data: R){ super() }
  map<U,V>(fright: Func<R,U>, fleft?: Func<W,V>): Either<U,V> {
    return fright? Right<U,V>(fright(this.data)) : (this as any)
  }
  chain<U,V>(fright?: Func<R,Either<U,V>>, fleft?: Func<W,Either<U,V>>): Either<U,V> {
    return fright? fright(this.data) : <any>this
  }
  get<T>(fright: Func<R,T> = identity, fleft?: Func<W,T>): T {
    return fright(this.data)
  }
  ap(either): any {
    return either.map(this.data)
  }
}
export class WrongType<R,W> extends Either<R,W> {
  constructor(private data: W){ super() }
  map<U,V>(fright?: Func<R,U>, fleft?: Func<W,V>): Either<U,V> {
    return fleft? Wrong<U,V>(fleft(this.data)) : (this as any)
  }
  chain<U,V>(fright?: Func<R,Either<U,V>>, fleft?: Func<W,Either<U,V>>): Either<U,V> {
    return fleft? fleft(this.data) : <any>this
  }
  get<T>(fright?: Func<R,T>, fleft: Func<W,T> = identity): T {
    return fleft(this.data)
  }
  ap(either): any {
    return this
  }
}
export function Right<R,W>(data: R): RightType<R,W> { return new RightType<R,W>(data) }
export function Wrong<R,W>(data: W): WrongType<R,W> { return new WrongType<R,W>(data) }

export function* imap<U,V>(f: Func<U,V>, i: Iterable<U>): Iterable<V> {
  for(let x of i)
    yield f(x)
}
export function* ifilter<T>(f: Func<T,boolean>, i: Iterable<T>): Iterable<T> {
  for(let x of i)
    if (f(x))
      yield x
}

export class Iter<T> {
  constructor(private iterable: Iterable<T>){}

  get() { return [...(<any>this.getIterator())] }
  each(f: (_:T) => void) {
    for(let x of this.iterable)
      f(x)
  }
  tryHead(): Maybe<T> {
    const result = this.getIterator().next()
    return result.done? None<T>() : Some(result.value)
  }
  filter(f: Func<T,boolean>): Iter<T>{
    return new Iter<T>(ifilter(f, this.iterable))
  }
  map<R>(f: Func<T,R>): Iter<R> {
    return new Iter<R>(imap(f, this.iterable))
  }
  private getIterator(){
    return this.iterable[Symbol.iterator]()
  }
}

export function iter<T>(iterable: T[]): Iter<T> { return new Iter<T>(iterable) }

type AsyncFunc<T> = (resolve: Func<T,void>, reject: Func<any,void>) => any
type CleanupFunc = Action<void>
export class Task<T> {
  _fork: AsyncFunc<T>
  cleanup: CleanupFunc
  static of<T>(value: T) { return new Task<T>((resolve,_) => resolve(value))}
  constructor(computation: AsyncFunc<T>, cleanup: CleanupFunc = () => {}){
    this._fork = computation
    this.cleanup = cleanup
  }
  fork(resolve: Func<T,void>, reject: Func<any,void>): any {
    return this._fork(reject, resolve)
  }
  map<T1>(f: Func<T,T1>): Task<T1> {
    const fork = this._fork

    return new Task<T1>((resolve, reject) => fork(a => resolve(f(a)), b => reject(b)), this.cleanup)
  }
  chain<T1>(f: Func<T,Task<T1>>): Task<T1> {
    const fork = this._fork

    return new Task<T1>((resolve, reject) => fork(a => f(a).fork(resolve, reject), b => reject(b)), this.cleanup)
  }
}
def identity(x): return x


def side_effect(f):
    def _from(x):
        f(x)
        return x
    return _from


def pipe(*fargs):
    def from_input(x=None):
        result = x
        for f in fargs:
            result = f(result)
        return result
    return from_input


# Optional monad
class Some:
    def __init__(self, value):
        self._data = value

    def is_some(self): return True

    def is_none(self): return False

    def map(self, f): return Some(f(self._data))

    def chain(self, f): return f(self._data)

    def get(self, default_func=None): return self._data

    def none_do(self, _): return self

    def some_do(self, f):
        f(self._data)
        return self

    def cata(self, fsome, fnone): return fsome(self._data)

    def ap(self, option): return option.map(self._data)

    def __eq__(self, other):
        return type(other) is Some and other._data == self._data


class NoneType:
    def is_some(self): return False

    def is_none(self): return True

    def map(self, f): return self

    def chain(self, f): return self

    def get(self, default_func=None): return default_func() if default_func else None

    def none_do(self, f):
        f()
        return self

    def some_do(self, f): return self

    def cata(self, fsome, fnone): return fnone()

    def ap(self, option): return self

    def __eq__(self, other): return type(other) is NoneType


__single_none = NoneType()


def Nothing(): return __single_none


def maybe(v):
    if v is None:
        return __single_none
    else:
        return Some(v)


def trying(f, data): return None if data is None else f(data)

# Eithe monad
class Right:
    def __init__(self, data):
        self._data = data

    def map(self, fright=None, fleft=None): return self if fright is None else Right(fright(self._data))

    def chain(self, f): return f(self._data)

    def ap(self, x): return x.map(self._data)

    def get(self, fright=identity, fleft=None): return fright(self._data)


class Wrong:
    def __init__(self, data):
        self._data = data

    def map(self, fright=None, fleft=None): return self if fleft is None else Wrong(fleft(self._data))

    def chain(self, f): return self

    def ap(self, x): return self

    def get(self, fright=None, fleft=identity): return fleft(self._data)


def option_to_either(fnone):
    def from_(option):
        return option.cata(Right, lambda: Wrong(fnone()))
    return from_


# memoirization
def memoize(f):
    def wrapped(*args, **kwargs):
        if hasattr(wrapped, '_cached_val'):
            return wrapped._cached_val
        result = f(*args, **kwargs)
        wrapped._cached_val = result
        return result
    return wrapped


def list_each(f, L):
    for item in L:
        f(item)

def cached(f):
    def wrapped(*args, **kwargs):
        if hasattr(wrapped, '_cached_val'):
            return wrapped._cached_val
        result = f(*args, **kwargs)
        wrapped._cached_val = result
        return result
    return wrapped