This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-03-25
Channels
- # aleph (9)
- # announcements (2)
- # babashka (32)
- # babashka-sci-dev (72)
- # beginners (77)
- # calva (1)
- # cider (3)
- # clj-kondo (19)
- # clojure (61)
- # clojure-brasil (13)
- # clojure-europe (25)
- # clojure-italy (1)
- # clojure-nl (2)
- # clojure-norway (27)
- # clojure-uk (23)
- # clojuredesign-podcast (6)
- # clojurescript (12)
- # conjure (2)
- # core-typed (3)
- # cursive (6)
- # datalevin (2)
- # datomic (13)
- # emacs (9)
- # events (19)
- # fulcro (6)
- # graphql (11)
- # gratitude (2)
- # helix (3)
- # honeysql (16)
- # jobs (1)
- # lsp (89)
- # malli (33)
- # meander (14)
- # off-topic (87)
- # pathom (4)
- # polylith (7)
- # portal (4)
- # practicalli (1)
- # rdf (6)
- # reagent (2)
- # releases (8)
- # remote-jobs (1)
- # shadow-cljs (59)
- # sql (8)
- # tools-deps (14)
- # xtdb (18)
I use the following idiom:
(m/rewrite [1 2 3]
[(m/and !a1 !a2) ...]
{:a1 [!a1 ...] :a2 [!a2 ...]})
How can I bind nested values without failing if a parent is absent?
(m/match {:a 1}
{:b {:c ?c}}
?c)
Execution error (ExceptionInfo) at clubhouse.resolvers.datalayer/eval641426 (REPL:203).
non exhaustive pattern match
in my real use case, I still want to bind a bunch of other things at other levels, something like
(m/match {:a 1 :c {:foo 3}}
{:a ?a
:b ?b
:c {:foo ?c}
:d {:bar ?d}}
[?a ?b ?c ?d])
I thought I could do :d {:bar (m/or ?d (m/let [?d 1]))}
, but that still gives me non-exhaustive pattern match
. Is that not the right level for the m/or
?
Yeah at that level there would have to be a map at :d. The key couldn't be missing. Moving it up one level allows that.
When matching a map, how can I distinguish between a key’s absence and its having the value nil
?
This is one of those areas where I don't have a great answer.
When I went to put together the map pattern matching semantics I based them on the observations that 1) find
use is uncommon, and 2) most folks are concerned with observable equivalence and not semantic equivalence when it comes to get
. The subtle difference between the following two expressions do not weight heavily on most. Its a pragmatic trade off I suppose.
(get {} :m)
(get {:m nil} :m)
Considering these observations, I chose to have the compiler use get
instead of find
and favor the common map access patterns. The nice thing is that it does help reduce the number of clauses you might write for map pattern matching. The drawback is exactly this case. 🙂If it is cheap, you could preprocess the map to have "semantic nil
s" i.e. ::blank
/ ::undefined
and then pattern match on those. So
user=> (def blank (fnil identity ::blank))
#'user/blank
user=> (blank (get {:m nil} :m ::undefined))
:user/blank
user=> (blank (get {} :m ::undefined))
:user/undefined
user=> (blank (get {:m 10} :m ::undefined))
10
(`blank` is probably a terrible name but you get the idea.)Interesting, that makes sense. It’s good to know I’m not missing an obvious way to do this.