2013-02-27 3 views
1

Мой вопрос заключается в переписывании вложенных условий if на один cond с ветвью, имеющей локальную привязку. Я очень новичок в Racket, просто делаю первые шаги, поэтому, если мой вопрос глуп, пожалуйста, будьте снисходительны.cond с локальным связыванием

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

Рабочим раствор использует рекурсивную вспомогательную функцию с вложенным МФСОМ

[vlen (vector-length vec)] 
[find-in-vector 
(lambda (pos) 
(if (= pos vlen)        ;; if the end of the vector has been reached 
    #f           ;; then return false 
    (let ([el (vector-ref vec pos)])   ;; Otherwise, extract current element from the vector, 
     (if (and (pair? el) (equal? v (car el))) ;; if the element is a pair and its car is what we want 
      el         ;; then return the element 
      (find-in-vector (+ 1 pos))))))]  ;; otherwise keep searching the vector 

Я хотел бы переписать его так, что он использует cond, что выглядит более компактным. Нижеприведенный код является возможной реализацией. Проблема заключается в том, что (vector-ref vec pos) вычисляется несколько раз, и это то, что я хотел бы переписать так, что она вычисляется только один раз, как и в предыдущей реализации с вложенным МФСОМ

[vlen (vector-length vec)] 
[find-in-vector 
(lambda (pos) 
    (cond [(= pos vlen) #f] 
     [(and (pair? (vector-ref vec pos))   ;; one 
       (equal? v (car (vector-ref vec pos)))) ;; two 
      (vector-ref vec pos)]      ;; three is too many 
     [#t (find-in-vector (+ 1 pos))]))]) 

И это то, что я достиг в больше всего: один вызов (vector-ref vec pos) в тест-выраж и другой вызов в результате-выраж

(cond 
    [(= pos vlen) #f] 
    [(letrec ([el (vector-ref vec pos)])  ;; extract current element from the vector 
    (and (pair? el) (equal? v (car el)))) ;; and use it in conditionals 
    (vector-ref vec pos)]     ;; again, extract and return. FIXIT 
    [#t (find-in-vector (+ 1 pos))]))])  ;; otherwise, keep searching 

Как можно дальше сделать el разделены между тест-ехрг и результатом экспрессии? И я бы хотел, чтобы el оставался локальным для этой конкретной кондиционной ветви. Данный код работает неправильно. AFAIU, целое выражение letrec: рассматривается как текст-выражение из cond?

(cond 
[(= pos vlen) #f] 
[(letrec ([el (vector-ref vec pos)]) 
    (and (pair? el) (equal? v (car el))) 
    el)] 
[#t (find-in-vector (+ 1 pos))]) 
+0

Самый простой способ ввести локальную привязку - это 'lambda'. Вот тэп кода из ответа Криса: '(cond ... (((lambda (el) (и (pair? El) (equal? ​​V (car el)) el)) (vector-ref vec pos))) (иначе ...)). Неловко, но работает. –

+0

(хотя, я тестировал его в MIT Scheme, а не в Racket). –

ответ

1

Вы можете это сделать, если импортировать SRFI 61 первый:

(require srfi/61) 
(define (find-in-vector vec v) 
    (define vlen (vector-length vec)) 
    (let loop ((pos 0)) 
    (cond 
     ((= pos vlen) #f) 
     ((vector-ref vec pos) 
     (lambda (el) (and (pair? el) (equal? v (car el)))) 
     => values) 
     (else (loop (add1 pos)))))) 

Важно, что SRFI 61 обеспечивает то, что он позволяет п (<generator> <guard> => <receiver>). Здесь генератор - это то, что создает общее значение, которое должно использоваться как предохранителем , так и приемником . Наш приемник в этом случае - это просто values, который возвращает значение, которое оно дано без какой-либо обработки.


Обновление: В настоящее время srfi/61 не работает для программ, которые используют #lang racket или т.п. (srfi/61 использует различные привязок для => и else от того, что racket/private/cond предоставляет). Это было recently fixed и должно появиться в будущем выпуске Racket.

+0

Я уже собирался жаловаться, что '=>' не работает для меня :). Я заменил 'else' на' # t', но до сих пор не знаю, как обращаться с '=>'. –

+0

@ NikO'Lai У меня есть модифицированная версия 'srfi/61', которая действительно работает, но я неохотно предлагаю людям модифицировать их установку Racket.На самом деле это непростая задача: прямо сейчас, srfi/61' работает только со старыми программами, но с моими изменениями он работает только с программами нового стиля. Мне жаль, что я не знаю решения, которое будет работать как с программами старого стиля, так и с новым стилем. –

+0

oh .. проблем нет. я могу жить с ifs :) Большое вам спасибо за ваше время! –

Смежные вопросы