// @flow import type { Monoid } from './Monoid' import type { Monad } from './Monad' import type { Foldable } from './Foldable' import type { Alt } from './Alt' import type { Plus } from './Plus' import type { Alternative } from './Alternative' import type { Setoid } from './Setoid' import type { Maybe } from './Maybe' import type { Predicate } from './Fun' import type { Ord } from './Ord' import type { Applicative } from './Applicative' import type { Traversable } from './Traversable' import type { Tuple } from './Tuple' import type { Unfoldable } from './Unfoldable' import { HKT } from './HKT' import * as maybe from './Maybe' import { id } from './Identity' import { toNativeComparator } from './Ord' import * as tuple from './Tuple' import { liftA2 } from './Apply' class IsArr {} export type ArrV = Array; export type Arr = HKT; export function inj(a: ArrV): Arr { return ((a: any): Arr) } export function prj(fa: Arr): ArrV { return ((fa: any): ArrV) } function copy(as: Arr): Array { return prj(as).slice() } export function empty(): Arr { return inj([]) } export const pempty = empty export function concat(x: Arr, y: Arr): Arr { return inj(prj(x).concat(prj(y))) } export function map(f: (a: A) => B, fa: Arr): Arr { return inj(prj(fa).map(f)) } export function ap(fab: Arr<(a: A) => B>, fa: Arr): Arr { const a = prj(fa) return inj(prj(fab).reduce((acc, f) => acc.concat(a.map(f)), [])) } export function of(a: A): Arr { return inj([a]) } export function chain(f: (a: A) => Arr, fa: Arr): Arr { return inj(prj(fa).reduce((acc, a) => acc.concat(prj(f(a))), [])) } export function reduce(f: (b: B, a: A) => B, b: B, fa: Arr): B { return prj(fa).reduce(f, b) } export function traverse(applicative: Applicative, f: (a: A) => HKT, ta: Arr): HKT> { const snocA2 = liftA2(applicative, snoc) return reduce((fab, a) => snocA2(fab, f(a)), applicative.of(empty()), ta) } export function unfoldr(f: (b: B) => Maybe>, b: B): Arr { const ret = [] let bb = b while (true) { // eslint-disable-line no-constant-condition const mt = f(bb) if (maybe.isNothing(mt)) { break } const t = maybe.fromJust(mt) ret.push(tuple.fst(t)) bb = tuple.snd(t) } return inj(ret) } export const alt = concat export function equals(setoid: Setoid, fx: Arr, fy: Arr): boolean { const x = prj(fx) const y = prj(fy) if (x.length !== y.length) { return false } for (let i = 0, len = x.length; i < len; i++) { if (!setoid.equals(x[i], y[i])) { return false } } return true } export function getSetoid(setoid: Setoid): Setoid> { return { equals(fx, fy) { return equals(setoid, fx, fy) } } } export function uncons(as: Arr, empty: () => B, otherwise: (head: A, tail: Arr) => B): B { const xs = prj(as) return xs.length === 0 ? empty() : otherwise(xs[0], inj(xs.slice(1))) } export function length(as: Arr): number { return prj(as).length } export function isEmpty(as: Arr): boolean { return length(as) === 0 } export function isOutOfBound(i: number, as: Arr): boolean { return i < 0 || i >= prj(as).length } export function index(as: Arr, i: number): Maybe { const xs = prj(as) return isOutOfBound(i, as) ? maybe.Nothing : maybe.of(xs[i]) } export function cons(a: A, as: Arr): Arr { return inj([a].concat(prj(as))) } export function snoc(as: Arr, a: A): Arr { return inj(prj(as).concat(a)) } export function head(as: Arr): Maybe { return isEmpty(as) ? maybe.Nothing : maybe.of(prj(as)[0]) } export function last(as: Arr): Maybe { return index(as, length(as) - 1) } export function tail(as: Arr): Maybe> { const xs = prj(as) const len = xs.length return len === 0 ? maybe.Nothing : maybe.of(inj(xs.slice(1))) } export function slice(start: number, end: number, as: Arr): Arr { return inj(prj(as).slice(start, end)) } export function init(as: Arr): Maybe> { const xs = prj(as) const len = xs.length return len === 0 ? maybe.Nothing : maybe.of(inj(xs.slice(0, len - 1))) } export function take(n: number, as: Arr): Arr { return slice(0, n, as) } export function takeWhile(predicate: Predicate, as: Arr): Arr { return inj(prj(as).slice().filter(predicate)) } export function drop(n: number, as: Arr): Arr { return slice(n, length(as), as) } export function dropWhile(predicate: Predicate, as: Arr): Arr { return takeWhile(a => !predicate(a), as) } export function findIndex(predicate: Predicate, as: Arr): Maybe { const xs = prj(as) for (let i = 0, len = xs.length; i < len; i++) { if (predicate(xs[i])) { return maybe.of(i) } } return maybe.Nothing } export function filter(predicate: (a: A) => boolean, as: Arr): Arr { return inj(prj(as).filter(predicate)) } export function unsafeInsertAt(i: number, a: A, as: Arr): Arr { const xs = copy(as) xs.splice(i, 0, a) return inj(xs) } export function insertAt(i: number, a: A, as: Arr): Maybe> { return i < 0 || i > prj(as).length ? maybe.Nothing : maybe.of(unsafeInsertAt(i, a, as)) } export function unsafeUpdateAt(i: number, a: A, as: Arr): Arr { const xs = copy(as) xs[i] = a return inj(xs) } export function updateAt(i: number, a: A, as: Arr): Maybe> { return isOutOfBound(i, as) ? maybe.Nothing : maybe.of(unsafeUpdateAt(i, a, as)) } export function unsafeDeleteAt(i: number, as: Arr): Arr { const xs = copy(as) xs.splice(i, 1) return inj(xs) } export function deleteAt(i: number, as: Arr): Maybe> { return isOutOfBound(i, as) ? maybe.Nothing : maybe.of(unsafeDeleteAt(i, as)) } export function modifyAt(i: number, f: (a: A) => A, as: Arr): Maybe> { return isOutOfBound(i, as) ? maybe.Nothing : updateAt(i, f(prj(as)[i]), as) } export function reverse(as: Arr): Arr { return inj(copy(as).reverse()) } export function mapMaybe(f: (a: A) => Maybe, as: Arr): Arr { return chain(a => maybe.maybe(empty(), of, f(a)), as) } export function catMaybes(as: Arr>): Arr { return mapMaybe(id, as) } export function sort(ord: Ord, as: Arr): Arr { return inj(copy(as).sort(toNativeComparator(ord.compare))) } export class Do { static of(a: A): Do { return new Do(of(a)) } value: Arr; constructor(value: Arr) { this.value = value } map(f: (a: A) => B): Do { return new Do(map(f, this.value)) } chain(f: (a: A) => Arr): Do { return new Do(chain(f, this.value)) } } export type FreeMonoid = Monoid>; if (false) { // eslint-disable-line ({ concat, empty, map, ap, of, chain, reduce, alt, pempty, traverse, unfoldr }: Monoid> & FreeMonoid<*> & Monad & Foldable & Alt & Plus & Alternative & Traversable & Unfoldable) }