`match` for parsing into hash

#lang racket

(match (list 7 2 3 7) ; displays: 7                                                                 
  [(list row b c row) row])

(match (list 7 2 3 (hash 7 'ok )) ; displays: (list 7 'ok)                                          
  [(list row b c (hash 7 val)) (list row val)])

;; (match (list 7 2 3 (hash 7 'ok )) ; should display: (list 7 'ok) but throws compiler error       
;;   [(list row b c (hash row val)) (list row val)])                                                

(match (list 7 2 (hash 7 (hash 2 'ok))) ; displays: (list 7 'ok)                                    
  [(list row col c row-hash)
   #:do [(match-define (hash* (row col-hash))    row-hash)]
   #:do [(match-define (hash* (col val)) col-hash)]
   (list row val)])

The first and second matches work as expected. The third match throws a compiler error saying:

; /Users/dstorrs/projects/sudoku/test.rkt:7:23: row: unbound identifier                             
;   in: row   

Took me a minute to realize what was happening, namely that id bindings aren't available in other parts of the pattern, which means they aren't available in the (hash ...) clause.

The fourth one decomposes the nested hashes as expected but seems a bit clunky.

Is there a better way to do this?

For a slight improvement: #:do [ body … ] has outer brackets because you have more than one body expression :slight_smile:

2 Likes

Not a better way at all, but using shenanigans and the deprecated hash-table:

(match (list 7 2 3 (hash 7 'ok))
  [(app reverse (list (hash-table [row val]) c b (== row)))
   (list row val)])

It does, however, highlight that it might be helpful to allow == to be used in the relatively new hash match-expander's key position?

(match (list 7 2 3 (hash 7 'ok))  
  [(list row b c (hash (== row) val))
   (list row val)])

Of course, this depends on how these things are scoped, because this doesn't work either:

(match (list 7 2 3 (hash 7 'ok))
  [(list row b c (hash-table [(== row) val]))
   (list row val)])
1 Like