2015-01-24 4 views
2

Я почти смущен тем, что задал этот вопрос Racket/Scheme, но кто-нибудь может сказать мне, как избежать повторения вызова функции внутри «там», если он был использован для определения условие «здесь» в первую очередь? (cond [здесь есть])Racket/Scheme: Как избежать повторения вызова функции в cond

То, что я пытаюсь получить, является эквивалентом следующего кода стиля C в Racket/Scheme (обратите внимание, что мне нужно было только один раз вызвать regex(), поскольку он был сохранен в переменной матч):

// initialiation code 
if (match = regex("start", "startofstring")) { 
    list->push(match); 
} 
else { 
    printf("No matching regex\n"); 
} 

ракетку код, который я хочу, чтобы избежать заключается в следующем, так как я должен назвать регулярное выражение-матч дважды:

(cond 
    [(regexp-match #rx"start" "startofstring") 
    (set! list (cons (regexp-match #rx"start" "startofstring") list)] 
    [else 
    (printf "No matching regex\n")]) 

Теперь, я мог бы сделать:

(define match (regexp-match #rx"start" "startofstring")) 
(cond 
    [match 
    (set! list (cons match list)] 
    [else 
    (printf "No matching regex\n")]) 

Но этот подход будет означать, что я должен определить очень много переменных, если у меня есть несколько условий (в моем фактическом коде у меня более одного условия ... но ради приведенного выше фрагмента я только ставил в одной). Так что это будет в конечном итоге выглядит некрасиво так:

(define match1 (regexp-match #rx"start" "startofstring")) 
(define match2 (regexp-match #rx"blah" "startofstring")) 
.... 
(define matchn (regexp-match #rx"blahn" "startofstring")) 
(cond 
    [match1 
    (set! list (cons match1 list)] 
    [match2 
    (set! list (cons match2 list)] 
    .... 
    [matchn 
    (set! list (cons matchn list)] 
    [else 
    (printf "No matching regex\n")]) 

То, что я хотел бы кое-что больше вдоль линий:

(cond 
    [(define match (regexp-match #rx"start" "startofstring")) 
    (set! list (cons match list)] 
    [(define match (regexp-match #rx"blah" "startofstring")) 
    (set! list (cons match list)] 
    ... 
    [(define match (regexp-match #rx"blahn" "startofstring")) 
    (set! list (cons match list)] 
    [else 
    (printf "No matching regex\n")]) 

Но это, очевидно, ошибка синтаксиса, так как (определить .. ..) не может использоваться в условии «здесь». Извините за отсутствие ясности ... Я старался изо всех сил передать то, что я говорю. Я знаю, что это очень просто, но я не могу обернуть вокруг себя (я не использую языки, кроме языков c-style).

ответ

5

Правильным решением заключается в использовании cond «s => форма:

(cond ((regexp-match #rx"start" "startofstring") 
     => (lambda (match) 
      (set! lst (cons match lst)))) 
     ...) 

(Обратите внимание, что я переименовал свой list переменную lst, чтобы избежать затенения . Встроенный list процедура)

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

(define (push! match) 
    (set! lst (cons match lst))) 
(cond ((regexp-match #rx"start" str) => push!) 
     ((regexp-match #rx"blah" str) => push!) 
     ...) 

В то время как над работами, я хочу предложить, чтобы вы не использовали set!, так как он не очень функциональный.Стандартная схема способ создать список из цикла является использование имени let, например, так:

(let loop ((result '()) 
      (strs strs)) 
    (define (next match) 
    (loop (cons match result) (cdr strs))) 
    (if (null? strs) 
     result 
     (let ((str (car strs))) 
     (cond ((regexp-match #rx"start" str) => next) 
       ...))) 
+1

«cond => лямбда (совпадение)» на самом деле именно то, что я искал, когда я сказал, что мне нужен эквивалент Racket/Scheme C »(match = regex (« start »,« startofstring »)« Спасибо! – brandonto

+0

Обратите внимание, что правая часть '=>' не должна быть выражением лямбда. Я обновил сообщение, чтобы указать, почему вы, возможно, захотите использовать именованную процедуру, чтобы уменьшить дублирование кода. –

2

Есть несколько простых способов сделать это. Прежде всего, вы можете использовать здесь match.

(match "startofstring" 
    [(regexp #rx"start" match) (cons match list)] 
    [(regexp #rx"blah" match) (cons match list)] 
    ... 
    [_ (printf "No matching regex.\n")]) 

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

(define (any-match str . regexes) 
    (for/or ([regex (in-list regexes)]) 
    (regexp-match regex str))) 

(let ([match (any-match "startofstring" 
         #rx"start" 
         #rx"blah")]) 
    (if match 
     (cons match list) 
     (printf "No matching regex\n"))) 

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

(let ([match (or (regexp-match #rx"start" "startofstring") 
       (regexp-match #rx"blah" "startofstring"))]) 
    (if match 
     (cons match list) 
     (printf "No matching regex\n"))) 
+1

При работе с регулярными выражениями, я почти всегда использую 'match'. Это особенно полезно, когда regexp захватывает. Например: '(match" cat "[(regexp" (.). (.) "(List _ x y)) (string-append x y)])' is '" ct ". –

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