Live data from Hacker News

Lisp Macros, Delayed Evaluation and the Evolution of Smalltalk

blog.metaobject.com

51–60 of 114 posts

Re: Lisp Macros, Delayed Evaluation and the Evolution of Smalltalk

#51
post #45
post #42

Earlier quoted context omitted.

Different name for the same thing, whats your point? Lambdas/AF are used to delay evaluation but keep the default semantics. Macros are more than simple code transformers, that wording somehow implies that they somehow retain the semantics of the data passed to them, which mighy be the case but is not required at all. S-Expressions are just a serialisation format for the m-expression AST.

Lambdas are just functions. Delaying functionality is just one use of functions. > that wording somehow implies that they somehow retain the semantics of the data passed to them Since they can do arbitrary transformations, retaining semantics is not in focus. Since the input may not have any semantics defined, the semantics is actually provided via the macro implementation. > S-Expressions are just a serialisation fo…

> Delaying functionality is just one use of functions.

This is why explicitly said Lambdas. Name one use of lambdas not covered by functions that is not delayed evaluation. If you want to be pedantic please be so consistently.

> S-expressions know nothing about 'syntax'. Thus they can't be an AST.

You seem to be confusing what the CL Hyperspec calls syntax, which is actually the semantics of evaluating a certain expression list, with the actual parse tree that can be generated from M-Expressions. And you seem to confuse Abstract Syntax Trees which can contain pretty much anything with Concrete Syntax Trees generated by parsing (it's explained on the very wiki page you linked). And even IF they were the same, M-Exps themselves are so flexible that they can express everything as function calls and arguments, and since the original Lisp only had a single symbol type your (3 4 +) argument itself is flawed.

You're way to focused on how CL does things, maybe it's your CL background that actually causes you to miss the bigger picture of lisp, something you accuse the people of that come from Java.

Re: Lisp Macros, Delayed Evaluation and the Evolution of Smalltalk

#52
post #2

That's a common misconception that Lisp macros are mostly used to 'delay' evaluation. What Smalltalk calls 'blocks' are just (anonymous) functions in Lisp. Books like SICP explain in detail how to use that for delayed evaluation in Lisp/Scheme: https://mitpress.mit.edu/sites/default/files/sicp/full-text/...

What are lisp macros for if not to delay evaluation? I assume you're making a distinction between purpose and mechanism here? I've always understood the semantics to be: fn: (a b c) => (call a (eval b) (eval c)) mac: (a b c) => (eval (call a b c))

What are lisp macros for if not to delay evaluation?

One class of use cases not covered in the blog post is that a variable appearing as a function's argument can only be a bound occurrence, a use of some name already in scope. A variable appearing as a macro's argument can be the binding occurrence of that name. This is why (using Racket examples) match, define-struct, for/list, and such things aren't functions.

[1]: https://docs.racket-lang.org/reference/match.html?q=match#%2...

[2]: https://docs.racket-lang.org/reference/define-struct.html?q=...

[3]: https://docs.racket-lang.org/reference/for.html?q=for%2Flist...

Re: Lisp Macros, Delayed Evaluation and the Evolution of Smalltalk

#53
post #45

Earlier quoted context omitted.

Lambdas are just functions. Delaying functionality is just one use of functions. > that wording somehow implies that they somehow retain the semantics of the data passed to them Since they can do arbitrary transformations, retaining semantics is not in focus. Since the input may not have any semantics defined, the semantics is actually provided via the macro implementation. > S-Expressions are just a serialisation fo…

I know you're rigorous and mostly right, but you forget to admit that for most practical uses s-exps encode trees and are used as ad-hoc AST's. People just make implicit grammars based on spec like predicate patterns.

He's not even right. He's pseudo rigorous to support is CL zealot trolling.

He made it far enough into the wikipedia article to find a graphic that pseudo supports his claim, but not far enough to actually read the definition of an Abstract Syntax Tree (the thing we talk about) vs Concrete Syntax Tree (the thing he talks about).

> This distinguishes abstract syntax trees from concrete syntax trees, traditionally designated parse trees, which are typically built by a parser during the source code translation and compiling process.

Re: Lisp Macros, Delayed Evaluation and the Evolution of Smalltalk

#54
post #53

Earlier quoted context omitted.

I know you're rigorous and mostly right, but you forget to admit that for most practical uses s-exps encode trees and are used as ad-hoc AST's. People just make implicit grammars based on spec like predicate patterns.

He's not even right. He's pseudo rigorous to support is CL zealot trolling. He made it far enough into the wikipedia article to find a graphic that pseudo supports his claim, but not far enough to actually read the definition of an Abstract Syntax Tree (the thing we talk about) vs Concrete Syntax Tree (the thing he talks about). > This distinguishes abstract syntax trees from concrete syntax trees, traditionally desi…

You might want to reread the Wikipedia article and tone down a bit:

Check out the abstract syntax tree on the right:

  https://en.wikipedia.org/wiki/Abstract_syntax_tree
It has a node which is a BRANCH and which has three relations CONDITION, IF-BODY, ELSE-BODY.

In an s-expression this is just

  (if (> a b)
      (setq a (- a b))
      (setq b (- b a))
 
Thus there is no representation that IF is a branching expression, there is no representation that A and B are variables. There is no representation that > is a compare op. And so on.

The s-expressions are just nested lists of tokens without any idea what the tokens refers to or what language construct it stands for. All we know is what the tokens are and a hierarchy. A is a symbol, but what kind we don't know: it could be a data object, a variable name, a function name, a goto tag, a name of a class, a name of a type, ...). In the abstract syntax tree the > is identified as a compare op, IF is identified as a branch, A is identified as a variable identifier, ...

The Lisp reader also does not create that information. It just creates a data structure, which could be anything, any kind of data.

Re: Lisp Macros, Delayed Evaluation and the Evolution of Smalltalk

#55
post #6

Earlier quoted context omitted.

What are lisp macros for if not to delay evaluation? I assume you're making a distinction between purpose and mechanism here? I've always understood the semantics to be: fn: (a b c) => (call a (eval b) (eval c)) mac: (a b c) => (eval (call a b c))

That might be more like what was called an FEXPR mechanism in some early Lisps or some niche Lisps, or even in languages like R. https://en.wikipedia.org/wiki/Fexpr When an FEXPR is called, it gets unevaluated args and can then at runtime decide what to do. Macros OTOH are a different mechanism, where expressions get rewritten at macro expansion time, which can be for example at compile time. The macro then gets call…

https://www.quotes.net/quote/36312

"The primary purpose of the DATA statement is to give names to constants; instead of referring to pi as 3.141592653589793 at every appearance, the variable PI can be given that value with a DATA statement and used instead of the longer form of the constant. This also simplifies modifying the program, should the value of PI change."

Or, quoting the other aphorism, what is constant for someone is a variable for someone else.

What is run time for LISP (which lacked good compiler at early stages - the famous two horse asses width constraint) can freely be a compile time for other language. Or for a LISP, for that matter, in our time.

The compile time expansion allows for better (because faster) error checking.

Re: Lisp Macros, Delayed Evaluation and the Evolution of Smalltalk

#56
post #51
post #45

Earlier quoted context omitted.

Lambdas are just functions. Delaying functionality is just one use of functions. > that wording somehow implies that they somehow retain the semantics of the data passed to them Since they can do arbitrary transformations, retaining semantics is not in focus. Since the input may not have any semantics defined, the semantics is actually provided via the macro implementation. > S-Expressions are just a serialisation fo…

> Delaying functionality is just one use of functions. This is why explicitly said Lambdas. Name one use of lambdas not covered by functions that is not delayed evaluation. If you want to be pedantic please be so consistently. > S-expressions know nothing about 'syntax'. Thus they can't be an AST. You seem to be confusing what the CL Hyperspec calls syntax, which is actually the semantics of evaluating a certain expr…

> This is why explicitly said Lambdas

A lambda is a function. There is nothing special about them. There is nothing which makes them less or more functional than other functions.

  ((lambda (x) (* x 10))
   30)
FYI: above is valid Scheme code.

  BiwaScheme Interpreter version 0.6.4
  Copyright (C) 2007-2014 Yutaka HARA and the BiwaScheme team
     ((lambda (x) (* x 10)) 
      30)
     => 300
   
Above is lambda expression applied to an argument. There is nothing 'delaying' about it.

> You seem to be confusing what the CL Hyperspec calls syntax,

No, I'm looking at the Racket documentation.

https://docs.racket-lang.org/reference/syntax-model.html

The reader in Racket reads expressions into syntax objects. In a second pass it then creates a complete parse.

In an Interpreter based Lisp one reads the s-expression into an internal representation of lists, symbols, numbers. The interpreter then has the syntax encoded into its code and walks these lists keeping track of functions, variables, built-in operators, bindings, ... etc.

That's pretty much what a Lisp interpreter did since the dawn of time. Two decades before CL even existed.

Clojure even doesn't use an interpreter.

Re: Lisp Macros, Delayed Evaluation and the Evolution of Smalltalk

#57
post #2

That's a common misconception that Lisp macros are mostly used to 'delay' evaluation. What Smalltalk calls 'blocks' are just (anonymous) functions in Lisp. Books like SICP explain in detail how to use that for delayed evaluation in Lisp/Scheme: https://mitpress.mit.edu/sites/default/files/sicp/full-text/...

Did you ever try to implement a macro in a Lisp?

If you ever try, you'll quickly find out that a macro is essentially a lambda without argument evaluation. That's it.

If we take another look on it, yep, that's a form of delayed evaluation of lambda parameters, however I would prefer the term "delayed expansion".

Re: Lisp Macros, Delayed Evaluation and the Evolution of Smalltalk

#58
post #46
post #44

Earlier quoted context omitted.

Yeah mentioning clojure in a thread where he's active is a surefire way to get downvoted. That guy hates everything not CL...

Experience shows that most Clojure users come from Java and have very little idea about Lisp. It might help to bring in some perspective, since Clojure is not a very typical Lisp: no interpreter, no linked lists as base data structure, no Lisp in Lisp, no Lisp runtime, no images, not the typical debugging tools like break loops, the runtime is from the JVM or another environment (.net, JavaScript), ... Lisp existed a…

> no interpreter

ClojureScript is interpreter, unless you run Closure compiler in compilation phase. Interpretation is done by default in repl. There is also Joker [0].

> no linked lists as base data structure

Not true. Linked lists are base data structure on the same level as vectors and hash maps. Unlike Scheme where hash maps are sometimes implemented as assoc-ed lists.

> no Lisp in Lisp

Check for CinC and derivatives [1] or Ferret [2].

> no Lisp runtime

What you define by "runtime"?

> no images

By this requirement, 90% Lisps out there would not be Lisp ;) Even some Common Lisp implementations (ABCL) doesn't have it. Or if you want another extreme, V8/nodejs can generate image/snapshot or you can dump JVM image via Criu [3].

> not the typical debugging tools like break loops

IntelliJ has it, CIDER has it, there is clj-debugger... It is not part of default implementation, just like Scheme doesn't have it.

[0] https://joker-lang.org/

[1] https://github.com/remleduff/CinC

[2] https://ferret-lang.org/

[3] https://www.criu.org/Main_Page

Re: Lisp Macros, Delayed Evaluation and the Evolution of Smalltalk

#59
post #2

That's a common misconception that Lisp macros are mostly used to 'delay' evaluation. What Smalltalk calls 'blocks' are just (anonymous) functions in Lisp. Books like SICP explain in detail how to use that for delayed evaluation in Lisp/Scheme: https://mitpress.mit.edu/sites/default/files/sicp/full-text/...

Did you ever try to implement a macro in a Lisp? If you ever try, you'll quickly find out that a macro is essentially a lambda without argument evaluation. That's it. If we take another look on it, yep, that's a form of delayed evaluation of lambda parameters, however I would prefer the term "delayed expansion".

Related discussion: https://news.ycombinator.com/item?id=14333824
Post reply on HN