This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-09-24
Channels
- # announcements (7)
- # babashka (5)
- # babashka-sci-dev (20)
- # beginners (125)
- # biff (98)
- # catalyst (1)
- # clerk (37)
- # clj-kondo (6)
- # clojure (49)
- # clojure-dev (18)
- # clojure-europe (6)
- # clojure-uk (2)
- # data-science (17)
- # deps-new (20)
- # emacs (11)
- # helix (5)
- # hyperfiddle (34)
- # malli (3)
- # missionary (4)
- # reitit (4)
- # sci (15)
- # solo-full-stack (7)
- # sql (5)
- # testing (2)
Do I need an LSP if I have clojure-mode and paredit installed in emacs? IF so what is the recommended one?
It is not essential but many choose to install LSP facilities. I do not. It is, however, essential to have a REPL connection in your editor. I would use CIDER if you’re on emacs
If you wanna try LSP, I suggest you use lsp-mode, using clojure-lsp as server Check here all features https://clojure-lsp.io/features/
Why can one not add metadata to any value?
user=> ^:foo "bar"
Syntax error reading source at (REPL:1:12).
Metadata can only be applied to IMetas
Someone else might have a more definitive answer for you, but I would assume because values like "bar" or 5 are Java types (String and Long or primitive long) and there's no facility in Java to attach metadata to anything.
Clojure values like vectors are Clojure defined types, so they can support it
Maybe https://clojure.org/reference/metadata#_metadata_reader_macros helps? > Note that metadata reader macros are applied at read-time, not at evaluation-time, and can only be used with values that support metadata, like symbols, vars, collections, sequences, namespaces, refs, atoms, agents, etc. Some important exceptions that don’t support metadata are strings, numbers, booleans, Java objects, keywords (these are cached and can be shared within the runtime), and deftypes (unless they explicitly implement clojure.lang.IMeta).
Well they seem to need to be instances of classes that implement IMeta (inferring from error message)
so that makes sense, though I'm pretty sure one could sort out a way to associate metadata with any object
user=> (type "bar")
java.lang.String
user=> (instance? clojure.lang.IMeta "bar")
false
user=> (instance? clojure.lang.IMeta :bar)
false
user=> (instance? clojure.lang.IMeta 'bar)
true
user=> (instance? clojure.lang.IMeta [])
true
user=> (with-meta "bar" {:foo true})
Execution error (ClassCastException) at user/eval7634 (REPL:1).
class java.lang.String cannot be cast to class clojure.lang.IObj (java.lang.String is in module java.base of loader 'bootstrap'; clojure.lang.IObj is in unnamed module of loader 'bootstrap')
applied at eval time. different error
Ya, the blurb I quoted was talking about the reader.
But the same rules apply to with-meta
.
@UE21H2HHD what's up with
user=> (meta ^:foo {})
{:foo true}
user=> (meta ^:foo 'xyz)
nil
given your:
user=> (instance? clojure.lang.IMeta 'bar)
true
I could make use of metadata on symbols, and it doesn't error, but how to retrieve it?
inneresting
unfortunately that defeats my use case 🙂
Not sure about your example above, someone else will surely answer but...
user=> (binding [*print-meta* true] (-> "^:foo 'x" read-string pr))
^{:foo true} (quote x)nil
This old man must now wind down for the day!g'night. and thanks for your time
Is there an easy way to determine equality of 2 values and their metadata (recursively)?
Perhaps convert to normal value you can compare with =
, then compare with =
?
It’s probably possible to write something that’s more computationally effective than what I wrote here.
@U3X7174KS
> Perhaps convert to normal value you can compare with =
, then compare with =
?
That's the conclusion I came to. Thanks for the code. I'll compare to what I come up with.
do you mind sharing what for you need this? it is very rare when you have to include metadata into equality checks
@U064X3EF3 That might be a good general rule, but I think its a bit presumptuous to state it absolutely. I'm working out a design for a various AST states for a compiler I'm writing. There's a lot of data involved but not all of it is important all the time. Things like source positions. These things are nice to hide as metadata, and clojure does the same. But for testing, you sometimes need to check the hidden things. I have a data driven test setup that is a very clean way to define tests, and thus I would like to figure this out.
It’s the whole premise of metadata, by definition
But understood for testing
Right, I only intend to use this for the testing.
Probably the best answer for my question here is "No" 😄
@U3X7174KS looks like you don't need the IMeta check 🙂
user=> (some? (meta "not IMeta"))
false
@U3X7174KS why do you use the ::value
and ::meta
instead of :value
and :meta
?
When I only want to convert from normal metadata to an “expanded form” like this — it probably wouldn’t matter.
But if I wanted to convert back from my representation to normal clojure data and metadata? Then I wouldn’t want to accidentally convert a map someone else wrote with {:value 3 :meta "no!"}
to metadata — as that would give me a different result than what I started with.
Instead, I wanted to use namespace qualified keys, to avoid collisions with user code.
Possibly premature abstraction 🙂
gotcha
btw, you don't need to keep value. it will be verified with regular equality check. just extract metadata recursively and compare
but then I need 2 different compares? one for value and one for meta?
just trying to understand what you are suggesting
yes, two checks.
that might actually work well for me
> btw, you don’t need to keep value. it will be verified with regular equality check. just extract metadata recursively and compare what if the value has metadata somewhere in it? Would that metadata be checked for equality then?
I define my tests in a yaml file (a seq of maps) and each map has a bunch of data keys:
'(:a :b :c :d :e :f :g)
Each mapping can define all of those keys or just some of them.
A given test file calls a loader function the takes:
• the path of the yaml file
• a need-keys
vec of keys
• a test-func
function
• a want-func
function that produces the expected result
The loader function loads the yaml seq and filters out the maps that contain all the need-keys
. Then it defines a test function for each map that calls:
(= (want-func test-map) (test-func test-map))
Generally for a given file I am using a need-keys
of just 2 of the many values. One for input and one for expected output. The compiler I'm writing has several stages that I need to test. This whole technique lets me define the test data very cleanly.This pattern is so common for me that I'll publish this as a reusable library later on.
@U04V4KLKC mixing the metadata with the actual data is messy so I like the idea of separating it, and only using it on some of the tests.
I would make a function similar to prewalk with an additional argument - the path suitable for get-in. for every value capable to carry meta it would compare value's meta with (meta (get-in other-obj path)). it can even shortcircuit on not identical metadata
@U3X7174KS I see your point:
(all-meta ^:x {:y ^:z [3]}) => {:x true}
I think if I do want the meta only I would need a second pass to prune stuffyeah, that ^:z [3]
is the sort of thing I thought might get lost. I think delguardo’s approach might work (and I think it’ll be faster than my code), but I don’t know how I would start writing it.
It might be possible to prune values that have no metadata from the bottom up. clojure.walk/postwalk
gives you leaf nodes first, then nodes with children afterwards.
I tried something like this:
1. Replace all leaf nodes that have no metadata with a ::prune
instruction (from {::value v}
to ::prune
)
2. When you later encounter a value where ::meta
is missing and ::value
is ::prune
, replace the value itself with ::prune
.
But now my head is spinning from all the recursion so I’m the problem down for now 😅
Hope you find something that works! Being able to follow your progress om yamlscript and lingy here on the slack is a treat.
So far I have
(defn show-meta [node & ignore]
(walk/prewalk
(fn [value]
(let [meta (apply dissoc (meta value) ignore)]
(if (some? meta)
{:M meta
:V (with-meta value nil)}
value)))
node))
basically yours with the feature to ignore certain meta keys
=> (show-meta ^:x {:y ^:z [3]})
{:M {:x true}, :V {:y {:M {:z true}, :V [3]}}}
thinking about what the prune would look like:
[{:x true} {_ [{:z true} [_]]}]
maybeNot sure I could readily read and understand that. Might be best not to separate.
user=> (case (type []) (type []) 42)
Execution error (IllegalArgumentException) at user/eval7706 (REPL:1).
No matching clause: class clojure.lang.PersistentVector
why?Case values need to be compile time constant
Classes are not constants
And the case value is not evaluated
If you take the name of the the class in the expression, you can match that
I also tried
user=> (case clojure.lang.PersistentVector clojure.lang.PersistentVector 42)
Execution error (IllegalArgumentException) at user/eval7709 (REPL:1).
No matching clause: class clojure.lang.PersistentVector
The expression is evaluated here to a clas but the case match is a symbol (not evaluated)
Depending on the rest of the context, cond with instance? is maybe better
Or vector?
There are vectors that are not PersistentVector
I was basically writing a walk because I wasn't familiar with clojure.walk
but I'm looking at that now.
@U05H8N9V0HZ a fascinating thing is that in your case
the second (type [])
is interpreted as TWO cases that share an outcome. The first of the two is type
and the second is []
. This is documented at https://clojure.github.io/clojure/clojure.core-api.html#clojure.core/case
clj꞉user꞉> (case 'type (type []) 42)
42
clj꞉user꞉> (case [] (type []) 43)
43
Fascinating indeed. >
Note that since
> lists are used to group multiple constants that map to the same
> expression, a vector can be used to match a list if needed.
that part I assume.Perhaps we can trace case's quirks, (1) unevaluated datums and (2) lists of datums, to Scheme's case
https://docs.racket-lang.org/reference/case.html
I wonder which Lisps Rich looked at most...
Probably in his History of Clojure paper...
Is there a way to call java methods that use "the signature-polymorphic parameter list"?
https://stackoverflow.com/questions/52378078/using-java-lang-invoke-methodhandle-in-clojure`MethodHandle#invokeExact`https://stackoverflow.com/questions/52378078/using-java-lang-invoke-methodhandle-in-clojure.
I've been playing with new foreign function and memory api. The api makes use of such functions. Another example is methods of java.lang.invoke.VarHandle
.
It would be nice to use the api without falling back to java.
Scala seems to have special support for these: https://www.scala-lang.org/2023/07/17/signature-polymorphic-methods.html
Another option is to generate byte code, https://github.com/IGJoshua/coffi/blob/3948e63089270aa1295ad5d13b87b6e4123d6107/src/clj/coffi/ffi.clj#L176
@U7RJTCH6J that looks cool! Thanks.
Saw a question on this Kahoot https://create.kahoot.it/share/clojurebridge-quiz/f45a89b7-b5f3-4c42-a655-ac8a6b9dcb24 How many different function calls are made in
(/(reduce + (map :angle a)) (count a))
Why is 4 not the answer(also, number of function calls can be pretty ambiguous. (/ 3 4)
could have quite a few different number of function calls depending on how familiar you are with Clojure internals, perhaps how familiar you are with jvm internals
map takes a function and applies it to a collection for each element in the collection right? So it calls :angle
as a function for each item in the a
collection
It also depends on if you mean the number of calls present in the syntax, or the number of calls that will be executed when the code is run
but it also creates a collection of the results and i don’t know off hand how many function calls that would take
Yeah likely it should be something like "how many values are being used as functions?"
Since the question was
> How many different function calls…
I counted 6:
• /
• reduce
• +
• map
• :angle
• count
Like @U11BV7MTK says, map calls :angle
as a function. I guess in my head I just automatically counted the second argument to map
as a function 😅 (same with reduce’s second argument)
Though that’s just a surface level counting that doesn’t take into account whatever happens behind the scenes!
Is there a simpler way:
user=> (def ks [:a :b])
#'user/ks
user=> (def ms [{:a 1 :b 1} {:a 1 :c 1} {:a 1 :b 1 :c 1}])
#'user/ms
user=> (filter #(every? (fn [k] (k %)) ks) ms)
({:a 1, :b 1} {:a 1, :b 1, :c 1})
I would not be surprised if someone else comes up with a simpler way, but you can't be too far from it with code that short.
I only wanted to comment that I personally think it is worth naming a function like that something like has-all-keys?
or contains-all-keys?
Then you could write (filter #(has-all-keys? ks %) ms)
Yeah. Just seems like a core need 🙂
> I would not be surprised if someone else comes up with a simpler way, but you can't be too far from it with code that short. /me waits for @U04V70XH6 😄
That's not actually has-all-keys, because it is invoking functions, not doing s contains key test, not all keys can be called as functions, and not all values are truthy
another version, not any shorter though
(filter (comp (partial clojure.set/subset? (set ks)) set keys) ms)
You could apply every-pred or whatever that ended up being called and then call the result if that non-generalness is acceptable
(filter #(every? % ks) ms)
will work nicely for me here. thanks.
need to get better at spotting those things
using truthy can backfire if your meta values ever contain false
. may not impact you but can be annoying when that’s a legit value in your metadata that starts failing these predicates
I actually had prodlems with the every-pred
Changed to using:
(defn has-keys? [keys map]
(every? map keys))
(filter #(has-keys [:a :b] %) maps)
^ that’s the issue i’m pointing out. you’re checking that a key is present by finding it’s truthy value
also up to you if you want to consider nil
to a key as “present”
(has-keys? [:a :b] {:a 1 :b nil})
false
again, just pointing out that it’s up to you how you want to consider this and your impl currently already has an opinion on it but it’s easy to missshould I use contains?
contains? and find will both look for the key or key/value in the map regardless of the value
(defn has-keys? [keys map]
(every? #(contains? map %) keys))
I probably don't have falsy vals, but I'd rather do it more correctly.they can spring up in funny ways :pure false
:io? false
or if you track some dependencies it might be convenient to have the set be nil or a set with items, etc
should I use contains?
How can I convert a qualified keyword to an unqualified one, i.e. just use the unqualified part of it?
Curious why you need to? Conversion to JSON? All the JSON libs have a way to do this automatically (with some it is the default).
Uhm, I’m trying to write a one pass run over an xml event sequence using clojure.data.xml where start elements have a :tag that is a qualified keyword where the namespace of the tag is the url encoded value of the corresponding xml namespace. I want to drop that qualifier and just get the tag w/o namespace.
I still don't understand why you need to throw the namespace portion away?
Are you trying to identify a "similar" tag across multiple namespaces?
Nope. In my case the qualifiers are just noise that I can get rid of, as there’s no collisions.
I’m still not 100% sure what I want, but atm the plan is to define a function for each tag I’m interested in, and then dispatch to that function whenever the tag is found.
If I want to keep the qualifiers, and I have :superlong-url-escaped-namespace-qualifier/myTag
I wouldnt know if I can create a clj file for that namespace so that clojure would find it where it’s expected.