"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.corresponds = exports.unfold = exports.partitionMap = exports.flatten = exports.concat = exports.reduceRight_ = exports.reduceRight = exports.reduce_ = exports.reduce = exports.foldMap = exports.never = exports.skip_ = exports.take_ = exports.of = exports.ap = exports.chain_ = exports.chain = exports.zip_ = exports.zip = exports.map_ = exports.map = exports.zipWith = void 0;
// ets_tracing: off
require("../Operator");
const A = __importStar(require("../Collections/Immutable/Array"));
const Tp = __importStar(require("../Collections/Immutable/Tuple"));
const Function_1 = require("../Function");
function* genOf(a) {
    yield a;
}
function* genMap(iterator, mapping) {
    let n = -1;
    while (true) {
        const result = iterator.next();
        if (result.done) {
            break;
        }
        n += 1;
        yield mapping(result.value, n);
    }
}
function* genChain(iterator, mapping) {
    while (true) {
        const result = iterator.next();
        if (result.done) {
            break;
        }
        const ib = mapping(result.value)[Symbol.iterator]();
        while (true) {
            const result = ib.next();
            if (result.done) {
                break;
            }
            yield result.value;
        }
    }
}
// inspired from "Closing Iterables is a Leaky Abstraction" by Reginald Braithwaite
// https://raganwald.com/2017/07/22/closing-iterables-is-a-leaky-abstraction.html
function zipWith(iterableA, iterableB, zipper) {
    return {
        [Symbol.iterator]() {
            let done = false;
            const ia = iterableA[Symbol.iterator]();
            const ib = iterableB[Symbol.iterator]();
            return {
                next() {
                    if (done) {
                        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
                        return this.return();
                    }
                    const va = ia.next();
                    const vb = ib.next();
                    return va.done || vb.done
                        ? // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
                            this.return()
                        : { done: false, value: zipper(va.value, vb.value) };
                },
                return(value) {
                    if (!done) {
                        done = true;
                        if (typeof ia.return === "function") {
                            ia.return();
                        }
                        if (typeof ib.return === "function") {
                            ib.return();
                        }
                    }
                    return { done: true, value };
                }
            };
        }
    };
}
exports.zipWith = zipWith;
function map(f) {
    return (i) => ({
        [Symbol.iterator]: () => genMap(i[Symbol.iterator](), f)
    });
}
exports.map = map;
function map_(i, f) {
    return {
        [Symbol.iterator]: () => genMap(i[Symbol.iterator](), f)
    };
}
exports.map_ = map_;
function zip(fb) {
    return (fa) => zipWith(fa, fb, Tp.tuple);
}
exports.zip = zip;
function zip_(fa, fb) {
    return zipWith(fa, fb, Tp.tuple);
}
exports.zip_ = zip_;
function chain(f) {
    return (i) => ({
        [Symbol.iterator]: () => genChain(i[Symbol.iterator](), f)
    });
}
exports.chain = chain;
function chain_(i, f) {
    return {
        [Symbol.iterator]: () => genChain(i[Symbol.iterator](), f)
    };
}
exports.chain_ = chain_;
function ap(fa) {
    return (fab) => chain_(fab, (f) => map_(fa, f));
}
exports.ap = ap;
function of(a) {
    return {
        [Symbol.iterator]: () => genOf(a)
    };
}
exports.of = of;
function take_(a, n) {
    return {
        *[Symbol.iterator]() {
            let i = 0;
            for (const x of a) {
                if (i++ >= n) {
                    return;
                }
                yield x;
            }
        }
    };
}
exports.take_ = take_;
function skip_(a, n) {
    return {
        *[Symbol.iterator]() {
            let i = 0;
            for (const x of a) {
                if (i++ >= n) {
                    yield x;
                }
            }
        }
    };
}
exports.skip_ = skip_;
exports.never = {
    // eslint-disable-next-line @typescript-eslint/no-empty-function
    *[Symbol.iterator]() { }
};
function foldMap(M) {
    return (f) => (fa) => {
        let res = M.empty;
        let n = -1;
        const iterator = fa[Symbol.iterator]();
        // eslint-disable-next-line no-constant-condition
        while (true) {
            const result = iterator.next();
            if (result.done) {
                break;
            }
            n += 1;
            res = M.concat(res, f(result.value, n));
        }
        return res;
    };
}
exports.foldMap = foldMap;
function reduce(b, f) {
    return (fa) => reduce_(fa, b, f);
}
exports.reduce = reduce;
function reduce_(fa, b, f) {
    let res = b;
    let n = -1;
    const iterator = fa[Symbol.iterator]();
    // eslint-disable-next-line no-constant-condition
    while (true) {
        const result = iterator.next();
        if (result.done) {
            break;
        }
        n += 1;
        res = f(res, result.value, n);
    }
    return res;
}
exports.reduce_ = reduce_;
function reduceRight(b, f) {
    return (fa) => {
        return A.reduceRightWithIndex_(Array.from(fa), b, (i, a, b) => f(a, b, i));
    };
}
exports.reduceRight = reduceRight;
function reduceRight_(fa, b, f) {
    return A.reduceRightWithIndex_(Array.from(fa), b, (i, a, b) => f(a, b, i));
}
exports.reduceRight_ = reduceRight_;
function concat(a, b) {
    return {
        *[Symbol.iterator]() {
            for (const x of a) {
                yield x;
            }
            for (const x of b) {
                yield x;
            }
        }
    };
}
exports.concat = concat;
function flatten(a) {
    return chain_(a, Function_1.identity);
}
exports.flatten = flatten;
function partitionMap(f) {
    return (as) => A.separate(Array.from(map_(as, f)));
}
exports.partitionMap = partitionMap;
/**
 * Infinite sequence produced by repeated application of f to a
 */
function unfold(a, f) {
    return {
        *[Symbol.iterator]() {
            yield a;
            let current = a;
            while (true) {
                current = f(a);
                yield current;
            }
        }
    };
}
exports.unfold = unfold;
function corresponds(left, right, f) {
    const leftIt = left[Symbol.iterator]();
    const rightIt = right[Symbol.iterator]();
    // eslint-disable-next-line no-constant-condition
    while (1) {
        const lnext = leftIt.next();
        const rnext = rightIt.next();
        if (lnext.done !== rnext.done) {
            return false;
        }
        if (lnext.done) {
            return true;
        }
        if (!f(lnext.value, rnext.value)) {
            return false;
        }
    }
    throw new Error("Bug");
}
exports.corresponds = corresponds;
//# sourceMappingURL=index.js.map