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