Как работают циклы в схеме? - PullRequest
4 голосов
/ 16 февраля 2012

Мне трудно понять, как работают циклы в схеме.В частности, этот код выполняется, но я не знаю, почему

 (define (bubblesort alist)
  ;; this is straightforward
  (define (swap-pass alist)
    (if (eq? (length alist) 1)
        alist
        (let ((fst (car alist)) (scnd (cadr alist)) (rest (cddr alist)))
          (if (> fst scnd)
              (cons scnd (swap-pass (cons fst rest)))
              (cons fst (swap-pass (cons scnd rest)))))))
  ; this is mysterious--what does the 'for' in the next line do?
  (let for ((times (length alist))
            (val alist))
    (if (> times 1)
        (for (- times 1) (swap-pass val))
        (swap-pass val))))

Я не могу понять, что здесь должен делать (let for ((, и выражение for от второй до последней строкиЭто также немного отстраняет - у меня была претензия переводчика, что for принимает только один аргумент, но здесь он, кажется, принимает два.

Есть мысли о том, что здесь происходит?

Ответы [ 2 ]

13 голосов
/ 16 февраля 2012

Это не цикл for, это имя let.Он создает функцию с именем for и вызывает ее;Поведение "зацикливания" вызвано рекурсией в функции.Вызов функции loop более идиоматичен, кстати.Например,

(let loop ((times 10))
   (if (= times 0)
     (display "stopped")
     (begin (display "still looping...")
            (loop (- times 1)))))

расширяется до чего-то вроде

(letrec ((loop (lambda (times)
                 (if (= times 0)
                   (display "stopped")
                   (begin (display "still looping...")
                          (loop (- times 1)))))))
  (loop 10))
5 голосов
/ 16 февраля 2012

На самом деле это не языковая функция for, а просто вариант let, который позволяет легко писать рекурсивные функции. См. эту документацию по let (там находится вторая форма).

То, что происходит, заключается в том, что эта форма let связывает имя, которое она передала (в данном случае for), с процедурой с заданным списком аргументов (times и val) и вызывает ее с начальными значениями , Использование связанного имени в теле - рекурсивные вызовы.

Итог: for здесь не имеет значения. Это просто имя. Вы можете переименовать его в foo, и он все равно будет работать. У Racket действительно есть петли, о которых вы можете прочитать здесь .

...