# Is it good style to use \`#:when\` instead of \`?\` in match expression?

**URL:** <https://racket.discourse.group/t/is-it-good-style-to-use-when-instead-of-in-match-expression/779>\
**Category:** Questions & Answers\
**Created:** [March 10, 2022, 3:50am UTC](https://racket.discourse.group/t/is-it-good-style-to-use-when-instead-of-in-match-expression/779 "2022-03-10T03:50:03Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![NoahStoryM](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/noahstorym/32/17_2.png) [@NoahStoryM](https://racket.discourse.group/u/NoahStoryM)\
**Post date:** [March 10, 2022, 3:50am UTC](https://racket.discourse.group/t/is-it-good-style-to-use-when-instead-of-in-match-expression/779/1 "2022-03-10T03:50:04Z")

</div>

Hi everyone, this question originally came to me while working with Typed Racket. The current Typed Racket seems not to support `match` very well, so in many cases, `?` cannot be used to mark type through predicate. For example, the following code will not work:

```scheme
#lang typed/racket

(match '[-> Number Number Number]
  [`[-> ,(? symbol? #{ts : (Listof Symbol)}) ... ,(? symbol? t1)]
   (displayln ts)
   (displayln t1)])

```

And we can use `#:when` to get the same behavior:

```scheme
#lang typed/racket

(: listof? (All (A) [-> (pred A) (pred (Listof A))]))
(define listof?
  (λ (pred)
    (λ (arg)
      (and (list? arg)
           (andmap pred arg)))))

(match '[-> Number Number Number]
  [`[-> ,ts ... ,t1]
   #:when (and ((listof? symbol?) ts)
               (symbol? t1))
   (displayln ts)
   (displayln t1)])

```

And this code looks much clearer than the previous one. So I wonder whether using `#:when` will reduce the performance of `match`? If not, should we try to use `#:when` instead of `?` and let Racket support `listof?` directly to improve code readability (even in untyped version)?

---

<div class="post-metadata">

**Author:** ![capfredf](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/capfredf/32/935_2.png) [@capfredf](https://racket.discourse.group/u/capfredf)\
**Post date:** [March 10, 2022, 5:33pm UTC](https://racket.discourse.group/t/is-it-good-style-to-use-when-instead-of-in-match-expression/779/2 "2022-03-10T17:33:34Z")

</div>

Put `typed/racket` aside. In your examples, it is more of a personal taste. In general, `?` allows you put your patterns together

```scheme
[(? some-predicate-list? (list-rest a d)) (do-something-with a d)]

```

a `#:when` version would not look as concise as the code above.

On the other hand, `#:when` allows you to do conditions on multiple pattern variables from different patterns:

`[(list a-pat b-pat c-pat ...) #:when (test a-from-pat b-from-pat c-from-c-pat) .....]`

a `?` version would look less intuitive in this case.

---

<div class="post-metadata">

**Author:** ![jbclements](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/jbclements/32/11_2.png) [@jbclements](https://racket.discourse.group/u/jbclements)\
**Post date:** [March 10, 2022, 6:57pm UTC](https://racket.discourse.group/t/is-it-good-style-to-use-when-instead-of-in-match-expression/779/3 "2022-03-10T18:57:41Z")

</div>

Oh, but wait... let's bring Typed Racket back into the picture!

It turns out that this `#:when` style preserves information that would be otherwise lost by TR. Specifically, consider the following program:

```nohighlight
#lang typed/racket

(define n1s : (Listof Number)
  (match '(a 3 9 d)
    [(list 'a (? number? ns) ... 'd) ns]))

(define n2s : (Listof Number)
  (match '(a 3 9 d)
    [(list 'a ns ... 'd)
     #:when (andmap number? ns)
     ns]))

```

The first one does not type-check, the second one does.

---

<div class="post-metadata">

**Author:** ![samth](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/samth/32/3_2.png) [@samth](https://racket.discourse.group/u/samth)\
**Post date:** [March 10, 2022, 7:01pm UTC](https://racket.discourse.group/t/is-it-good-style-to-use-when-instead-of-in-match-expression/779/4 "2022-03-10T19:01:09Z")

</div>

The second way, with `#:when`, does two traversals of the list, so it can be slower. The `?` pattern shown by @capfredf will also do two traversals, but one can be fast if `list?` is fast.

In general Typed Racket finds it hard to see through the loop generated by `...` in `match`, unless the `...` is the end of the list. For example, if you omit the `t1` binding then your example typechecks, and similarly for @jbclements' example given an appropriate type annotation.

---

<div class="post-metadata">

**Author:** ![NoahStoryM](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/noahstorym/32/17_2.png) [@NoahStoryM](https://racket.discourse.group/u/NoahStoryM)\
**Post date:** [March 11, 2022, 2:59am UTC](https://racket.discourse.group/t/is-it-good-style-to-use-when-instead-of-in-match-expression/779/5 "2022-03-11T02:59:51Z")

</div>

Thanks for your answers! I rarely wrote very complex `pat`s in the past, so I overlooked a lot of `?` applies, thanks @capfredf for the example!

Maybe this problem finally has to go back to Typed Racket, because using match in TR, we generally need to use predicate to check the types of pattern variables, so what I want to ask is what @capfredf said about the second case: is it more appropriate to use `#:when` than `?` if I want to match pattern variables.

Judging from @samth's answer, in the `#:when` case, `val-expr` needs to be matched by `pat` first, and then checked by `#:when`, so that `match` does a repeat operation.

For me in general it may be rare to match very large data, so I think the cost of using `#:when` is acceptable to me.

Thanks for all your help!
