Hi
apologies for the stupid question. I was reviewing some teaching material and looked at the following Scheme (form SICP) code about "streams".
(define (integral integrand initial-value dt) (define int (cons-stream initial-value (add-streams (scale-stream integrand dt) int))) int)
The question is how you'd rendered it in Common Lisp or how you would provide some macrology to mimic the inner define. I know this has been asked before... I am sure somebody knows the answer.
All the best
Maybe I'm missing the point of the question, but I'm not sure I understand why that internal `define` is not equivalent to a `let`. It looks like the code is binding its value and then returning that value. Unless there's something going on here involving lazy evaluation or something? Without knowing more about how `cons-stream`, `scale-stream` and `add-streams` work, it's hard to know.
Do you have a pointer into SICP (chapter, exercise number, etc.)?
On 13 Dec 2021, at 14:04, Marco Antoniotti wrote:
Hi
apologies for the stupid question. I was reviewing some teaching material and looked at the following Scheme (form SICP) code about "streams".
(define (integral integrand initial-value dt) (define int (cons-stream initial-value (add-streams (scale-stream integrand dt) int))) int)
The question is how you'd rendered it in Common Lisp or how you would provide some macrology to mimic the inner define. I know this has been asked before... I am sure somebody knows the answer.
All the best
-- Marco Antoniotti, Professor tel. +39 - 02 64 48 79 01 DISCo, Università Milano Bicocca U14 2043 http://dcb.disco.unimib.it Viale Sarca 336 I-20126 Milan (MI) ITALY
On 13 Dec 2021, at 21:04, Marco Antoniotti marco.antoniotti@unimib.it wrote:
Hi
apologies for the stupid question. I was reviewing some teaching material and looked at the following Scheme (form SICP) code about "streams".
(define (integral integrand initial-value dt) (define int (cons-stream initial-value (add-streams (scale-stream integrand dt) int))) int)
The question is how you'd rendered it in Common Lisp or how you would provide some macrology to mimic the inner define. I know this has been asked before... I am sure somebody knows the answer.
The inner define needs to receive the remainder of the body of the outer define as one of its arguments. Common Lisp’s defmacro sees only arguments passed directly to the macro itself, not whatever comes after the macro invocation.
The only way to solve that is that the outer define parses its body and looks for inner defines, and then rearranges the forms into the proper binding forms (letrec* in Scheme, let*/labels in Common Lisp, depending on which namespace you want to affect).
Pascal
Hi Marco,
The last function below is the Common Lisp equivalent. The function before that contains the essence of it. Because cons-stream's second arg is evaluated only much later, by the time it is evaluated the setf has completed and int has been fully installed. (SICP section 4.1.6 shows that Scheme's inner defines are really just syntactic sugar for the same kind of thing.)
;SICP doesn't delay cars (defstruct my-stream delayed-car delayed-cdr)
(defvar *to-init* (gensym))
;SICP's memo-proc approach avoids creating memo symbols (defmacro delay (x) (let ((memo (gensym))) `(let ((,memo *to-init*)) #'(lambda () (cond ((eql ,memo *to-init*) (setf ,memo ,x)) (t ,memo)))))) (defun force (delayed-val) (funcall delayed-val))
(defmacro cons-stream (x y) `(make-my-stream :delayed-car (delay ,x) :delayed-cdr (delay ,y)))
(defvar *stream-nil* (gensym))
(defun stream-car (s) (force (my-stream-delayed-car s))) (defun stream-cdr (s) (force (my-stream-delayed-cdr s))) (defun stream-null (s) (eql s *stream-nil*))
(defun example1 (x) (let ((int nil)) (setf int (cons-stream x int)))) ; (stream-car (stream-cdr (stream-cdr (rec-stream 'a)))) ; -> A
; omitting defs of add-streams scale-stream (defun integral (integrand initial-value dt) (let ((int nil)) (setf int (cons-stream initial-value (add-streams (scale-stream integrand dt) int)))))
Thanks.
My brain was not working AND I did not do the necessary RTFM of SICP. The
(let ((somestuff nil)) (setf somestuff (something-with-somestuff-closed-over-and-delayed)))
works of course.
The rest is easy macrology.
All the best
Marco
On Tue, Dec 14, 2021 at 6:44 AM Vibhu Mohindra vibhu.mohindra@gmail.com wrote:
Hi Marco,
The last function below is the Common Lisp equivalent. The function before that contains the essence of it. Because cons-stream's second arg is evaluated only much later, by the time it is evaluated the setf has completed and int has been fully installed. (SICP section 4.1.6 shows that Scheme's inner defines are really just syntactic sugar for the same kind of thing.)
;SICP doesn't delay cars (defstruct my-stream delayed-car delayed-cdr)
(defvar *to-init* (gensym))
;SICP's memo-proc approach avoids creating memo symbols (defmacro delay (x) (let ((memo (gensym))) `(let ((,memo *to-init*)) #'(lambda () (cond ((eql ,memo *to-init*) (setf ,memo ,x)) (t ,memo)))))) (defun force (delayed-val) (funcall delayed-val))
(defmacro cons-stream (x y) `(make-my-stream :delayed-car (delay ,x) :delayed-cdr (delay ,y)))
(defvar *stream-nil* (gensym))
(defun stream-car (s) (force (my-stream-delayed-car s))) (defun stream-cdr (s) (force (my-stream-delayed-cdr s))) (defun stream-null (s) (eql s *stream-nil*))
(defun example1 (x) (let ((int nil)) (setf int (cons-stream x int)))) ; (stream-car (stream-cdr (stream-cdr (rec-stream 'a)))) ; -> A
; omitting defs of add-streams scale-stream (defun integral (integrand initial-value dt) (let ((int nil)) (setf int (cons-stream initial-value (add-streams (scale-stream integrand dt) int)))))
-- Vibhu