// @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)
}