首页 文章

球拍/方案:如何避免在cond中重复函数调用

提问于
浏览
2

我对于询问这个球拍/方案问题几乎感到尴尬,但有人可以告诉我如何避免在“那里”重复一个函数调用,如果它首先用于确定“这里”的条件吗? (cond [here there])

我想要得到的是相当于Racket / Scheme中的以下C样式代码(注意我只需要调用regex()一次,因为它存储在变量匹配中):

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

我想要避免的Racket代码如下,因为我必须两次调用regexp-match:

(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")])

但这显然是语法错误,因为(define .. ..)不能在条件“here”中使用 . 对不起因为缺乏清晰度......我尽我所能来表达我的意思 . 我知道这非常简单,但我不能完全围绕它(我没有使用除c风格语言之外的语言) .

2 回答

  • 5

    正确的解决方案是使用 cond=> 形式:

    (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! ,因为它不是很实用 . 从循环中构建列表的标准Scheme方法是使用名为 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)
                  ...)))
    
  • 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")))
    

相关问题