Как работают «значения» в Scheme?

Из стандарта R5RS:

Values might be defined as follows:
(define (values . things)
  (call-with-current-continuation
    (lambda (cont) (apply cont things))))

Моей первой интерпретацией этого было то, что такое выражение, как (+ (values 1 2)), эквивалентно (apply + '(1 2)) и даст результат 3. Но, согласно моим тестам, эта интерпретация неверна. Вот моя интерпретация приведенного выше кода: values — это функция, принимающая любое количество аргументов, объединенных в список с именем things. Затем вызывается текущее продолжение (место, где используется values) со списком things "развязанным".

Что мне не хватает? Пример выше (+ (values 1 2)) дает ошибку или 1 в зависимости от используемого мной интерпретатора.


person Gradient    schedule 03.04.2018    source источник
comment
Я думаю, что вы упускаете то, что + не является продолжением.   -  person molbdnilo    schedule 04.04.2018


Ответы (2)


Смотрите, когда вы печатаете

(+ (values 1 2))

продолжение вызова values на самом деле является одним аргументом +. Таким образом, это либо рассматривается как 1 (первый элемент в списке, первое значение, полученное процедурой), либо как ошибка. R5RS говорит по этому поводу:

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

С другой стороны, call-with-values правильно свяжет элементы вашего списка с формальными аргументами аргумента consumer:

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

person bipll    schedule 03.04.2018
comment
Ах я вижу! Я протестировал (+ (values 1)), и он работает в интерпретаторе, который выдал ошибку (+ (values 1 2)). - person Gradient; 04.04.2018

Чтобы понять, что означает это определение values, вам необходимо также понять определение call-with-current-continuation, в терминах которого оно определяется. И кстати, документация для values упоминает call-with-values в качестве примера того, как использовать результат values.

Таким образом, вы можете использовать (values 1 2) в таком контексте, как:

(call-with-values (lambda () (values 1 2))
                  (lambda (x y) (+ x y)))
person amalloy    schedule 03.04.2018