Fork me on GitHub

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.


@deleted-user you are 100% correct about it being shorthand

👍 2
Rob Haisfield02:07:53

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 '[ :only [sh]])
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))


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


what you're trying to do is probably (map * [1 2 3] [4 5 6] [7 8 9])


your #(... %&) wraps the list of vectors in a list (a sequence, really), and your apply then unwraps it, doing effectively the same

João Galrito15:07:53

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

João Galrito15:07:00

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

João Galrito15:07:56

yea I think using loop will work


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

João Galrito15:07:12

yea nvm, the thing I need to do can be accomplished with reduce as well


how much time memorize will keep the values in cache ?


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 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


just wanted to improve the code, Do not want to use new dependency


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}
  (let [mem (atom {})]
    (fn [& args]
      (if-let [e (find @mem args)]
        (val e)
        (let [ret (apply f args)]
          (swap! mem assoc args ret)

mario-star 2

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


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

Noah Moss17:07:07

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)))

Noah Moss17:07:49

that makes sense, I feel dumb for not thinking of that haha. thanks!


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

👍 2

(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


always paste the full stack trace. (in a snippet if possible CMD+Shift+Enter)


Thanks for the shortcut - I suspect that's going to save me some time.


eliding it throws away the ability for others to help you, and perhaps for you to help yourself


above full stacktrace ☝️


seems like some element vector without an element name?

👀 2

" is not a valid element name." - looks like bad input

👀 2

inspect your input without the terminal call to hiccup/html


is not a valid element name. yeah. somehow you ended up with [] or [nil]

👀 2

Some invalid conclusions on my side. I'll test a bit before asking further 🙂


Debugging is science™

👍 2

I found a [] in my edn file. Removed that, and now it produces valid HTML. So you guys were right ☝️ Thanks!


Genius! 😄

✔️ 2

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")


lazy-seq is not indexed, you'll need to count it yourself

👍 2

(or add indexes to the input items)

👍 2

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.


(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:


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:


@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)


That’s right, no need anymore!


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

Jakub Šťastný21:07:12

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?

Jakub Šťastný21:07:05

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))

👍 2
Jakub Šťastný21:07:00

OK, fair enough, just wanted a sanity check.


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)

Jakub Šťastný21:07:27

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

👍 3

When things are very nesty, this (and the others in the -> family) tend to help

👍 3

With rainbow parens in your editor, you eventually just stop seeing the parens 🙂


Same experience when I started though! But loving it now!