import type { Semigroup } from "@principia/prelude/Semigroup"; import { fromCombine } from "@principia/prelude/Semigroup"; /* * ------------------------------------------- * FreeSemigroup Model * ------------------------------------------- */ export interface Element { readonly _tag: "Element"; readonly value: A; } export interface Combine { readonly _tag: "Combine"; readonly left: FreeSemigroup; readonly right: FreeSemigroup; } export type FreeSemigroup = Element | Combine; /* * ------------------------------------------- * FreeSemigroup Constructors * ------------------------------------------- */ /** * @category Constructors * @since 1.0.0 */ export const combine = (left: FreeSemigroup, right: FreeSemigroup): FreeSemigroup => ({ _tag: "Combine", left, right }); /** * @category Constructors * @since 1.0.0 */ export const element = (a: A): FreeSemigroup => ({ _tag: "Element", value: a }); /* * ------------------------------------------- * FreeSemigroup Destructors * ------------------------------------------- */ /** * @category Destructors * @since 1.0.0 */ export const fold = (onOf: (value: A) => R, onConcat: (left: FreeSemigroup, right: FreeSemigroup) => R) => ( f: FreeSemigroup ): R => { switch (f._tag) { case "Element": return onOf(f.value); case "Combine": return onConcat(f.left, f.right); } }; /* * ------------------------------------------- * FreeSemigroup Instances * ------------------------------------------- */ /** * @category Instances * @since 1.0.0 */ export const getSemigroup = (): Semigroup> => fromCombine(combine);