Racket/Scheme: 如何避免在 cond 中重复函数调用
Racket/Scheme: How to avoid repeating function call in cond
问这个 Racket/Scheme 问题我几乎感到尴尬,但是谁能告诉我如何避免在 "there" 中重复函数调用,如果它被用来确定条件 "here" 首先? (cond [这里那里])
我想要得到的是 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 风格语言以外的语言)。
有几种干净的方法可以做到这一点。首先,你可以在这里使用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")))
正确的解决方案是使用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)
...)))
问这个 Racket/Scheme 问题我几乎感到尴尬,但是谁能告诉我如何避免在 "there" 中重复函数调用,如果它被用来确定条件 "here" 首先? (cond [这里那里])
我想要得到的是 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 风格语言以外的语言)。
有几种干净的方法可以做到这一点。首先,你可以在这里使用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")))
正确的解决方案是使用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)
...)))