Определение цикла For в схеме
Примечание. По-видимому, это версия схемы Gauche 0.9.3.3.
Кажется, я не могу обернуться вокруг этих языков Lisp:/.
Я пытаюсь определить синтаксис цикла for в схеме. Я не уверен, что это выполнимо с помощью рекурсивной функции (я думаю, что это так), но на данный момент я действительно хочу получить define-syntax
за работой.
Я могу заставить цикл запускаться один раз (и тогда он выглядит так, как будто он заканчивается) следующим кодом:
(define-syntax forloop
(syntax-rules ()
((forloop start stop exps)
(letrec ((aloop (lambda (astart astop aexps)
(if (<= astart astop) (begin aexps (aloop (+ astart 1) astop aexps))))))
(aloop start stop exps)))))
Было бы неплохо также иметь возможность определить его с помощью многоточия, но это дает "шаблон содержит повторение постоянной формы". Я прочитал раздел макросов спецификации R5RS, хотя скоро буду перечитывать раздел шаблонов:
(define-syntax forloop
(syntax-rules ()
((forloop start stop exps ...)
(letrec ((aloop (lambda (astart astop aexps ...)
(if (<= astart astop) (begin aexps ... (aloop (+ astart 1) astop aexps ...))))))
(aloop start stop exps ...)))))
Сначала я попробовал это сделать, но он работает в течение 10 секунд, а затем завершается с ошибкой без вывода... Я использую http://www.compilonline.com/, так что это может иметь какое-то отношение к этому:
(define-syntax forloop
(syntax-rules ()
((forloop start stop exps ...)
(if (<= start stop)
(begin exps ... (forloop (+ start 1) stop exps ...))))))
Нет проблем, если я никогда не вызову forloop (что я думаю, потому что он никогда не должен расширять макрос), поэтому код, который я использовал для проверки, это:
(forloop 6 8 (display "g"))
Что я делаю неправильно? Я успешно реализовал when
заявление (самостоятельно, но есть десятки примеров, и я уже видел много из них). Я думаю, что рекурсивный характер того, что я хочу сделать, и многоточие меня портят.
1 ответ
Макросы раскрываются во время компиляции, что-то вроде (begin exps ... (forloop (+ start 1) stop exps ...))
будет расширяться forloop
снова и снова, независимо от того, что значение (+ start 1)
есть (который оценивается во время выполнения).
Возможно, лучшее, что вы можете сделать, по крайней мере, с syntax-rules
, должен использовать макрос для захвата только выражений для выполнения и использовать немарокодовый код для борьбы с циклом:
(define-syntax forloop
(syntax-rules ()
((forloop start stop exps ...)
(let ((j stop))
(let loop ((i start))
(when (<= i j)
exps ...
(loop (+ i 1))))))))
Вы также можете использовать do
цикл:
(define-syntax forloop
(syntax-rules ()
((forloop start stop exps ...)
(let ((j stop))
(do ((i start (+ i 1)))
((> i j))
exps ...)))))