Reputation: 125
I'm almost embarrassed for asking this Racket/Scheme question, but can anybody tell me how to avoid repeating a function call inside "there" if it was used to determine the condition "here" in the first place? (cond [here there])
What I am trying to get is the equivalent of the following C style code in Racket/Scheme (notice that I only had to call regex() once, since it was stored in a variable match):
// initialiation code
if (match = regex("start", "startofstring")) {
list->push(match);
}
else {
printf("No matching regex\n");
}
The Racket code that I want to avoid is the following since I have to call regexp-match twice:
(cond
[(regexp-match #rx"start" "startofstring")
(set! list (cons (regexp-match #rx"start" "startofstring") list)]
[else
(printf "No matching regex\n")])
Now, I could do:
(define match (regexp-match #rx"start" "startofstring"))
(cond
[match
(set! list (cons match list)]
[else
(printf "No matching regex\n")])
But this approach will mean that I have to define very many variable if I have more than one condition (in my actual code, I have more than one condition... but for the sake of the snippet above, I only put in one). So it will end up looking ugly like this:
(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")])
What I would like is something more along the lines of:
(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")])
But this is obviously a syntax error because (define .. ..) can't be used in the condition "here". Sorry for the lack of clarity... I tried the best I could to convey what I am saying. I know this is very super simple but I can't quite wrap my head around it (I haven't use languages other than c-style languages).
Upvotes: 2
Views: 488
Reputation: 223003
The correct solution is to use cond
's =>
form:
(cond ((regexp-match #rx"start" "startofstring")
=> (lambda (match)
(set! lst (cons match lst))))
...)
(Note that I renamed your list
variable to lst
to avoid shadowing the built-in list
procedure.)
If you have many patterns, and the same action for multiple patterns, you should extract out the common code into a separate procedure:
(define (push! match)
(set! lst (cons match lst)))
(cond ((regexp-match #rx"start" str) => push!)
((regexp-match #rx"blah" str) => push!)
...)
While the above works, I want to suggest that you don't use set!
, since it's not very functional. The standard Scheme way to build up a list from a loop is to use a named let
, like so:
(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)
...)))
Upvotes: 5
Reputation: 43842
There are a couple of clean ways to do this. First of all, you could use match here.
(match "startofstring"
[(regexp #rx"start" match) (cons match list)]
[(regexp #rx"blah" match) (cons match list)]
...
[_ (printf "No matching regex.\n")])
Of course, even that has a lot of repetition. You could do this a little differently with a small helper function.
(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")))
Alternatively, if you don't want the baggage of a helper function, but you're okay with a little bit more repetition, you can just do this:
(let ([match (or (regexp-match #rx"start" "startofstring")
(regexp-match #rx"blah" "startofstring"))])
(if match
(cons match list)
(printf "No matching regex\n")))
Upvotes: 2