// Generated by purs version 0.14.5
"use strict";
var Control_Bind = require("../Control.Bind/index.js");
var Control_Monad = require("../Control.Monad/index.js");
var Data_Either = require("../Data.Either/index.js");
var Data_Functor = require("../Data.Functor/index.js");
var Data_Identity = require("../Data.Identity/index.js");
var Data_Maybe = require("../Data.Maybe/index.js");
var Data_Monoid = require("../Data.Monoid/index.js");
var Data_Semigroup = require("../Data.Semigroup/index.js");
var Data_Unit = require("../Data.Unit/index.js");
var Effect = require("../Effect/index.js");
var Effect_Ref = require("../Effect.Ref/index.js");
var Loop = (function () {
    function Loop(value0) {
        this.value0 = value0;
    };
    Loop.create = function (value0) {
        return new Loop(value0);
    };
    return Loop;
})();
var Done = (function () {
    function Done(value0) {
        this.value0 = value0;
    };
    Done.create = function (value0) {
        return new Done(value0);
    };
    return Done;
})();
var tailRecM = function (dict) {
    return dict.tailRecM;
};
var tailRecM2 = function (dictMonadRec) {
    return function (f) {
        return function (a) {
            return function (b) {
                return tailRecM(dictMonadRec)(function (o) {
                    return f(o.a)(o.b);
                })({
                    a: a,
                    b: b
                });
            };
        };
    };
};
var tailRecM3 = function (dictMonadRec) {
    return function (f) {
        return function (a) {
            return function (b) {
                return function (c) {
                    return tailRecM(dictMonadRec)(function (o) {
                        return f(o.a)(o.b)(o.c);
                    })({
                        a: a,
                        b: b,
                        c: c
                    });
                };
            };
        };
    };
};
var untilJust = function (dictMonadRec) {
    return function (m) {
        return tailRecM(dictMonadRec)(function (v) {
            return Data_Functor.mapFlipped((((dictMonadRec.Monad0()).Bind1()).Apply0()).Functor0())(m)(function (v1) {
                if (v1 instanceof Data_Maybe.Nothing) {
                    return new Loop(Data_Unit.unit);
                };
                if (v1 instanceof Data_Maybe.Just) {
                    return new Done(v1.value0);
                };
                throw new Error("Failed pattern match at Control.Monad.Rec.Class (line 155, column 43 - line 157, column 19): " + [ v1.constructor.name ]);
            });
        })(Data_Unit.unit);
    };
};
var whileJust = function (dictMonoid) {
    return function (dictMonadRec) {
        return function (m) {
            return tailRecM(dictMonadRec)(function (v) {
                return Data_Functor.mapFlipped((((dictMonadRec.Monad0()).Bind1()).Apply0()).Functor0())(m)(function (v1) {
                    if (v1 instanceof Data_Maybe.Nothing) {
                        return new Done(v);
                    };
                    if (v1 instanceof Data_Maybe.Just) {
                        return Loop.create(Data_Semigroup.append(dictMonoid.Semigroup0())(v)(v1.value0));
                    };
                    throw new Error("Failed pattern match at Control.Monad.Rec.Class (line 148, column 45 - line 150, column 26): " + [ v1.constructor.name ]);
                });
            })(Data_Monoid.mempty(dictMonoid));
        };
    };
};
var tailRec = function (f) {
    var go = function ($copy_v) {
        var $tco_done = false;
        var $tco_result;
        function $tco_loop(v) {
            if (v instanceof Loop) {
                $copy_v = f(v.value0);
                return;
            };
            if (v instanceof Done) {
                $tco_done = true;
                return v.value0;
            };
            throw new Error("Failed pattern match at Control.Monad.Rec.Class (line 93, column 3 - line 93, column 25): " + [ v.constructor.name ]);
        };
        while (!$tco_done) {
            $tco_result = $tco_loop($copy_v);
        };
        return $tco_result;
    };
    return function ($59) {
        return go(f($59));
    };
};
var monadRecMaybe = {
    tailRecM: function (f) {
        return function (a0) {
            var g = function (v) {
                if (v instanceof Data_Maybe.Nothing) {
                    return new Done(Data_Maybe.Nothing.value);
                };
                if (v instanceof Data_Maybe.Just && v.value0 instanceof Loop) {
                    return new Loop(f(v.value0.value0));
                };
                if (v instanceof Data_Maybe.Just && v.value0 instanceof Done) {
                    return new Done(new Data_Maybe.Just(v.value0.value0));
                };
                throw new Error("Failed pattern match at Control.Monad.Rec.Class (line 129, column 7 - line 129, column 31): " + [ v.constructor.name ]);
            };
            return tailRec(g)(f(a0));
        };
    },
    Monad0: function () {
        return Data_Maybe.monadMaybe;
    }
};
var monadRecIdentity = {
    tailRecM: function (f) {
        var runIdentity = function (v) {
            return v;
        };
        var $60 = tailRec(function ($62) {
            return runIdentity(f($62));
        });
        return function ($61) {
            return Data_Identity.Identity($60($61));
        };
    },
    Monad0: function () {
        return Data_Identity.monadIdentity;
    }
};
var monadRecFunction = {
    tailRecM: function (f) {
        return function (a0) {
            return function (e) {
                return tailRec(function (a) {
                    return f(a)(e);
                })(a0);
            };
        };
    },
    Monad0: function () {
        return Control_Monad.monadFn;
    }
};
var monadRecEither = {
    tailRecM: function (f) {
        return function (a0) {
            var g = function (v) {
                if (v instanceof Data_Either.Left) {
                    return new Done(new Data_Either.Left(v.value0));
                };
                if (v instanceof Data_Either.Right && v.value0 instanceof Loop) {
                    return new Loop(f(v.value0.value0));
                };
                if (v instanceof Data_Either.Right && v.value0 instanceof Done) {
                    return new Done(new Data_Either.Right(v.value0.value0));
                };
                throw new Error("Failed pattern match at Control.Monad.Rec.Class (line 121, column 7 - line 121, column 33): " + [ v.constructor.name ]);
            };
            return tailRec(g)(f(a0));
        };
    },
    Monad0: function () {
        return Data_Either.monadEither;
    }
};
var monadRecEffect = {
    tailRecM: function (f) {
        return function (a) {
            var fromDone = function (v) {
                if (v instanceof Done) {
                    return v.value0;
                };
                throw new Error("Failed pattern match at Control.Monad.Rec.Class (line 113, column 30 - line 113, column 44): " + [ v.constructor.name ]);
            };
            return function __do() {
                var r = Control_Bind.bindFlipped(Effect.bindEffect)(Effect_Ref["new"])(f(a))();
                (function () {
                    while (!(function __do() {
                        var v = Effect_Ref.read(r)();
                        if (v instanceof Loop) {
                            var e = f(v.value0)();
                            Effect_Ref.write(e)(r)();
                            return false;
                        };
                        if (v instanceof Done) {
                            return true;
                        };
                        throw new Error("Failed pattern match at Control.Monad.Rec.Class (line 104, column 22 - line 109, column 28): " + [ v.constructor.name ]);
                    })()) {

                    };
                    return {};
                })();
                return Data_Functor.map(Effect.functorEffect)(fromDone)(Effect_Ref.read(r))();
            };
        };
    },
    Monad0: function () {
        return Effect.monadEffect;
    }
};
var functorStep = {
    map: function (f) {
        return function (m) {
            if (m instanceof Loop) {
                return new Loop(m.value0);
            };
            if (m instanceof Done) {
                return new Done(f(m.value0));
            };
            throw new Error("Failed pattern match at Control.Monad.Rec.Class (line 27, column 1 - line 27, column 48): " + [ m.constructor.name ]);
        };
    }
};
var forever = function (dictMonadRec) {
    return function (ma) {
        return tailRecM(dictMonadRec)(function (u) {
            return Data_Functor.voidRight((((dictMonadRec.Monad0()).Bind1()).Apply0()).Functor0())(new Loop(u))(ma);
        })(Data_Unit.unit);
    };
};
var bifunctorStep = {
    bimap: function (v) {
        return function (v1) {
            return function (v2) {
                if (v2 instanceof Loop) {
                    return new Loop(v(v2.value0));
                };
                if (v2 instanceof Done) {
                    return new Done(v1(v2.value0));
                };
                throw new Error("Failed pattern match at Control.Monad.Rec.Class (line 29, column 1 - line 31, column 34): " + [ v.constructor.name, v1.constructor.name, v2.constructor.name ]);
            };
        };
    }
};
module.exports = {
    Loop: Loop,
    Done: Done,
    tailRec: tailRec,
    tailRecM: tailRecM,
    tailRecM2: tailRecM2,
    tailRecM3: tailRecM3,
    forever: forever,
    whileJust: whileJust,
    untilJust: untilJust,
    functorStep: functorStep,
    bifunctorStep: bifunctorStep,
    monadRecIdentity: monadRecIdentity,
    monadRecEffect: monadRecEffect,
    monadRecFunction: monadRecFunction,
    monadRecEither: monadRecEither,
    monadRecMaybe: monadRecMaybe
};
