Fork me on GitHub
#beginners
<
2020-09-14
>
zhuxun200:09:24

Is there a way to compile my project into a executable jar without lein? I do have a deps.edn and one of my namespaces has a -main function.

dpsutton01:09:23

Check out depstar

seancorfield01:09:05

@zhuxun2 There's a #depstar channel if you get stuck or have follow-on questions about it.

olle14214:09:58

Can I destruct one of my arguments, while let doing it for another one? The first argument is a string, and the second one a map which I would like to destruct

olle14214:09:31

Using :keys maybe?

cgrand14:09:19

@olle142 something like that?

(let [{x :my-string {:keys [a b] #_any-kind-of-destructuring-can-go-here} :my-submap} {:my-string "s" :my-submap {:a 12 :b 34}}]
   [x a b])
=> ["s" 12 34]

olle14209:09:56

Yes that is exactly it, thank you very much @

matthew.pettis15:09:13

Is there the concept of NA or NaN in clojure? That is, is there a NA value such that (+ 1 NA) would yield NA? nil doesn't work, as (+ 1 nil) gives me a null pointer exception...

matthew.pettis15:09:28

Thanks. I haven't tried yet, but I'm guessing that nil works with nicely with missing string arguments. I'm trying some limited incanter type operations, and I'd like the missing construct.

alexmiller15:09:37

which is really just java.lang.Double/NaN

andy.fingerhut15:09:31

Beware that (= ##NaN ##NaN) returns false for reasons from the IEEE standard for floating point values, and thus ##NaN used as a set element or a map key will not be able to be looked up successfully, and any collections you might want to call = on will return false if either or both of them contain ##NaN values.

matthew.pettis15:09:02

This seems consistent with many constructs, like NULL in SQL... is there a function that returns true for ##NaN? like a isNaN function?

andy.fingerhut15:09:01

Yes there is a Java method:

user=> (Double/isNaN ##NaN)
true

matthew.pettis15:09:06

I see from your link maybe I can make (.equals ##NaN ##NaN) work...

matthew.pettis15:09:25

OK, that helps, thanks.

andy.fingerhut15:09:14

You cannot override the definition of Clojure's =, or the way it looks up elements in sets or as map keys, without hacking on Clojure's Java implementation.

matthew.pettis15:09:36

Got it. I was thinking that if Double/isNaN didn't exist, I could implement something like (defn isNan [x] (.equals ##NaN x))

matthew.pettis15:09:19

... I am much removed from the skill to rewrite internals 🙂 ...

andy.fingerhut15:09:42

I would not recommend it 🙂. I was merely answering the possible followup question of whether one could change how those language features work in Clojure.

matthew.pettis16:09:42

I'll bring this back to top level... Is this the idiomatic way to parse a list of strings, some of which will parse, and some of which will fail to parse?

matthew.pettis16:09:46

(map #(try (Integer. %) (catch Exception e ##NaN)) ["1" "" nil])

dpsutton16:09:01

sure. although I would probably not keep the nans. not sure what your usecase is but i would probably do (keep #(try (Long/parseLong %) (catch Exception _ nil)) collection)

matthew.pettis16:09:25

Thanks. My use case is reading in a CSV, which has a column that should be measurements, but some are missing. Let's say I have two such columns, and I want to average them. If one of the columns has a missing value, I want the corresponding row output to have a missing value. Dropping values means columns won't line up, and keeping nil values makes arithmetic throw exceptions. So I want to make an output for each row, and if there are missing values, the computation should be missing. I'm coming from R and python-pandas, where I am operating on tabular-shaped dataframes. I have some small subset of those operations I want/need to do in Clojure to be able to leverage other tools in Clojure. Thanks for the help.

matthew.pettis16:09:09

I'll add, for posterity, and anyone who stumbles on this: This has a lot of great information as well: https://stackoverflow.com/questions/2640169/whats-the-easiest-way-to-parse-numbers-in-clojure

pablog16:09:23

Hello everyone, I have a doubt about dependencies in CLJ(S). I have a project where, among other things, I use [email protected] and [email protected] I want to upgrade re-frame to 1.1.1, but in the changelong said that re-frame upgrades reagent to 0.10.0 on its version 0.12.0. Should I also upgrade reagent version in my project, or do the libraries compile and use the versions they need from their own dependencies?

smith.adriane16:09:03

unless there's a specific reason to stay at 0.8.1, then I would upgrade

donyorm18:09:42

Hey I'm working on a web server using ring and jetty, and getting a bunch of 500 errors, with almost no information anyone know how to get more details/a stack trace from that setup?

ryan07218:09:55

I'm looking to write some coercion code that expects a string or nil, coerces nil to "" and otherwise returns the string

ryan07218:09:40

in other languages, I might write (or s "") . is that idiomatic? is there something more idiomatic?

donyorm18:09:05

I believe this is considered idiomatic

dpsutton18:09:03

I can’t think of anything wrong with it

valtteri18:09:24

Looks good to me as well.

ryan07218:09:00

cool, thanks

valtteri18:09:56

Another option is to call str on the argument. If it’s nil it’ll coerce it to "" . Note that str also coerces all different types of values.

ryan07218:09:27

oh, I didn't realize str coerced nil to "". Thanks. It's for some url handling stuff, so everything is a string or nil anyway

mksybr20:09:49

Having some issues around using sorted-set-by, I'm trying to order a set of strings by their length but it demolishes the entire list to only (I think) one string per length? I want all the lists and for the set-y-ness's to apply to the string not the length, just want to be sorted by length. Please assist.

(def domains
  (into (sorted-set) 
    (map clojure.string/lower-case
      (drop-while #(< (count %) 4)
        (sort-by count
          (re-seq #"(?m)^.*$" (slurp "domains.txt")))))))
(count domains)
;; => 52664
(defn count-comparator [a b]
  (compare (count a) (count b)))
(def domains
  ;; right here vvvvvvvvvvvv
  (into (sorted-set-by count-comparator) 
    (map clojure.string/lower-case
      (drop-while #(< (count %) 4)
        (sort-by count
          (re-seq #"(?m)^.*$" (slurp "domains.txt")))))))
(count domains)
;; => 19
;; should be higher, whats wrong with my comparator? (I assume?)

jason35820:09:03

The 2nd example seems to be specifically about your problem

mksybr20:09:24

Oops, youre right thanks!

andy.fingerhut22:09:17

You could have the sort key be not only the length, but a vector of [length string-value]. That will sort first by the length, and only use the string-value as a tie-breaker for same-length strings.

andy.fingerhut22:09:02

Note that if your input strings have duplicates of the same identical string, then sorted-set-by will only include one of those in the resulting sorted-set.

andy.fingerhut23:09:23

If you want to retain duplicates, then it sounds more like what you would want is to sort a sequence, i.e. list, vector, array, etc., and give back a sequence with the same number of items, including any duplicate strings in the input. That cannot be done with a sorted-set unless you somehow make each equal string into different values, e.g. by making it a vector with a unique id for each string or something like that.

andy.fingerhut23:09:14

It can be done with a vector or array, and you can use sort or sort-by with appropriate comparator functions.

franklineapiyo20:09:12

I'm having trouble upgrading the dependencies for this project

franklineapiyo20:09:16

(defn js-dir
      "Prefix with full JavaScript directory."
      [path]
      (str "resources/public/js/compiled/" path))

(defproject onaio/chimera "0.0.13"
  :description "Collection of useful Clojure(Script) functions."
  :dependencies [[clj-time "0.15.2"]
                 [com.cognitect/transit-cljs "0.8.264"]
                 [com.taoensso/tempura "1.2.1"]
                 ;; For CSV->XLSForm
                 [clojure-csv/clojure-csv "2.0.2"]
                 [dk.ative/docjure "1.11.0"]
                 [onelog "0.5.0"]
                 [org.clojure/clojure "1.8.0"]
                 [org.clojure/clojurescript "1.10.773"
                  :exclusions [org.clojure/clojure]]
                 [org.clojure/core.async "1.3.610"]
                 [org.omcljs/om "0.9.0"]
                 [slingshot "0.12.2"]
                 ;; JS
                 [cljsjs/moment "2.24.0-0"]]
  :license "Apache 2"
  :url ""
  :profiles {:dev {:dependencies [[midje "1.8.3"]]}}
  :plugins [[jonase/eastwood "0.2.1"]
            [lein-bikeshed-ona "0.2.1"]
            [lein-cljfmt "0.3.0"]
            [lein-cljsbuild "1.1.2"]
            [lein-environ "1.0.1"]
            [lein-kibit "0.1.2"]
            [lein-midje "3.1.3"]]
  :cljfmt {:file-pattern #"[^\.#]*\.clj[s]?$"}
  :eastwood {:exclude-linters [:constant-test]
             :add-linters [:unused-fn-args
                           :unused-locals
                           :unused-namespaces
                           :unused-private-vars]
             :namespaces [:source-paths]
             :exclude-namespaces [chimera.async]}
  :test-paths ["test"]
  :cljsbuild {
              :builds {:dev
                       {:compiler {:output-to ~(js-dir "chimera.js")
                                   :output-dir ~(js-dir "out")
                                   :optimizations :whitespace
                                   :pretty-print true
                                   :source-map ~(js-dir "chimera.js.map")}}
                       :test
                       {:source-paths ["src" "test"]
                        :notify-command ["phantomjs"
                                         "phantom/unit-test.js"
                                         "phantom/unit-test.html"
                                         "target/main-test.js"]
                        :compiler {:output-to "target/main-test.js"
                                   :optimizations :whitespace
                                   :pretty-print true}}
                       :prod
                       {:source-paths ["src"]
                        :compiler {:output-to ~(js-dir "chimera.js")
                                   :output-dir ~(js-dir "out-prod")
                                   :optimizations :advanced
                                   :pretty-print false}
                        :jar true}}
              :test-commands {"unit-test"
                              ["phantomjs"
                               "phantom/unit-test.js"
                               "phantom/unit-test.html"
                               "target/main-test.js"]}}
  :global-vars {*warn-on-reflection* true})

franklineapiyo20:09:46

I keep getting this error

seancorfield20:09:47

Let me create a local lein project and see what happens with that project.clj...

franklineapiyo20:09:02

Thank you very much @

seancorfield20:09:25

@ How do you run lein ancient in interactive mode?

seancorfield20:09:00

The report from lein ancient only identifies these three deps as being outdated -- is this what you get too?

[dk.ative/docjure "1.14.0"] is available but we use "1.11.0"
[org.clojure/clojure "1.10.1"] is available but we use "1.8.0" (use :check-clojure to upgrade)
[midje "1.9.9"] is available but we use "1.8.3"

franklineapiyo20:09:22

yes... I have updated all the other's just now

franklineapiyo20:09:32

lein ancient :interactive

seancorfield20:09:27

That gives me this warning

(warn)  option ':interactive' is not applicable for this task.

franklineapiyo20:09:27

sorry.. that's not the correct command

franklineapiyo20:09:44

lein ancient upgrade :interactive

seancorfield20:09:00

Okay, the conflict is coming from onelog "0.5.0" which is bringing in an older version of Aviso:

Retrieving io/aviso/pretty/0.1.12/pretty-0.1.12.pom from clojars

seancorfield20:09:25

I did lein deps :tree and looked through to see what was using aviso pretty.

seancorfield20:09:00

That is earlier than the change to pretty which introduced the *traditional* var (0.1.15).

seancorfield20:09:55

And the problem shows up when lein ancient tries to run your tests after the updates I think...?

seancorfield20:09:33

Possible solutions: add :exclusions to the onelog dependency to exclude io.aviso/pretty; or add a top-level dependency directly on io.aviso/pretty "0.1.37"

franklineapiyo20:09:20

alright... thanks will try that.... I didn't think of using lein deps :tree... that's one new thing I just learned

seancorfield20:09:20

That still may not work, because onelog may depend on something in the older version of Aviso Pretty but it's worth a try.

seancorfield20:09:27

I would definitely recommend not using interactive tools that "help" by modifying your project configuration -- do it manually instead.

franklineapiyo20:09:09

Thanks you very much... It's pretty late over here... so I'm going to sleep on in though... it's pretty late on this side of the planet... 😄

seancorfield20:09:40

I personally would also recommend not using Midje. It's considered non-idiomatic and drags in a lot of transitive dependencies that can be problematic.

franklineapiyo21:09:06

what do you think is the better substitute for midje?

seancorfield21:09:16

Just use plain old clojure.test

franklineapiyo21:09:25

aaah... alright

seancorfield21:09:37

Midje isn't compatible with any standard test runners or test tooling.

seancorfield21:09:56

It's why I created expectations.clojure.test so there's a fully clojure.test-compatible version of Expectations. It provides the expressiveness of classic Expectations but still lets you use all the standard clojure.test tooling built into all the editors and (standard) test runners.

franklineapiyo20:09:50

Syntax error compiling var at (midje/util/exceptions.clj:75:3).
Unable to resolve var: aviso.exception/*traditional* in this context

ghadi20:09:03

if you have a long block of text, use a snippet CMD-Shift-Enter (on Mac, probably control on Windows). It will even do clojure syntax highlighting

franklineapiyo20:09:35

Thanks... good to know

michal.kurtak21:09:42

Hi I’m having a trouble with implementing priority queue with sorted-set-by. I am not able to figure out how to implement “deque” operation. first function correctly returns element with lowest priority, but i am not able to get sorted set without the first element using supplied comparator.

(sorted? (rest (sorted-set my-compare [3 1 2 4])))
returns false Could anybody help?

dpsutton21:09:05

if you're using clojure.core/sorted-set it takes the elements of the set, not a comparator and a collection as you are using it. what is returned from (sorted-set my-compare [3 1 2 4])?

dpsutton21:09:56

did you mean to use sorted-set-by ?

dpsutton21:09:13

but just kinda doing dimensional analysis on it, the sorting of the set has a custom sorter whereas the call to sorted? does not use this custom sorter. So most likely they will not agree. EDIT: just read how sorted? works and this doesn't seem true to me now. the sorted-set will implement clojure.lang.Sorted. but the seq returned from rest won't

jason35821:09:03

but rest returns a seq, not a set

jason35821:09:53

@michal.kurtak try using disj perhaps?

michal.kurtak21:09:27

sorry i’ve used sorted-set-by of course. the thing is, i’ve expected that rest function returns same collection type but without the first elemenet

jason35821:09:25

I wonder if sorted-set is a good fit for priority queues; it's gonna drop items if the comparator sees them as equal

michal.kurtak21:09:23

yes, i understand your point. i have unique values so i thought it is good enough. The disj trick worked. Thank you

michal.kurtak21:09:33

This is the code without comparator (but the same works with comparator)

(let [s (sorted-set 3 2 1 4)]
    (sorted? (disj s
                   (first s))))

michal.kurtak21:09:45

BTW, what will you suggest for priority queue? sorted-map?

jason35821:09:04

no idea. my first take would still probably be sorted-set-by, but with some kind of tie-breaker (or, as in your case, a guarantee that there are no duplicates)

jason35822:09:12

or a sorted-map with sets / vectors for values, depending on what the specific task needs

seancorfield22:09:13

@michal.kurtak Have you looked at clojure.data.priority-map? https://github.com/clojure/data.priority-map (I am not the author or maintainer, despite having made the most recent commit)

michal.kurtak14:09:38

Hi, thank you for your tip. I think this what i ’ve been looking for the case with non-unique values (for unique values sorted-set is sufficient). I’ve also managed to use sorted-map with little trick from https://clojuredocs.org/clojure.core/sorted-map-by (you have to wrap sorted-map-by to data that holds both sorted and unsorted map and lookup for value in unsorted map in comparator), but clojure.data.priority-map is better because all standart colletion functions (first, rest, count, contains…) work out of box without wrappers