Is Scheme's letrec only meant for defining procedures, especially recursive ones? I am asking because it appears to be possible to bind non-procedures using letrec. For example, (letrec ((x 1) (y 2)) (+ x y)). If Scheme's letrec is only meant for procedures, then why isn't its syntax constrained to allow procedures only?
Consider this use of letrec to define two mutually recursive procedures:
(letrec ((is-even? (lambda (n)
(let ((n (abs n)))
(if (= n 0)
#t
(is-odd? (- n 1))))))
(is-odd? (lambda (n)
(let ((n (abs n)))
(if (= n 0)
#f
(is-even? (- n 1)))))))
(is-even? 123))
If we use Common Lisp's LABELS instead of Scheme's letrec, these two mutually recursive procedures would be defined like this instead:
(labels ((even-p (n)
(let ((n (abs n)))
(if (= n 0)
t
(odd-p (- n 1)))))
(odd-p (n)
(let ((n (abs n)))
(if (= n 0)
nil
(even-p (- n 1))))))
(even-p 123))
If letrec is only useful for defining procedures, then why isn't its syntax constrained like that of LABELS to allow only procedures in its initialization forms?
It is mostly useful for binding procedures, yes: the variables bound by
letreccan't refer to their own bindings until afterwards, so something likeDoes not work: see my other answer.
However first of all it would be a strange restriction, in a Lisp-1 like Scheme, to insist that
letreccan only be used for procedures. It's also not enforcable other than dynamically:More importantly,
letreccan be used in places like this:which is fine, because the reference to the binding of
xis delayed. So if you have streams, you can then do this: