- . . - . ? , - [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);
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.