для / продолжить в схеме / LISP - PullRequest
5 голосов
/ 03 января 2011

Я пишу небольшой интерпретатор для C-подобного языка в Scheme (R5RS) и пытаюсь преобразовать что-то вроде:

for (i = 0; i < 100; i++)
{
    if (isprime(i)) continue;
    else /* do something with i */
}

в правильную Scheme (функция isprime является лишь примером, а неважный).

Однако, пытаясь некоторое время, я не смог найти эффективный / простой способ добавить эквивалент оператора continue в цикл do в Scheme.Что было бы еще лучше, так это макрос «for», который позволяет использовать «continue» и «break».

Я подумываю о переходе на Common Lisp.Разве это было бы проще в CL?

Ответы [ 6 ]

5 голосов
/ 04 января 2011

Мы можем написать FOR как макрос.Версия Common Lisp:

(defmacro for ((var start end) &body body)
  (let ((block-name (gensym "BLOCK")))
    `(loop for ,var from ,start below ,end
           do (block ,block-name
                (flet ((continue ()
                         (return-from ,block-name)))
                  ,@body)))))


CL-USER 2 > (for (i 10 20)
              (if (evenp i) (continue))
              (print i))

11 
13 
15 
17 
19 
2 голосов
/ 03 января 2011

CL's tagbody - удобная цель:

(let (i)
  (tagbody
     (setf i 0)
   body
     (if (isprime i)
         (go increment))
     (do-something-with i)
   increment
     (setf i (1+ i))
     (if (< i 100)
         (go body))))
1 голос
/ 03 января 2011

Я бы пошел на продолжений , как в этом примере псевдосхемы.

Просто сохраните текущую точку выполнения в продолжении и при необходимости вызовите ее.

(call/cc (lambda break ; jump outside the for
  (for 0 100 (lambda i 
    (call/cc (lambda continue ; jump to the next iteration
      (if (isprime i)
        (continue)
        (break))))))))
0 голосов
/ 10 июня 2019

Я знаю, что это на 8 лет позже, но я подумал, что это может кому-то помочь.

Используя конструкцию iterate в Common Lisp, вы можете использовать предложение следующей итерации:

(iter (for i from 0 to 100) 
  (if (isprime i)
      (next-iteration)
      (do-something-else)))
0 голосов
/ 03 января 2011

Я думаю, что ответ Виджая может быть расширен таким образом, чтобы он работал (извините за ответ на мой вопрос, но не могу понять, как отформатировать код в комментарии):

(let loop ((i 0))
    (define (next)
      (loop (+ i 1)))
    (call/cc 
      (lambda (break)
        (if (< i 100)
         (begin
           (if (isprime i)
             (next)
             (begin
               (if (isbad i)
                 (break break))
               (do-something)
               (next))))))))

Это не макрос, но, несомненно, приводит к достаточно общему. Мне было бы интересно увидеть какие-либо улучшения. Я довольно новичок в Схеме.

0 голосов
/ 03 января 2011

Для реализации этого конкретного примера кода в Схеме вам не нужны continue, break или call/cc:

(let loop ((i 0))
  (when (< i 100)
      (if (prime? i)
          (loop (add1 i)))
      (do-something-else)))
...