Does Scheme or do any dialects of scheme have a kind of "self" operator so that anonymous lambdas can recur on themselves without doing something like a Y-combinator or being named in a letrec etc.
Something like:
(lambda (n)
(cond
((= n 0) 1)
(else (* n (self (- n 1)))))))
There is a tradition of writing “anaphoric” macros that define special names in the lexical scope of their bodies. Using
syntax-case
, you can write such a macro on top ofletrec
andlambda
. Note that the definition below is as hygienic as possible considering the specification (in particular, invisible uses ofalambda
will not shadowself
).Most people avoid anaphoric operators since they make the structure of the code less recognizable. In addition, refactoring can introduce problems rather easily. (Consider what happens when you wrap the
let/alambda
form in the factorial function above in anotheralambda
form. It's easy to overlook uses ofself
, especially if you're not reminded of it being relevant by having to type it explicitly.) It is therefore generally preferable to use explicit names. A “labeled” version oflambda
that allows this can be defined using a simplesyntax-rules
macro:I have found a way using continuations to have anonymous lambdas call themselves and then using Racket macros to disguise the syntax so the anonymous lambda appears to have a "self" operator. I don't know if this solution is possible in other versions of Scheme since it depends on the Call-with-composable-continuation function of racket and the Macro to hide the syntax uses syntax parameters.
The basic idea is this, illustrated with the factorial function.
The continuation k is the call to the anonymous factorial function, which takes two arguments, the first being the continuation itself. So that when in the body we execute (k k N) that is equivalent to the anonymous function calling itself (in the same way that a recursive named lambda would do).
We then disguise the underlying form with a macro. Rackets syntax-parameters allow the transformation of (self ARGS ...) to (k k ARGS ... )
so we can have:
The complete Racket program to do this is:
This also answers my previous question about the differences between the different kinds of continuations. Different kinds of continuations in Racket
This only works because unlike call-with-current-continuation, call-with-composable-continuation doesn't abort back to a continuation prompt but invokes the continuation at the place it was invoked.
No. The trouble with the "current lambda" approach is that Scheme has many hidden lambdas. For example:
let
forms (includinglet*
,letrec
, and namedlet
)do
(which expands to a namedlet
)delay
,lazy
,receive
, etc.To require the programmer to know what the innermost lambda is would break encapsulation, in that you'd have to know where all the hidden lambdas are, and macro writers can no longer use lambdas as a way to create a new scope.
All-round lose, if you ask me.