import type { Predicate } from "../Function"; import type { Stack } from "../support/Stack"; import * as S from "../support/Stack"; import type { Filter, FreeMonoid, Map } from "./model"; /* * ------------------------------------------- * FreeSemigroup Destructors * ------------------------------------------- */ /** * @category Destructors * @since 1.0.0 */ export const fold_ = ( f: FreeMonoid, patterns: { Empty: () => R; Element: (value: A) => R; Filter: (fa: FreeMonoid, f: Predicate) => R; Map: (fa: FreeMonoid, f: (a: A) => A) => R; Combine: (l: FreeMonoid, r: FreeMonoid) => R; } ): R => { switch (f._tag) { case "Empty": return patterns.Empty(); case "Element": return patterns.Element(f.value); case "Combine": return patterns.Combine(f.left, f.right); case "Filter": return patterns.Filter(f.fa, f.f); case "Map": return patterns.Map(f.fa, f.f); } }; /** * @category Destructors * @since 1.0.0 */ export const fold = (patterns: { Empty: () => R; Element: (value: A) => R; Filter: (fa: FreeMonoid, f: Predicate) => R; Map: (fa: FreeMonoid, f: (a: A) => A) => R; Combine: (l: FreeMonoid, r: FreeMonoid) => R; }) => (f: FreeMonoid): R => fold_(f, patterns); type Ops = Filter | Map; /** * https://github.com/Matechs-Garage/matechs-effect/blob/master/packages/system/src/FreeAssociative/index.ts * * @category Destructors * @since 1.0.0 */ export const toArray = (fs: FreeMonoid): ReadonlyArray => { const as: Array = []; let current: FreeMonoid | undefined = fs; let stack: Stack> | undefined = undefined; let ops: Stack> | undefined = undefined; while (current !== undefined) { switch (current._tag) { case "Empty": { current = undefined; break; } case "Element": { if (ops !== undefined) { let op: Stack> | undefined = ops; let drop = false; let a = current.value; while (op !== undefined && !drop) { switch (op.value._tag) { case "Filter": { if (!op.value.f(a)) { drop = true; } break; } case "Map": { a = op.value.f(a); break; } } op = op.previous; } if (!drop) as.push(a); } else { as.push(current.value); } current = undefined; break; } case "Filter": { ops = S.stack(current, ops); current = current.fa; break; } case "Map": { ops = S.stack(current, ops); current = current.fa; break; } case "Combine": { const p: any = stack; stack = S.stack(current.right, p); current = current.left; break; } } if (current === undefined) { if (stack !== undefined) { current = stack.value; stack = stack.previous; } } } return as; };