This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-07-12
Channels
- # announcements (1)
- # aws (1)
- # babashka (63)
- # beginners (108)
- # calva (12)
- # cider (6)
- # cljdoc (2)
- # cljsrn (33)
- # clojure (150)
- # clojure-europe (28)
- # clojure-nl (13)
- # clojure-spain (1)
- # clojure-spec (8)
- # clojure-uk (25)
- # clojurescript (16)
- # conjure (7)
- # cursive (7)
- # datomic (15)
- # duct (2)
- # eastwood (2)
- # figwheel (1)
- # figwheel-main (1)
- # fulcro (6)
- # graalvm (1)
- # graalvm-mobile (1)
- # helix (6)
- # honeysql (23)
- # integrant (6)
- # introduce-yourself (4)
- # jobs (10)
- # lsp (132)
- # malli (4)
- # meander (1)
- # membrane (1)
- # off-topic (223)
- # pathom (23)
- # pedestal (3)
- # re-frame (18)
- # reagent (13)
- # releases (1)
- # remote-jobs (2)
- # shadow-cljs (68)
- # tools-deps (217)
- # vim (19)
- # xtdb (79)
It's an interesting idea to use (defn ^:private foo [] ...)
given that we don't have def-
so a private var has to use (def ^:private thing ...)
-- there's a consistency to that I guess. I would probably still lean toward defn-
since that's what I "grew up with" in Clojure and it's definitely more common.
https://clojure.org/reference/reader#_metadata Some light reading about metadata 🙂
Is it possible to run bash from within Clojure code?
Uh… @borkdude probably knows xD
there are a number of ways to run bash depending on the use case. As an example:
test> (use '[clojure.java.shell :only [sh]])
nil
test> (sh "/bin/bash" "-c" "pwd")
{:exit 0, :out "/var/tmp\n", :err ""}
there's also the more flexible ProceessBuilder / Process
user=> (-> (ProcessBuilder. ["/bin/bash" "-c" "pwd"]) (.inheritIO) (.start) (.waitFor))
/home/justin/clojure-experiments
0
better match for the functionality though
(let [builder (ProcessBuilder. ["/bin/bash" "-c" "pwd"])
process (.start builder)
out (.getInputStream process)
err (.getErrorStream process)]
{:result (.waitFor process)
:out (slurp out)
:err (slurp err)})
but that's just feature-for-feature match of shell/sh, you can also use the streams interactively / async while keeping the process alive(#(map * %&) [1 2 3] [4 5 6] [7 8 9])
gives an error where as (#(apply map * %&) [1 2 3] [4 5 6] [7 8 9])
gives result, What does apply
do here
your #(... %&)
wraps the list of vectors in a list (a sequence, really), and your apply
then unwraps it, doing effectively the same
hello, is there a way to filter a coll based on some state computed from the previous items? I know I could use reduce
for this but I'm trying to avoid build the whole coll
maybe this doesn't make sense
you can use reduced
to terminate reduce early, otherwise your other option is loop
which is more complex than using reduce
yea I think using loop
will work
thanks
the thing is, with loop you need to traverse the list "by hand" and reduce already does that for you, loop makes the code more complex if you are walking a list in order
yea nvm, the thing I need to do can be accomplished with reduce
as well
thanks!
i am calling same database twice in my two different function which gives same result! can I make use of memorize
instead ?
the clojure.core function memoize
(note no r
) has no eviction policy for cached results, and is suitable only for functions with a small set of inputs or in non-production environments. There's a library clojure.core/memoize that exposes more advanced strategies for managing the cache of results, like bounded queues and time based cache evictions
is the library. and the always fantastic
http://grep.app can help find usage in the wild
how can avoid calling database twice from different function twice ? Can I assign those values in def
and make use of that ?
Yes, rather than memo-ize, you can have a map called cache-db-results
or something and check it for entries first. If empty, query the db and store the result
def is for globals (and shouldn't be re-defined at runtime from regular code), you can use core.cache for result caching
or just a hash-map inside an atom
@popeyepwr since this is #beginners I feel like I should warn that caching is a harder problem than it looks like at first, and you gain a lot by using a dedicate pre-existing cache library
memoization is typically meant for pure computations, while caching is meant for arbitrary data that might be expensive to acquire
my database query returns only 5 result everytime, So i thought of using memoize , But till when the values are cached if we use it?
the memoize
function returns a new function that stores results until the function goes out of scope
memoize will not work here because it never lets go of any of the data
@popeyepwr as I mentioned before this is a much harder problem than it looks like at first, and rolling this yourself is a lot more work (and almost guaranteed to be buggy) compared to adding a dep
no it does not
org.noisesmith.expecting=> (source memoize)
(defn memoize
"Returns a memoized version of a referentially transparent function. The
memoized version of the function keeps a cache of the mapping from arguments
to results and, when calls with the same arguments are repeated often, has
higher performance at the expense of higher memory use."
{:added "1.0"
:static true}
[f]
(let [mem (atom {})]
(fn [& args]
(if-let [e (find @mem args)]
(val e)
(let [ret (apply f args)]
(swap! mem assoc args ret)
ret)))))
nil

it creates an atom and puts every arg list and result in the atom
it's not appropriate for caching an endpoint at all
right, clojure's memoize doesn't use either of those - it's very naiive, see the snippet above
right
you could even reasonably call memoize inside a smaller scope that doesn't live as long as the entire program, if you know a given arg list should always map to the same result and don't mind the occasional double-call when there's a data race
Is there a good way to write a test that asserts that two functions, say f and g, have approximately the same runtime? I.e. it doesn’t matter whether they’re fast or slow, we just want to make sure that the average runtime of f and g doesn’t differ by more than 10% (or whatever threshold).
time
doesn’t seem quite accurate enough, and I was getting weird results when running it in a loop (maybe because of laziness?). But a benchmarking lib like Criterium seems way too heavy and not fit for a testing use case
I think performance regression testing is a good case for criterium; I would just tag the tests as benchmark tags that don't get run all the time (e.g. only in CI or between releases, etc)
instead of running time in a loop, run a loop inside time
(sounds like a doctor who quote doesn't it...)
(time (dotimes [_ 10000] (your code goes here)))
I love this ruby library https://github.com/evanphx/benchmark-ips
criterium does this (both figuring out how many times to run, and showing stats on variation)
@noah688 I removed the doall / dorun above because they only work if your code returns a sequence, I think it's up to you to figure out how to ensure the full result of your code is realized inside the dotimes body
(eg. what if you returned a lazy-seq of lazy-seqs etc.)
I guess (dorun (tree-seq coll? seq x))
is generally safe but it's probably more than you actually need and probably colors the timing result
(require '[hiccup.core :as h])
(->> (edn-paths)
(map slurp)
(map edn/read-string)
(map h/html))
;; fails with:
;; Can't take value of a macro: #'hiccup.core/html
Is there an alternative to h/html that I can use as a function?you could look at what h/html expands to, or use #(h/html %)
Wrapping in a function didn't look like it helped too much:
(->> (edn-paths)
(map slurp)
(map edn/read-string)
(map #(hiccup.core/html %)))
;; 1. Caused by java.lang.IllegalArgumentException
eliding it throws away the ability for others to help you, and perhaps for you to help yourself
I found a [] in my edn file. Removed that, and now it produces valid HTML. So you guys were right ☝️ Thanks!
I'm separating items by dates and wanted to get his index from the list he belongs to, but I don't know how to get the index from a lazy-seq
(defn part-by [item items]
(partition-by #(cond
(= (:date %) (:date item)) "value"
:else "string")
items))
How does one go about writing tests for their clojure code...? Is there a guide which explains?
@abhishek.mazy It's probably worth looking at some OSS projects on GitHub that have good test suites. Most folks use clojure.test
because it's "built-in". I don't know if there are any good tutorials on writing tests in Clojure tho'...
Hi Sean, Thanks for that. I was asking about clojure.test itself. I am developing in clojurescript for now... but I don't understand how or even if clojure.test links with that... if yes how? The documentation on this is thin from my searches...
ClojureScript has the clojure.test
namespace too, yes. and Olical's cljs-test-runner
project lets you run tests for ClojureScript.
See https://github.com/seancorfield/honeysql/blob/develop/run-tests.sh#L5 and the deps.edn
in that project.
(the whole project is .cljc
files so it can be run as both Clojure and ClojureScript)
The syntax for importing the test ns is slightly different, but the tests are then nearly all identical for both languages: https://github.com/seancorfield/honeysql/blob/develop/test/honey/sql_test.cljc#L6-L7
Ah, I use cljs.test
but I'm pretty sure clojure.test
exists too? Anyways, there's an example of how to write cljs tests and run them...
thanks for all the info Sean!! cljs.test or clojure.test - I am not informed enough to know the difference or point out the distinction!! I'll look through the links!! Many thanks again!
Ya, you can now get away with only requiring clojure.test
in cljc files. ClojureScript will automatically convert to cljs.test
. For example: https://github.com/clj-commons/rewrite-clj/blob/52f429e09429a6e942837fabb481045698cba54f/test/rewrite_clj/zip_test.cljc#L4
@UE21H2HHD Oh, you don't even need the conditional and the :refer-macros
stuff now? (I don't track the cljs world so I haven't seen if/how it has advanced in terms of language compatibility lately)
Good to know -- I'll create an issue to clean that up in HoneySQL. Thanks.
Hi Sean, Thanks for that. I was asking about clojure.test itself. I am developing in clojurescript for now... but I don't understand how or even if clojure.test links with that... if yes how? The documentation on this is thin from my searches...
hi, in lein project.clj I have
(defproject foo "0.1.0-SNAPSHOT"
:dependencies [ [clojure-csv/clojure-csv "2.0.1"]
which I can see in lein deps :tree
but in the lein repl if I try (use '[clojure-csv [parse-csv :as pp]])
it errors
Could not locate clojure_csv/parse_csv__init.class, clojure_csv/parse_csv.clj or clojure_csv/parse_csv.cljc on classpath.
I does seem to be there under ~/.m2/repository/clojure-csv/clojure-csv/2.0.1/, anyone can give my noob self a hint please?It should be either (use 'clojure-csv.core)
which will refer in all symbols from that namespace or something like (require '[clojure-csv.core :as csv :refer [parse-csv]])
which will refer in just parse-csv
but will also make everything else available via the alias csv
.
The namespace in a project very often does not match the library name. The README for the library has a Use section that says "The clojure-csv.core
namespace exposes two functions to the user:" so that's where you'd figure out what namespace to require @gabor.jasko
> The namespace in a project very often does not > match the library name These simple things! thank you @U04V70XH6
Probably really silly question, but (let [filtered-names (filter (fn [name] (match-name name search-key-chars)) names)] (println filtered-names)) I don't think this is how things are done? I mean assigning like that result of a whole function in the body of the let block? If not, than what? Always a separate (probably private?) function?
By one doesn't assign variables using def
within a function, correct?
Correct. def
is always global.
let
is how you declare local bindings.
Whether you bother to bind a local symbol, depends on whether you're going to use it multiple times.
If all you want to do is print the filtered list, I'd just do
(println (filter #(match-name % search-key-chars) names))
OK, fair enough, just wanted a sanity check.
Perfect!
A lot of the time, it's purely about readability. Some people might prefer:
(let [match-name #(match-name % search-key-chars)]
(println (filter match-name names)))
(I'm deliberately shadowing match-name
there to get a similar name in a more limited context -- but I'd also say that match-name
is perhaps not a very descriptive name in the first place)(depending on what your match-name
function actually does, I might just inline it -- I don't find much value in wrapping core functions, if it's just doing a re-find
for example)
OK, that's what I wanted to know. Yeah it can get ((((((very))((nesty)))(((very))((fast)).
If it's getting that way quickly, would recommend having a look at https://clojuredocs.org/clojure.core/-%3E https://clojuredocs.org/clojure.core/-%3E%3E
With rainbow parens in your editor, you eventually just stop seeing the parens 🙂
Good point