получение только одного из значений из вызова

#racket

#racket

Вопрос:

Есть ли способ получить только один из результатов, возвращаемых из values ? Я пытался сделать (define x (first (values 1 2))) , но это не сработало. Это единственный способ написать что-то вроде (define-values (x dont-care) (values 1 2)) и определить дополнительную переменную?

Ответ №1:

Это единственный способ написать что-то вроде (define-values (x dont-care) (values 1 2)) и определить дополнительную переменную?

Все единственные способы получить одно из значений из многозначной вещи включают определение дополнительных переменных, как dont-care здесь. Однако вы можете использовать область видимости, либо локальную, либо макроскопическую, чтобы смягчить это и скрыть их.

Вы можете использовать let-values для ограничения области следующим образом:

 (define x (let-values ([(x dont-care) (values 1 2)]) x))
  

Или вы можете использовать макрос, чтобы «скрыть» другие переменные:

 (define-syntax-rule (define-first-of-two-values x expr/2vs)
  (define-values (x dont-care) expr/2vs))

(define-first-of-two-values x (values 1 2))
  

После этого определение x будет доступно, но dont-care не будет, поскольку оно ограничено областью определения макроса.

Вы также можете использовать существующий макрос, такой как match-define-values , с _ подстановочным знаком для значений, которые вас не интересуют.

 (match-define-values (x _) (values 1 2))
  

match-define-values Макрос фактически расширяется во что-то очень похожее на первый let-values пример выше.

Комментарии:

1. Спасибо! Возможно, не связанный с этим вопрос: является ли multiple-values лучшим способом реализации функции, которая возвращает несколько значений? Или лучше использовать такие вещи, как пары? (с тем преимуществом, что возвращаемыми значениями можно манипулировать с помощью car и cdr )

2. Многозначности определенно менее гибки, чем такие данные, как пары, кортежи или списки. Было много случаев, когда я выбирал возвращать список фиксированной длины вместо нескольких значений, особенно если я хочу, чтобы что-то либо завершилось успехом с несколькими значениями, либо завершилось неудачей с одним значением #f . Подобные шаблоны плохо сочетаются с values возвратами, но списки фиксированной длины более гибкие.

3. @JRR Хотя схема с несколькими значениями, вероятно, быстрее, чем CL, ее гораздо менее удобно использовать. В CL вы всегда можете использовать каждую функцию, которая возвращает несколько значений, и она будет использовать только первое вне multiple-value-bind (так же, как Scheme let-values ).

4. Спасибо обоим. Я пытался найти эквивалент «параллельного присваивания» python в racket и наткнулся на это. Не уверен, правильно ли это делать?

5. Сопоставление с шаблоном, из racket/match

Ответ №2:

Я использовал этот макрос:

 (define-syntax-rule (first-value expr)
  (call-with-values (λ () expr)
    (λ (result . ignored) result)))

> (first-value (values 10 20 30 40 50))
10
  

Это работает с любым количеством значений. Смотрите call-with-values документацию.