Схема раннего "возврата короткого замыкания"? - PullRequest
4 голосов
/ 12 марта 2010

Я пытаюсь выяснить, как я могу выполнить «ранний возврат» в схеме процедуры без с использованием конструкции верхнего уровня if или cond.

(define (win b)
 (let* ((test (first (first b)))
        (result (every (lambda (i) (= (list-ref (list-ref b i) i) test))
                       (enumerate (length b)))))
  (when (and (not (= test 0)) result) test))
 0)

Например, в приведенном выше коде я хочу, чтобы win вернул test, если выполнено условие when, в противном случае вернет 0. Однако происходит то, что процедура всегда вернуть 0 независимо от результата условия when.

Причина, по которой я структурирую свой код таким образом, заключается в том, что в этой процедуре мне нужно выполнить множество сложных проверок (несколько блоков, подобных let* в примере), и поместить все в большой cond будет очень громоздко .

Ответы [ 4 ]

7 голосов
/ 12 марта 2010

Вот как использовать call / cc для сборки return самостоятельно.

(define (example x)
  (call/cc (lambda (return)
    (when (< x 0) (return #f))
    ; more code, including possible more calls to return
    0)))

Некоторые схемы определяют макрос под названием let / cc, который позволяет вам избавиться от некоторого шума лямбды:

(define (example x)
  (let/cc return
    (when (< x 0) (return #f))
    0))

Конечно, если ваша Схема этого не делает, пусть / cc написать тривиально.


Это работает, потому что call / cc сохраняет точку, в которой он был вызван как продолжение. Он передает это продолжение в свой аргумент функции. Когда функция вызывает это продолжение, Scheme отказывается от созданного им стека вызовов и продолжает работу с конца вызова / вызова cc. Конечно, если функция никогда не вызывает продолжение, она просто возвращается нормально.

Продолжения не будут по-настоящему утомительными, пока вы не начнете возвращать их из этой функции или, возможно, не сохраните их в глобальной структуре данных и не вызовете их позже. В противном случае они похожи на любые структурированные операторы goto любого другого языка (в то время как / для / прерывания / возврата / продолжения / исключения / условия).


Я не знаю, как выглядит ваш полный код, но, возможно, было бы лучше использовать cond и разделить сложные проверки на отдельные функции. Необходимость return и let* обычно является признаком чрезмерно императивного кода. Однако метод call / cc должен заставить ваш код работать на данный момент.

1 голос
/ 12 марта 2010

Одним из способов было бы использование рекурсии вместо цикла, тогда досрочный выход достигается, если больше не повторяться.

0 голосов
/ 13 марта 2010

В этом случае вы не хотите, когда, вы хотите, если, хотя не верхнего уровня.

(define (win b)
  (let* ((test (first (first b)))
         (result (every (lambda (i) (= (list-ref (list-ref b i) i) test))
                        (enumerate (length b)))))
    (if (and (not (= test 0)) result) 
        test
        0)))

Причина, по которой он всегда возвращал ноль, состоит в том, что независимо от того, было ли выполнено тело оператора, его результат будет отброшен на пол. Видите ли, лямбда, неявная в форме определения функции, тоже создает неявный блок начала, поэтому

(define foo 
  (lambda (b)
     (begin
       (let ...)
       0)))

и способ начать работу состоит в том, что он возвращает результат последней формы внутри, отбрасывая все промежуточные результаты на пол. Эти промежуточные результаты имеют побочные эффекты. Вы не используете ничего из этого, что замечательно (!), Но вы должны быть осторожны, чтобы в определении функции была только одна форма (результат которой вы действительно хотите).

Grem

0 голосов
/ 12 марта 2010

Вы можете использовать поддержку «Вызов с текущим продолжением» для имитации возврата. В википедии есть пример. Функция называется call-with-current-продолжением , хотя часто встречается псевдоним call / cc , что в точности то же самое. Есть также немного более чистый пример здесь

Примечание: Это довольно продвинутая техника программирования на Схеме, и поначалу она может быть немного изнурительной ... !!!!

...