I suppose it’s about basic facts, so don’t expect much. Without a macro, you’d have to encapsulate expr in a lambda to be able to evaluate it repeatedly.
I think I’m still encapsulating expr in a lambda above. I couldn’t expand it forever, after all. The title of the section is “Changing an Expression’s Dynamic Context”. I guess I don’t quite [get] the section. No worries, though.
@anything I only glanced at it quickly. But. I think section 1.5 is setting you up for section 1.6, where you’ll rewrite your forever macro to delegate most of the work to a plain old procedure. Leaving the macro doing just the work that only a macro can do. Which I think is the point of section 1.6?
I agree with you, though. The forever macro doesn’t seem like an example of “dynamic context”, really. Maybe just ignore that for now and plod ahead? :slightly_smiling_face:
I don’t know about “dynamic context” but section 1.6 talks about “dynamic behavior”. I understand that to mean “run time” — as opposed to the work your macro does at “compile time”. ¯_(ツ)_/¯
Hehe. Cool. Thanks so much. I’m continuing.
One quick thing I’ll mention in case it helps when you’re reading 1.6. Sometimes in Racket there will be a function named call-with-x and it takes a procedure as one of the arguments. And there will also be a with-x macro. Mainly that saves you having to wrap things in a lambda to give to call-with-x. It’s just “sugar”. And so, usually, it’s best to write the call-with-x function, first. And test it, etc. Then finally write the with-x macro. Also that naming convention — call-with- vs. with- — can be nice for people to keep it straight. IMHO.
Nice! Thanks!
I think your paragraph above is fantastically insightful!
@louis has joined the channel
I’m not sure what is the idiom here. I can’t write the procedure below because ~begin doesn’t accept that define~ I can’t write a define when an expression is apparently expected. It’s not clear what I’m violating here. (All I wanted to do was to write an else-clause for the if with more than one statement.)
(define (call-with-my-and ls-of-fn)
(if (null? ls-of-fn)
#f
(begin
(define first-boolean ((car ls-of-fn)))
(if first-boolean
first-boolean
(call-with-my-and (rest ls-of-fn))))))
fact-example-syntax.rkt>
; fact-example-syntax.rkt::735: define: not allowed in an expression context
; in: (define first-boolean ((car ls-of-fn))) So I wrote it as… (define (call-with-my-and ls-of-fn)
(cond [(null? ls-of-fn) #f]
[else
(define first-boolean ((car ls-of-fn)))
(if first-boolean
first-boolean
(call-with-my-and (rest ls-of-fn)))]))
cond is the right thing to use here
But if you really want to use if, switch (begin ...) to (let () ...)
Got ya. Let me expand begin and see what it’s made of! (Just thought of that.)
It seems to be a primitive. It expands to itself.
What do you mean by that?
I mean expanding it doesn’t seem to change it into anything else. For example, if I write (f x) this get expanded to something like (#%app f x), but (begin 1 2 3) expands to (begin (quote 1) (quote 2) (quote 3)). (I thought of checking out what sort of macro begin was.)
Not exactly
begin is weird. I wrote about it here: https://github.com/racket/rhombus-brainstorming/issues/87. Might be of your interest.
Yes, I thought it was meant to group things. Cool. I’ll study this.
Maybe I shouldn’t as I’m kinda of just seeing the problem here, but I gave it a +1 there. I do like different names for different things and obvious names are great. For instance, block seems nicer than begin. I think I prefer progn over begin. I have been able to invent a meaning for progn in my mind, but I never did for begin. So maybe I would have voted for splicing-block. But I don’t really know what’s going on. So nevermind that.