Question

(define-macro slambda
  (lambda (args body)
    `(let ((self (lambda ,args ,body)))
        self)))

Hello, I have a "problem" with this macro for self-referencing lambda.. It works, but fails when I want to refer to "self" from outside.. meaning that first aplication works, second doesn't

  1. ((slambda (x) (+ x 1)) 10)

  2. ((slambda () self))

Was it helpful?

Solution 3

You need to quote the lambda-part where you quasiqute so it can be assigned to self.

(define-macro slambda
  (lambda (arg1 . arg2)
    `(let ((self '(slambda ,arg1 ,@arg2)))
       (lambda ,arg1 ,@arg2))))

The dot and unquote-splicing is needed there if you want to use it with more than one argument.

OTHER TIPS

Perhaps it would work better you replaced let for letrec like this:

(define-macro slambda
  (lambda (args body)
    `(letrec ((self (lambda ,args ,body)))
        self)))

In Scheme you have lexical scope and self is not in effect until the body of the let. The procedure called self in the body of the let is not defined by that name inside itself. It's perhaps easier to see if you desugar let:

((lambda (self) ...)
 (lambda () self)) ; self referenced outside procedure that defines it

Notice that define-macro isn't a standard scheme syntax so you should have specified which implementation you are using. Luckily this problem had nothing to do with macros.

If you are using scheme you might be better off using standard define-syntax rather than the not-always-supported define-macro. With define-syntax, you have to use datum->syntax to get the macro to act unhygienically and inject the name 'self' into the output syntax. This is your code translated to define-syntax, as tested with guile:

(define-syntax slambda
  (lambda (x)
    (syntax-case x ()
      [(slambda formals body0 body1 ...)
       (with-syntax ([self (datum->syntax #'slambda 'self)])
                    #'(letrec ([self (lambda formals body0 body1 ...)])
                        self))])))

Sylwester's answer is correct, but I wanted to make a bigger point: unless your Scheme implementation doesn't provide a hygienic procedural macro system, there is no good reason to use define-macro.

For anaphoric macros, such as the one you want to write, it's best to use syntax parameters, if you're using a Scheme implementation that supports it, such as Racket or Guile. Here's a Racket example:

#lang racket
(provide slambda self)
(require racket/stxparam srfi/31)

(define-syntax-parameter self
  (lambda (stx)
    (raise-syntax-error 'self "Can only be used inside slambda")))

(define-syntax slambda
  (syntax-rules ()
    ((_ params body ...)
     (rec (ohai . params)
       (syntax-parameterize ((self (make-rename-transformer #'ohai)))
         body ...)))))

Of course, as you can see in my example, I used rec. In the general case where you want to make self-referential procedures, it's best to use rec for that; you simply specify the name you want to refer to the procedure by (rather than using a hardcoded self). Since rec is not anaphoric, its definition is much simpler:

(define-syntax rec
  (syntax-rules ()
    ((_ (id . params) body ...)
     (rec id (lambda params body ...)))
    ((_ id value)
     (letrec ((id value)) id))))

You would use it like this (in this case, I use recur as the self-reference; of course, you can choose any name you like):

(define nested-length
  (rec (recur x)
    (cond ((null? x) 0)
          ((pair? x) (+ (recur (car x)) (recur (cdr x))))
          (else 1))))
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top