I’m having trouble understanding Java interop. I was trying to convert this expression from the Java docs into Clojure but it’s not working so I’m obviously getting it wrong:
FileSystems.getDefault().getPath("logs", "access.log");
My best effort was:
(.getPath (java.nio.file.FileSystems/getDefault) "logs" "access.log")
Which earns me:
; eval (root-form): (.getPath (java.nio.file.FileSystems/getDefault) "logs" "...
; (err) Execution error (ClassCastException) at cli.core/eval1683 (form-init9547531439919407953.clj:49).
; (err) class java.lang.String cannot be cast to class [Ljava.lang.String; (java.lang.String and [Ljava.lang.String; are in module java.base of loader 'bootstrap')
Any help getting me unstuck would be appreciated.(.getPath (java.nio.file.FileSystems/getDefault) "logs" (into-array String ["access.log"]))
https://clojure.org/reference/java_interop#_vararg_methods “Java vararg methods treat the trailing varargs parameter as an array. They can be invoked from Clojure by passing an explicit array in place of the vargs.” you are def not the first to get bitten by this : )
I’m glad I asked. I would have been there forever figuring that one out. Thanks very much, @dane.email.
the official guide on interop is very short and does mention this, by the way https://clojure.org/reference/java_interop#_vararg_methods
There is a longer faq entry btw
Probably should link those up
I have a macro which expands to lots of concentric (let [x# ~x] ...)
constructs. When I look at the macro expansion I have lots of let
s with the exact same symbol such as (let [value_19667__auto__ value_19667__auto__] ...)
, in this case I could check in my macro and just omit the let (let [a b] ...)
where (= a b)
, and eliminate the let
. Is this a redundant optimization? will the clojure compiler do this optimization for me?
OK, thanks. in this case I don't need a general purpose code walker, because the lets are begin generated by my own macro, so I know their limited form. So a very limited optimized-let
macro is completely sufficient for my needs.
certainly the expanded macro is more humanly readable, if I expand to code eliminating this useless let.
(defmacro optimized-let [[a b] c]
(if (= a b)
c
`(let [~a ~b] ~c)))
sorry if that question doesn't make sense...
It looks like the compiler doesn't optimize this for you. The JIT might, later. You can write a tree walking function or use meander to perform the inlining
I wrote something similar about a month ago, you can look https://github.com/bsless/contextual/blob/master/src/contextual/impl/let.clj#L130
Is there a way to write a unit test for a function defined by (defn- ...)
? certainly it is a good idea to test internal function. right?
you can access private functions by var
instead of (ns/private-f
you can do (@#'ns/private-f
do I have to use the real ns name, or can I use an abbreviation?
you can use an alias
in general, clojure's compiler doesn't tend to optimize things (with a few notable exceptions like locals clearing)
Hi, what the best way to filter the first large maps contains in a list or vector? Do I have to use a loop and acc or filter + predicate is possible? Eg. Turn this collection of maps
(def mymap '({:name "Susan", :id "3", :age "20", :weight "120", :Cool true, :height "48"}
{:name "Bob", :id "2", :age "23", :weight "90", :Cool false, :height "50", :parent "yes"}
{:name "John", :id "1", :age "21", :weight "150", :Cool true, :height "45", :parent "yes"}
{:name "Ben", :id "4", :age "20", :weight "100", :Cool true, :height "43"}))
and return {:name "Bob", :id "2", :age "23", :weight "90", :Cool false, :height "50", :parent "yes"}
can you rephrase your question? "filter the first large maps contains in a list or vector?". You have a collection of maps and you want to filter them?
if you're looking for the map who's name is "Bob" you can
(filter (comp #{"Bob"} :name)
'({:name "Susan", :id "3", :age "20", :weight "120", :Cool true, :height "48"}
{:name "Bob", :id "2", :age "23", :weight "90", :Cool false, :height "50", :parent "yes"}
{:name "John", :id "1", :age "21", :weight "150", :Cool true, :height "45", :parent "yes"}
{:name "Ben", :id "4", :age "20", :weight "100", :Cool true, :height "43"}))
just filter the records and take the firstor use some
(some (fn [x] (when (= "Bob" (:name x)) x))
'({:name "Susan", :id "3", :age "20", :weight "120", :Cool true, :height "48"}
{:name "Bob", :id "2", :age "23", :weight "90", :Cool false, :height "50", :parent "yes"}
{:name "John", :id "1", :age "21", :weight "150", :Cool true, :height "45", :parent "yes"}
{:name "Ben", :id "4", :age "20", :weight "100", :Cool true, :height "43"}))
{:name "Bob",
:id "2",
:age "23",
:weight "90",
:Cool false,
:height "50",
:parent "yes"}
also, minor note, it's almost always better to use [{.. .. } ...]
instead of '({... ...} ...)
- we typically only use '
in clojure when we need unresolved symbols, which is not the case here
> also, minor note, it’s almost always better to use `[{.. .. } ...]` instead of `'({... ...} ...)` - we typically only use `'` in clojure when we need unresolved symbols, which is not the case here is this always the case, even if you know beforehand you only need sequential access?
both style wise and performance, there's zero advantage to using ' to create lists
it's a lispism, and I think people do it because they are used to it from other lisps? it usually isn't needed in clojure
and this is just for literals just to be clear
right - none of this makes any sense if you aren't talking about data literals
but even when constructing a collection, if you aren't writing a macro you probably shouldn't be using lists
(nb. lazy-seqs as returned by map, filter, etc. are not lists)
and if you're wondering one reason, is that the quote can do way more than just what you intend ("just give me the list of these things")
foo> '(1 2 (+ 1 2))
(1 2 (+ 1 2))
foo> [1 2 (+ 1 2)]
[1 2 3]
foo>
In fact, i want to be able to search and filter the largest hashmap so by its size and not its content
size being the number of key value pairs?
(->> mymap (sort-by count) last ...)
Thank both for the advices.
oops - that first
should be last
(fixing...)
For the eg., I use list instead vector because it's like that that the precedent function output in code. But manually, I always a vector of hashmaps.
How can I update an element in a map that is itself a map. e.g.
(let [foo {:bar 5 :quax {:abc 6 :def 7}}]
; I want to update :def in foo
)
?@qmstuart update-in is the function that does that
user=> (update-in {:bar 5 :quax {:abc 6 :def 7}} [:quax :def] inc)
{:bar 5, :quax {:abc 6, :def 8}}
it takes a one arg function that updates the value at that paththank you! thats perfect
if you don't always know the path, or need to update multiple leaves, then clojure.walk helps
So I don't have a functino for the last param, just a value.
(update-in memory [:memory location]
(Integer/parseInt (->> (map (fn [m v] (if (= \X m) v m)) mask (pad v))
(apply str)
2)))
It errors because float can't be converted to a function, because the Integer/parseInt returns a number (which it evaluates eagerly?), Im guessing, and its trying to call that number as a function?read the docstrings of update-in
and assoc-in
but if you just use assoc-in
here it will work. but understanding the differences will greatly ease your Clojure studies
https://github.com/plumatic/plumbing is this still the generally recommend library for creating computation graphs in clojure? I'm looking at improving the start up time of our API, which pre-loads of a bunch of metadata. A number of the metadata caches depend on each other, and while I could manually create a dependency order to parallelize the startup efforts, but a graph type approach that auto-computes the parallelization would be more flexible & maintainable.
thank you
The function can take an arbitrary number of arguments but the value being updated is passed as the first argument. /pedant
dev=> (update-in {:bar 5 :quax {:abc 6 :def 7}} [:quax :def] + 42)
{:bar 5, :quax {:abc 6, :def 49}}
💯
@qmstuart ^ FYI
This is the first time I come across this concepts, thank you for sharing!
Hey folks, is there a simple way to implement a lazy seq where the nth term is defined as f(n-1)?
(->> (range) (map dec))
(iterate f initial-value)
> Returns a lazy sequence of x, (f x), (f (f x)) etc. f must be free of side-effects
perfect
whoops. this should probably be
(->> (range) (map dec) (map f))