Lambda Calculus (LC) versus LISP is not just about lexical scoping, but also about partial application (currying), which is cumbersome in LISP and natural in LC. In LC (where \ = lambda) (\xy.x)M ==> \y.M
while in LISP ((lambda (x y) x) M) ==> undefined
because the lambda function expects two arguments. Of course\xy.x is just an abbreviation for \x.\y.x, so the LISP counterpart would really be ((lambda (x) (lambda (y) x)) M) ==> (lambda (y) M)
but this only proves the point that currying is natural in LC and not in LISP, because LC provides syntactic sugar that allows to treat higher-order functions and functions of multiple variables in the same way.Also, LC is not compatible with functions with a variable number of arguments, which is common in LISP. For instance, (+ 1) ==> 1
in most LISPs, but given PLUS == \mnfx.mf(nfx) and 1 == \x.fx PLUS 1 ==> \nfx.f(nfx) == SUCC
i.e., (PLUS 1) reduces to "SUCCessor", the function adding one to its argument.In most LISP dialects, you can pass any number of arguments to a variable-argument function like +. So what does the syntax (F X) denote in general? The application of a unary function to one argument or the partial application of a binary function? Or a ternary one...? In LC it does not matter, because multi-variable functions and higher-order functions are the same. I have developed a LISPy language that uses currying instead of functions of multiple arguments in the book Compiling Lambda Calculus (https://www.t3x.org/clc/index.html). You can download the code here: https://www.t3x.org/clc/lc1.html. |