(ps:defpsmacro fvals (&rest vals) (cond ((zerop (length vals)) `(progn null)) ((= (length vals) 1) `(if (eql (typeof ,@vals) :function) (lambda () ,@vals) ,@vals)) (t `(let ((avals (ps:array ,@(reverse vals)))) (lambda () (pop avals)))))) (ps:defpsmacro fmvb (vars valf &body body) (if (= (length vars) 1) `(let ((,@vars ,valf)) ,(if (or (numberp valf) (stringp valf)) `(progn ,@body) `(progn (when (eql (typeof ,@vars) :function) (setf ,@vars (funcall ,@vars))) ,@body))) (let* ((fnname (gensym "fn")) (bindings (mapcar (lambda (v) `(,v (funcall ,fnname))) vars))) `(let* ((,fnname ,valf) ,@bindings) ,@body)))) (ps:defpsmacro vlet* (var-valfs &body body) (labels ((bind-vvfs (vvfs form) (if (null vvfs) `(progn ,@form) (destructuring-bind (v vf) (car vvfs) `(fmvb (,v) ,vf ,(bind-vvfs (cdr vvfs) form)))))) (bind-vvfs var-valfs body))) (defun foo () (fvals 1 2)) #| function foo() { var avals = [2, 1]; return function () { return avals.pop(); }; }; ==> function() |# (defun bar () (fvals 1)) #| function bar() { return typeof(1) === "function" ? function () { return 1; } : 1; }; ==> 1 |# (defun rab () (fmvb (x) (bar) x)) #| function rab() { var x = bar(); if (typeof(x) === "function") { x = x(); }; return x; }; ==> 1 |# (defun oof () (fmvb (x y) (foo) (+ x y))) #| function oof() { var FN1633 = foo(); var x = FN1633(); var y = FN1633(); return x + y; }; ==> 3 |# (defun empty () (fvals)) #| function empty() { return null; }; ==> null |# (defun return-single-fn () (fvals (lambda () :fine))) #| function returnSingleFn() { return typeof(function () { return "fine"; }) === "function" ? function () { return function () { return "fine"; }; } : function () { return "fine"; }; }; ==> function() |# (defun return-multiple-fns () (fvals (lambda () :fine) (lambda () :and) (lambda () :dandy))) #| function returnMultipleFns() { var avals = [function () { return "dandy"; }, function () { return "and"; }, function () { return "fine"; }]; return function () { return avals.pop(); }; }; ==> function() |# (defun getsinglefn (callme) (fmvb (fn) (funcall callme) fn)) #| function getsinglefn(callme) { var fn = callme(); if (typeof(fn) === "function") { fn = fn(); }; return fn; }; getsinglefn(returnSingleFn)() ==> "fine" getsinglefn(returnMultipleFns)() ==> "fine" |# (defun get-2-fns () (fmvb (f1 f2) (returnmultiplefns) (ps:array f1 f2))) #| function get2Fns() { var FN3795 = returnMultipleFns(); var f1 = FN3795(); var f2 = FN3795(); return [f1, f2]; }; ==> [ function(), function() ] get2Fns()[0]() ==> "fine" get2Fns()[1]() ==> "and" |# (defun get-3-fns () (fmvb (f1 f2 f3) (returnmultiplefns) (strcat (funcall f1) " " (funcall f2) " " (funcall f3)))) #| function get3Fns() { var FN3796 = returnMultipleFns(); var f1 = FN3796(); var f2 = FN3796(); var f3 = FN3796(); return f1() + " " + f2() + " " + f3(); }; ==> "fine and dandy" |# (defun tvlet () (vlet* ((x 1) (y "foo ") (a (foo)) (b (bar)) (c 0)) (if (= (- a b) c) (strcat "Yay, " y x) :fail!))) #| function tvlet() { var x = 1; var y = "foo "; var a = foo(); if (typeof(a) === "function") { a = a(); }; var b = bar(); if (typeof(b) === "function") { b = b(); }; var c = 0; return a - b === c ? "Yay, " + y + x : "fail!"; }; ==> "Yay, foo 1" |# (defun foo-key (a &key (b 0)) (fvals (strcat "strings: a, " a " and b, " b) (* a b))) #| function fooKey(a) { var _js1096 = arguments.length; for (var n1095 = 1; n1095 < _js1096; n1095 += 2) { switch (arguments[n1095]) { case "b": b = arguments[n1095 + 1]; }; }; var b = "undefined" === typeof b ? 0 : b; var avals = [a * b, "strings: a, " + a + " and b, " + b]; return function () { return avals.pop(); }; }; ==> function() |# (defun use-foo-key1 (x y) (vlet* ((dftstr (fookey x))) (fmvb (ndftstr nought) (fookey x :b y)) (ps:array dftstr ndftstr nought))) #| function useFooKey1(x, y) { var dftstr = fooKey(x); if (typeof(dftstr) === "function") { dftstr = dftstr(); }; var FN5919 = fooKey(x, "b", y); var ndftstr = FN5919(); var nought = FN5919(); return [dftstr, ndftstr, nought]; }; ==> [ "strings: a, 1 and b, 0", "strings: a, 1 and b, 2", 2 ] |# (defun use-foo-key2 (x y) (fmvb (ndftstr nought) (fookey x :b y)) (ps:array ndftstr nought)) #| function useFooKey2(x, y) { var FN5959 = fooKey(x, "b", y); var ndftstr = FN5959(); var nought = FN5959(); return [ndftstr, nought]; }; ==> [ "strings: a, 1 and b, 2", 2 ] |#