clojure-spec 2024-10-14

Similar to the above ... now with symbols. Is there a neater way to handle symbols? I have something working / workable on this code but would rather just have the symbols than their quoted form

(let [in-exprs '(let [symbol-keys {'first-name "Jane"
                                     'last-name "Doe"}
                        first-name (get symbol-keys 'first-name)]
                    first-name)]
    (let->destructured-let (pr-str in-exprs)))
=>
{:string-form "(let [symbol-keys {(quote first-name) \"Jane\", (quote last-name) \"Doe\"} 
                     first-name (get symbol-keys (quote first-name))] first-name)",
 :edn-form (let [symbol-keys {(quote first-name) "Jane", (quote last-name) "Doe"}
                 first-name (get symbol-keys (quote first-name))]
             first-name)} 
it's more to do with the reader than with spec but still, would welcome suggestions

the biggest problem is that I need to eval the list to get the symbol ... or at least I think that's what I need to do 🤨

to put it in the spec scope ... this is how I have the spec for get

(s/def ::get-k-from-m
  (s/cat
    :name (s/and symbol? #(= 'get %))
    :map ::map-value
    :key (s/or :keyword keyword?
               :string string?
               :symbol (s/or :sym symbol?
                             :quoted-sym list?))
    :default (s/? any?)))

would be great to avoid the need for (s/or :sym symbol? :quoted-sym list?)

maybe a tighter question: how should one spec a map with keys that are symbols?

@hiredman thanks for challenging my approach. I am still learning.

I have made the context clearer now

;; A spec for `get` that works only on maps, with keywords, strings or symbols as keys
;; It is only applicable for conforming data from :init-expr (the right hand side) of :bindings
(s/def ::get-k-from-m
  (s/cat
    :name (s/and symbol? #(= 'get %))
    :map ::map-value
    :key (s/or :keyword keyword?
               :string string?
               :symbol (s/or :sym symbol?
                             :quoted-sym (s/coll-of symbol? :distinct true :count 2)))
    :default (s/? any?)))

I would still like a better spec than (s/coll-of symbol? :distinct true :count 2) but it does the job for now

that isn't a map with keys that are symbols

' is a reader macro so 'x is read into the same form as (quote x) (which is a list containing two symbols)

it sounds like you are trying to use the same spec for data pre and post evaluation, which doesn't seem like a good idea

Yeah, agreed. And it’s why I’m asking for alternatives

maybe step back and talk about what you are trying to achieve?

you get for example breaks down on (let [get (constantly nil) ] (get x :foo)) or whatever, which is basically another way of saying it is conflating different levels of meaning

The project is to demonstrate how access to maps can be conducted using destructuring

and how is that connected to spec?

The specs are there to conform cases that would match that use case rather than all use cases

And I’m using conform as a parser

sure, but a parser here is context free

but you need a context (an evnironment) to properly do the static analysis

There are tests in there to demonstrate the use cases

sure, but I am saying at a fundamental level, spec is a context free analysis, but in order to do abstract interpretation of the code to understand it, you need context

The context is the let form

no, that is the code

like how do you know that get somewhere is clojure.core/get?

The specs are designed to work within that context

Oh, ok. I see. I hadn’t backed out that far. It didn’t feel necessary.

(let [m {:a/k1 1 :b/k2 2 :c/k3 3}
      get (constantly 1)
      k1 (get m :a/k1)
      k2 (:b/k2 m)]
  (+ k1 k2))

It’s a assumption that I’m happy to live with though

that assumption is why your spec doesn't work with the quoted symbols

Sure, that’s gonna parse ok

Actually it does work

I’m seeking something more elegant

But maybe that’s as good as it gets within these assumptions 🤷🏻‍♂️

I only apply the get spec to the rhs