> Wrapping code in (let() …) instead of (begin …) works fine, but it is a strange quirk to explain to someone else.
This is because begin actually does not create new scope in racket, where as (let () ...) does. Consider the following code: #lang racket (define (f x) (begin (define g 5)) (+ x g)) (f 6) ; => 11 Here, g is still in scope, despite it being defined in a begin. If it was changed to a (let () ...) then the code would error. The reason it doesn't make sense to allow for sequencing statements in an if block is a matter of binding. Consider the following expression: (if #f (begin (define x 5) x) 12)) (displaln x) ; ??? Should x be bound outside the if? There are a few ways to get around this. The first would be to make if forms create new scope in it's then and else clauses. This is what when and unless do, and why you can use define in it. If you want to do this you could with a macro: (define-syntax-rule (my-if condition then else) (if condition (let () then) (let () else))) (my-if #f (begin (define x 5) x) 12) Another is to use a form that creates new scope. (let () ...) does this, but if you find (let () ...) unappealing, you can create a macro to get rid of it. (define-syntax-rule (new-scope . body) (let () . body)) (if #f (new-scope (define x 5) x) 12) I hope that makes it more clear why you can use let but not begin to define variables in an if. ~Leif Andersen On Mon, Sep 14, 2015 at 6:24 PM, Matthias Felleisen <matth...@ccs.neu.edu> wrote: > > On Sep 14, 2015, at 6:16 PM, John Carmack <jo...@oculus.com> wrote: > > > Is there a deep reason why defines aren’t allowed in the branches of an > if, but are for cond / while / unless? > > > > Wrapping code in (let() …) instead of (begin …) works fine, but it is a > strange quirk to explain to someone else. > > > It exposes our history. Traditionally there are no extra markers in > LISP-style syntax to introduce phrases within a grammatical sentence. Thus, > an if-expression obeys the grammar > > (if test-expression > then-expression > else-expression) > > not an Algol-style variant with additional keywords: > > (if test-expression > #:then then-expression > #:else else-expression) > > If we had those markers (not just in if-expressions but wherever we may > allow sequences of expressions), we could mixin definitions wherever we > wanted. > > In cond, it is obvious which phrase is a branch (due to the > parentheses/brackets) and that the first part of each branch is a > test-expression. The extra pair of parens play the role of Algol-style > markers. > > Now, if Racket had emerged as an alternative attempt to address all of > Lisp's weaknesses, we might have overcome this problem, too. But Racket > grew organically and we value backward compatibility very highly for our > programmers. You might say we are the C++ of the LISP world, but I hope we > can do better in the long run. > > -- Matthias > > -- > You received this message because you are subscribed to the Google Groups > "Racket Users" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to racket-users+unsubscr...@googlegroups.com. > For more options, visit https://groups.google.com/d/optout. > -- You received this message because you are subscribed to the Google Groups "Racket Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.