import type * as P from "@principia/prelude";
import * as HKT from "@principia/prelude/HKT";
import { pipe } from "../Function";
import { Functor, map } from "./functor";
import type { URI, V } from "./model";
import { unit } from "./unit";
/*
* -------------------------------------------
* Monad Array
* -------------------------------------------
*/
export const chainWithIndex_: (
fa: ReadonlyArray,
f: (i: number, a: A) => ReadonlyArray
) => ReadonlyArray = (fa, f) => {
let outLen = 0;
const len = fa.length;
const temp = new Array(len);
for (let i = 0; i < len; i++) {
const e = fa[i];
const arr = f(i, e);
outLen += arr.length;
temp[i] = arr;
}
const out = Array(outLen);
let start = 0;
for (let i = 0; i < len; i++) {
const arr = temp[i];
const l = arr.length;
for (let j = 0; j < l; j++) {
out[j + start] = arr[j];
}
start += l;
}
return out;
};
export const chainWithIndex: (
f: (i: number, a: A) => ReadonlyArray
) => (fa: ReadonlyArray) => ReadonlyArray = (f) => (fa) => chainWithIndex_(fa, f);
/**
* ```haskell
* chain_ :: Monad m => (m a, (a -> m b)) -> m b
* ```
*
* Composes computations in sequence, using the return value of one computation as input for the next
*
* @category Monad
* @since 1.0.0
*/
export const chain_ = (fa: ReadonlyArray, f: (a: A) => ReadonlyArray): ReadonlyArray =>
chainWithIndex_(fa, (_, a) => f(a));
/**
* ```haskell
* chain :: Monad m => (a -> m b) -> m a -> m b
* ```
*
* Composes computations in sequence, using the return value of one computation as input for the next
*
* @category Monad
* @since 1.0.0
*/
export const chain = (f: (a: A) => ReadonlyArray) => (fa: ReadonlyArray): ReadonlyArray => chain_(fa, f);
/**
* ```haskell
* flatten :: Monad m => m m a -> m a
* ```
*
* Removes one level of nesting from a nested `NonEmptyArray`
*
* @category Monad
* @since 1.0.0
*/
export const flatten = (mma: ReadonlyArray>): ReadonlyArray => {
let rLen = 0;
const len = mma.length;
for (let i = 0; i < len; i++) {
rLen += mma[i].length;
}
const r = Array(rLen);
let start = 0;
for (let i = 0; i < len; i++) {
const arr = mma[i];
const l = arr.length;
for (let j = 0; j < l; j++) {
r[j + start] = arr[j];
}
start += l;
}
return r;
};
/**
* ```haskell
* tap_ :: Monad m => (ma, (a -> m b)) -> m a
* ```
*
* Composes computations in sequence, using the return value of one computation as input for the next
* and keeping only the result of the first
*
* @category Monad
* @since 1.0.0
*/
export const tap_ = (ma: ReadonlyArray, f: (a: A) => ReadonlyArray): ReadonlyArray =>
chain_(ma, (a) =>
pipe(
f(a),
map(() => a)
)
);
/**
* ```haskell
* tap :: Monad m => (a -> mb) -> m a -> m a
* ```
*
* Composes computations in sequence, using the return value of one computation as input for the next
* and keeping only the result of the first
*
* @category Monad
* @since 1.0.0
*/
export const tap = (f: (a: A) => ReadonlyArray) => (ma: ReadonlyArray): ReadonlyArray => tap_(ma, f);
export const chainFirst = tap;
export const Monad: P.Monad<[URI], V> = HKT.instance({
...Functor,
flatten,
unit
});