I want to define a constant foo using an auxiliary function, say, bar. And I want to hide bar inside the definition of foo, so I come with this code:
(define foo
(define (bar n)
(+ n n))
(bar 1))
However, this definition causes syntax errors in many scheme implementations(mit-scheme, racket, guile, etc.).
I have three workarounds but none of them seems satisfactory:
(define foo1
((lambda ()
(define (bar n)
(+ n n))
(bar 1))))
(define foo2
(let ((bar (lambda (n) (+ n n))))
(bar 1)))
(define (foo3)
(define (bar n)
(+ n n))
(bar 1))
foo1 uses lambda to create an environment of writing auxiliary definitions and the parentheses seem somehow confusing.
foo2 uses let expression but I can no longer use the syntactic sugar (define (f n) ...) => (define f (lambda (n) ...))
foo3 requires less modification comparing with the original one, but every time I want this value, I have to call (foo3) and do the computation all over again.
My questions are:
- I think this kind of nested definition makes sense, but why it is considered a syntax error?
- is there any decent way to write the definition of
foo?
Answering your questions:
definecan only be used in certain ways, as mandated by the specification. What you want to do isn't covered by the specification, hence the error. As you know,defineassigns a name to the value of an expression, it's just that you can't directly create internal definitions in its context.foo2is the best option here, and it's idiomatic, too. And ifbarwere a recursive definition, you could useletrec.But if loosing a bit of syntactic sugar bothers you (because of the way procedures are defined inside a
letexpression), then try usinglocal, it'll work in Racket: