# Is it possible to match a set?

**URL:** <https://racket.discourse.group/t/is-it-possible-to-match-a-set/3142>\
**Category:** Questions & Answers\
**Created:** [September 1, 2024, 3:12am UTC](https://racket.discourse.group/t/is-it-possible-to-match-a-set/3142 "2024-09-01T03:12:59Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![dstorrs](https://avatars.discourse-cdn.com/v4/letter/d/898d66/32.png) [@dstorrs](https://racket.discourse.group/u/dstorrs)\
**Post date:** [September 1, 2024, 3:12am UTC](https://racket.discourse.group/t/is-it-possible-to-match-a-set/3142/1 "2024-09-01T03:12:59Z")

</div>

I can't believe I've never noticed this before, but is there a way to use `match` with `set`?

```scheme
(match (set 1 2 3)
  [(set 1 2 3) 'matched]
  [_ 'not-matched])

;; Error: syntax error in pattern in: (set 1 2 3)

```

I suppose it could always be done via `#:when` but that feels like cheating, and it doesn't allow for decomposing a set that contains non-primitive values.

```scheme
(struct cell (value candidates) #:transparent)

(match (cell #f (set 1 2 4 8 9))
  [(cell _ cands) #:when (set-member? cands 4)
                  "cell can have a value of 4"]
  [else "nope"])

;; "cell can have a value of 4"

```

For context, I'm working on a sudoku-making program and I was going to use a system where `cell` is a struct that contains, among other things, the remaining candidates for that cell. This would allow me to use `match` to determine if the cell has a specific candidate.

---

<div class="post-metadata">

**Author:** ![SamPhillips](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/samphillips/32/15_2.png) [@SamPhillips](https://racket.discourse.group/u/SamPhillips)\
**Post date:** [September 1, 2024, 4:50am UTC](https://racket.discourse.group/t/is-it-possible-to-match-a-set/3142/2 "2024-09-01T04:50:28Z")

</div>

Making a match expander that will pattern match on all of the elements of the set is not too bad. A problem I have with this solution is that it copies the set into a list to make a match.

```scheme
(define-match-expander set^
  (syntax-parser
    [(_ pat ...)
     #'(? set? (app set->list (list-no-order pat ...)))]))

(match (set 3 2 1)
  [(set^ 1 2 3) 'ok]
  [_ 'nope])
;; => 'ok

(match (set 'y 'x 'z)
  [(set^ a b c) (list a b c)]
  [_ #f])
;; => '(x y z)

```

The previous expander could be modified slightly to match a subset. A better (IMO) expander that matches a subset of values (not patterns) can also be done like this:

```scheme
(define-match-expander subset^-aux
  (syntax-rules ()
    [(_ v) (? (λ (s) (set-member? s v)))]
    [(_ v . vs) (? (λ (s) (set-member? s v))
                   (subset^-aux . vs))]))

(define-match-expander subset^
  (syntax-rules ()
    [(_ v ...) (? set? (subset^-aux v ...))]))

(match (for/set ([i 100]) i)
  [(subset^ 100) 'nope]
  [(subset^ 45 80 90) 'ok]
  [_ 'wha])
;; => 'ok

```

---

<div class="post-metadata">

**Author:** ![dstorrs](https://avatars.discourse-cdn.com/v4/letter/d/898d66/32.png) [@dstorrs](https://racket.discourse.group/u/dstorrs)\
**Post date:** [September 1, 2024, 4:12pm UTC](https://racket.discourse.group/t/is-it-possible-to-match-a-set/3142/3 "2024-09-01T16:12:07Z")

</div>

Very cool. Thank you.
