Определение цикла 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 ...)))))
Другие вопросы по тегам