How to apply callcc so that it provides a continuation mechanism for use with the continuation of the monad

I am trying to implement a continuation monad in Javascript to handle the continuation traversal style and asynchronous control flows. Here is my continuing education monad:

// auxiliary functions

const log = prefix => x => console.log(prefix, x);
const addk = x => y => k => setTimeout((x, y) => k(x + y), 0, x, y);
const inck = x => k => setTimeout(x => k(x + 1), 0, x);
const sqr = x => x * x;


// continuation monad

const cont = {
  of: x => k => k(x),

  map: ftor => f => k => ftor(x => k(f(x))),

  ap: ftor => gtor => k => ftor(x => gtor(f => k(f(x)))),

  chain: ftor => mf => k => ftor(x => mf(x) (k)),

  callcc: f => k => f(x => () => k(x)) (k)
};


// map a normal, unary function with an asynchronous function:

cont.map(inck(9)) (sqr) (log("map"));


// chain two asynchronous CPS computations with an asynchronous binary CPS function

const comp1 = cont.map(inck(4)) (sqr);
const comp2 = cont.map(inck(9)) (sqr);

cont.chain(comp1) (x => cont.chain(comp2) (y => addk(x) (y))) (log("chain"));
Run code

In addition cont.ap, whose benefits do not open to me, everything works fine.

Now I would like to simulate a mechanism throw/ catchsynchronous control flow in Javascript. callccseems appropriate as it provides a continuation mechanism for use with monads continued, as indicated at http://hackage.haskell.org/ .

But I cannot figure out how to apply it callcc, and I have not found a suitable source describing such an application.

+4
1

- . . - . ? , - [1] " invokable." .

, - , ?

, - . , , , . " " (a.k.a. ). , :

  (add1 (* 3 x))
;       |_____|
;          |
;     computation

  (add1 [])
; |_______|
;     |
;  context

(* 3 x) (add1 []), [] . . (add1 [result]) result. - . , (lambda (result) (add1 result)) (add1 []).

, (* 3 x) . (lambda (context) (context (* 3 x))), context , . , Cont Haskell , .

, ?

, - , invokable." , , . , .

, (* 3 x), :

(lambda (context)
  (context (* 3 x)))

, context ? , :

(lambda (context)
  (+
    (context (* 3 x))
    (context (* 3 x))))

context add1, (* 2 (add1 (* 3 x))).

, , context? :

(lambda (context)
  (* 3 x))

call/cc. , . , :

(call/cc (lambda (short-circuit)
  (add1 (short-circuit (* 3 x)))))

(* 3 x) add1. , call/cc (.. short-circuit) . , (.. add1) .

call/cc?

, , callCC Haskell:

callCC :: ((a -> Cont r b) -> Cont r a) -> Cont r a
       -- |___________________________|
       --               |
       --               f
callCC f = Cont $ \k -> runCont (f (\a -> Cont $ \_ -> k a)) k
       --        __|___            |______________________|
       --       |      |                       |
       --       (a -> r)                 short-circuit

, k (.. ). f callCC. Cont r a, , . k .

short-circuit , . , k , .

JavaScript.

, . , callCC Haskell. callCC JavaScript:

var Cont = defclass({
    constructor: function (runCont) {
        this.runCont = runCont;
    },
    map: function (f) {
        return new Cont(k => this.runCont(x => k(f(x))));
    },
    apply: function (g) {
        return new Cont(k => this.runCont(f => g.runCont(x => k(f(x)))));
    },
    bind: function (f) {
        return new Cont(k => this.runCont(x => f(x).runCont(k)));
    }
});

Cont.of = x => new Cont(k => k(x));

var callCC = f => new Cont(k => f(x => new Cont(_ => k(x))).runCont(k));

var log = prefix => x => console.log(prefix, x);

var add1 = x => Cont.of(x + 1);

callCC(short_circuit => short_circuit(15).bind(add1)).runCont(log("short"));

callCC(short_circuit => Cont.of(15).bind(add1)).runCont(log("no short"));

function defclass(prototype) {
    var constructor = prototype.constructor;
    constructor.prototype = prototype;
    return constructor;
}

, callCC goto.

callCC , throw, goto, :

var Cont = defclass({
    constructor: function (runCont) {
        this.runCont = runCont;
    },
    map: function (f) {
        return new Cont(k => this.runCont(x => k(f(x))));
    },
    apply: function (g) {
        return new Cont(k => this.runCont(f => g.runCont(x => k(f(x)))));
    },
    bind: function (f) {
        return new Cont(k => this.runCont(x => f(x).runCont(k)));
    }
});

Cont.of = x => new Cont(k => k(x));

var callCC = f => new Cont(k => f(x => new Cont(_ => k(x))).runCont(k));

var log = (x, ms) => new Cont(k => setTimeout(_ => k(console.log(x)), ms));

var omega = x => x(x); // This is a very dangerous function. Run `omega(omega)`.

callCC(omega).bind(cc => log("loop", 1000).bind(_ => cc(cc))).runCont(x => x);

function defclass(prototype) {
    var constructor = prototype.constructor;
    constructor.prototype = prototype;
    return constructor;
}

:

forever:
    delay(1000);
    print("loop");
    goto forever;

, .


[1] . , , . , , - , invokable.

+3

Source: https://habr.com/ru/post/1656352/


All Articles