"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.mergeAllParN_ = exports.mergeAllParN = exports.mergeAllPar_ = exports.mergeAllPar = exports.mergeAll_ = exports.mergeAll = void 0;
// ets_tracing: off
const Function_1 = require("../Function");
const I = __importStar(require("../Iterable"));
const Ref = __importStar(require("../Ref"));
const core = __importStar(require("./core"));
const forEach = __importStar(require("./excl-forEach"));
const zipWith_1 = require("./zipWith");
const zipWithPar_1 = require("./zipWithPar");
/**
 * Merges an `Iterable[IO]` to a single IO, working sequentially.
 *
 * @ets_data_first mergeAll_
 */
function mergeAll(zero, f, __trace) {
    return (as) => mergeAll_(as, zero, f, __trace);
}
exports.mergeAll = mergeAll;
/**
 * Merges an `Iterable[IO]` to a single IO, working sequentially.
 */
function mergeAll_(as, zero, f, __trace) {
    return core.suspend(() => I.reduce_(as, core.succeed(zero), (b, a) => (0, zipWith_1.zipWith_)(b, a, f)), __trace);
}
exports.mergeAll_ = mergeAll_;
/**
 * Merges an `Iterable[IO]` to a single IO, working in parallel.
 *
 * Due to the parallel nature of this combinator, `f` must be both:
 * - commutative: `f(a, b) == f(b, a)`
 * - associative: `f(a, f(b, c)) == f(f(a, b), c)`
 *
 * It's unsafe to execute side effects inside `f`, as `f` may be executed
 * more than once for some of `in` elements during effect execution.
 *
 * @ets_data_first mergeAllPar_
 */
function mergeAllPar(zero, f, __trace) {
    return (as) => mergeAllPar_(as, zero, f, __trace);
}
exports.mergeAllPar = mergeAllPar;
/**
 * Merges an `Iterable[IO]` to a single IO, working in parallel.
 *
 * Due to the parallel nature of this combinator, `f` must be both:
 * - commutative: `f(a, b) == f(b, a)`
 * - associative: `f(a, f(b, c)) == f(f(a, b), c)`
 *
 * It's unsafe to execute side effects inside `f`, as `f` may be executed
 * more than once for some of `in` elements during effect execution.
 */
function mergeAllPar_(as, zero, f, __trace) {
    return core.suspend(() => I.reduce_(as, core.succeed(zero), (b, a) => (0, zipWithPar_1.zipWithPar_)(b, a, f)), __trace);
}
exports.mergeAllPar_ = mergeAllPar_;
/**
 * Merges an `Iterable[IO]` to a single IO, working in with up to `n` fibers in parallel.
 *
 * Due to the parallel nature of this combinator, `f` must be both:
 * - commutative: `f(a, b) == f(b, a)`
 * - associative: `f(a, f(b, c)) == f(f(a, b), c)`
 *
 * It's unsafe to execute side effects inside `f`, as `f` may be executed
 * more than once for some of `in` elements during effect execution.
 *
 * @ets_data_first mergeAllParN_
 */
function mergeAllParN(n, zero, f, __trace) {
    return (as) => mergeAllParN_(as, n, zero, f, __trace);
}
exports.mergeAllParN = mergeAllParN;
/**
 * Merges an `Iterable[IO]` to a single IO, working in with up to `n` fibers in parallel.
 *
 * Due to the parallel nature of this combinator, `f` must be both:
 * - commutative: `f(a, b) == f(b, a)`
 * - associative: `f(a, f(b, c)) == f(f(a, b), c)`
 *
 * It's unsafe to execute side effects inside `f`, as `f` may be executed
 * more than once for some of `in` elements during effect execution.
 */
function mergeAllParN_(as, n, zero, f, __trace) {
    return core.chain_(Ref.makeRef(zero), (acc) => core.chain_(forEach.forEachUnitParN_(as, n, core.chain((a) => (Ref.update_(acc, (b) => f(b, a)))), __trace), () => acc.get));
}
exports.mergeAllParN_ = mergeAllParN_;
//# sourceMappingURL=mergeAll.js.map