рдЖрдкрдХрд╛ рд╕реНрд╡рд╛рдЧрдд рд╣реИ! рдореИрдВ рдЖрдкрдХреЛ рдЕрдкрдиреА рдЬрд╛рд╡рд╛рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдкреНрд░реЛрдЧреНрд░рд╛рдорд┐рдВрдЧ рднрд╛рд╖рд╛ - рдкреАрдПрд▓ рдЯреНрдпреВрдЯреЛрд░рд┐рдпрд▓ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдореЗрд░реЗ рдЕрдиреБрд╡рд╛рдж рдХреЗ рддреАрд╕рд░реЗ рднрд╛рдЧ рдХреЗ рд▓рд┐рдП рдкреНрд░рд╕реНрддреБрдд рдХрд░рддрд╛ рд╣реВрдВред
рдЕрдиреБрд╡рд╛рджрдХ рд╕реЗ
рд╣рдо рдЕрдкрдиреА рдкреНрд░реЛрдЧреНрд░рд╛рдорд┐рдВрдЧ рднрд╛рд╖рд╛ - ╬╗ рднрд╛рд╖рд╛ (рдореВрд▓ - ╬╗anguage рдореЗрдВ) рдмрдирд╛рдПрдВрдЧреЗред рдирд┐рд░реНрдорд╛рдг рдХреА рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдореЗрдВ, рд╣рдо рдХрдИ рджрд┐рд▓рдЪрд╕реНрдк рддрдХрдиреАрдХреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗ, рдЬреИрд╕реЗ рдХрд┐ рдкреБрдирд░рд╛рд╡рд░реНрддреА рд╡рдВрд╢, рдирд┐рдпрдВрддреНрд░рдг рд╣рд╕реНрддрд╛рдВрддрд░рдг рд╢реИрд▓реА, рдФрд░ рдмреБрдирд┐рдпрд╛рджреА рдЕрдиреБрдХреВрд▓рди рддрдХрдиреАрдХред рджреБрднрд╛рд╖рд┐рдпрд╛ рдХреЗ рджреЛ рд╕рдВрд╕реНрдХрд░рдг рдмрдирд╛рдП рдЬрд╛рдПрдВрдЧреЗ - рдирд┐рдпрдорд┐рдд рдФрд░ рд╕реАрдкреАрдПрд╕ рджреБрднрд╛рд╖рд┐рдпреЛрдВ, рдЬрд╛рд╡рд╛рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдореЗрдВ рдЯреНрд░рд╛рдВрд╕-рдХрдВрдкрд╛рдЗрд▓рд░ред
рдореВрд▓ рдХреЗ рд▓реЗрдЦрдХ рдорд┐рд╣рд╛рдИ Bazon , рдкреНрд░рд╕рд┐рджреНрдз UglifyJS рдкреБрд╕реНрддрдХрд╛рд▓рдп (рдЬреЗрдПрд╕ рдХреЛрдб рдХреЛ рдХрдо рдХрд░рдиреЗ рдФрд░ рдкреНрд░рд╛рд░реВрдкрд┐рдд рдХрд░рдиреЗ рдХрд╛ рдПрдХ рдЙрдкрдХрд░рдг) рдХреЗ рд▓реЗрдЦрдХ рд╣реИрдВред
PS рдЗрдВрдЯрд░рдкреНрд░реЗрдЯрд░ рдФрд░ рдХрдВрдкрд╛рдЗрд▓рд░ рдореЗрдВ рдПрдХ рдмрдЧ рд╣реИ: a() && b()
рдпрд╛ a() || b()
a() || b()
рджреЛрдиреЛрдВ рднрд╛рдЧреЛрдВ рдХреЛ рд╣рдореЗрд╢рд╛ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдпрд╣, рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ, рдЧрд▓рдд рд╣реИ рдХреНрдпреЛрдВрдХрд┐ a()
&&
рдСрдкрд░реЗрдЯрд░ рдХреЗ рд▓рд┐рдП рдЧрд▓рдд рд╣реИ, рдпрд╛ рдЙрд╕рдХреЗ рд▓рд┐рдП рдЧрд▓рдд рдирд╣реАрдВ рд╣реИ ||
, рддрдм b()
рдХрд╛ рдорд╛рди b()
рдХреЛрдИ рднреВрдорд┐рдХрд╛ рдирд╣реАрдВ рдирд┐рднрд╛рддрд╛ рд╣реИред рдЗрд╕реЗ рдареАрдХ рдХрд░рдирд╛ рдореБрд╢реНрдХрд┐рд▓ рдирд╣реАрдВ рд╣реИред
рд╕реАрдкреАрдПрд╕ рджреБрднрд╛рд╖рд┐рдпрд╛
рд╣рдорд╛рд░реА ╬╗ рднрд╛рд╖рд╛ рдореЗрдВ рджреЛ рдХрдорд┐рдпрд╛рдВ рд╣реИрдВ:
- рд░рд┐рдХрд░реНрд╕рди рдЬреЗрдПрд╕ рд╕реНрдЯреИрдХ рддрдХ рд╕реАрдорд┐рдд рд╣реИ, рдЗрд╕рд▓рд┐рдП рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рд▓реВрдк рдХрд░рдиреЗ рдХрд╛ рд╕рд╛рдорд╛рдиреНрдп рддрд░реАрдХрд╛ рдирд╣реАрдВ рд╣реИред
- рджреБрднрд╛рд╖рд┐рдпрд╛ рдзреАрдорд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ рдмрд╣реБрдд рдзреАрдореА рд╣реИред
рдЕрдм рд╣рдо рдЗрд╕ рддрдереНрдп рдкрд░ рдзреНрдпрд╛рди рджрд┐рдП рдмрд┐рдирд╛ рдкрд╣рд▓рд╛ рджреЛрд╖ рдареАрдХ рдХрд░реЗрдВрдЧреЗ рдХрд┐ рджреБрднрд╛рд╖рд┐рдпрд╛ рдФрд░ рднреА рдзреАрдорд╛ рд╣реЛ рдЬрд╛рдПрдЧрд╛ред рд╣рдо рджреБрднрд╛рд╖рд┐рдпрд╛ рдХреЛ "рдирд┐рд░рдВрддрд░рддрд╛-рдЧреБрдЬрд░ рд╢реИрд▓реА" (рд╕реАрдкреАрдПрд╕) рд╢реИрд▓реА рдореЗрдВ рдлрд┐рд░ рд╕реЗ рд▓рд┐рдЦреЗрдВрдЧреЗред
"рдирд┐рд░рдВрддрд░рддрд╛ рд╣рд╕реНрддрд╛рдВрддрд░рдг" рдХреНрдпрд╛ рд╣реИ
рдЖрдк рд╣рд░ рд╕рдордп NodeJS рдореЗрдВ рдРрд╕рд╛ рдХрд░рддреЗ рд╣реИрдВ:
fs.readFile("file.txt", "utf8", function CC(error, data){
рд╣рд░ рдХрджрдо рдкрд░ рдПрдХ рдХреЙрд▓рдмреИрдХ рд╣реЛрддрд╛ рд╣реИ рдЬрд┐рд╕реЗ рдЖрдкрдХреЛ рдЬрд╛рд░реА рд░рдЦрдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрдиреЗ рдкрд░ рдХреЙрд▓ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред рдирд┐рд░рдВрддрд░рддрд╛ рд╣рд╕реНрддрд╛рдВрддрд░рдг рд╢реИрд▓реА рдирд┐рдпрдВрддреНрд░рдг рд╣рд╕реНрддрд╛рдВрддрд░рдг рдХреЛ "рд╕реНрдкрд╖реНрдЯ" рдмрдирд╛рддреА рд╣реИ - рдЖрдк return
, throw
, break
рдпрд╛ continue
рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд░рддреЗ return
ред рдХреЛрдб рдореЗрдВ рдХреЛрдИ рдирд┐рд╣рд┐рдд рдЫрд▓рд╛рдВрдЧ рдирд╣реАрдВ рд╣реИред рдЖрдк рдЕрддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ рдХрд╛рд░реНрдпреЛрдВ рдХреЗ рд╕рд╛рде рдпрд╛ рдЗрд╕рдХреЗ for
рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ, рд╣рдореЗрдВ рдкреНрд░реЛрдЧреНрд░рд╛рдорд┐рдВрдЧ рднрд╛рд╖рд╛ рдореЗрдВ рдЙрдирдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдХреНрдпреЛрдВ рд╣реИ?
рдПрдХ рдирд┐рд░рдВрддрд░рддрд╛ рдХреЛ рдкреНрд░реЗрд╖рд┐рдд рдХрд░рдиреЗ рдХреА рд╢реИрд▓реА рдореЗрдВ рдХреЛрдб рд▓рд┐рдЦрдирд╛ рдореБрд╢реНрдХрд┐рд▓ рдФрд░ рдЖрд╕рд╛рди рд╣реИ, рд▓реЗрдХрд┐рди рд╣рдо рдХреЗрд╡рд▓ рдЙрд╕ рд╢реИрд▓реА рдореЗрдВ рджреБрднрд╛рд╖рд┐рдпрд╛ рдХреЛ рдлрд┐рд░ рд╕реЗ рд▓рд┐рдЦреЗрдВрдЧреЗред
рдлрд╝рдВрдХреНрд╢рди рдХрд╛ evaluate
рдХрд░реЗрдВ
evaluate
рдлрд╝рдВрдХреНрд╢рди рдХреЛ рддреАрди рддрд░реНрдХ рдкреНрд░рд╛рдкреНрдд рд╣реЛрдВрдЧреЗ: рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐ (рдПрдПрд╕рдЯреА), рд╕рдВрджрд░реНрдн (рдкрд░реНрдпрд╛рд╡рд░рдг), рдФрд░ рдлрд╝рдВрдХреНрд╢рди рдЬрд┐рд╕реЗ рдкрд░рд┐рдгрд╛рдо рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИред рдпрд╣рд╛рдБ рдХреЛрдб рд╣реИ, рдкреНрд░рддреНрдпреЗрдХ рдЯреБрдХрдбрд╝реЗ рдХреЗ рд▓рд┐рдП рдПрдХ рд╕реНрдкрд╖реНрдЯреАрдХрд░рдг рд╣реИ:
function evaluate(exp, env, callback) { switch (exp.type) {
рд╕реНрдерд┐рд░рд╛рдВрдХ рдХреЗ рд▓рд┐рдП, рд╣рдо рдХреЗрд╡рд▓ рдЙрдирдХрд╛ рдорд╛рди рд▓реМрдЯрд╛рдПрдВрдЧреЗред рд▓реЗрдХрд┐рди рдпрд╛рдж рд░рдЦреЗрдВ, рд╣рдорд╛рд░реЗ рдкрд╛рд╕ return
рдирд╣реАрдВ рд╣реИ - рдЗрд╕рдХреЗ рдмрдЬрд╛рдп рд╣рдо рдХреЗрд╡рд▓ рдХреЙрд▓рдмреИрдХ рдХрд╣рддреЗ рд╣реИрдВ рдФрд░ рдореВрд▓реНрдп рдкрд╛рд╕ рдХрд░рддреЗ рд╣реИрдВред
case "num": case "str": case "bool": callback(exp.value); return;
var
рдиреЛрдб рднреА рд╕рд░рд▓ рд╣реИ - рд╕рдВрджрд░реНрдн рд╕реЗ рдЪрд░ рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВ рдФрд░ рдЗрд╕реЗ рдлрд╝рдВрдХреНрд╢рди рдореЗрдВ рдкрд╛рд╕ рдХрд░реЗрдВ:
case "var": callback(env.get(exp.value)); return;
assign
рдиреЛрдбреНрд╕ рдХреЗ рд▓рд┐рдП, рд╣рдореЗрдВ рдмрд╛рдИрдВ рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐ ( right
) рдХрд╛ рдореВрд▓реНрдп рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо evaluate
рдХрд╣рддреЗ рд╣реИрдВ, рдПрдХ рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдкрд╛рд╕ рдХрд░рдирд╛ рдЬреЛ рдкрд░рд┐рдгрд╛рдо рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдЧрд╛ (рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐ рдХреЗ рджрд╛рдИрдВ рдУрд░)ред рдФрд░ рдлрд┐рд░ рд╣рдо рдЪрд░ рдХреЛ рд╡рд░реНрддрдорд╛рди рдорд╛рди рдореЗрдВ рдЪрд░ рд╕реЗрдЯ рдХрд░рддреЗ рд╣реБрдП рдЪрд░ рдорд╛рди рдХреЗ рд╕рд╛рде callback
рдХрд╣рддреЗ рд╣реИрдВ:
case "assign": if (exp.left.type != "var") throw new Error("Cannot assign to " + JSON.stringify(exp.left)); evaluate(exp.right, env, function(right){ callback(env.set(exp.left.value, right)); }); return;
рдЯрд╛рдЗрдк binary
рдиреЛрдбреНрд╕ рдХреЗ рд▓рд┐рдП рд▓рдЧрднрдЧ рд╕рдорд╛рди рд╣реИ, рд▓реЗрдХрд┐рди рдпрд╣рд╛рдВ рд╣рдореЗрдВ рдкрд╣рд▓реЗ left
рдХреНрд╖реЗрддреНрд░ рдХрд╛ рдореВрд▓реНрдп рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рдФрд░ рдЙрд╕рдХреЗ рдмрд╛рдж рд╣реА right
рдХреНрд╖реЗрддреНрд░ рдХрд╛ рдореВрд▓реНрдпред рддрдм рд╣рдо рд╕рд┐рд░реНрдл рдХреЙрд▓рдмреИрдХ рдХрд╣рддреЗ рд╣реИрдВ, рдСрдкрд░реЗрд╢рди рдХреЗ рдкрд░рд┐рдгрд╛рдо рдХреЛ рдкрд╛рд╕ рдХрд░рддреЗ рд╣реБрдП:
case "binary": evaluate(exp.left, env, function(left){ evaluate(exp.right, env, function(right){ callback(apply_op(exp.operator, left, right)); }); }); return;
let
рдиреЛрдб рдЕрдзрд┐рдХ рдЬрдЯрд┐рд▓ рджрд┐рдЦрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдпрд╣ рд╕рд░рд▓ рд╣реИред рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдХреБрдЫ рд╕рдВрдЦреНрдпрд╛ рдореЗрдВ рдЪрд░ рд╣реИрдВред рдЙрдирдХрд╛ def
рдХреНрд╖реЗрддреНрд░ (рдкреНрд░рд╛рд░рдВрднрд┐рдХ рдореВрд▓реНрдп) рдЦрд╛рд▓реА рд╣реЛ рд╕рдХрддрд╛ рд╣реИ, рдЬрд┐рд╕ рд╕реНрдерд┐рддрд┐ рдореЗрдВ рд╣рдо рдЗрд╕реЗ false
рд╕реЗрдЯ рдХрд░реЗрдВрдЧреЗред рд▓реЗрдХрд┐рди рдЕрдЧрд░ рдХреЛрдИ рдореВрд▓реНрдп рд╣реИ, рддреЛ рд╣рдореЗрдВ рдЗрд╕реЗ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкреБрдирд░рд╛рд╡рд░реНрддреА рд░реВрдк рд╕реЗ evaluate
рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред
рдпрджрд┐ рдЖрдкрдиреЗ рдкрд╣рд▓реЗ NodeJS рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд┐рдпрд╛ рд╣реИ, рддреЛ рдЖрдкрдиреЗ рдкрд╣рд▓реЗ рднреА рдХрдИ рдмрд╛рд░ рдРрд╕рд╛ рдХрд┐рдпрд╛ рд╣реИред рдХреЙрд▓рдмреИрдХ рдХреЗ рдХрд╛рд░рдг, рд╣рдо рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдЗрд╕рд▓рд┐рдП, рд╣рдореЗрдВ рдЗрди рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐рдпреЛрдВ рдХреА рдПрдХ рдмрд╛рд░ рдореЗрдВ рд╡реНрдпрд╛рдЦреНрдпрд╛ рдХрд░рдиреА рдЪрд╛рд╣рд┐рдП ( evaluate
рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдЕрддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ рдХреЗ рд░реВрдк рдореЗрдВ рдХрд▓реНрдкрдирд╛ рдХрд░реЗрдВ)ред рдиреАрдЪреЗ рджрд┐рдП рдЧрдП loop
рдлрд╝рдВрдХреНрд╢рди (рддреБрд░рдВрдд рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИ) рдХреЛ рд╕рдВрджрд░реНрдн рдФрд░ рдЙрд╕ рдкрд░рд┐рднрд╛рд╖рд╛ рдХреА рд╕рдВрдЦреНрдпрд╛ рдорд┐рд▓рддреА рд╣реИ рдЬрд┐рд╕реЗ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИ:
- рдпрджрд┐ рдпрд╣ рд╕рдВрдЦреНрдпрд╛ рдЪрд░ (
vars.length
) рдХреА рд╕рдВрдЦреНрдпрд╛ рдХреЗ рдмрд░рд╛рдмрд░ рд╣реИ, рддреЛ рдЗрд╕рдХрд╛ рдорддрд▓рдм рд╣реИ рдХрд┐ рд╣рдордиреЗ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рд╕рднреА рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐рдпреЛрдВ рдХреЛ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд┐рдпрд╛ рд╣реИ рддрд╛рдХрд┐ рд╣рдо рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐ рдХреЗ рд╢рд░реАрд░ рдХреЛ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░ рд╕рдХреЗрдВред рдХреГрдкрдпрд╛ рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐ рдЗрд╕ рдмрд╛рд░ рд╣рдо callback
рдирд╣реАрдВ рдХрд╣рддреЗ callback
, рд▓реЗрдХрд┐рди рдЗрд╕реЗ evaluate
рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкрд╛рд╕ рдХрд░рддреЗ рд╣реИрдВ, рдЬреЛ рддрдм рдЗрд╕реЗ рдХреЙрд▓ рдХрд░реЗрдЧрд╛ред - рдпрджрд┐ рдпрд╣ рд╕рдВрдЦреНрдпрд╛ рдХрдо рд╣реИ, рддреЛ рдЖрдкрдХреЛ рд╡рд░реНрддрдорд╛рди рдкрд░рд┐рднрд╛рд╖рд╛ рдХреА рдЧрдгрдирд╛ рдХрд░рдиреЗ рдФрд░ рд╕рдВрджрд░реНрдн рдХреА рдкреНрд░рддрд┐рд▓рд┐рдкрд┐ рдмрдирд╛рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рдПрдХ рдлрд╝рдВрдХреНрд╢рди рдкрд╛рд╕ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ рдЬреЛ
loop(scope, i + 1)
рдХрд╣реЗрдЧрд╛ред
case "let": (function loop(env, i){ if (i < exp.vars.length) { var v = exp.vars[i]; if (v.def) evaluate(v.def, env, function(value){ var scope = env.extend(); scope.def(v.name, value); loop(scope, i + 1); }); else { var scope = env.extend(); scope.def(v.name, false); loop(scope, i + 1); } } else { evaluate(exp.body, env, callback); } })(env, 0); return;
lambda
рдиреЛрдб рдХреЛ рдкрд╣рд▓реЗ рдХреА рддрд░рд╣ рдПрдХ рдЕрд▓рдЧ рдлрд╝рдВрдХреНрд╢рди рдореЗрдВ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛:
case "lambda": callback(make_lambda(env, exp)); return;
if
рд╡реНрдпрд╛рдЦреНрдпрд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо рдкрд╣рд▓реЗ рд╕реНрдерд┐рддрд┐ рдХреА рд╡реНрдпрд╛рдЦреНрдпрд╛ рдХрд░рддреЗ рд╣реИрдВред рдпрджрд┐ рдпрд╣ рдЧрд▓рдд рдирд╣реАрдВ рд╣реИ, рддреЛ рд╣рдо then
рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐ рдХреА рд╡реНрдпрд╛рдЦреНрдпрд╛ рдХрд░рддреЗ рд╣реИрдВ, рджреВрд╕рд░реЗ рдорд╛рдорд▓реЗ рдореЗрдВ, рдпрджрд┐ рдХреЛрдИ рдПрдХ рд╣реИ, рддреЛ рдЙрд╕рдХреА рд╡реНрдпрд╛рдЦреНрдпрд╛ рдХрд░реЗрдВ рдпрд╛ рдирд╣реАрдВ рддреЛ false
ред рдкрд╣рд▓реЗ рдХреА рддрд░рд╣, then
рдФрд░ then
рд╣рдо рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐ рдХреА "рдирд┐рд╖реНрдкрд╛рджрди рдХреЗ рдмрд╛рдж рдХреА рдЬрд╛рдиреЗ рд╡рд╛рд▓реА рдХрд╛рд░реНрд░рд╡рд╛рдИ" рдХреЗ рд░реВрдк рдореЗрдВ callback
рдкрд╛рд╕ рдХрд░рддреЗ рд╣реИрдВ:
case "if": evaluate(exp.cond, env, function(cond){ if (cond !== false) evaluate(exp.then, env, callback); else if (exp.else) evaluate(exp.else, env, callback); else callback(false); }); return;
prog
рдиреЛрдб рдХреЛ let
рдиреЛрдб рдХреЗ рд╕рдорд╛рди рд╕рдордЭрд╛ рдЬрд╛рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдЗрд╕ рдЕрдВрддрд░ рдХреЗ рд╕рд╛рде рдХрд┐ рд╣рдореЗрдВ рд╕рдВрджрд░реНрдн рдХреА рдкреНрд░рддрд┐рд▓рд┐рдкрд┐ рдмрдирд╛рдиреЗ рдпрд╛ рдЪрд░ рдХреЛ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИред рдФрд░ рдлрд┐рд░, рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдПрдХ loop
рдлрд╝рдВрдХреНрд╢рди рд╣реИ рдЬреЛ рдПрдХ рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐ рд╕рдВрдЦреНрдпрд╛ рд▓реЗрддрд╛ рд╣реИред рдЬрдм рдпрд╣ prog.length
рдмрд░рд╛рдмрд░ prog.length
, рддреЛ рд╣рдордиреЗ рд╕рднреА рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐рдпреЛрдВ рдХреЛ рдкреВрд░рд╛ рдХрд░ рд▓рд┐рдпрд╛ рд╣реИ рдФрд░ рд╣рдо рдХреЗрд╡рд▓ рдЕрдВрддрд┐рдо рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐ рдХрд╛ рдкрд░рд┐рдгрд╛рдо рджреЗрддреЗ рд╣реИрдВ (рд╢рдмреНрдж "рд╡рд╛рдкрд╕реА" рд╕реЗ рдореЗрд░рд╛ рдорддрд▓рдм рд╣реИ рдХрд┐ рд╣рдо рдЗрд╕рдХреЗ рд╕рд╛рде callback
рдХрд╣рддреЗ рд╣реИрдВ)ред рдХреГрдкрдпрд╛ рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐ рд╣рдо loop
рдлрд╝рдВрдХреНрд╢рди рдХреЗ рддрд░реНрдХ рдХреЗ рд░реВрдк рдореЗрдВ рдЗрд╕реЗ рдкрд╛рд░рд┐рдд рдХрд░рдХреЗ рдЕрдВрддрд┐рдо рдореВрд▓реНрдп рдХреЛ рдпрд╛рдж рдХрд░рддреЗ рд╣реИрдВ (рд╢реБрд░реБрдЖрдд рдореЗрдВ рдпрд╣ рдЙрд╕ рд╕реНрдерд┐рддрд┐ рдХреЗ рд▓рд┐рдП false
рдЬрдм рд╢рд░реАрд░ рдЦрд╛рд▓реА рд╣реИ):
case "prog": (function loop(last, i){ if (i < exp.prog.length) evaluate(exp.prog[i], env, function(val){ loop(val, i + 1); }); else { callback(last); } })(false, 0); return;
рдПрдХ рдкреНрд░рдХрд╛рд░ рдХреА call
рд╣рдореЗрдВ func
рд╡реНрдпрд╛рдЦреНрдпрд╛ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ рдФрд░ рдлрд┐рд░ рд╕рднреА рддрд░реНрдХ рдХреНрд░рдо рдореЗрдВ рд╣реИрдВред рдФрд░ рдлрд┐рд░, рдПрдХ loop
рдлрд╝рдВрдХреНрд╢рди рд╣реЛрддрд╛ рд╣реИ рдЬреЛ рдПрдХ рд╣реА рд╕рд┐рджреНрдзрд╛рдВрдд рдкрд░ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ рдЬреИрд╕реЗ let
рдпрд╛ prog
, рдЗрд╕ рдЕрдВрддрд░ рдХреЗ рд╕рд╛рде рдХрд┐ рдЕрдм рдпрд╣ рдПрдХ рдкрд░рд┐рдгрд╛рдо рдХреЗ рд░реВрдк рдореЗрдВ рдПрдХ рд╕рд░рдгреА рдмрдирд╛рддрд╛ рд╣реИ:
case "call": evaluate(exp.func, env, function(func){ (function loop(args, i){ if (i < exp.args.length) evaluate(exp.args[i], env, function(arg){ args[i + 1] = arg; loop(args, i + 1); }); else { func.apply(null, args); } })([ callback ], 0); }); return;
рдареАрдХ рд╣реИ, рдорд╛рдирдХ рд╕рдорд╛рдкреНрдд рд╣реЛрдирд╛: рдЕрдЧрд░ рд╣рдореЗрдВ рдирд╣реАрдВ рдкрддрд╛ рдХрд┐ рдХреНрдпрд╛ рдХрд░рдирд╛ рд╣реИ, рддреЛ рдПрдХ рдЕрдкрд╡рд╛рдж рдлреЗрдВрдХреЗрдВ:
default: throw new Error("I don't know how to evaluate " + exp.type); } }
рдЖрдк рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ рдКрдкрд░ рджрд┐рдпрд╛ рдЧрдпрд╛ рдкреНрд░рддреНрдпреЗрдХ case
return
рдХреАрд╡рд░реНрдб рдХреЗ рд╕рд╛рде рд╕рдорд╛рдкреНрдд рд╣реЛрддрд╛ рд╣реИред рд▓реЗрдХрд┐рди рдХреЛрдИ рд╡рд╛рдкрд╕реА рдореВрд▓реНрдп рдирд╣реАрдВ рд╣реИ - рдкрд░рд┐рдгрд╛рдо рд╣рдореЗрд╢рд╛ callback
рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдкрд╛рд╕ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред
рдирдпрд╛ make_lambda
рдлрд╝рдВрдХреНрд╢рди
рдЗрд╕ рд╡реНрдпрд╛рдЦреНрдпрд╛рдХрд╛рд░ рдореЗрдВ, рд╕рднреА рдлрд╝рдВрдХреНрд╢рди рдкрд╣рд▓реЗ рддрд░реНрдХ рдХреЗ рд░реВрдк рдореЗрдВ рдПрдХ "рдирд┐рд░рдВрддрд░рддрд╛" рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВрдЧреЗ - рдкрд░рд┐рдгрд╛рдо рдкрд╛рд░рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╣рдореЗрдВ рдЬрд┐рд╕ рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдХреЙрд▓ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред рдЗрд╕рдХреЗ рдмрд╛рдж рдлрд╝рдВрдХреНрд╢рди рдХреЗ рд▓рд┐рдП рд╕рд╛рдорд╛рдиреНрдп рддрд░реНрдХ рд╣реИрдВред рдпрд╣рд╛рдБ make_lambda
рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рдирдпрд╛ рдХреЛрдб рд╣реИ:
function make_lambda(env, exp) { if (exp.name) { env = env.extend(); env.def(exp.name, lambda); } function lambda(callback) { var names = exp.vars; var scope = env.extend(); for (var i = 0; i < names.length; ++i) scope.def(names[i], i + 1 < arguments.length ? arguments[i + 1] : false); evaluate(exp.body, scope, callback); } return lambda; }
рд╡рд╣ рдЬреНрдпрд╛рджрд╛ рдЕрд▓рдЧ рдирд╣реАрдВ рд╣реИред рдпрд╣ рдирдП рдЪрд░ рдХреЛ рдПрдХ рдирдП рд╕рдВрджрд░реНрдн рдореЗрдВ рдЬреЛрдбрд╝рддрд╛ рд╣реИред рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рд╣рдореЗрдВ рдпрд╣ рд╡рд┐рдЪрд╛рд░ рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП рдХрд┐ рдкрд╣рд▓рд╛ рддрд░реНрдХ callback
ред рдЕрдВрдд рдореЗрдВ, evaluate
рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдлрд╝рдВрдХреНрд╢рди рдХреЛрдб рдХреЛ рдПрдХ рдирдП рд╕рдВрджрд░реНрдн рдореЗрдВ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди, рдкрд╣рд▓реЗ рдХреА рддрд░рд╣, рд╣рдо callback
рдкрд╛рд╕ рдХрд░рддреЗ callback
ред
рд╡реИрд╕реЗ, рдпрд╣ рдПрдХрдорд╛рддреНрд░ рд╕реНрдерд╛рди рд╣реИ рдЬрд┐рд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдореИрдВрдиреЗ рд▓реВрдк рдХреЗ for
рдХрд┐рдпрд╛ рдерд╛ред рдРрд╕рд╛ рддрдм рд╣реЛрддрд╛ рд╣реИ рдХреНрдпреЛрдВрдХрд┐ call
рдиреЛрдб рд╕рдВрд╕рд╛рдзрд┐рдд рд╣реЛрдиреЗ рдкрд░ рддрд░реНрдХ рдорд╛рди рдкрд╣рд▓реЗ рд╣реА рдЧрдгрдирд╛ рдХрд░ рд▓рд┐рдП рдЬрд╛рддреЗ рд╣реИрдВред
рдореВрд▓ рдХрд╛рд░реНрдп
рдЗрд╕ рджреБрднрд╛рд╖рд┐рдпрд╛ рдореЗрдВ, рдореВрд▓ рдХрд╛рд░реНрдпреЛрдВ рдХреЛ рдкрд╣рд▓реЗ рддрд░реНрдХ рдХреЗ рд░реВрдк рдореЗрдВ callback
рдорд┐рд▓рддрд╛ рд╣реИред рджреЗрд╢реА рдХрд╛рд░реНрдпреЛрдВ рдХреЛ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░рддреЗ рд╕рдордп рд╣рдореЗрдВ рдпрд╣ рдпрд╛рдж рд░рдЦрдирд╛ рдЪрд╛рд╣рд┐рдПред рдпрд╣рд╛рдБ рдирдП рджреБрднрд╛рд╖рд┐рдпрд╛ рдХреЗ рд▓рд┐рдП рдирдореВрдирд╛ рдХреЛрдб рд╣реИ:
var code = "sum = lambda(x, y) x + y; print(sum(2, 3));"; var ast = parse(TokenStream(InputStream(code))); var globalEnv = new Environment();
рдереЛрдбрд╝рд╛ рдкрд░реАрдХреНрд╖рдг
рдЖрдЗрдП рдлрд┐рд░ рд╕реЗ рдлрд╛рдЗрдмреЛрдиреИрдЪрд┐ рд╕рдВрдЦреНрдпрд╛рдУрдВ рдХреА рдЧрдгрдирд╛ рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░реЗрдВ:
fib = ╬╗(n) if n < 2 then n else fib(n - 1) + fib(n - 2); time( ╬╗() println(fib(10)) );
рд▓реЗрдХрд┐рди, рдпрджрд┐ рд╣рдо 27 рд╡реЗрдВ рдирдВрдмрд░ рдХреЛ рдЦреЛрдЬрдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рд╣рдореЗрдВ рд╕реНрдЯреИрдХ рдУрд╡рд░рдлреНрд▓реЛ рдорд┐рд▓рддрд╛ рд╣реИред рд╕рд╛рдорд╛рдиреНрдп рддреМрд░ рдкрд░, рд╕реНрдЯреИрдХ рдЕрдм рдмрд╣реБрдд рддреЗрдЬреА рд╕реЗ рдмрдврд╝ рд░рд╣рд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдпрд╣ рдкрддрд╛ рдЪрд▓рд╛ рд╣реИ рдХрд┐ рдЕрдм рд╣рдо рдлрд╛рдЗрдмреЛрдиреИрдЪрд┐ рд╕рдВрдЦреНрдпрд╛ рдХреЛ рдХреЗрд╡рд▓ 12 рд╡реЗрдВ (рдХрдо рд╕реЗ рдХрдо рдореЗрд░реЗ рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдореЗрдВ) рдЧрд┐рди рд╕рдХрддреЗ рд╣реИрдВред рдпрд╣ рдмрд╣реБрдд рдЕрдЪреНрдЫрд╛ рдирд╣реАрдВ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдЖрдкрдХреЛ рдЗрд╕реЗ рдХрд┐рд╕реА рддрд░рд╣ рдареАрдХ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред
рд╣рдо рдвреЗрд░ рдХреА рд░рдХреНрд╖рд╛ рдХрд░рддреЗ рд╣реИрдВ
рд╕реАрдкреАрдПрд╕ рджреБрднрд╛рд╖рд┐рдпрд╛ рдореЗрдВ, рд╕реНрдЯреИрдХ рдмрд╣реБрдд рддреЗрдЬреА рд╕реЗ рдмрдврд╝рддрд╛ рд╣реИ рдХреНрдпреЛрдВрдХрд┐ рджреБрднрд╛рд╖рд┐рдпрд╛ рд╣рдореЗрд╢рд╛ рдХрд╛рд░реНрдпреЛрдВ рдХреЛ рдкреБрдирд░рд╛рд╡рд░реНрддреА рдХрд╣рддрд╛ рд╣реИ, рдХрднреА рднреА рдкрд░рд┐рдгрд╛рдо рдирд╣реАрдВ рджреЗрддрд╛ рд╣реИред рд╣рд╛рд▓рд╛рдВрдХрд┐ рд╣рдо рджреБрднрд╛рд╖рд┐рдпрд╛ рдореЗрдВ return
, рд╣рдореЗрдВ рдЙрдирдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдмрд╣реБрдд рдЧрд╣рд░реА рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ рдХреЗ рдорд╛рдорд▓реЗ рдореЗрдВ, рд╣рдо рдЙрди рддрдХ рдХрднреА рдирд╣реАрдВ рдкрд╣реБрдВрдЪрддреЗ рд╣реИрдВред
рдЖрдЗрдП рдХрд▓реНрдкрдирд╛ рдХрд░реЗрдВ рдХрд┐ рдПрдХ рдмрд╣реБрдд рд╣реА рд╕рд░рд▓ рдХрд╛рд░реНрдпрдХреНрд░рдо рдХреЗ рд▓рд┐рдП рд╣рдорд╛рд░рд╛ рд╕реНрдЯреИрдХ рдХреИрд╕рд╛ рджрд┐рдЦрддрд╛ рд╣реИред рдореИрдВ рдЫрджреНрдо рдХреЛрдб рджрд┐рдЦрд╛рдКрдВрдЧрд╛ рдФрд░ рдореИрдВрдиреЗ env
рдирд╣реАрдВ рдЬреЛрдбрд╝рд╛ рдХреНрдпреЛрдВрдХрд┐ рдпрд╣ рдпрд╣рд╛рдВ рдХреЛрдИ рднреВрдорд┐рдХрд╛ рдирд╣реАрдВ рдирд┐рднрд╛рддрд╛ рд╣реИ:
print(1 + 2 * 3);
рдХреЗрд╡рд▓ рдЕрдВрддрд┐рдо рдХреЙрд▓ рдХреЗ рдмрд╛рдж, рдмреЗрдХрд╛рд░ return
рдХрд╛ рдПрдХ рд▓рдВрдмрд╛ рдХреНрд░рдо рд╕реНрдЯреИрдХ рдХреЛ рдХрдо рдХрд░рддрд╛ рд╣реИред рдпрджрд┐ рд╣рдо рдПрдХ рд╕рд╛рдзрд╛рд░рдг рдкреНрд░реЛрдЧреНрд░рд╛рдо рдХреЗ рд▓рд┐рдП рдмрд╣реБрдд рдЕрдзрд┐рдХ рд╕реНрдЯреИрдХ рд╕реНрдкреЗрд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдпрд╣ рдХрд▓реНрдкрдирд╛ рдХрд░рдирд╛ рдореБрд╢реНрдХрд┐рд▓ рд╣реИ рдХрд┐ fib(13)
рд▓рд┐рдП рдХреНрдпрд╛ рд╣реЛрдЧрд╛ред
рдвреЗрд░ рдХреА рд╕реБрд░рдХреНрд╖рд╛
рд╣рдорд╛рд░реЗ рдирдП рджреБрднрд╛рд╖рд┐рдпрд╛ рдореЗрдВ, рд╕реНрдЯреИрдХ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИред рдПрдХ callback
рдореЗрдВ рдХреБрдЫ рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐ рд╣реЛрдиреЗ рдХреЗ рдмрд╛рдж рд╕рднреА рдХреЛ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИ, рдЬрд┐рд╕реЗ рдПрдХ рддрд░реНрдХ рдХреЗ рд░реВрдк рдореЗрдВ рдкрд╛рд░рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рддреЛ рдпрд╣рд╛рдВ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдПрдХ рд╕рд╡рд╛рд▓ рд╣реИ: рдХреНрдпрд╛ рд╣реЛрдЧрд╛ рдпрджрд┐ рдЬрд╛рд╡рд╛рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдиреЗ рд╕реНрдЯреИрдХ рдХреЛ "рдбрдВрдк" рдХрд░рдирд╛ рд╕рдВрднрд╡ рдмрдирд╛ рджрд┐рдпрд╛ред рдлрд┐рд░ рд╣рдо рд╕реНрдЯреИрдХ рдХреЛ рдЫреЛрдбрд╝ рд╕рдХрддреЗ рд╣реИрдВ, рдФрд░ рдЕрд╕реАрдо рд░реВрдк рд╕реЗ рдЧрд╣рд░реА рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ рдХрд╛рдо рдХрд░реЗрдЧреАред
рдЖрдЗрдП рдХрд▓реНрдкрдирд╛ рдХрд░реЗрдВ рдХрд┐ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдПрдХ GUARD
рдлрд╝рдВрдХреНрд╢рди рд╣реИ рдЬреЛ рдРрд╕рд╛ рдХрд░ рд╕рдХрддрд╛ рд╣реИред рдЗрд╕реЗ рджреЛ рдорд╛рди рджрд┐рдП рдЬрд╛рддреЗ рд╣реИрдВ: рдХреЙрд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдлрд╝рдВрдХреНрд╢рди, рдФрд░ рддрд░реНрдХ рдЬреЛ рдЗрд╕реЗ рдкрд╛рд░рд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдпрд╣ рдЬрд╛рдВрдЪрддрд╛ рд╣реИ: рдпрджрд┐ рд╕реНрдЯреИрдХ рдмрд╣реБрдд рдЧрд╣рд░рд╛ рд╣реИ, рддреЛ рдпрд╣ рд╕реНрдЯреИрдХ рдХреЛ рд╕рд╛рдл рдХрд░реЗрдЧрд╛ рдФрд░ рдкрд╛рд░рд┐рдд рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдХреЙрд▓ рдХрд░реЗрдЧрд╛ред рдПрдХ рдЕрдиреНрдп рдорд╛рдорд▓реЗ рдореЗрдВ, рд╡рд╣ рдХреБрдЫ рдирд╣реАрдВ рдХрд░рддреА рд╣реИред
рдирдП рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реБрдП, рд╣рдо рдиреАрдЪреЗ рджрд┐рдЦрд╛рдП рдЧрдП рдЕрдиреБрд╕рд╛рд░ рджреБрднрд╛рд╖рд┐рдпрд╛ рдХреЛ рдлрд┐рд░ рд╕реЗ рд▓рд┐рдЦрддреЗ рд╣реИрдВред рдореИрдВ рдкреНрд░рддреНрдпреЗрдХ рд╡реНрдпрдХреНрддрд┐рдЧрдд рдорд╛рдорд▓реЗ рдкрд░ рдЯрд┐рдкреНрдкрдгреА рдирд╣реАрдВ рдХрд░реВрдВрдЧрд╛, рдкрд╣рд▓реЗ рдмрддрд╛рдпрд╛ рдЧрдпрд╛ рдХреЛрдб рд╣реИ, рд▓реЗрдХрд┐рди GUARD
рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣рд╛ рд╣реИ:
function evaluate(exp, env, callback) { GUARD(evaluate, arguments); switch (exp.type) { case "num": case "str": case "bool": callback(exp.value); return; case "var": callback(env.get(exp.value)); return; case "assign": if (exp.left.type != "var") throw new Error("Cannot assign to " + JSON.stringify(exp.left)); evaluate(exp.right, env, function CC(right){ GUARD(CC, arguments); callback(env.set(exp.left.value, right)); }); return; case "binary": evaluate(exp.left, env, function CC(left){ GUARD(CC, arguments); evaluate(exp.right, env, function CC(right){ GUARD(CC, arguments); callback(apply_op(exp.operator, left, right)); }); }); return; case "let": (function loop(env, i){ GUARD(loop, arguments); if (i < exp.vars.length) { var v = exp.vars[i]; if (v.def) evaluate(v.def, env, function CC(value){ GUARD(CC, arguments); var scope = env.extend(); scope.def(v.name, value); loop(scope, i + 1); }); else { var scope = env.extend(); scope.def(v.name, false); loop(scope, i + 1); } } else { evaluate(exp.body, env, callback); } })(env, 0); return; case "lambda": callback(make_lambda(env, exp)); return; case "if": evaluate(exp.cond, env, function CC(cond){ GUARD(CC, arguments); if (cond !== false) evaluate(exp.then, env, callback); else if (exp.else) evaluate(exp.else, env, callback); else callback(false); }); return; case "prog": (function loop(last, i){ GUARD(loop, arguments); if (i < exp.prog.length) evaluate(exp.prog[i], env, function CC(val){ GUARD(CC, arguments); loop(val, i + 1); }); else { callback(last); } })(false, 0); return; case "call": evaluate(exp.func, env, function CC(func){ GUARD(CC, arguments); (function loop(args, i){ GUARD(loop, arguments); if (i < exp.args.length) evaluate(exp.args[i], env, function CC(arg){ GUARD(CC, arguments); args[i + 1] = arg; loop(args, i + 1); }); else { func.apply(null, args); } })([ callback ], 0); }); return; default: throw new Error("I don't know how to evaluate " + exp.type); } }
рдЕрдирд╛рдо рдлрд╝рдВрдХреНрд╢рдВрд╕ рдХреЗ рд▓рд┐рдП, рд╣рдореЗрдВ рдПрдХ рдирд╛рдо рдЬреЛрдбрд╝рдирд╛ рд╣реЛрдЧрд╛ рддрд╛рдХрд┐ рд╣рдо рдЙрдиреНрд╣реЗрдВ GUARD
рдлрд╝рдВрдХреНрд╢рди рдореЗрдВ рдкрд╛рд╕ рдХрд░ рд╕рдХреЗрдВред рдореИрдВрдиреЗ CC
( current continuation
) рдирд╛рдо рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ред рдЖрдк arguments.callee
рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред arguments.callee
, рд▓реЗрдХрд┐рди рдпрд╣ рдПрдХ рдкреБрд░рд╛рдирд╛ рдПрдкреАрдЖрдИ рд╣реИред
рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, make_lambda
рдореЗрдВ рд╕рдорд╛рди рдкрд░рд┐рд╡рд░реНрддрди:
function make_lambda(env, exp) { if (exp.name) { env = env.extend(); env.def(exp.name, lambda); } function lambda(callback) { GUARD(lambda, arguments);
GUARD
рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдмрд╣реБрдд рд╕рд░рд▓ рд╣реИред рдХреИрд╕реЗ рдПрдХ рдЧрд╣рд░реА рдХреЙрд▓ рд╕реЗ рдмрд╛рд╣рд░ рдирд┐рдХрд▓рдиреЗ рдХреЗ рд▓рд┐рдП? рдЕрдкрд╡рд╛рджреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдПрдХ рд╡реИрд╢реНрд╡рд┐рдХ рдЪрд░ рд╣реЛрдЧрд╛ рдЬреЛ рдпрд╣ рдЗрдВрдЧрд┐рдд рдХрд░реЗрдЧрд╛ рдХрд┐ рд╣рдо рдХрд┐рддрдиреА рдЕрдзрд┐рдХ рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдпрджрд┐ рдпрд╣ рд╢реВрдиреНрдп рдкрд░ рдкрд╣реБрдВрдЪ рдЬрд╛рддрд╛ рд╣реИ, рддреЛ рд╣рдо Continuation
рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЛ рдлреЗрдВрдХ рджреЗрддреЗ рд╣реИрдВ, рдЬрд┐рд╕рдореЗрдВ рдПрдХ рдирд┐рд░рдВрддрд░рддрд╛ рд╣реЛрдЧреА - рдлрд╝рдВрдХреНрд╢рди рдФрд░ рддрд░реНрдХ:
var STACKLEN; function GUARD(f, args) { if (--STACKLEN < 0) throw new Continuation(f, args); } function Continuation(f, args) { this.f = f; this.args = args; }
рдФрд░ рдЕрдВрдд рдореЗрдВ, рд╣рдореЗрдВ рдПрдХ рд▓реВрдк рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ рдЬреЛ Continuation
рдСрдмреНрдЬреЗрдХреНрдЯреНрд╕ рдХреЛ рдкрдХрдбрд╝реЗрдЧрд╛ред рд╣рдореЗрдВ рдЗрд╕ рд▓реВрдк рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рджреБрднрд╛рд╖рд┐рдП рдХреЛ рдмреБрд▓рд╛рдирд╛ рдЪрд╛рд╣рд┐рдП рддрд╛рдХрд┐ рд╕рдм рдХреБрдЫ рдХрд╛рдо рдХрд░реЗ:
function Execute(f, args) { while (true) try { STACKLEN = 200; return f.apply(null, args); } catch(ex) { if (ex instanceof Continuation) f = ex.f, args = ex.args; else throw ex; } }
Execute
рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдХреЙрд▓ рдХрд┐рдП рдЬрд╛рдиреЗ рд╡рд╛рд▓реЗ рдлрд╝рдВрдХреНрд╢рди рдФрд░ рдЗрд╕рдХреЗ рд▓рд┐рдП рддрд░реНрдХ рдХреЛ рд╕реНрд╡реАрдХрд╛рд░ рдХрд░рддрд╛ рд╣реИред рдпрд╣ рдПрдХ рд▓реВрдк рдореЗрдВ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдЕрдЧрд░ return
рдмрд┐рдирд╛ рд╕реНрдЯреИрдХ рдУрд╡рд░рдлреНрд▓реЛ рдХреЗ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ, рддреЛ рд╣рдо return
рдзреНрдпрд╛рди рджреЗрддреЗ рд╣реИрдВ, рд╣рдо рддреБрд░рдВрдд рд░реБрдХ рдЬрд╛рддреЗ рд╣реИрдВред рдЬрдм рд╣рдо рд▓реВрдк рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ рд╢реБрд░реВ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рд╣рд░ рдмрд╛рд░ рд░реАрд╕реЗрдЯ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред 200
рдорд╛рди - рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕реЗ рдлрд┐рдЯ рдмреИрдарддрд╛ рд╣реИред рдЬрдм рд╣рдо Continuation
рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЛ рдкрдХрдбрд╝рддреЗ рд╣реИрдВ, рддреЛ рд╣рдо рдПрдХ рдирдП рдлрд╝рдВрдХреНрд╢рди рдФрд░ рддрд░реНрдХреЛрдВ рдХреЛ рдкреНрд░рддрд┐рд╕реНрдерд╛рдкрд┐рдд рдХрд░рддреЗ рд╣реИрдВ, рдФрд░ рд▓реВрдк рдХреЛ рдЬрд╛рд░реА рд░рдЦрддреЗ рд╣реИрдВред рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдПрдХ рдЕрдкрд╡рд╛рдж рдХреЗ рдХрд╛рд░рдг, рдвреЗрд░ рдХреЛ рд╕рд╛рдл рдХрд░ рджрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рддрд╛рдХрд┐ рд╣рдо рдЬрд╛рд░реА рд░рдЦ рд╕рдХреЗрдВред
рджреБрднрд╛рд╖рд┐рдпрд╛ рд╢реБрд░реВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо рдЕрдм Execute
рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ:
Execute(evaluate, [ ast, globalEnv, function(result){ console.log("*** Result:", result); }]);
рдХрд╕реМрдЯреА
рдЕрдм рдпрд╣ рдХрд╛рдо рдХрд░реЗрдЧрд╛:
fib = ╬╗(n) if n < 2 then n else fib(n - 1) + fib(n - 2); time( ╬╗() println(fib(20)) );
рдпрд╣ рдЕрдлрд╝рд╕реЛрд╕ рдХреА рдмрд╛рдд рд╣реИ, рд▓реЗрдХрд┐рди рдпрджрд┐ рдЖрдк fib(27)
рдЦреЛрдЬрдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдпрд╣ рдирд┐рдпрдорд┐рдд рджреБрднрд╛рд╖рд┐рдпрд╛ рдХреЗ рд░реВрдк рдореЗрдВ рд▓рдЧрднрдЧ рдЪрд╛рд░ рдЧреБрдирд╛ рд▓рдВрдмрд╛ рд╣реЛрдЧрд╛ред рд▓реЗрдХрд┐рди рддрдм рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдЕрдм рдЕрдирдВрдд рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ рд╣реИ:
sum = ╬╗(n, ret) if n == 0 then ret else sum(n - 1, ret + n); # compute 1 + 2 + ... + 50000 time( ╬╗() println(sum(50000, 0)) ); # 1250025000, ~700ms
рдмреЗрд╢рдХ, рдЬрд╛рд╡рд╛рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХреА рддреБрд▓рдирд╛ рдореЗрдВ ╬╗ рднрд╛рд╖рд╛ рдмрд╣реБрдд рдзреАрдореА рд╣реИред рдЬрд░рд╛ рдХрд▓реНрдкрдирд╛ рдХреАрдЬрд┐рдП, рдПрдХ рдЪрд░ рддрдХ рд╣рд░ рдкрд╣реБрдВрдЪ рдПрдХ Environment
рд╡рд╕реНрддреБ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдЬрд╛рддреА рд╣реИред рдЗрдВрдЯрд░рдкреНрд░реЗрдЯрд░ рдХреЛ рдСрдкреНрдЯрд┐рдорд╛рдЗрдЬрд╝ рдХрд░рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░рдиреЗ рдХрд╛ рдХреЛрдИ рдорддрд▓рдм рдирд╣реАрдВ рд╣реИ - рд╣рдореЗрдВ рдПрдХ рдорд╣рддреНрд╡рдкреВрд░реНрдг рдкреНрд░рджрд░реНрд╢рди рд▓рд╛рдн рдирд╣реАрдВ рдорд┐рд▓реЗрдЧрд╛ред рдкреНрд░рджрд░реНрд╢рди рдореЗрдВ рд╕реБрдзрд╛рд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдПрдХ рд╕рдорд╛рдзрд╛рди рд╣реИ: рдЬреЗрдПрд╕ рдореЗрдВ ╬╗ рднрд╛рд╖рд╛ рдХреЛ рд╕рдВрдХрд▓рд┐рдд рдХрд░реЗрдВ, рдФрд░ рдпрд╣реА рд╣рдо рдХрд░реЗрдВрдЧреЗред рдкрд╣рд▓реЗ, рдЖрдЗрдП рджреЗрдЦреЗрдВ рдХрд┐ рд╕реАрдкреАрдПрд╕ рджреБрднрд╛рд╖рд┐рдпрд╛ рдХреЗ рд╕рд╛рде рд╣рдо рдХреНрдпрд╛ рджрд┐рд▓рдЪрд╕реНрдк рдЪреАрдЬреЗрдВ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред
рдЕрдЧрд▓реА рдХрдбрд╝рд┐рдпреЛрдВ
рдЕрдм рдЬрдм рджреБрднрд╛рд╖рд┐рдпрд╛ рдирд┐рд░рдВрддрд░рддрд╛ рдХреЛ рдкреНрд░реЗрд╖рд┐рдд рдХрд░рдиреЗ рдХреА рд╢реИрд▓реА рдореЗрдВ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ, рдФрд░ рд╕рднреА рдХрд╛рд░реНрдп, ╬╗ рднрд╛рд╖рд╛ рдлрд╝рдВрдХреНрд╢рди рдФрд░ рджреЗрд╢реА JS рдлрд╝рдВрдХреНрд╢рди, рдкрд░рд┐рдгрд╛рдо рдЬрд╛рд░реА рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкрд╣рд▓реЗ рддрд░реНрдХ рдХреЗ рд░реВрдк рдореЗрдВ рдирд┐рд░рдВрддрд░рддрд╛ рдлрд╝рдВрдХреНрд╢рди рдкреНрд░рд╛рдкреНрдд рдХрд░рддреЗ рд╣реИрдВ (рдпрд╣ рддрд░реНрдХ рдЬрд╛рд╡рд╛рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХрд╛рд░реНрдпреЛрдВ рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рд╣реИ, рд╣рд╛рд▓рд╛рдВрдХрд┐ рдпрд╣ ╬╗ рднрд╛рд╖рд╛ рдлрд╝рдВрдХреНрд╢рди рдХреЗ рд▓рд┐рдП рдЕрджреГрд╢реНрдп рд╣реИ)ред
рдЪрд░ callback
рдорддрд▓рдм рдкреВрд░реЗ рдХрд╛рд░реНрдпрдХреНрд░рдо рдХреА рдирд┐рд░рдВрддрд░рддрд╛ рд╣реИред рд╡рд╣ рд╕рдм рдЖрдЧреЗ рдХрд╛рд░реНрдпрдХреНрд░рдо рдХрд░реЗрдВрдЧреЗред рд╣рдо рдЗрд╕ рдЪрд░ рдХреЛ 'рд╡рд░реНрддрдорд╛рди рдирд┐рд░рдВрддрд░рддрд╛' рдпрд╛ рдХреЛрдб рдореЗрдВ k
рдХрд╣реЗрдВрдЧреЗред
рд╕рд╛рде рд╣реА, рдпрджрд┐ рд╣рдо рдирд┐рд░рдВрддрд░рддрд╛ рдХрд╛ рдХрд╛рд░рдг рдирд╣реАрдВ рдмрдирддреЗ рд╣реИрдВ, рддреЛ рдХрд╛рд░реНрдпрдХреНрд░рдо рдмрдВрдж рд╣реЛ рдЬрд╛рдПрдЧрд╛ред рд╣рдо рдЗрд╕реЗ ╬╗ рднрд╛рд╖рд╛ рд╕реЗ рдирд╣реАрдВ рдХрд░ рд╕рдХрддреЗ рдХреНрдпреЛрдВрдХрд┐ make_lambda
рд╡реИрд╕реЗ рднреА рдЬрд╛рд░реА make_lambda
рд╣реИред рд▓реЗрдХрд┐рди рд╣рдо рдЗрд╕реЗ рдПрдХ рджреЗрд╢реА рдлрд╝рдВрдХреНрд╢рди рд╕реЗ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдореИрдВрдиреЗ рдпрд╣ рджрд┐рдЦрд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рд╕рдорд╛рд░реЛрд╣ рдмрдирд╛рдпрд╛ рдХрд┐ рдпрд╣ рдХреИрд╕реЗ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ:
globalEnv.def("halt", function(k){});
рдпрд╣ рдПрдХ рдлрд╝рдВрдХреНрд╢рди рд╣реИ рдЬреЛ рдХреБрдЫ рднреА рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИред рд╡рд╣ рдирд┐рд░рдВрддрд░рддрд╛ ( k
) рдкреНрд░рд╛рдкреНрдд рдХрд░рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдЗрд╕реЗ рдХреЙрд▓ рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ:
println("foo"); halt(); println("bar");
рдирд┐рд╖реНрдХрд░реНрд╖:
foo
рдпрджрд┐ рдЖрдк halt()
рдХреЙрд▓ рдХреЛ рд╣рдЯрд╛рддреЗ рд╣реИрдВ, рддреЛ рдЖрдЙрдЯрдкреБрдЯ рд╣реЛрдЧрд╛: foo / bar / ***Result: false
(рдХреНрдпреЛрдВрдХрд┐ рдЕрдВрддрд┐рдо println
false
рдЖрддреА false
)ред рд▓реЗрдХрд┐рди halt()
рдпрд╣ рдХреЗрд╡рд▓ foo
рдЖрдЙрдЯрдкреБрдЯ рдХрд░рддрд╛ рд╣реИред * рдЕрдм рдПрдХ рдкрд░рд┐рдгрд╛рдо рднреА рдирд╣реАрдВ рд╣реИ рдХреНрдпреЛрдВрдХрд┐ halt()
рдПрдХ рдирд┐рд░рдВрддрд░рддрд╛ рдХрд╛ рдХрд╛рд░рдг рдирд╣реАрдВ рдмрдирддрд╛ рд╣реИ рдФрд░ рдЗрд╕рд▓рд┐рдП, рдХреЙрд▓рдмреИрдХ рдЬрд┐рд╕реЗ рд╣рдордиреЗ evaluate
рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкрд╛рд░рд┐рдд рдХрд┐рдпрд╛ evaluate
- рд╡рд╣ рдЬреЛ рд╕реНрдЯреНрд░рд┐рдВрдЧ ***Result
рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рддрд╛ рд╣реИ, рдХрднреА рдирд╣реАрдВ рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИред рдлрд╝рдВрдХреНрд╢рди рдЬрд┐рд╕реЗ evaluate
рдХрд╣рд╛ evaluate
рд╣реИ, рдпрд╣ рдзреНрдпрд╛рди рдирд╣реАрдВ рджреЗрддрд╛ рд╣реИ рдХрд┐ рдХрд╛рд░реНрдпрдХреНрд░рдо рдмрдВрдж рд╣реЛ рдЧрдпрд╛ рд╣реИред NodeJS рдореЗрдВ, рдпрд╣ рдкреИрд░ рдореЗрдВ рдПрдХ рдЧреЛрд▓реА рд╣реЛрдЧреАред
рдХрд▓реНрдкрдирд╛ рдХрд░реЗрдВ рдХрд┐ рд╣рдореЗрдВ рдПрдХ sleepe
рд╕рдорд╛рд░реЛрд╣ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ рдЬреЛ рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдХреЛ рдмрдВрдж рдХрд┐рдП рдмрд┐рдирд╛ рдПрдХ рдХрд╛рд░реНрдпрдХреНрд░рдо рдХреЛ рд░реЛрдХрддрд╛ рд╣реИ (рдЗрд╕рд▓рд┐рдП, рдмреЗрд╡рдХреВрдл рдЫреЛрд░реЛрдВ рдХреЗ рдмрд┐рдирд╛)ред рд╣рдо рдореВрд▓ рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЗрд╕реЗ рдЖрд╕рд╛рдиреА рд╕реЗ рд▓рд╛рдЧреВ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:
globalEnv.def("sleep", function(k, milliseconds){ setTimeout(function(){ Execute(k, [ false ]);
рдереЛрдбрд╝реА рд╕реА рдЕрд╕рд╛рд╡рдзрд╛рдиреА рдпрд╣ рд╣реИ рдХрд┐ рд╣рдореЗрдВ Execute
рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рд╣реЛрдЧрд╛, рдХреНрдпреЛрдВрдХрд┐ setTimeout
рдХреЙрд▓рдмреИрдХ рдХрд╛ рдХрд╛рд░рдг рдмрдиреЗрдЧрд╛, рдЬреЛ рддрдм Continuation
рдлреЗрдВрдХрддрд╛ рд╣реИ, рдФрд░ рдХреЛрдИ рднреА рдЗрд╕реЗ рдирд╣реАрдВ рдкрдХрдбрд╝реЗрдЧрд╛ред рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХреИрд╕реЗ рдХрд░реЗрдВ:
let loop (n = 0) { if n < 10 { println(n); sleep(250); loop(n + 1); } }; println("And we're done");
рдирд┐рд╖реНрдХрд░реНрд╖:
0 1 2 3 4 5 6 7 8 9 And we're done ***Result: false
рдзреНрдпрд╛рди рджреЗрдВ, рдкреНрд░рддреНрдпреЗрдХ рдкрдВрдХреНрддрд┐ рдХреЗ рдмреАрдЪ рдереЛрдбрд╝реА рджреЗрд░реА рд╣реИред рдЖрдк рдореВрд▓ рд▓реЗрдЦ рдореЗрдВ рдЗрд╕ рдХреЛрдб рдХреЛ рдЪрд▓рд╛рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред
рдпрд╣ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдХреБрдЫ рд╣реИ рдЬрд┐рд╕реЗ рдЖрдк рд╕рд╛рдорд╛рдиреНрдп рдЬрд╛рд╡рд╛рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдореЗрдВ рдирд╣реАрдВ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдирд┐рд░рдВрддрд░рддрд╛ рдХреЗ рдореИрдиреБрдЕрд▓ рдЯреНрд░рд╛рдВрд╕рдорд┐рд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рдЕрд▓рд╛рд╡рд╛ (рдФрд░ рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдЖрдк рдЗрд╕рдХреЗ for
рд▓реВрдк рдХреЗ for
рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ):
(function loop(n){ if (n < 10) { console.log(n); setTimeout(function(){ loop(n + 1); }, 250); } else { println("And we're done");
рдХрд▓реНрдкрдирд╛ рдХрд░реЗрдВ рдХрд┐ рдЖрдк ode рднрд╛рд╖рд╛ рдореЗрдВ NodeJS API рдХрд╛ рдЙрдкрдпреЛрдЧ рдХреИрд╕реЗ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:
globalEnv.def("readFile", function(k, filename){ fs.readFile(filename, function(err, data){
рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ:
copyFile = ╬╗(source, dest) { writeFile(dest, readFile(source)); }; copyFile("foo.txt", "bar.txt");
рдФрд░ рдпрд╣ рд╕рдм рдПрд╕рд┐рдВрдХреНрд░реЛрдирд╕ рд░реВрдк рд╕реЗ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред рдХреЛрдИ рдФрд░ рдЕрдзрд┐рдХ рдХреЙрд▓рдмреИрдХ рдирд░рдХред
рдпрд╣рд╛рдБ рдПрдХ рдФрд░ рджрд┐рд▓рдЪрд╕реНрдк рдЙрджрд╛рд╣рд░рдг рд╣реИред рдореИрдВрдиреЗ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдореВрд▓ рдХрд╛рд░реНрдп рд▓рд┐рдЦрд╛ рд╣реИ:
globalEnv.def("twice", function(k, a, b){ k(a); k(b); });
рдХрд╛рд░реНрдпрдХреНрд░рдо рджреЛ рддрд░реНрдХ a
рдФрд░ b
рд▓реЗрддрд╛ a
рдФрд░ рдкреНрд░рддреНрдпреЗрдХ рддрд░реНрдХ рдХреЗ рд▓рд┐рдП рдПрдХ рдмрд╛рд░ рдирд┐рд░рдВрддрд░рддрд╛ рдХрд╣рддрд╛ рд╣реИред рдЖрдЗрдП рдЗрд╕реЗ рдХреЙрд▓ рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░реЗрдВ:
println(2 + twice(3, 4)); println("Done");
рдирд┐рд╖реНрдХрд░реНрд╖:
5 Done ***Result: false 6 Done ***Result: false
рдирд┐рд╖реНрдХрд░реНрд╖ рдЕрдЬреАрдм рд╣реИ рдЕрдЧрд░ рдЖрдкрдиреЗ рдкрд╣рд▓реЗ рдХрднреА рднреА рдирд┐рд░рдВрддрд░рддрд╛ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдирд╣реАрдВ рдХрд┐рдпрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдЗрд╕ рдХреЛрдб рдХреЛ рд╕реНрд╡рдпрдВ рд╕рдордЭрдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░реЗрдВред рдереЛрдбрд╝рд╛ рд╕рдВрдХреЗрдд: рдХрд╛рд░реНрдпрдХреНрд░рдо рдПрдХ рдмрд╛рд░ рд╢реБрд░реВ рд╣реЛрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдкрд░рд┐рдгрд╛рдо рджреЛ рдмрд╛рд░ рд▓реМрдЯрддрд╛ рд╣реИред
рд╕рд╛рдорд╛рдиреНрдпреАрдХрд░рдг: CallCC
рдЬрдм рд╣рдо рджреЗрд╢реА рдХрд╛рд░реНрдп рд▓рд┐рдЦрддреЗ рдереЗ рддреЛ рд╣рдо рдЖрдЧ рд╕реЗ рдЦреЗрд▓рддреЗ рдереЗред рд╡рд░реНрддрдорд╛рди рдирд┐рд░рдВрддрд░рддрд╛ рдХреЗ рдирд┐рд╖реНрдкрд╛рджрди рдХреЛ рдмрд╛рдзрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП ╬╗ рднрд╛рд╖рд╛ рдореЗрдВ рдХреЛрдИ рд░рд╛рд╕реНрддрд╛ рдирд╣реАрдВ рд╣реИред CallCC
рдЗрд╕ рд╕рдорд╕реНрдпрд╛ рдХреЛ рд╣рд▓ рдХрд░рдиреЗ рдореЗрдВ рдорджрдж рдХрд░реЗрдЧреАред рдирд╛рдо рдпреЛрдЬрдирд╛ рд╕реЗ рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рд╕рдВрдХреНрд╖рд┐рдкреНрдд рдирд╛рдо рд╣реИ - call-with-current-continuation
(рдЬрд┐рд╕реЗ рдЖрдорддреМрд░ рдкрд░ рдпреЛрдЬрдирд╛ рдореЗрдВ рдХреЙрд▓ / рд╕реАрд╕реА рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИ)ред
globalEnv.def("CallCC", function(k, f){ f(k, function CC(discarded, ret){ k(ret); }); });
рдпрд╣ рдПрдХ рдлрдВрдХреНрд╢рди рдореЗрдВ рд╡рд░реНрддрдорд╛рди рдирд┐рд░рдВрддрд░рддрд╛ рдХреЛ рджрд░реНрд╢рд╛рддрд╛ рд╣реИ рдЬрд┐рд╕реЗ рд╕реАрдзреЗ ╬╗ рднрд╛рд╖рд╛ рд╕реЗ рдХрд╣рд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рдпрд╣ рдлрд╝рдВрдХреНрд╢рди рдЗрд╕рдХреА рдореВрд▓ CallCC
рдирд┐рд░рдВрддрд░рддрд╛ рдХреЛ рдЕрдирджреЗрдЦрд╛ discarded
рджреЗрдЧрд╛ рдФрд░ рдЗрд╕рдХреЗ рдмрдЬрд╛рдп рдЙрд╕ рдирд┐рд░рдВрддрд░рддрд╛ рдХреЛ рдХреЙрд▓ рдХрд░реЗрдЧрд╛ рдЬреЛ CallCC
рдлрд╝рдВрдХреНрд╢рди рдХреЛ рджреА CallCC
ред
рдЗрд╕ рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реБрдП, рд╣рдо рд▓рд╛рдЧреВ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ (рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рд╕реАрдзреЗ рднрд╛рд╖рд╛ рдореЗрдВ, рджреЗрд╢реА рдХрд╛рд░реНрдпреЛрдВ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдирд╣реАрдВ!) рдирд┐рд╖реНрдкрд╛рджрди рдкреНрд░рд╡рд╛рд╣ рдХреЗ рд▓рд┐рдП рдирд┐рдпрдВрддреНрд░рдг рдХрдердиреЛрдВ рдХрд╛ рдПрдХ рдмрдбрд╝рд╛ рд╕реЗрдЯ рдЬрд┐рд╕реЗ рд╣рдордиреЗ рдкрд╣рд▓реЗ рднреА рдирд╣реАрдВ рд╕реЛрдЪрд╛ рдерд╛ - рдЕрдкрд╡рд╛рджреЛрдВ рд╕реЗ рд╢реБрд░реВ рдФрд░ return
рд╕рд╛рде рд╕рдорд╛рдкреНрддред рдЪрд▓реЛ рдЖрдЦрд┐рд░реА рд╕реЗ рд╢реБрд░реВ рдХрд░рддреЗ рд╣реИрдВред
рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди return
foo = ╬╗(return){ println("foo"); return("DONE"); println("bar"); }; CallCC(foo);
рдирд┐рд╖реНрдХрд░реНрд╖:
foo ***Result: DONE
foo
рдлрд╝рдВрдХреНрд╢рди рдПрдХ рддрд░реНрдХ рдкреНрд░рд╛рдкреНрдд рдХрд░рддрд╛ рд╣реИ рдЬреЛ рдЬрд╛рд╡рд╛рд╕реНрдХреНрд░рд┐рдкреНрдЯ рд╕реЗ return
рдХреЗ рд╕рдорд╛рди рд╣реЛрддрд╛ рд╣реИ (рд▓реЗрдХрд┐рди рдЗрд╕реЗ рдирд┐рдпрдорд┐рдд рдлрд╝рдВрдХреНрд╢рди рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИ)ред рдпрд╣ рд╡рд░реНрддрдорд╛рди рдирд┐рд░рдВрддрд░рддрд╛ рдХреЛ рдЫреЛрдбрд╝ рджреЗрддрд╛ рд╣реИ (рдЬреЛ 'рдмрд╛рд░' рдЖрдЙрдЯрдкреБрдЯ рдХрд░реЗрдЧрд╛) рдФрд░ рдлрд╝рдВрдХреНрд╢рди рд╕реЗ рдмрд╛рд╣рд░ рдирд┐рдХрд▓рддрд╛ рд╣реИ, рджрд┐рдП рдЧрдП рдореВрд▓реНрдп ("рдкреВрд░рд╛") рдХреЛ рд╡рд╛рдкрд╕ рдХрд░рддрд╛ рд╣реИред рдмреЗрд╢рдХ, рдпрд╣ рдХреЗрд╡рд▓ рддрднреА рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ рдЬрдм рдЖрдк рдХреЙрд▓ рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдХреЙрд▓ рдХреЛ return
рд░реВрдк рдореЗрдВ рдЬрд╛рд░реА рд░рдЦрдиреЗ рдХреЗ рд▓рд┐рдП рдкрд╛рд╕ рдХрд░рддреЗ return
ред рд╣рдо рдЗрд╕рдХреЗ рд▓рд┐рдП рдПрдХ рдЖрд╡рд░рдг рдмрдирд╛ рд╕рдХрддреЗ рд╣реИрдВ:
with-return = ╬╗(f) ╬╗() CallCC(f); foo = with-return(╬╗(return){ println("foo"); return("DONE"); println("bar"); }); foo();
рдирд┐рд╖реНрдХрд░реНрд╖:
foo ***Result: DONE
рдЗрд╕ рдкрджреНрдзрддрд┐ рдХрд╛ рд▓рд╛рдн рдпрд╣ рд╣реИ рдХрд┐ рдЬрдм рд╣рдо foo
рдлреЛрди рдХрд░рддреЗ рд╣реИрдВ рддреЛ рд╣рдореЗрдВ CallCC
рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реЛрддреА рд╣реИред рдпрд╣ рдЕрдЪреНрдЫрд╛ рд╣реЛрдЧрд╛, рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ, рдЕрдЧрд░ рд╣рдореЗрдВ рдПрдХ рддрд░реНрдХ рдХреЗ рд░реВрдк рдореЗрдВ return
рдХреЛ рд╕реНрд╡реАрдХрд╛рд░ рдХрд░рдиреЗ рдпрд╛ with-return
рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рдереА, рд▓реЗрдХрд┐рди рднрд╛рд╖рд╛ рдореЗрдВ рд╕реАрдзреЗ рд╕реЗ рд╕реЗрдиреЗрдЯрд┐рдХ рдЪреАрдиреА рдЬреЛрдбрд╝рдиреЗ рдХрд╛ рдХреЛрдИ рддрд░реАрдХрд╛ рдирд╣реАрдВ рд╣реИ, рдЗрд╕рдХреЗ рд▓рд┐рдП рд╣рдореЗрдВ рдХрдо рд╕реЗ рдХрдо рдкрд╛рд░реНрд╕рд░ (рд▓рд┐рд╕реНрдк рдХреЗ рд▓рд┐рдП +1) рдХреЛ рд╕рдВрд╢реЛрдзрд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред
рд╕рдВрдХреНрд░рдордг
рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рд╣рдореЗрдВ рдПрдХ рдкреНрд░реЛрдЧреНрд░рд╛рдо рд▓рд┐рдЦрдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рдЬреЛ 100 рддрдХ рдХреЗ рд╕рднреА рд╕рдХрд╛рд░рд╛рддреНрдордХ рдкреВрд░реНрдгрд╛рдВрдХ рдХреЗ рдЬреЛрдбрд╝реЗ рдХреЛ рджреЗрдЦреЗрдЧрд╛, рдпрджрд┐ рдЙрдирдХрд╛ рдЧреБрдгрди 84 рд╣реЛ рдЬрд╛рддрд╛ рд╣реИред рдпрд╣ рдХреЛрдИ рдореБрд╢реНрдХрд┐рд▓ рдХрд╛рдо рдирд╣реАрдВ рд╣реИ рдФрд░ рдЖрдк рдЗрд╕реЗ рд╣рд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рддреБрд░рдВрдд рджреЛ рдиреЗрд╕реНрдЯреЗрдб рд▓реВрдкреЛрдВ рдХреА рдХрд▓реНрдкрдирд╛ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдпрд╣рд╛рдВ рд╣рдо рдПрдХ рдЕрд▓рдЧ рддрд░реАрдХреЗ рд╕реЗ рдЬрд╛рддреЗ рд╣реИрдВред рд╣рдо рджреЛ рдХрд╛рд░реНрдп рдмрдирд╛рдПрдВрдЧреЗ: guess
рдФрд░ fail
ред рдкрд╣рд▓рд╛ рдирдВрдмрд░ рдЪреБрдиреЗрдЧрд╛, рдФрд░ рджреВрд╕рд░рд╛ рдЙрд╕реЗ рдмрддрд╛рддрд╛ рд╣реИ "рджреВрд╕рд░реЗ рдирдВрдмрд░ рдкрд░ рдкреНрд░рдпрд╛рд╕ рдХрд░реЗрдВред" рд╣рдо рдЙрдиреНрд╣реЗрдВ рдЗрд╕ рддрд░рд╣ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗ:
a = guess(1);
:
fail = ╬╗() false; guess = ╬╗(current) { CallCC(╬╗(k){ let (prevFail = fail) { fail = ╬╗(){ current = current + 1; if current > 100 { fail = prevFail; fail(); } else { k(current); }; }; k(current); }; }); }; a = guess(1); b = guess(a); if a * b == 84 { print(a); print(" x "); println(b); }; fail();
, , a
, 84
, b
, 84 / a
. guess
: start
end
тАФ . , .
try
catch
Common Lisp
тАФ catch
throw
. :
f1 = ╬╗() { throw("foo", "EXIT"); print("not reached"); }; println(catch("foo", ╬╗() { f1(); print("not reached"); }));
catch(TAG, function)
, , TAG
', function
.throw(TAG, value)
, , TAG
' , value
.
:
рдПрдХ рдЙрджрд╛рд╣рд░рдг:
catch
, , , . , , , CallCC
. , . " " тАФ тАФ . , , , catch
/ throw
, .
. , catch
. , throw
, , catch
, . рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП:
exit = false;
рдирд┐рд╖реНрдХрд░реНрд╖:
After catch After catch ERROR: No more catch handlers!
'After catch' , 'ERROR: No more catch handlers!'. - , 'After catch' , . , '' , catch
. , 'XXX' catch
, throw
, catch
.
( , .)
CallCC (, , CallCC ). , тАФ CallCC
.
Yield
, , yield
:
foo = with-yield(╬╗(yield){ yield(1); yield(2); yield(3); "DONE"; }); println(foo());
yield
, . , return
. , , yield
, .
:
fib = with-yield(╬╗(yield){ let loop (a = 1, b = 1) { yield(b); loop(b, a + b); }; });
fib
. . yield
. , , 50 , 50 .
, , , , .
, .
yield
, , . , , return
. , , yield
, yield
, . , . :
with-yield = ╬╗(func) {
yield
, . , , , "DONE".
, . , - , , 4 :
println(foo()); foo();
.
тДЦ1: yield
, , , , yield
( kyld
, , ) :
yield(2); yield(3); "DONE";
yield
? yield
, , yield
. , . , yield
return
, :
with-yield = ╬╗(func) { let (return, yield) { yield = ╬╗(value) { CallCC(╬╗(kyld){ func = kyld; return(value);
, , yield
, yield
( ). yield
.
, , println(foo())
:
with-yield = ╬╗(func) { let (return, yield) { yield = ╬╗(value) { CallCC(╬╗(kyld){ func = kyld; return(value); }); }; ╬╗(val) { CallCC(╬╗(kret){ return = kret; func(val || yield); }); }; }; }; foo = with-yield(╬╗(yield){ yield(1); yield(2); yield(3); "DONE"; }); println(foo()); println(foo()); println(foo());
, . , print(foo()); foo()
. , println(foo())
? ...
тДЦ2: WTF?
. : , foo()
. , ? тАФ .
println(foo());
with-yield
:
func(val || yield);
yield
, , #...
. , , ( "DONE"
), , "DONE"
, . foo()
, "DONE"
. :
println(foo()); println("bar"); println(foo()); println(foo()); foo();
: 1, bar, 2, 3, DONE, bar, DONE, bar, ...
.
func
- , . , "no more continuations"
:
val = func(val || yield); func = ╬╗() "NO MORE CONTINUATIONS"; kret(val);
:
with-yield = ╬╗(func) { let (return, yield) { yield = ╬╗(value) { CallCC(╬╗(kyld){ func = kyld; return(value); }); }; ╬╗(val) { CallCC(╬╗(kret){ return = kret; val = func(val || yield); func = ╬╗() "NO MORE CONTINUATIONS"; kret(val); }); }; }; }; foo = with-yield(╬╗(yield){ yield(1); yield(2); yield(3); "DONE"; }); println(foo()); println(foo()); println(foo()); println(foo());
, :
1 2 3 DONE NO MORE CONTINUATIONS NO MORE CONTINUATIONS NO MORE CONTINUATIONS ***Result: false
1, 2, 3, DONE
, "NO MORE CONTINUATIONS"
. , :
print("A. "); println(foo()); print("B. "); println(foo()); print("C. "); println(foo()); print("D. "); println(foo());
, : , , , , "B."
.
, yield
, :
with-yield = ╬╗(func) { let (return, yield) { yield = ╬╗(value) { CallCC(╬╗(kyld){ func = kyld; return(value); }); }; ╬╗(val) { CallCC(╬╗(kret){ return = kret; val = func(val || yield); func = ╬╗() "NO MORE CONTINUATIONS"; kret(val); }); }; }; }; fib = with-yield(╬╗(yield){ let loop (a = 1, b = 1) { yield(b); loop(b, a + b); }; });
рдирд┐рд╖реНрдХрд░реНрд╖ 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765 10946 17711 28657 46368 75025 121393 196418 317811 514229 832040 1346269 2178309 3524578 5702887 9227465 14930352 24157817 39088169 63245986 102334155 165580141 267914296 433494437 701408733 1134903170 1836311903 2971215073 4807526976 7778742049 12586269025 20365011074 ***Result: false
, (, ), " ".
: reset
shift
yield
: reset
shift
. " " тАФ , . reset
, shift
, CallCC
.
, reset
shift
тАФ . reset
, shift
, reset
.
, with-yield
:
with-yield = ╬╗(func) { let (yield) {
, reset
. , , , reset
. , . , .
:
with-yield = ╬╗(func) { let (yield) { yield = ╬╗(val) { shift(╬╗(k){ func = k; val; }); }; ╬╗(val) { reset( ╬╗() func(val || yield) ); }; } }; foo = with-yield(╬╗(yield){ yield(1); yield(2); yield(3); "DONE"; }); println(foo());
reset
shift
, . . . , , , . Scheme ( тАФ Oleg Kiselyov ). .
, ( CallCC
) . :
var pstack = []; function _goto(f) { f(function KGOTO(r){ var h = pstack.pop(); h(r); }); } globalEnv.def("reset", function(KRESET, th){ pstack.push(KRESET); _goto(th); }); globalEnv.def("shift", function(KSHIFT, f){ _goto(function(KGOTO){ f(KGOTO, function SK(k1, v){ pstack.push(k1); KSHIFT(v); }); }); });
, reset
, shift
_goto
, тАФ . . _goto
( KGOTO
). , f
( CallCC
) - KGOTO
, . , f
, , KGOTO
, , .
reset
( KRESET
) _goto(th)
. , , , _goto
. , , KGOTO
KRESET
.
, shift
KGOTO
, KGOTO
pstack
, SK
, , shift
( shift
тАФ KSHIFT
). SK
тАФ тАФ ( k1
) . , shift2
, , pstack.push(k1);
:
println(reset(╬╗(){ 1 + shift( ╬╗(k) k(k(2)) ); })); println(reset(╬╗(){ 1 + shift2( ╬╗(k) k(k(2)) ); }));
рдирд┐рд╖реНрдХрд░реНрд╖:
4 3 ***Result: false
shift
( k
), reset
. тАФ 1 shift
:
1 + [?]
k
, ?
. тАФ k(k(2))
. 2 , k(2)
3. , k(3)
3 , 4.
shift2
: k(2) .
CallCC
, , CallCC
, . , JS, , , . , CallCC
, .
тАФ goto
, ( ):
pstack = NIL; goto = false; reset = ╬╗(th) { CallCC(╬╗(k){ pstack = cons(k, pstack); goto(th); }); }; shift = ╬╗(f) { CallCC(╬╗(k){ goto(╬╗(){ f(╬╗(v){ CallCC(╬╗(k1){ pstack = cons(k1, pstack); k(v); }); }); }); }); }; let (v = CallCC( ╬╗(k){ goto = k; k(false) } )) { if v then let (r = v(), h = car(pstack)) { pstack = cdr(pstack); h(r); } };
тАФ !