// @flow import type { Monoid } from './Monoid' import type { Maybe } from './Maybe' import type { Predicate } from './Fun' import type { Either } from './Either' import type { Foldable } from './Foldable' import { arrayMonoid, all as allMonoid, any } from './Monoid' import { id } from './Identity' import * as maybe from './Maybe' import * as either from './Either' import { HKT } from './HKT' import * as foldable from './Foldable' export interface Fold { /** * map each target to a Monoid and combine the results * underlying representation of [[Fold]], all [[Fold]] methods are defined in terms of foldMap */ foldMap(monoid: Monoid, f: (a: A) => M, s: S): M } /** combine all targets using a target's Monoid */ export function fold(fold: Fold, monoid: Monoid, s: S): A { return fold.foldMap(monoid, id, s) } /** * get all the targets of a [[Fold]] */ export function getAll(fold: Fold, s: S): Array { return fold.foldMap(arrayMonoid, a => [a], s) } /** find the first target of a [[Fold]] matching the predicate */ export function find(fold: Fold, p: Predicate, s: S): Maybe { return fold.foldMap(maybe.first, a => p(a) ? maybe.of(a) : maybe.Nothing, s) } /** get the first target of a [[Fold]] */ export function headOption(fold: Fold, s: S): Maybe { return find(fold, () => true, s) } /** check if at least one target satisfies the predicate */ export function exist(fold: Fold, p: Predicate, s: S): boolean { return fold.foldMap(any, p, s) } /** check if all targets satisfy the predicate */ export function all(fold: Fold, p: Predicate, s: S): boolean { return fold.foldMap(allMonoid, p, s) } /** join two Fold with the same target */ export function choice(fold1: Fold, fold2: Fold): Fold, A> { return { foldMap(monoid: Monoid, f: (a: A) => M, s: Either): M { return either.either(s1 => fold1.foldMap(monoid, f, s1), s2 => fold2.foldMap(monoid, f, s2), s) } } } export function composeFold(ab: Fold, sa: Fold): Fold { return { foldMap(monoid: Monoid, f: (b: B) => M, s: S): M { return sa.foldMap(monoid, a => ab.foldMap(monoid, f, a), s) } } } export function fromFoldable(fold: Foldable): Fold, A> { return { foldMap(monoid: Monoid, f: (a: A) => M, s: HKT): M { return foldable.foldMap(fold, monoid, f, s) } } }