1
votes

I'm currently attempting to create a stream using a macro, as shown below:

(define-syntax create-stream
  (syntax-rules (using starting at with increment )
    [(create-stream name using f starting at i0 with increment delta)
     (letrec 
       ([name (lambda (f current delta) 
                      (cons current (lambda () (name (f (+ current delta) delta)))))])
       (lambda () (name f i0 delta)))
    ]))

What happens though is I get a compilation error later on when I try to pass it the following lambda function, which says "lambda: not an identifier, identifier with default, or keyword".

(create-stream squares using (lambda (x) (* x x)) starting at 5 with increment 2)

What I suspect is happening is that by attempting to use lambda in a macro, it's shadowing the actual lambda function in Racket. If this is true, I'm wondering in what way one can create a stream without using lambda, since as far as I can tell, there needs to be a function somewhere to create said stream.

Also this is a homework problem, so I do have to use a macro. My equivalent function for creating the stream would be:

(define create-stream
  (letrec ([name (lambda (f current delta) (cons current (lambda () (name (f (+ current delta) delta)))))])
    (lambda () (name f i0 delta))))
2
instead of stripping away the define name part, try keeping (define name (lambda () (fn i0)) as is, adding name after it, and see what happens. but you really should post a new question with all this. - Will Ness

2 Answers

1
votes

What I suspect is happening is that by attempting to use lambda in a macro, it's shadowing the actual lambda function in Racket

No, that's not correct.

The problem here is that you use f and delta in binding positions, in (lambda (f current delta) ...). That means after (create-stream squares using (lambda (x) (* x x)) starting at 5 with increment 2) is expanded, you will get code like:

(lambda ((lambda (x) (* x x)) current 2) ...)

which is obviously a syntax error.

You can see this yourself by using the macro stepper in DrRacket.

The fix is to rename the identifiers to something else. E.g.,

(define-syntax create-stream
  (syntax-rules (using starting at with increment )
    [(create-stream name using f starting at i0 with increment delta)
     (letrec 
       ([name (lambda (f* current delta*) 
                      (cons current (lambda () (name (f* (+ current delta*) delta*)))))])
       (lambda () (name f i0 delta)))
    ]))

This will make your code start running, but there are still other several bugs in your code. Since this is your homework, I'll leave them to you.

0
votes

Your current problem essentially boils down to this (broken) code

(let ((x 0))
    (define y x))

This is not equivalent to (define y 0) - y's definition is local to the let-binding.

The solution is to flip the definitions around and make the letrec local to the define:

(define name
    (letrec (... fn definition ...)
        (lambda () (fn i0))))