3 ms·
I think you're overstating a supposed worry. I could equally say, "why are all of these languages making me worry about which scope a VAR is attached to?" In ei
by reikonomusha 3y ago
I think you're overstating a supposed worry. I could equally say, "why are all of these languages making me worry about which scope a VAR is attached to?" In either case, it doesn't seem to actually be a worry, it's just different than what you're used to day-to-day.
Lisp's design, I find, is best understood through the lens of how we might most straightforwardly interpret the semantics of the syntax, i.e., how we might write an evaluator for the language. It's a large part of the appeal of using Lisp; it's possible to understand the language—from parsing to execution—so well that you could in principle write a conforming interpreter for even something like Common Lisp without Herculean effort. Having such an understanding of the language has a variety of practical benefits even if you're just using the language.
A construct that you suggest like
(VAR <variable> <value>)
would be quite laborious to nail down semantically, especially if we want VAR to work in as many contexts as possible. This goes against the above ethos.
Even then, if we do make a variety of decisions about syntax and scoping rules to allow VAR, we have additional questions to answer in the context of Lisp specifically. For example, are macros allowed to expand into VAR statements? Is this allowed?
(defmacro bind ()
'(var x 5))
(defun f (y)
(bind)
(+ x y))
This sort of shenanigan can't happen with LET quite as opaquely, since the closest equivalent would require the sum to be wrapped:
(defmacro bind (&body b)
`(let ((x 5))
,@b))
(defun f (y)
(bind
(+ x y)))
Now I'm clued in to something goofy potentially happening when looking at the definition of F.
So we might ban macros expanding into VAR statements. So then how do we write binding macros? Introduce a dedicated SCOPE special operator?
(defmacro bind (&body b)
`(scope
(var x 5)
,@b))
(defun f (y)
(bind
(+ x y)))
But now we just have an obscure LET. :)
Languages with very complicated grammars also typically come with comparatively complicated scoping rules (e.g., Python). Lisp's LET maybe seems gratuitous in a world of "var x = 2" syntax, but it's also abundantly clear what it means and how it works at all times, regardless of nesting or context.
To leave the reader with one last thing to ponder: What should this do in a compiled implementation of Common Lisp with VAR?
(defun what? ()
(tagbody
(if (= 0 (random 2))
(go :bind)
(go :print))
:bind
(var x 1)
:print
(print x)))
- ogogmad 3y agoOne possible alternative is to combine PROGN with LET, which you might then call BLOCK, with the macro definition of BLOCK looking for `VAR`s. The VAR syntax wouldn't make sense anywhere else. More exactly: (block (var first-thing 'EXAMPLE) (do-something) (var foo 'EXAMPLE) (do-something-else)) Expand this into: (let ((first-thing 'EXAMPLE)) (do-something) (let ((foo 'EXAMPLE')) (do-something-else))) This would reduce indentation. But it would also involve big changes to Common Lisp.
- Jtsummers 3y agoIt wouldn't require any changes to the language. It would probably require a tree-walking macro, which are not too uncommon. You'd want a different name though since `block` is already a thing in CL. http://clhs.lisp.se/Body/s_block.htm http://clhs.lisp.se/Body/s_block.htm I'd recommend On Lisp by Paul Graham and Let Over Lambda by Doug Hoyt if you're interested in trying it.
- reikonomusha 3y agoIf BLOCK weren't already the name of something in Common Lisp, this sort of syntax is very easy to add, easy enough to write in an HN comment. Let's call it OGOGMAD instead. (defmacro ogogmad (&body b) (cond ((endp b) '(progn)) ((endp (rest b)) b) (t (let ((f (first b)) (r (rest b))) (if (eq 'var (first f)) `(let (,(rest f)) (ogogmad ,@r)) `(progn ,f (ogogmad ,@r)))))) Exactly as you specify, this only lets you put VAR syntax immediately inside of OGOGMAD forms. (Untested, typed on mobile.)
- lispm 3y agoReducing indentation is mostly a non-goal in Lisp. Can't work with nested lists? Don't use Lisp. Lisp processes nested lists. Lisp means List Processor. You may want to do it in a text oriented language, but not so much in an expression oriented language, where programmers edit an expression tree, by tree manipulation commands. In Lisp the "tree" is "nested lists". Btw., what does (block (when (foo) (var first-thing 'EXAMPLE)) (do-something) (var foo 'EXAMPLE) (do-something-else)) mean? Is it legal? Your macro would need to traverse the expression tree, knowing the whole Lisp syntax, including expanding macros, possibly in a source interpreter. WHEN is a macro. BLOCK would need to find the VAR expression inside the WHEN macro, which is not easy for the general case. This would be very very strange. Macros are usually expanded outside to inside. Your BLOCK macro would need to expand macros in enclosed code, to find VAR expressions. In JavaScript something like above is legal in a function.