
Beautiful Racket: Why Racket? Why Lisp? - ProfDreamer
http://beautifulracket.com/appendix/why-racket-why-lisp.html#why-racket-why-lisp
======
martyalain
I did appreciate your original 2014 version and I still love the way you speak
of Lisps. About functional programming you write "Func­tional pro­gram­ming
refers to a stricter style where func­tions receive cer­tain data as input,
process only that data, and return a result." and it's a common way of
defining it. But most languages - and Lisps too - comes with closures and
lexical scoping and (IMHO) that breaks the functional purity. Thanks to a
closure an inner function can work on variables defined in the outer function,
free variables can be defined and used out of the arguments list. It's nothing
but side effects, the function is not isolated in a black box. Maybe you can
think that the lack of closure is a strong weakness of a language. It is and
it is not! You can see what can be done without closures in the [lambdaway
project]([http://epsilonwiki.free.fr/lambdaway/](http://epsilonwiki.free.fr/lambdaway/)).
And so with a true functional language. Your opinion is welcome.

~~~
kazinator
Closures and lexical scoping are not side effects and do not break functional
purity.

If a function can "work on" variables, where that means mutate their values,
it is the mutation that isn't functional, not the scoping.

If one function can see another's internal variables, that's because that
child function is enclosed in the black box; it is nested under the definition
which makes those variables visible.

~~~
martyalain
Thank you for these precisions. You say that "it is the mutation that isn't
functional, not the scoping" and I agree with that, at least the inner
function must not mutate the outer variables in order to respect the pure
functional paradigm. But what about lexical scoping? The behaviour of the
inner function depends on its environment and the inner function is not what I
would call a black box. A function containing free variables, out of the
arguments' list, is not a pure function, a bijection between inputs and
outputs. Lexical scoping is useful - as are side effects - but it does
introduce some bias in coding. What I wanted to think about is that a more
pure functional approach can be reached replacing closure and lexical scoping
by the partial application capability: a function called with a number of
values less than its arity will store the given values and return a function
waiting for the rest. Everything is done inside the function. Let's compare
how [cons, car, cdr] are built in Scheme, with closure, and lambdatalk, with
partial application:

1) Scheme

    
    
      (define cons (lambda (x y) (lambda (z) (z x y))))
      (define car (lambda (z) (z (lambda (x y) x))))
      (define cdr (lambda (z) (z (lambda (x y) y))))
      (car (cons 12 34)) -> 12
      (cdr (cons 12 34)) -> 34
    

2) Lambdatalk

    
    
      {def cons {lambda {:x :y :z} {:z :x :y}}}
      {def car {lambda {:z} {:z {lambda {:x :y} :x}}}}
      {def cdr {lambda {:z} {:z {lambda {:x :y} :y}}}}
      {car {cons 12 34}} -> 12
      {cdr {cons 12 34}} -> 34
    

More to see, for instance, in
[http://epsilonwiki.free.fr/lambdaway/?view=krakow](http://epsilonwiki.free.fr/lambdaway/?view=krakow)
.

~~~
kazinator
That isn't even close to how cons, car and cdr are actually built in Scheme.
(How would you add the "pair?" function to the above? Or stop any old one-
argument lambda from being passed into car?)

Anyway, you _could_ have lexical scope in your text based substitution hack if
you worked a little harder at it:

    
    
      {lambda {:outer} {lambda {:inner :x} :outer :inner}}
    

Don't denounce lexical scope just because you don't have it working yet.

~~~
martyalain
" That isn't even close to how cons, car and cdr are actually built in Scheme.
" I know that, I have read SICP and some others, it's not my question.

" {lambda {:outer} {lambda {:inner :x} :outer :inner}} " Yes it could be an
interesting way. Following Peter Norvig, I have written my small lisp here
[http://epsilonwiki.free.fr/lambdaway/?view=lambdalisp](http://epsilonwiki.free.fr/lambdaway/?view=lambdalisp)
coming with nested environments, closures, lexical scoping. But not partial
application.

" Don't denounce lexical scope just because you don't have it working yet. " I
denounce nothing, I do respect the way Lisp and its dialects have been
implemented! But I think it's not forbidden to explore another implementation
where partial application (with memoization) could replace closure, lexical
scoping, nested environments. Before this exploration I thought such a
language couldn't have any interest. Today I changed my point of vue.

~~~
kazinator
Partial application isn't in conflict with closure.

Partial application doesn't really compensate for an identifier reference not
being able to reach its apparent definition across a lambda boundary.

To an extent it does. Yes, story: "I'd like to pass Z as an argument here.
Oops, Z is an outer variable outside the current lambda, so not reachable.
But, aha, this is the last argument of the call I'm making, so just omit it. A
function will then evaluate out of here and emerge as a value in the outer
scope where Z _is_ visible. There we _can_ apply Z to that function and
presto: effectively, we got Z as the last argument."

I get it, but it's a very limited workaround scenario. What if Z isn't the
last argument; what if it is two scopes removed instead of just one, and so
on.

Pretty much most functional languages that have partial application sugar are
also lexically scoped, aren't they?

(You know, even Niklaus Wirth's Pascal has local functions that can see the
local variables in their parent functions! When those functions are used as
functional arguments, they can go downward only ("downward funargs"). So they
aren't first class closures.)

~~~
martyalain
I learned a lot with you. Thanks.

