Я нашел способ использовать продолжения, чтобы анонимные лямбды вызывали самих себя, а затем использовать макросы Racket для маскировки синтаксиса, чтобы у анонимной лямбды был оператор «я».Я не знаю, возможно ли это решение в других версиях Scheme, поскольку оно зависит от функции Call-with-composable-продолжения ракетки и макроса, чтобы скрыть синтаксис, использует параметры синтаксиса.
Основная идеяэто, проиллюстрировано факториальной функцией.
( (lambda (n)
(call-with-values
(lambda () (call-with-composable-continuation
(lambda (k) (values k n))))
(lambda (k n)
(cond
[(= 0 n) 1]
[else (* n (k k (- n 1)))])))) 5)
Продолжение k - это вызов анонимной факториальной функции, которая принимает два аргумента, первый из которых - само продолжение.Так что, когда в теле мы выполняем (kk N), что эквивалентно анонимной функции, вызывающей себя (так же, как это делает рекурсивный с именем lambda).
Затем мы замаскируем базовую форму с помощью макроса,Синтаксические параметры ракеток позволяют преобразовывать (self ARGS ...) в (kk ARGS ...)
, поэтому мы можем иметь:
((lambda-with-self (n)
(cond
[(= 0 n) 0]
[(= 1 n) 1]
[else (* n (self (- n 1)))])) 5)
Полная программа Racket для этогоis:
#lang racket
(require racket/stxparam) ;required for syntax-parameters
( define-syntax-parameter self (λ (stx) (raise-syntax-error #f "not in `lambda-with-self'" stx)))
(define-syntax-rule
(lambda-with-self (ARG ... ) BODY ...)
(lambda (ARG ...)
(call-with-values
(lambda ()(call/comp (lambda (k) (values k ARG ...))))
(lambda (k ARG ...)
(syntax-parameterize ([self (syntax-rules ( )[(self ARG ...) (k k ARG ...)])])
BODY ...)))))
;Example using factorial function
((lambda-with-self (n)
(cond
[(= 0 n) 0]
[(= 1 n) 1]
[else (* n (self (- n 1)))])) 5)
Это также отвечает на мой предыдущий вопрос о различиях между различными типами продолжений. Различные виды продолжений в Racket
Это работает только потому, что в отличие от call-with-current-продолжением, call-with-composable-продолжением не прерывается обратно к приглашению продолжения, но вызываетпродолжение в том месте, где оно было вызвано.