Fork me on GitHub
#clojure
<
2018-02-16
>
seancorfield00:02:46

I was hoping it would get fixed for 1.9 -- I opened that ticket 18 months ago after seeing several people trip over it (via Slack and via the mailing list) and it's a "known" issue that goes back longer than that...

caleb.macdonaldblack00:02:34

How can I expand a symbol being passed into a macro in both clojure and clojurescript?

(s/def :my-spec/my-thing (s/keys :req-un my-keys))
I want to expand my-keys here

caleb.macdonaldblack00:02:09

I was able to get things working in clojure by doing

(s/def :my-spec/my-thing (eval `(s/keys :req-un ~my-keys)))
But this did not work in clojurescript as the eval works differently

moxaj00:02:19

@caleb.macdonaldblack write another macro which emits the correct s/def form

caleb.macdonaldblack00:02:24

@moxaj

(defmacro def-my-spec [my-keys]
  `(s/def :my-spec/my-thing (s/keys :req-un ~my-keys)))
(def-my-spec my-keys)

caleb.macdonaldblack00:02:05

@moxaj Thanks that works. Do you think this could be improved or reduced any further?

caleb.macdonaldblack00:02:16

And is this pretty much the standard solution to this problem?

moxaj00:02:40

I think this is as good as it gets, and yes

qqq08:02:48

(defn vec-dot [lhs rhs]
  (reduce + (map * lhs rhs)))

(vec-dot [1 2 3] [2 3 4])

(defn my-do [f v offsets]
  (letfn [(helper [so-far rst]
            (if (= (count rst) 0)
              (f so-far (vec-dot so-far offsets))
              (let [[h & rst] rst]
                (doseq [i (range h)]
                  (helper (conj so-far i) rst)))))]
    (helper [] v)))

(my-do (fn [& args] (println args))
       [2 4 3] 
       [1 2 3])

Is there a better way to write this? I'd like to get rid of the * in vec-dot by cleverly incrementing while looping, and I would like ot generate the 'lattice' without using nested function calls.

roklenarcic12:02:12

what's the difference between with-bindings and binding?

mpenet12:02:31

singular vs plural 🙂 diff args input

mpenet12:02:51

the docstring should be quite self explanatory

joelsanchez12:02:51

with-bindings is easier to use when the binding map is dynamic

Ondřej Čermák12:02:51

Hello everyone, lets assume I have structure like this:

({:logged_at #<DateTime 2013-03-29T12:00:05.000Z, :data "somedata"} ,
 {:logged_at #<DateTime 2013-03-29T12:10:05.000Z, :data "someotherdata"} )
what im trying to do is convert it to something like this:
({:logged_at "2013-03-29" :data "somedata"},
{:logged_at "2013-03-29" :data "somedata"} )
I wanted to achieve this by something like this:
(map #({:logged_at (t/date->formatter (:logged_at %) "dd.MM.yyyy")
              :data (:data %)})  my-map))
but clojure wont allow me to do that 😕 Any ideas how to achieve this?

Ondřej Čermák12:02:38

In other words I want to convert all the DateTimes to just string represantation of date 🙂

jarohen12:02:49

try adding do?

(map #(do {:logged_at (t/date->formatter (:logged_at %) "dd.MM.yyyy")
           :data (:data %)})  
     my-map))

jarohen12:02:57

actually, if you're just updating the logged_at key, you can use update

Ondřej Čermák12:02:42

i still get the clojure.lang.ArityException: Wrong number of args (0) passed to: PersistentArrayMap error

Ondřej Čermák12:02:41

oh nvm, got it now, any explanation why it works with do and not with only map?

joelsanchez12:02:51

you can't use map literals with function literals

joelsanchez12:02:31

do #(hash-map :k :v) or (fn [] {:k :v}) but not both

jarohen12:02:52

that error message is telling you that it tried to invoke the map as a function, passing it 0 args

jarohen12:02:38

the anonymous function you've got there is expanding out to something like (fn [m] ({:logged_at ..., :data ...}))

jarohen12:02:43

hence the arity error

jarohen12:02:31

whereas, with do, it expands to (fn [m] (do {:logged_at ..., :data ...})), which is no longer attempting to invoke the map as a function

abdullahibra12:02:51

@ondrej.l.cermak (mapv (fn [{:keys [logged_at] :as h}] (assoc h :logged_at (t/date->formatter logged_at "dd.MM.yyyy"))) data)

jarohen12:02:07

given you're only updating one key, it's preferable to use update - something like (map #(update % :logged_at t/date->formatter "dd.MM.yyyy") my-map) should do the trick

Ondřej Čermák12:02:41

Oh, I understand it now, thanks guys. i did not realize its trying to invoke the map definition as a function.

sundarj12:02:06

@ondrej.l.cermak you can find out these things from the repl:

user=> (macroexpand '#({}))
(fn* [] ({}))

Ondřej Čermák13:02:08

Btw one more thing, how would you then transform it, most efficiently to something like this? I cant find solution other that iterate over the map more than once 😕

Ondřej Čermák13:02:13

({:data({...}), :logged_at 10.02.2018} 
{:data({...}), :logged_at 10.02.2018} 
{:data({...}), :logged_at 12.02.2018} 
{:data({...}), :logged_at 10.02.2018} 
{:data({...}), :logged_at 12.02.2018} 
{:data({...}), :logged_at 16.02.2018} 
{:data({...}), :logged_at 18.02.2018} 
{:data({...}), :logged_at 16.02.2018})
{ :dates ["10.02.2018" "12.02.2018" "16.02.2018" "18.02.2018"]
  :dates_count [{ :data [3 2 2 1]}]}

Ondřej Čermák13:02:06

I tried group-by , but its kinda unfortunate solution

Ondřej Čermák13:02:31

@sundarj well the point of it is to have unique dates, sorted from lowest to highest and then in the :dates_count i need to have the count of theese dates in the same order. It is for frontend graph plugin, which accepts data exactly like this:

{ :dates ["10.02.2018" "12.02.2018" "16.02.2018" "18.02.2018"]
  :dates_count [{ :data [3 2 2 1]}]}

sundarj13:02:50

ah, i see. yeah i think the sorting has to happen in a separate step to the building of that map

sundarj13:02:22

or you could use a sorted-set-by for the dates

Ondřej Čermák13:02:41

well, i can sort it out when querying from the database. I just need the order of the dates and date-count be the same, so the count would truly represent the count of that given date in the sequence of maps

Ondřej Čermák13:02:50

But I seem to be unable to do it. My knowledge in clojure is very limitted 😕

sundarj13:02:53

well if you conj the corresponding data to the different vectors at the same time, the indexes will match up, right?

Ondřej Čermák14:02:51

I never used conj, I always used assoc or merge. So im thinking how to add teh logic of uniquness and counting to the code you posted

sundarj14:02:21

for uniqueness, use a set instead of a vector

sundarj14:02:10

the convert it into a vector when you pass it to the graph plugin

Ondřej Čermák13:02:45

what is in the :data field of the map doesnt really matter to me

Andrei15:02:14

Hi, I'm trying to suppress logging output from a third-party library while I'm at the REPL. I've tried multiple variations of with-binding, binding, alter-var-root, even (System/setOut (java.io.NullPrintStream.)) and still I get output

timgilbert16:02:32

Say, as an exercise as much as anything else, would it be possible to construct a thing that looked like a map (and maybe implemented the IMap protocol or whatever it's called), but would always return a constant value when accessed with (get m :keyword) or (:keyword m)? Like (constantly 43) but with a map interface?

timgilbert16:02:52

Like a map with conceptually infinite keys?

tbaldridge16:02:31

Sure, probably the smallest such interface you can implement is clojure.core.ILookup @timgilbert

timgilbert16:02:39

Ah, right you are, thanks @tbaldridge:

(def m (reify clojure.lang.ILookup
         (valAt [o k] 42)
         (valAt [o k n] 42)))
         
=> #'user/m
(:foo m)
=> 42
(get m :foo)
=> 42

gganley18:02:18

Hey folks, I’m writing a functino that creates a spectrogram but the biggest slow down at the moment is the process of actually slicing up the data. partition is by far taking the most time. I was curious if there was a better way of writing this function

gganley18:02:25

One moment I pasted the wrong thing

gganley18:02:44

Ok it is fixed

noisesmith18:02:05

getting numerics to be fast in clojure is non-trivial, the fastest thing in terms of developer time is likely writing something in java

gganley18:02:18

the fft is purley java

noisesmith18:02:23

but if it must be clojure, you can use *warn-on-boxed*

gganley18:02:32

I’m using apache commons

gganley18:02:42

so the fft is dumb fast

gganley18:02:00

and the wfun is very simple let me grab an example

noisesmith18:02:28

that .multiply call is still going to be slow - you probably want to hint it

noisesmith18:02:53

and that window function is going to be very slow

gganley18:02:00

I used pmap and it helped but not too much

gganley18:02:23

I took the pmap out of the example just so I don’t confuse myself

fmnoise18:02:26

is there any way to build uberjar without boot/lein?

gganley18:02:52

That is a matter of my own ignorance, I understand the words you are saying but I don’t know

gganley18:02:25

I could typehint the multiply call and use pmap and see the results

noisesmith18:02:29

@gganley that raised-cos (and the hamming derived from it) is still going to be extremely slow, and if you must write it in clojure *warn-on-boxed* will at least tell you what the slowest parts are http://insideclojure.org/2014/12/15/warn-on-boxed/

gganley18:02:10

let me try it without the windowing function

gganley18:02:16

Just tested, literally the same time

noisesmith18:02:34

not only that, but the partitioned data coming in is not a counted type, so it’s literally iterating through to count the items in an O(n) manner every time the inner function is called

gganley18:02:49

The data coming in is a short-array

noisesmith18:02:58

I mean line 3

noisesmith18:02:15

(of the window function paste)

noisesmith18:02:38

that is using segment, generated by partition, which is not a counted type

gganley18:02:39

I think the window function is not the issue since it is the same running time w/ or w/o the windowing functino

noisesmith18:02:58

are you forcing the result in the benchmark? because I find that surprising

gganley18:02:15

doall forces right?

noisesmith18:02:28

not in a nested way though - depends on the shape

noisesmith18:02:49

it forces the “spine”, but you need nested doall if there are nested lazy results

gganley18:02:38

[[complex]] is the result of spectrogram-array

noisesmith18:02:48

(doall (map doall result))

gganley18:02:05

alright, it’s twice as slow

gganley18:02:05

Unfortunately I need to go to a meeting but this is illuminating, I’ll be back but thank you for the help

carocad19:02:43

can someone explain me how is this possible?

(identical? Double/POSITIVE_INFINITY Double/POSITIVE_INFINITY)
;; => false

noisesmith19:02:09

@carocad identical? is explicitly asking if two objects in the vm are the same object

noisesmith19:02:06

making singleton objects for every double-precision floating point value would be a huge waste of memory, in practice only some numerics (integral types between -128 and 127 inclusive AFAIK) are cached and shared as singleton objects

noisesmith19:02:12

what clojure does when you use a double in a form is to put it in a box of type Double

noisesmith19:02:40

(except for rare circumstances where it can optimize because it knows the value can be used unboxed)

noisesmith19:02:17

so in the case of identical? here you are putting the same value in a box twice, and asking if it’s the same exact box (and the answer is no, it was put into two different boxes)

carocad19:02:29

@noisesmith thanks for the explanation. It does makes sense from the point of view of Clojure. However I still find it confusing. If I do (identical? "foo" "foo") then I get true. I would expect it to be false base on your explanation 😞

noisesmith19:02:45

strings and numbers are handled differently

noisesmith19:02:43

is there a reason you need object identity and not just equality?

carocad19:02:51

@noisesmith do you know of a way to bypass this for static final numbers? I would not like to use the slower =

carocad19:02:00

yes, speed

noisesmith19:02:44

I’ll repeat what I told gganley - if you need speed with numbers your most efficient thing in terms of developer time is likely to write some java

noisesmith19:02:09

I don’t know about caching number instances - someone in #clojure-dev might have some clever suggestions

noisesmith19:02:06

also I have a hunch == should be faster with floats than =, not absolutely certain though

carocad19:02:30

@noisesmith You are right, I will stick with = in Clojure and once I get to the Java code I will use the strict comparison. Thanks for the help

qqq19:02:33

I find that as I use better code folding / code jumping tools, I tend to have fewer modules with more lines of code (some going up as high as 5k lines of code / file). Is there fundamentally any downsides to *.cljc files with line count in the thousands ?

Alex Miller (Clojure team)21:02:56

You can eventually hit method size limits in the init class if you aot

mfikes21:02:37

Also, as it stands now, Cursive can get sluggish with several thousands of lines in one file

Alex Miller (Clojure team)02:02:59

That’s not the issue - every var has some setup bytecode that goes in the class initializer and eventually you’ll hit the max method size

jaide21:02:32

I want to create a terminal program like HTOP where it’s constantly updating and redrawing as opposed to printing new lines to stdout. How can that be achieved in Clojure? Is there a way to output to the terminal that can be erased later?

andy.fingerhut22:02:44

Check out the Unix/Linux program 'watch' in case it simplifies your life dramatically -- basically runs any other program that outputs to stdandard out, with a configurable period.

andy.fingerhut22:02:21

redrawing the screen each time.

chris21:02:27

in general you do that with ansi terminal codes

chris21:02:44

usually though people use something like ncurses

chris21:02:04

it's nothing clojure specific

chris21:02:13

I see things for lantern (apparently a java ncurses-like lib) which have bindings written in clojure

manutter5121:02:54

Yeah, I’ve used Lanterna for clojure-y ncurses-y stuff. Kinda nice. https://sjl.bitbucket.io/clojure-lanterna/

jaide21:02:53

Ah thanks a ton @chris & @manutter51 I’ve been trying to learn what the terminology is for that feature. I’ll definitely give laterna a shot.

qqq22:02:24

is there a better way to write:

(defn foo [obj]
  (fn [& args]
    (let [[t1 t2 t3 t4 t5 t6 t7 t8 t9] args]
      (case (count args)
        0 (.go obj)
        1 (.go obj r1)
        2 (.go obj t1 t2)
        3 (.go obj t1 t2 t3)
        4 (.go obj t1 t2 t3 t4)
        5 (.go obj t1 t2 t3 t4 t5)
        6 (.go obj t1 t2 t3 t4 t5 t6)
        7 (.go obj t1 t2 t3 t4 t5 t6 t7)
        8 (.go obj t1 t2 t3 t4 t5 t6 t7 t8)
        9 (.go obj t1 t2 t3 t4 t5 t6 t7 t8 t9)))))

qqq22:02:51

the r1 is meant to be t1

greglook23:02:24

you could condense it with a macroexpansion, but otherwise not to my knowledge

tdantas23:02:32

I’m with a interesting problem:

(loop
   I'm building a bot that will query some external resource ( rateLimit 20 requests/s ) and do   some computation with the results.
(recur))
I’m monitoring the application and after some time the application stop to work. there is no exception, nothing

noisesmith23:02:13

is this happening inside a future?

noisesmith23:02:34

the default behavior of futures is to stash the exception and only throw if you deref the future

noisesmith23:02:10

you can use either C-\ or jstack to see the stack traces of all currently running threads, that can verify what’s actually still executing

tdantas23:02:59

(future (loop recur))

noisesmith23:02:08

if it’s a future you never plan to deref, the best bet is (future (try .... (catch Exception e (log/error e))))

noisesmith23:02:32

because without that logging, you’ll never see the error

tdantas23:02:58

cool ! thanks sir ! will let you know in a few minutes

tdantas23:02:59

@noisesmith thanks sir, you were correct !

noisesmith23:02:39

cool- yeah I have had exactly this problem in my own project - it’s a good idea to put a try/catch with a log message in any future that you don’t dereference

tdantas23:02:45

clj-http throws exception on http responses code other than (200..300) range

noisesmith23:02:03

it has an optional :throw-exceptions false config though

tdantas23:02:29

interesting, thanks