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.