Summary

matchable: Add conversion pattern(s)

Metadata

Attachments

Description

The attached patch adds two new pattern types to matchable:

  {{(-> convert pat-1 … pat-n)}}
  {{(-?> convert pat-1 … pat-n)}}

These patterns work like the (? predicate pat-1 … pat-n) pattern in that convert must be an expression evaluating to a single argument function which is applied to the corresponding value. However, in contrast to ?, the following patterns

 {{{convert}}}. In addition, {{{-?>}}} only matches when {{{convert}}}
 does not return {{{#f}}}, so it can be expressed as combination of
 {{{->}}} and {{{?}}} like this:
 
   {{{(-> convert (? (lambda (x) x) pat-1 … pat-n))}}}
 
 The rationale is that it allows to match against a converted value and
 at the same time being able to bind that value to a variable instead
 of having to apply the conversion again in the body. One might argue
 that {{{-?>}}} is not really necessary so I'd be happy with only
 adding {{{->}}}, too. It should be noted that this patch is not
 backwards compatible.
 
 
 Some examples:
 
 {{{
 (match '("foo" "10")
   (("foo" (-> string->number x)) (+ x x)))
 
 ;; => 20
 
 
 (match '("foo" "bar")
   (("foo" (-> string->number x)) (+ x x)))
 
 ;; Error: (+) bad argument type: #f
 
 
 (match '("foo" "10")
   (("foo" (-?> string->number x)) (+ x x))
   (else 'nothing))
 
 ;; => 20
 
 
 (match '("foo" "bar")
   (("foo" (-?> string->number x)) (+ x x))
   (else 'nothing))
 
 ;; => nothing

Changes and comments

[2013-07-12 10:49:05 UTC] syn attached arrows-and-questionmarks.diff (description=#f)

[2013-07-12 10:53:02 UTC] syn changed description

[2013-07-12 11:12:28 UTC] syn wrote:

Another nice use is destructuring records using slot accessors rather than the positional ($ struct pat-1 … pat-n) pattern:

 (define-record point x y)
 
 (match (list (make-point 1 2) (make-point 3 4))
   (((-> point-x xs) ...) xs))
 
 ;; => (1 3)

[2013-07-12 15:10:41 UTC] ashinn changed status from new to accepted

[2013-07-12 15:10:41 UTC] ashinn wrote:

Interesting. I believe -> is equivalent to the existing =.

-?> can be achieved by combining ? and =. I'm not sure if the use cases are common enough to warrant the shortcut, but I'll consider it.

[2013-07-12 15:20:38 UTC] syn wrote:

Ah, you are right, = is almost the same, except that it only allows for exactly one following pattern. I didn't notice it because the documentation is a bit misleading (suggesting that it only works on fields, although this is only one common case). Maybe I can think of something to improve that. Should you consider adding a shortcut, perhaps =? would be a good name. How about extending = to allow for more than one following pattern in any case? This would even be backwards compatible.

[2013-07-12 15:29:59 UTC] ashinn wrote:

Multiple patterns can be done with an and. This could be made implicit, at which point the only disadvantage is loss of portability.

The -?> is also just a matter of nesting ?:

(match '("foo" "10")

  (("foo" (= string->number (? values x))) (+ x x)))

This isn't too much more verbose and no less efficient.

In general the idea is to do more with less, and try to keep the match syntax simple - it's already complex enough that people overlook things like the = syntax :)

If you have real-world examples that show -?> as a likely common idiom I can consider it, but I'm more likely to just add a single extension mechanism and stop adding any new fixed syntax.

BTW, "field accessor" comes from the original description in Wright's paper. Suggestions for improvement are welcome.

[2013-07-13 11:49:34 UTC] syn wrote:

Right, implicit `and' makes for more convenient patterns but agreed, loss of portability is an issue, too. I'm also aware of the fact that -?> can be expressed by nesting ? (see the original ticket description) but I found it a bit verbose. Nice trick to use `values' for identity, by the way, I shall keep that one in mind. Anyhow, the use case I encountered for -?> is indeed what I gave as an example. This is especially handy when matching on (command-line-arguments) where some arguments are numbers. OTOH, maybe it is better to use = in that case, too, so that one can give a more meaningful error message rather than falling through to no matching pattern.

I am much more in favor of a general extension mechanism, though, so that we can stop piling features on top :-) Do you have anything in mind how this could be accomplished? I'd gladly try my hand at implementing that!