Live data from Hacker News

Lisp Macros, Delayed Evaluation and the Evolution of Smalltalk

blog.metaobject.com

91–100 of 114 posts

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

#91
post #23

Earlier quoted context omitted.

> But an infix transform does delay the evaluation of expressions you've passed to it. Eg (infix (avg b) * (sgn a)). It doesn't 'delay' anything. It just rewrites at compile time (infix (avg b) * (sgn a)) into (* (avg b) (sgn a)) That's all. At runtime only the rewritten statement will be executed. > At a very low level, macros operate by having the evaluation of their arguments delayed Not at all. The main purpose o…

I believe that if you're trying to understand what macros do from a fundamental level, treating them like functions with different semantics is a very good learning method. You implement them in a SICP style interpreter and then write a few. Totally clears up the mystery. I'm not arguing with you about what happens in any production lisp. I'm sure you know more than me, but I do understand how they're implemented in…

treating them like functions with different semantics is a very good learning method

If you mean run-time functions that act a bit funny about evaluation order, that mental model is incompatible with common introductory examples like `let`.

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

#92
post #91

Earlier quoted context omitted.

I believe that if you're trying to understand what macros do from a fundamental level, treating them like functions with different semantics is a very good learning method. You implement them in a SICP style interpreter and then write a few. Totally clears up the mystery. I'm not arguing with you about what happens in any production lisp. I'm sure you know more than me, but I do understand how they're implemented in…

treating them like functions with different semantics is a very good learning method If you mean run-time functions that act a bit funny about evaluation order, that mental model is incompatible with common introductory examples like `let`.

No, it's not. You eval the return value of the call. There is no loss of expressive power. Compile time macro expansion in this model is simply partial evaluation.

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

#93
post #91

Earlier quoted context omitted.

treating them like functions with different semantics is a very good learning method If you mean run-time functions that act a bit funny about evaluation order, that mental model is incompatible with common introductory examples like `let`.

No, it's not. You eval the return value of the call. There is no loss of expressive power. Compile time macro expansion in this model is simply partial evaluation.

If `let` is a function, how and when are its arguments (say, `((x 2) (y 3))` and `(+ x y)`) evaluated?

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

#94
post #93

Earlier quoted context omitted.

No, it's not. You eval the return value of the call. There is no loss of expressive power. Compile time macro expansion in this model is simply partial evaluation.

If `let` is a function, how and when are its arguments (say, `((x 2) (y 3))` and `(+ x y)`) evaluated?

The call would return:

   ((fn [x]
      ((fn [y]
         (+ x y)) 3)) 2)
Which is in turn evaluated as you'd expect.

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

#95
post #93

Earlier quoted context omitted.

If `let` is a function, how and when are its arguments (say, `((x 2) (y 3))` and `(+ x y)`) evaluated?

The call would return: ((fn [x] ((fn [y] (+ x y)) 3)) 2) Which is in turn evaluated as you'd expect.

How and when are its arguments evaluated?

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

#96
post #95

Earlier quoted context omitted.

The call would return: ((fn [x] ((fn [y] (+ x y)) 3)) 2) Which is in turn evaluated as you'd expect.

How and when are its arguments evaluated?

The first argument is not evaluated but used as data, the second argument is evaluated after the macro function returns, as part of the macro evaluation rules, i.e. (eval (let '((x 3) (y 5)) '(+ x y)))

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

#97
post #95

Earlier quoted context omitted.

How and when are its arguments evaluated?

The first argument is not evaluated but used as data, the second argument is evaluated after the macro function returns, as part of the macro evaluation rules, i.e. (eval (let '((x 3) (y 5)) '(+ x y)))

In conclusion, it is definitely not working like a run-time function with different evaluation order.

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

#98
post #97

Earlier quoted context omitted.

The first argument is not evaluated but used as data, the second argument is evaluated after the macro function returns, as part of the macro evaluation rules, i.e. (eval (let '((x 3) (y 5)) '(+ x y)))

In conclusion, it is definitely not working like a run-time function with different evaluation order.

In conclusion, it's working exactly as I laid it out in my original post:

fn: (a b c) => (call a (eval b) (eval c))

mac: (a b c) => (eval (call a b c))

Everyone jumped on it, as production lisps don't implement macros this way. But it's the natural way to implement them in a SICP style metacircular evaluator, and a good way to learn them.

This is about mental models, not implementation details. And in my opinion this thread is full of experts who have forgotten what it's like to not understand how macros work.

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

#99
post #97

Earlier quoted context omitted.

In conclusion, it is definitely not working like a run-time function with different evaluation order.

In conclusion, it's working exactly as I laid it out in my original post: fn: (a b c) => (call a (eval b) (eval c)) mac: (a b c) => (eval (call a b c)) Everyone jumped on it, as production lisps don't implement macros this way. But it's the natural way to implement them in a SICP style metacircular evaluator, and a good way to learn them. This is about mental models, not implementation details. And in my opinion this…

The sequence of events you describe is a thing that functions do not do at run time: they do not operate on pieces of syntax. Macro expansion time is a different series of events than run time. Macros operate on pieces of program syntax, not on anything from run time.

Everyone jumped on it, as production lisps don't implement macros this way. … This is about mental models, not implementation details

It looks to me like you're the one who brought up implementation details, talking about what happens "at a very low level." You're the one who has presented a questionable implementation strategy as a mental model and has been corrected on it multiple times by multiple people. Everyone else has been describing the semantics of macros. Having separate timelines for expansion and execution is a semantic distinction, not merely a common implementation strategy.

And in my opinion this thread is full of experts who have forgotten what it's like to not understand how macros work.

Your confusion is because you insist on a mental model of macros that is incompatible with their semantics. Letting that model go is necessary in order to understand macros. Otherwise, refusing to distinguish expansion time from run time, you are working towards reinventing fexprs.

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

#100
post #99

Earlier quoted context omitted.

In conclusion, it's working exactly as I laid it out in my original post: fn: (a b c) => (call a (eval b) (eval c)) mac: (a b c) => (eval (call a b c)) Everyone jumped on it, as production lisps don't implement macros this way. But it's the natural way to implement them in a SICP style metacircular evaluator, and a good way to learn them. This is about mental models, not implementation details. And in my opinion this…

The sequence of events you describe is a thing that functions do not do at run time: they do not operate on pieces of syntax. Macro expansion time is a different series of events than run time. Macros operate on pieces of program syntax, not on anything from run time. Everyone jumped on it, as production lisps don't implement macros this way. … This is about mental models, not implementation details It looks to me li…

I'm not confused, and nothing I'm talking about is novel, eg:

http://matt.might.net/articles/metacircular-evaluation-and-f...

SICP is a great way to learn lisp and learning macros by extending the evaluator is a natural progression.

I don't care how many lisp experts are "correcting" me on the way it works in the real world, because:

a) I actually do understand how they're implemented in existing production lisps. No, really. I am not confused. In my own toy lisp compiler, I rely on first class macros and am attempting (and so far failing) to use partial evaluation to make the implementation cost somewhat sane. I am under no illusions this is normal.

b) Being an expert doesn't automatically make you good at teaching (often the correlation is reversed), and the article being commented on was a tutorial on macros.

The smug lisp weenie trope exists for a reason, and it's that the lisp community is too busy falling over themselves to prove how smart they are with arcane knowledge to give a shit about the experience beginners face. Clojure gets no end of flak from CL users who bristle at the suggestion that it even be called a lisp, but the community actually gets it and does a great job of teaching.

I have an opinion on how best to teach macros. Maybe I'm wrong. Maybe it's not a good idea to extend SICP with macros, or maybe there's a better way, and I'd love to hear arguments in those directions. But correcting it by explaining how they're implemented in CL is absolutely baffling to me.

Post reply on HN