#clojure log - May 03 2016

The Joy of Clojure
Main Clojure site
Google Group
IRC
List of all logged dates

0:12 sdegutis: wait no

0:12 is that actually working?

0:12 ok yeah i think so

0:13 which is more efficient on cpu? apply max or reduce max?

0:13 how about memory?

0:13 oh wait

0:13 profile.

0:23 dysfun: i'm going to guess at 'apply max', however

0:23 (just a hunch)

3:44 Valentijn: Hi, quick question:

3:47 I have a vector looking like this [{:id 1 :from "F" :to "T" :pricing atom([*some pricings*])}, *more entries*], how can I update the pricings atom of each entry of the vector? When using (map (function-to-update-single-atom) myvector), the vector doesn't get updated. What am I doing wrong?

3:54 Hmm, doall did the trick. Can anyone explain?

3:54 opqdonut: map is lazy

3:54 it returns a lazy sequence

3:54 the computation is only done when somebody starts looking at the sequence

3:54 for things with side-effects it's clearer to use https://clojuredocs.org/clojure.core/doseq

3:57 Valentijn: Thanks! I don't do IO or something in the update function (just an update of the :pricing of the map with swap!), is doall then equal to doseq, or does something happen behind the scenes.

3:57 opqdonut: well swap! is a side effect

3:57 of sorts

3:57 doall and doseq are different, doall takes a sequence and forces (evaluates) all the elements

3:58 doseq is a macro that you use like this: (doseq [el my-vector] (do-something el) (do-something-else el))

3:58 ridcully: lazyness?

4:04 pnor: what is the easiest way to groupby a map { x: .. y: ... }

4:04 by x and y at the same time

4:04 (group-by :x input) works fine for x only

4:05 ridcully: (group-by (juxt :x :y))

4:05 luma: (group-by (juxt :x :y) input)

4:06 pnor: ok thanks guys

4:33 Valentijn: hehe den dyl

5:04 sunset-shimmer: hi, clojurians!

5:06 Can you recomend me some course or book or articles about concurrency? I want to know, what the difference between async/await and futures/promises, what the actors are, what the chans are, and so on.

5:08 dysfun: well we don't have actors if that helps a little :)

5:09 futures are computed on a thread pool

5:10 you can wait for them to complete if you need them and you can chain them together

5:11 promises are like futures except that you get a function to deliver the result and it's up to you where it gets computed

5:11 pythys: Hi Folks. So issuing a simple command in repl like (require 'compojure.core :refer :all) would crash with java.lang.Exception: Unsupported option(s) supplied: :all

5:11 Reading through the official documentation, it does not mandate that you only use :refer inside (ns)

5:11 dysfun: pythys: add vector-parens

5:12 pythys: dysfun: to what? the whole expression? where to where?

5:12 dysfun: (require '[compojure.core :refer :all])

5:12 hiredman: (require '[...])

5:12 pythys: Oh ...

5:12 hiredman: just like it would be in a :require clause of an ns form

5:13 pythys: why do I need to quote the vector in here and not in (ns,,,)

5:13 dysfun: because ns is a macro

5:13 pythys: Ahhhh I see

5:13 dysfun: so it won't be evaluated and fail to find the symbols named

5:13 pythys: because you're passing in "data" that will eventually become "code" right?

5:14 Now it all makes sense. that's why it's a compiler exception!

5:14 dysfun: no, not really

5:14 when you call (require '[compojure.core :refer :all

5:14 the require function is passed that vector as data

5:15 pythys: which is then fed to the macro and converted to actual code ...

5:15 right?

5:15 clojurebot: right is not wrong

5:15 dysfun: it then goes and loads the code, which has the side effect of attaching the namespace vars

5:15 (ns ...) actually expands to the (require '[..]) form (and not just for require, :use etc.)

5:16 pythys: oh I see I see

5:16 it's data to data

5:16 but in another form

5:17 dysfun: think of it more like when you execute some clojure in the repl you are asking it to evaluate data

5:17 pythys: okay

5:17 dysfun: and when it's not a list, it evaluates to itself

5:17 when it's a list, after evaluating the subforms inside of it, the function gets called with the given parameters

5:17 pythys: the doc for require officially says (require & args) and lists some keywords below ...

5:18 How do I generally know when to quote and when not to quote?

5:18 dysfun: the quote simply stops it trying to evaluate the vector (which contains symbols which are nlt yet in the namespace)

5:18 you almost never want to quote. for the specific case of require, use etc., when you have to put a : on the front because you're in ns, you don't quote. otherwise, you quote

5:19 if you did not quote here, it would complain it could not find compojure.core because it hasn't been loaded (how could it? you're passing it as an argument to require!)

5:20 a vector evaluates to itself, so we could also individually quote the symbols

5:20 but most of us prefer to just quote the entire vector

5:21 (a symbol is evaluated by looking up the value it names)

5:21 pythys: Sorry I'm not getting this ...

5:22 dysfun: when you 'run' clojure, you evaluate it one step at a time

5:22 pythys: as I understood, clojure only evaluates the first thing on the list, and the rest is data

5:22 so (1 2 3) would execute 1 on 2 and 3

5:22 dysfun: no. when you evaluate the list, you first evaluate the contents of the list, then you call the function

5:22 pythys: and therefore (run [a] [b] [c] ,,,) would just execute "run"

5:23 oh

5:23 dysfun: first it will execute [a] [b] [c]

5:23 because it needs the values to pass

5:23 pythys: dysfun: does that also apply on maps?

5:23 dysfun: it will also evaluate run (because run is a symbol)

5:23 pythys: and sets?

5:23 dysfun: yes, it does

5:23 pythys: so any data structure executes unless quoted?

5:23 dysfun: yes. but bear in mind the quoting might be done by a macro

5:24 pythys: is the execution of a vector similar to a list? e.g. [a b c] would also apply a on b & c?

5:24 dysfun: (the 'calling' of a macro implicitly quotes the rest of the list)

5:25 yes

5:25 pythys: ouch! why?

5:25 Why would I evaluate a vector as something to run!

5:25 dysfun: you wouldn't. only lists get 'run'

5:26 pythys: then why quote a vector in the first place?

5:26 dysfun: because it has the side effect of quoting everything in it recursively

5:26 thus we trade one quote per symbol for one quote for the whole expression

5:26 pythys: and why quote everything inside?

5:26 TEttinger: not even side effect, it's kinda what quote does, right?

5:26 if you had to quote every thing individually it would be a pain

5:27 dysfun: because that vector contains symbols, the evaluation of which is looking up the value contained in the var named by the symbol

5:27 TEttinger: there's ~ to unquote and I can't remember if it only works in certain places

5:27 ,(str '[hey ~Math/PI])

5:27 clojurebot: "[hey (clojure.core/unquote Math/PI)]"

5:27 luma: it only works inside syntax-quote

5:27 TEttinger: hm

5:27 pythys: dysfun: OH, so it's because there is "no value" for that symbol

5:27 TEttinger: thanks luma

5:27 luma: as does unquote-splicing

5:27 pythys: dysfun: and it is only needed by the macro to flag something

5:27 dysfun: you could for example (require [(symbol "compojure.core") :refer :all])

5:27 that is valid, but it's annoying to write

5:28 pythys: right. we don't care that it doesn't name anything yet, we still need to use a name to communicate the information about what we want to require

5:28 pythys: I seeeeee

5:28 damn, now it clicks

5:28 dysfun: clojure could in an alternate world take a string argument instead

5:29 then there would be no need to quote and it would be marginally fuglier

5:30 pythys: yeah, :refer evaluates to itself, :all evaluated to itself, compojure.core evaluates to nil which crashes the thing

5:30 because no symbol called compojure.core is defined

5:30 dysfun: well no, it doesn't evaluate to nil so much as it doesn't evaluate - an error is thrown. clojure is upset.

5:30 pythys: I seeee ... sort of undefined

5:31 compiler getting pissed

5:31 jonathanj: what do Clojurians think of Racket?

5:31 dysfun: pythys: isn't it always? have you noticed the length of stacktraces?

5:32 pythys: uh-huh of course

5:32 dysfun: jonathanj: it's good if you like scheme more than clojure or if you want to learn something for the things it explores rather than to get work done

5:32 jonathanj: Typed Racket is pretty attractive and so is the ability to handily write a DSL

5:32 pythys: dysfun: by the way, how do you know that you need to pass a vector to require in the first place? the definition in the official documentation is just (require & args)

5:32 dysfun: DSL-writing comes for free with every lisp

5:32 pythys: do you have to look at the code for that?

5:32 luma: if you want to see what happens when a language allows you to "handily write a DSL", see scala

5:33 dysfun: pythys: because i saw other people do it on the internet, probably

5:33 jonathanj: well, Racket is a lot saner than Scala

5:33 Scala started at the deep end and went off whatever comes after the deep end

5:33 pythys: dysfun: yeah but I mean generally speaking, you access a new library and want to figure out what to pass. How do you do that?

5:33 dysfun: no argument here

5:33 jonathanj: anyway, Racket isn't an option for me, the main reason I use Clojure is because I need java interop

5:34 dysfun: pythys: i read the documentation (usually the README.md on github). if it isn't working then, i go read the test suite to see how they made it run

5:34 jonathanj: everytime i read something about Racket i leave finding myself wondering if i have a suitable project to use it for

5:34 pythys: dysfun: okay, so this is sort of a penalty of using a dynamic language

5:34 dysfun: well if you want to build a GUI app, javafx/swing/awt is the pits, so that could be a good domain for racket

5:35 pythys: no. contrary to most scala programmers, i don't think a type signature constitutes the wholeness of documentation

5:35 jonathanj: John Carmack wrote a networked game server in Racket

5:35 and he had a lot of good things to say about the experience

5:35 pythys: dysfun: but you just mentioned yourself that you have to "dig out" how the thing works

5:35 dysfun: this is exactly why I was confused and joined the channel for help for example

5:36 I was trying to make sense of it

5:36 dysfun: pythys: right. and i also program haskell. the best button on hackage is the 'read source' link

5:36 pythys: dysfun: right, I see

5:36 dysfun: usually data validation is in the first few lines of (doc require) for example

5:36 so you would immediately know it's a vector

5:36 sorry I meant (source require)

5:36 dysfun: right

5:37 pythys: got that!

5:37 jonathanj: dysfun: you write Clojure and Haskell code?

5:37 dysfun: i write a lot of things

5:37 jonathanj: dysfun: you're not bipolar, are you?

5:37 dysfun: is there a type system joke in there?

5:37 pythys: hmmmm, leaving a sour taste in my mouth. I'm too addicted to type systems

5:37 jonathanj: Haskell people hiss and recoil when you talk about about dynamic languages

5:38 dysfun: yes, i know, but despite the community it's a great tool

5:38 sadly many in the community are also tools

5:38 jonathanj: i can't get into it, i've tried a few times but i keep getting stuck on theory

5:39 pythys: dysfun: do you have a preference of dynamic vs static? cases where the sacrifice is worth it?

5:39 jonathanj: and the infix operator soup is really disheartening as a beginner

5:39 dysfun: well my view ("ignore the type theory and just write the code") isn't that popular

5:40 pythys: for cases where incorrectness is catastrophic and difficult to spot, use a statically typed language. Otherwise, use whatever you think will enable you to get the job done

5:40 jonathanj: i read through the haskell-servant tutorial the other day, and it seems like a really great way to write (and test!) web services

5:41 pythys: dysfun: okay I see. Well the upside I guess is that you have a very focused dense effective code with clojure without too much ceremony

5:41 dysfun: clojure is one of my favourite tools to work with. It's very practical and easy to get things done with

5:41 pythys: but I need a repl all the time to see what's up.

5:41 uh-huh I see

5:42 dysfun: so natually, less lines of code in comparison to any typed language I assume

5:42 naturally

5:42 dysfun: depends

5:43 haskell gets pretty close until i start working with monads

5:43 pythys: which is where "real" work is anyway

5:43 otherwise it's just a hot CPI

5:43 CPU

5:44 dysfun: well there is definitely a point in solving modern problems with haskell that way too much code is in the IO monad

5:45 pythys: I see

5:45 Thank you so much, things are much clearer now overall

5:45 I hit small things but make big discoveries each time

6:18 jonathanj: searching on clojuredocs:

6:18 Search results for query: clojure.java.shell

6:18 1 to 1 of 1 results.

6:18 0 examples

6:18 but there are 0 results listed

6:19 is there something like `/usr/bin/which` in Clojure/Java?

6:19 ie. first discover whether something exists before trying to spawn it

6:19 dysfun: if you're going to shell out, you may as well shell out to `which`

6:19 jonathanj: that's a bit of a weird way of thinking about it

6:20 `which` doesn't exist on Windows, for example

6:22 dysfun: no, i'm not aware of anything that handles this

6:25 jonathanj: i guess you'd have to just implement which oneself (or deal with the exceptions)

6:25 ridcully: expect it's there, but capture stderr etc and make sure you get a rock solid error message out. try it with a missing binary or even add a test for it. this way some ops person (or future you) can handle it on OS level

6:25 if its most likely not on PATH (windows?) then make it a mandatory config

6:26 there is nothing worse then getting a 3trillion line stacktrace with an NPE for some missing binary ;)

6:29 ilevd: What's best modern clojurescript framework/lib except zelkova, reframe. Is zelkova production ready?

6:47 henderson: What is the most efficient way to find the map where :id = 2 in the following structure: ({:id 1 :otherVal "someval"},{:id 2 :otherVal "someOtherVal"}) ?

6:47 the structure is a list of maps

6:48 hamid: , ({:id 1 :otherVal "someval"},{:id 2 :otherVal "someOtherVal"})

6:49 clojurebot: nil

6:49 hamid: henderson, you have to filter

6:50 , (filter #(= 2 (:id %)) '({:id 1 :otherVal "someval"},{:id 2 :otherVal "someOtherVal"}))

6:50 clojurebot: ({:id 2, :otherVal "someOtherVal"})

6:50 henderson: Oh, thanks man!

6:50 hamid: henderson, glad i could help! this channel is kinda sleep i guess!

6:52 henderson: haha, true

6:55 hamid: ilevd, what about Om.Next?

7:04 jonathanj: https://pb.codehash.net/c4f583de7927485cab94a8b2e3752afd

7:05 if anyone wants to code golf that :)

7:12 ridcully: path is unused?

7:59 mettekou: Say I have a data structure contained in an atom and I would first like to select an element of it and then update this element. I could do both operations inside a single swap!, which is correct with respect to race conditions and other nasty things, but does not allow for much concurrency. Is there a better solution?

8:00 In other words: I'm looking to split up selecting the element and updating it without sacrificing safe concurrency.

8:05 ridcully: update-in ?

8:07 luma: ,(let [a (atom {:foo 0, :bar 0})] (swap! a update :foo inc))

8:07 clojurebot: {:foo 1, :bar 0}

8:52 ilevd: hamid, I don't know, I'm considering return back to Elm

9:02 dysfun: mettekou: you always have to check when you update

9:02 swap! is basically compare-and-set in a loop until it succeeds

9:03 mettekou: dysfun: I rewrote the code using a compare-and-set! in a loop, which indeed changed nothing.

9:04 dysfun: well this is how you do it

9:04 turns out that optimistic CAS results in higher average throughput

9:07 of course if the computation takes an unreasonably long time, you may wish to consider another strategy

9:08 ilevd: You want get a value from when you swap?

9:09 dysfun: i read it as he is concerned about the concurrency properties of using swap

9:19 mettekou: dysfun: Yeah, I'm concerned about the fact that most of my computation is a look-up which does not modify anything but does take place inside swap!.

9:33 dysfun: you mean like an update-in?

9:34 i mean the simple way of writing it would be using update-in, were it not for your artificial separation?

9:35 pythys: Hey folks, (defn registration-page [& [id]] ,,,) what does the "[& [id]]" mean?

9:35 are we passing an optional vector inside a vector?

9:35 dysfun: & is rest args, [] is destructuring the rest args, id is the first item in the rest args

9:35 justin_smith: mettekou: refs are more general and allow access and update as separate steps if you are concerned about maximum concurrency

9:36 dysfun: so it's essentially just a single optional parameter

9:36 justin_smith: mettekou: also, they can coordinate update of multiple refs, which can significantly reduce the number of retries needed when changes are frequent

9:37 pythys: (fn [& [id]] ...) is the bad way to write (fn f ([] (f nil)) ([id] ...))

9:38 pythys: ok, I need a second to try and swallow this!

9:39 justin_smith: another way to say that, is that for a single optional arg, the right thing to do is multiple arities

9:39 pythys: justin_smith: what does multiple arities mean?

9:39 justin_smith: ,((fn f ([] (f 2)) ([x] (* x x x))))

9:39 clojurebot: 8

9:39 mettekou: Hmmm... Doesn't doall force the result of a for just like that of a map or other function that yields a lazy sequence?

9:40 justin_smith: pythys: that's a function that takes either 0 args or 1

9:40 mettekou: doall realizes a top level lazy sequence, yes

9:40 pythys: ok, i understood that part, but I don't get it syntactically

9:41 so [& [x]] means destructure the "rest" of the arguments passed and fetch the first one>

9:41 ?

9:41 justin_smith: pythys: (f ([arg] (1 arg body)) ([two args] (two arg body))) etc.

9:41 mettekou: ,(doall (for [id (range 10)] {:id id :from "BRU" :to (nth destinations (mod id 10)) :pricing [[(+ (rand-int 200) 200) (+ (rand-int 100) 200) 0] [(+ (rand-int 400) 200) (+ (rand-int 100) 150) 0] [(+ (rand-int 600) 200) (+ (rand-int 100) 100) 0]]})))

9:41 clojurebot: #error {\n :cause "Unable to resolve symbol: destinations in this context"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.RuntimeException: Unable to resolve symbol: destinations in this context, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyze "Compiler.java" 6688]}\n {:type java.lang.RuntimeException\n :message "Unable to resolve symbol:...

9:41 justin_smith: pythys: yes, and it accepts any number of args, only using the first (if present)

9:41 mettekou: ,(doall (for [id (range 10)] {:id id :from "BRU" :to (nth [1 2 3 4 5 6 7 8 9 10] (mod id 10)) :pricing [[(+ (rand-int 200) 200) (+ (rand-int 100) 200) 0] [(+ (rand-int 400) 200) (+ (rand-int 100) 150) 0] [(+ (rand-int 600) 200) (+ (rand-int 100) 100) 0]]})))

9:41 clojurebot: ({:id 0, :from "BRU", :to 1, :pricing [[296 298 0] [272 174 0] [714 180 0]]} {:id 1, :from "BRU", :to 2, :pricing [[339 222 0] [368 183 0] [318 198 0]]} {:id 2, :from "BRU", :to 3, :pricing [[227 230 0] [396 194 0] [258 173 0]]} {:id 3, :from "BRU", :to 4, :pricing [[295 264 0] [209 187 0] [287 147 0]]} {:id 4, :from "BRU", :to 5, :pricing [[310 219 0] [295 223 0] [593 163 0]]} ...)

9:42 pythys: justin_smith: but if I'm not mistaken, destructing happens with let

9:42 justin_smith: pythys: you are mistaken

9:42 pythys: destructuring is available in any binding context

9:42 pythys: destructuring sorry

9:42 justin_smith: what is a binding context?

9:42 justin_smith: pythys: you can destructure in function args, loop bindings, for bindings, doall bindings, etc. etc. etc.

9:43 pythys: a vector where you name an arg

9:43 mettekou: ,(vec (doall (for [id (range 10)] {:id id :from "BRU" :to (nth [1 2 3 4 5 6 7 8 9 10] (mod id 10)) :pricing [[(+ (rand-int 200) 200) (+ (rand-int 100) 200) 0] [(+ (rand-int 400) 200) (+ (rand-int 100) 150) 0] [(+ (rand-int 600) 200) (+ (rand-int 100) 100) 0]]}))))

9:43 clojurebot: [{:id 0, :from "BRU", :to 1, :pricing [[226 224 0] [359 220 0] [566 149 0]]} {:id 1, :from "BRU", :to 2, :pricing [[372 253 0] [296 224 0] [704 108 0]]} {:id 2, :from "BRU", :to 3, :pricing [[390 275 0] [285 179 0] [722 123 0]]} {:id 3, :from "BRU", :to 4, :pricing [[225 215 0] [450 216 0] [432 136 0]]} {:id 4, :from "BRU", :to 5, :pricing [[207 255 0] [565 174 0] [274 186 0]]} ...]

9:43 justin_smith: pythys: or a value, more generally

9:43 mettekou: ,(vec (for [id (range 10)] {:id id :from "BRU" :to (nth [1 2 3 4 5 6 7 8 9 10] (mod id 10)) :pricing [[(+ (rand-int 200) 200) (+ (rand-int 100) 200) 0] [(+ (rand-int 400) 200) (+ (rand-int 100) 150) 0] [(+ (rand-int 600) 200) (+ (rand-int 100) 100) 0]]})))

9:43 clojurebot: [{:id 0, :from "BRU", :to 1, :pricing [[261 285 0] [220 154 0] [339 104 0]]} {:id 1, :from "BRU", :to 2, :pricing [[356 229 0] [412 178 0] [482 129 0]]} {:id 2, :from "BRU", :to 3, :pricing [[280 250 0] [348 191 0] [370 157 0]]} {:id 3, :from "BRU", :to 4, :pricing [[336 227 0] [505 189 0] [417 110 0]]} {:id 4, :from "BRU", :to 5, :pricing [[223 203 0] [596 156 0] [277 154 0]]} ...]

9:43 justin_smith: mettekou: (vec (doall ...)) is never useful

9:43 mettekou: Yeah, I just found out. :P

9:44 pythys: justin_smith: sorry, not sure I understand. What do you mean by a vector where you name an arg or a value?

9:44 justin_smith: pythys: function args, let blocks, loop bindings, macro args

9:44 pythys: for bindings, doseq bindings

9:44 etc.

9:44 pythys: in all of them you have a vector, and assign names to values

9:44 pythys: justin_smith: so any place where you have []? or any place where you "assign" values?

9:45 justin_smith: pythys: where you assign symbols to values

9:45 pythys: ok

9:45 justin_smith: inside a vector, specifically

9:45 pythys: I think this is probably the most challenging part in clojure, destructuring. It's where I get majorly challenged

9:46 Too many variations on destructing with multiple different syntaxes

9:46 justin_smith: pythys: there's about 3

9:46 pythys: and they can be used in a bunch of contexts that are all very similar to each other

9:47 {foo :foo}, {:keys [foo]} [foo] [foo & bar], and then you can do nesting but not inside :keys

9:47 pythys: which three? I have let, defn, loop, recur, def, fn, plus the above example [& [x]]

9:47 seems to be too many

9:48 justin_smith: pythys: those are contexts

9:48 not syntaxes

9:48 pythys: oh oh

9:48 ok, then what are the three syntaxes you referred to?

9:48 justin_smith: pythys: they all use the same destructure syntax

9:48 pythys: two ways to do a hash-map, and one way to do a sequence

9:48 with optional :as and :or keys

9:50 pythys: justin_smith: aren't maps also sequences?

9:51 jonathanj: ridcully: ah, indeed, a remnant from a previous iteration

9:53 pythys: justin_smith: my bad, i got things confused

10:42 justin_smith: am I in the right place reading here for our discussion -> http://clojure-doc.org/articles/language/functions.html#extra-arguments-aka-named-parameters

10:49 zephalos: Hi, what is the best way to replace the thirdelement of a list by the third element of another list? E.g. [[1 2 100],[1 2 100],[1 2 100]] and [[4 5 200],[4 6 100],[4 7 200]] would then give [[4 5 100],[4 6 100],[4 7 100]]

10:56 ridcully: ,(map (fn [[_ _ c] [a b _]] [a b c]) [[1 2 100],[1 2 100],[1 2 100]] [[4 5 200],[4 6 100],[4 7 200]])

10:56 clojurebot: ([4 5 100] [4 6 100] [4 7 100])

10:56 zephalos: thanks man!

10:57 ridcully: to a certain definition of "best"

11:25 sdegutis: What's going on?

11:39 What's happening!?

11:45 justin_smith: zephalos: if you have a vector and not a list, (like in your example) you can use get and assoc (map (fn [a b] (assoc a 2 (get b 2))))

11:46 ,(map (fn [a b] (assoc a 2 (get b 2))) [[1 2 100],[1 2 100],[1 2 100]] [[4 5 200],[4 6 100],[4 7 200]])

11:46 clojurebot: ([1 2 200] [1 2 100] [1 2 200])

11:46 justin_smith: oh, that was backward

11:47 ,(map (fn [b a] (assoc a 2 (get b 2))) [[1 2 100],[1 2 100],[1 2 100]] [[4 5 200],[4 6 100],[4 7 200]])

11:47 clojurebot: ([4 5 100] [4 6 100] [4 7 100])

11:52 sdegutis: Pop quiz time!

11:52 It's someone else's turn to come up with it this time.

12:00 hfaafb: This US state is closest to Africa (if one were to fly a plane between the two)

12:01 luma: maine?

12:03 hfaafb: that's correct

12:28 mloveless: not florida?

12:29 sdegutis: I mean a Clojure pip quiz.

12:31 Oh here I got one.

12:31 (f [:a [:b [:c {:foo 1 :bar 2}] {:quux 3}]])

12:31 => [[[:a :b :c] {:foo 1 :bar 2}] [[:a :b] {:quux 3}]]

12:31 What's f?

12:33 Bonus points for using Transducers.

12:46 ambrosebs: How do I eliminate reflection here? https://www.irccloud.com/pastebin/0IaxP9K6/

12:57 sdegutis: ^Long maybe?

13:00 ambrosebs: sdegutis: ;!!CompilerException java.lang.UnsupportedOperationException: Can't type hint a local with a primitive initializer, compiling:(clojure/math/combinatorics.clj:311:3)

13:00 dysfun: ambrosebs:

13:00 sdegutis: Right.

13:00 dysfun: you need to use a let

13:00 and type hint *that*

13:00 ran across this the other day

13:00 ambrosebs: dysfun: let bind 1?

13:01 dysfun: well, 'acc'

13:01 ambrosebs: dysfun: I've tried lots of similar things I've had no luck

13:01 other than doing something like (first [1]) to trick the compiler

13:02 dysfun: can you share an example please?

13:02 dysfun: so my first instinct is that zero? is probably causing boxing

13:02 sdegutis: Right.

13:02 dysfun: (loop [acc l n n] (let [^long acc' acc ^long n] ...))

13:03 that was enough to make my boxing problem go away

13:04 ambrosebs: dysfun: replacing zero? with (== 0 n) seemed to work :)

13:04 dysfun: yay!

13:04 ambrosebs: is there a difference between the two?

13:04 I'm rusty on = vs ==

13:04 dysfun: == is int math, = is generic compare

13:04 (usually .equals())

13:04 justin_smith: ,(== 5.0 5 5M)

13:05 clojurebot: true

13:05 ambrosebs: dysfun: and I assume that never makes a difference for zero?

13:05 justin_smith: ,(= 5.0 5)

13:05 clojurebot: false

13:05 justin_smith: ,(= 0.0 0)

13:05 clojurebot: false

13:05 justin_smith: ,(== 0.0 0)

13:05 clojurebot: true

13:06 dysfun: ambrosebs: no, it won't. but on the other hand = is much more complicated

13:06 ambrosebs: dysfun: makes sense thanks!

13:06 dysfun: yw

13:07 justin_smith: dysfun: == is not int math, it's generic across exact vs. inexact (while = is generic otherwise, but does not cross exact/inexact boundaries)

13:07 dysfun: i stand corrected

13:08 ambrosebs: wait no, I'm still stuck :)

13:08 false alarm

13:08 justin_smith: ambrosebs: == if for when you want exact and inexact numbers to be potentially equal

13:09 ambrosebs: justin_smith: is there a preference for integer maths?

13:09 justin_smith: ambrosebs: I don't understand that question - if you know all the inputs are integral, you don't need == and = will suffice?

13:10 ambrosebs: Sorry. I just don't want to make this code any slower unnecessarily

13:10 but yes, thats my question

13:11 but for factorial it really doesn't matter

13:11 thinking about it :)

13:13 Apparently this solved my reflection errors. https://www.irccloud.com/pastebin/JUePI4NG/

13:14 moving the loop into a function

13:14 does that mean the reflection is gone? :/

13:21 felipedvorak: I'm installing Clojure and it asks if I want jdk7 or 8?

13:22 dysfun: jdk7 is EOL

13:23 felipedvorak: jdk8 then. Thanks dysfun.

13:23 TimMc: jdk1.2 4 lyfe

13:25 mettekou: I wish every? would work like map, allowing n-ary predicates on the elements of n collections.

13:26 (every? true? (map predicate-2 ones twos)) is too clunky.

13:29 sdegutis: Be there a convenient function for adding to a list or if the thing isn't a list then making it into a list to add to?

13:29 So that (f 1 2) and (f 1 [2]) both return [1 2] ?

13:32 Ah, yes. Found it.

13:40 ,(let [f #(->> (vector %2) (cons %1) (flatten))] (= (f 1 2) (f 1 [2]) [1 2]))

13:40 clojurebot: true

13:40 sdegutis: :D

13:40 I have 2 uses of clojure.core/flatten in production.

13:41 ambrosebs: quite a feat

13:41 luma: that's probably two uses too many...

13:46 sdegutis: The one above is one of them.

13:47 luma: that one's broken if you feed it a vector as the first parameter

13:48 (f [1] 2) isn't [[1] 2] but [1 2]

13:54 sdegutis: luma: right, only strings are ever needed

13:54 luma: it's a convenience thing for building a list of strings; it can accept a string or a coll of strings

15:19 bsamorim: guys, I have a few questions regarding the usage of java classes in clojure, regarding the mutability

15:19 could any1 help me out a bit?

15:19 it's pretty vanilla stuff, I s'ppose

15:20 suppose I have a nested clojure structure, with one of its elements being a java object

15:20 how does clojure handle that?

15:21 is this structure partially mutable? totally? or not at all?

15:25 justin_smith: bsamorim: the structure is not mutable, the object inside the structure is

15:26 bsamorim: this can be a real gotcha if you used the object as a key in a hash-map - because you could have changed its hash-code, which as you might expect, makes hash-maps much less useful and sane

15:26 bsamorim: justin_smith: why would the hash-code change?

15:26 justin_smith: bsamorim: see also clojure's concurrency safe containers, which are the opposite - a mutable box meant to hold something immutable

15:27 bsamorim: because objects that are mutable can use their state to determine their hash-code - I mean they don't always do that, but they could

15:27 sdegutis: Right.

15:28 bsamorim: justin_smith: oh, sure, but a different binding wouldn't change it, right?

15:28 I mean, that's all clojure does with a mutable object, right?

15:28 justin_smith: bsamorim: absolutely not

15:28 if you mutate a java object, it is mutated

15:29 clojure does not hide or prevent this in any way

15:29 bsamorim: justin_smith: yeah, I know....sry, I was explaining my doubt as shit

15:29 justin_smith: I'll rephrase it

15:30 justin_smith: ,(let [d (java.util.Date.) h (.hashCode d) _ (.setTime d 0) h' (.hashCode d)] [h h'])

15:30 clojurebot: [2014932744 0]

15:30 justin_smith: bsamorim: if you use a java.util.Date as a key in a hash map, then mutated it, you would break lookup in the map

15:30 because it's hash would no longer be relevant to its bin

15:30 bsamorim: suppose I have a class Foo, with one public attribute x

15:31 if I do the following commands:

15:31 (def a (new Foo))

15:31 (. x a 1)

15:31 justin_smith: maybe you want (set (.x a) 1) ?

15:32 err, set!

15:32 sdegutis: I often do (. date before end-date)

15:33 justin_smith: bsamorim: but what's your question?

15:39 ,(defprotocol IFoo (getX [this]) (setX [this x]))

15:39 clojurebot: IFoo

15:40 justin_smith: ,(deftype Foo [^:volatile-mutable x] IFoo (getX [this] x) (setX [this v] (set! x v)))

15:40 clojurebot: sandbox.Foo

15:40 justin_smith: ,(def f (Foo. 1))

15:40 clojurebot: #error {\n :cause "Unable to resolve classname: Foo"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.IllegalArgumentException: Unable to resolve classname: Foo, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyzeSeq "Compiler.java" 6875]}\n {:type java.lang.IllegalArgumentException\n :message "Unable to resolve classname: Foo"\n :at [clojure...

15:40 justin_smith: ,(deftype Foo [^:volatile-mutable x] IFoo (getX [this] x) (setX [this v] (set! x v)))

15:40 clojurebot: #error {\n :cause "Unable to resolve symbol: IFoo in this context"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.RuntimeException: Unable to resolve symbol: IFoo in this context, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyzeSeq "Compiler.java" 6875]}\n {:type java.lang.RuntimeException\n :message "Unable to resolve symbol: IFoo in this...

15:40 justin_smith: ,(defprotocol IFoo (getX [this]) (setX [this x]))

15:40 clojurebot: IFoo

15:40 justin_smith: ,(deftype Foo [^:volatile-mutable x] IFoo (getX [this] x) (setX [this v] (set! x v)))

15:40 clojurebot: sandbox.Foo

15:40 justin_smith: ,(def f (Foo. 1))

15:40 clojurebot: #'sandbox/f

15:40 justin_smith: ,(.getX f)

15:40 clojurebot: 1

15:41 justin_smith: ,(.setX f "whatever")

15:41 clojurebot: "whatever"

15:41 justin_smith: ,(.getX f)

15:41 clojurebot: "whatever"

15:41 justin_smith: bsamorim: anyway, if you still have a quesiton, the above might help us

15:41 stisti: what's the easiest way to get a working lein? I have Oracle JDK 1.8 on Mac + brew install clojure lein but I can't get it to work

15:41 lein new app x; cd x; lein install

15:41 justin_smith: stisti: don't use a package manager to install lein, just download the file from leiningen.org

15:41 stisti: Warning: The Main-Class specified does not exist within the jar. It may not be executable as expected. A gen-class directive may be missing in the namespace which contains the main method.

15:42 justin_smith: stisti: that just means your project doesn't have a valid main, that's not a lein problem

15:42 stisti: easiest thing is to take out the part of project.clj that claims you have a main that isn't actually there

15:44 stisti: shouldn't I have a main if I'm making an app?

15:44 justin_smith: stisti: then make sure your main actually exists

15:44 also why lein install an app? I would uberjar an app, and lein install for libs

15:44 lein install isn't

15:44 err

15:45 it isn't "install globally so you can run" it's "add to your local library dependency cache"

15:45 stisti: ok, I'm new to clojure and lein, trying to learn them. Could you just point me to some tutorial that allows me to get Hello World off the ground? Thanks

15:48 justin_smith: lein new foo; cd foo; lein run

15:48 after that you start by finding foo.core/-main, and editing it

15:48 stisti: have you seen this? https://github.com/technomancy/leiningen/blob/master/doc/TUTORIAL.md

15:51 stisti: been checking that out but I thought "lein new app foo" would create a something that would run. It seems to but I'm newbie enough to now see what it is missing

15:52 lein new foo; cd foo; lein run says there is no main

15:52 ridcully: it does. lein run, runs it

15:52 stisti: for me it says

15:52 No :main namespace specified in project.clj.

15:52 justin_smith: stisti: I think you need "lein new app foo" maybe?

15:52 one moment, double checking

15:52 ridcully: also a lein uberjar gives you something runable

15:53 justin_smith: stisti: that was my bad 'lein new app foo; cd foo; lein run' will work

15:54 then you can paly with foo.core, modify -main, add more namespaces, etc.

15:54 but it's a working starting point

15:54 stisti: yes, and when I do: lein new app foo2; cd foo2; lein run

15:54 Can't find 'foo2.core' as .class or .clj for lein run: please check the spelling.

15:55 ridcully: stisti: just for the record, whats your lein -version?

15:56 stisti: > lein -version Leiningen 2.6.1 on Java 1.8.0_74 Java HotSpot(TM) 64-Bit Server VM

15:56 justin_smith: stisti: lein new app foo2; cd foo2; lein run works locally

15:56 ridcully: dito (2.6.1, jdk 1.8.92)

15:57 justin_smith: stisti: did you try making foo2 from within foo? that might do something funky

15:57 stisti: since lein would try to load your project if present I bet...

15:58 stisti: I deleted all foo*

15:58 justin_smith: OK

15:58 stisti: lein new app abc; cd abc; lein run

15:58 Can't find 'abc.core' as .class or .clj for lein run: please check the spelling.

15:58 justin_smith: then something is severely wrong, my first course of action would be deleting lein from homebrew and just installing the shell script

15:59 package-managing lein tends not to work so nicely in my experience

15:59 stisti: ok, thanks

16:01 sdegutis: I found this funny.

16:02 https://github.com/xsc/lein-ancient

16:02 "A Leiningen plugin to check your project for outdated dependencies and plugins."

16:02 "dependencies: out of date"

16:03 justin_smith: sdegutis: clearly we need to make a lein-ancient-ancient plugin, to see if the deps of lein-ancient are up to date

16:03 sdegutis: :D

16:03 ridcully: but then would need to create lein-ancient-ancient-ancient'

16:04 justin_smith: ridcully: we could use a new naming scheme, lein-ancient, lein-ancient', lein-ancient'' etc.

16:04 sdegutis: Not if we just keep lein-ancient-ancient's dependencies up todate.

16:04 justin_smith: sdegutis: if we were capable of "just keeping dependencies up to date" we wouldn't need lein-ancient, now would we?

16:05 ridcully: that is impossible. why else is there a tool for it?

16:05 that said, lein-ancient is a mighty fine tool

16:05 justin_smith: yes, it is

16:07 ystael: justin_smith: i'd prefer lein-heroic, lein-prehistoric, lein-hominin

16:15 sdegutis: lein-outdated

16:15 lein-outmoded

16:15 lein-can-upgrade

16:17 xemdetia: lein-can-lean

16:18 hxegon: lein-with-it-then-wreq-with-it

18:33 mettekou: ((resolve (symbol "Math/random")))

18:33 ,((resolve (symbol "Math/random")))

18:33 clojurebot: #error {\n :cause nil\n :via\n [{:type java.lang.NullPointerException\n :message nil\n :at [sandbox$eval25 invokeStatic "NO_SOURCE_FILE" 0]}]\n :trace\n [[sandbox$eval25 invokeStatic "NO_SOURCE_FILE" 0]\n [sandbox$eval25 invoke "NO_SOURCE_FILE" -1]\n [clojure.lang.Compiler eval "Compiler.java" 6927]\n [clojure.lang.Compiler eval "Compiler.java" 6890]\n [clojure.core$eval invokeStatic "core...

18:33 mettekou: ,((resolve (symbol "Math" "random")))

18:33 clojurebot: #error {\n :cause nil\n :via\n [{:type java.lang.NullPointerException\n :message nil\n :at [sandbox$eval49 invokeStatic "NO_SOURCE_FILE" 0]}]\n :trace\n [[sandbox$eval49 invokeStatic "NO_SOURCE_FILE" 0]\n [sandbox$eval49 invoke "NO_SOURCE_FILE" -1]\n [clojure.lang.Compiler eval "Compiler.java" 6927]\n [clojure.lang.Compiler eval "Compiler.java" 6890]\n [clojure.core$eval invokeStatic "core...

18:35 mettekou: ,(symbol "Math" "random")

18:35 clojurebot: Math/random

18:37 justin_smith: mettekou: resolve is for namespaces containing vars, not for classes and static methods

18:38 mettekou: justin_smith: Thanks. That's what I needed it for anyway, but no way of quickly doing that here came to mind.

19:11 WorldsEndless: What's the long form of the #"" regexp macro? My function needs to compose a regexp pattern from a pair of strings

19:12 justin_smith: WorldsEndless: (re-compile s)

19:12 WorldsEndless: Thanks

19:12 justin_smith: you probably need to call str on the strings to get one string for re-compile

19:12 WorldsEndless: Google was not helping me much

19:13 justin_smith: WorldsEndless: conj.io / cheatsheet has this under the regex section last I checked

19:13 WorldsEndless: What namespace is re-compile?

19:14 justin_smith: sorry!

19:14 it's re-pattern

19:14 WorldsEndless: ah

19:14 justin_smith: ,(re-pattern ".*")

19:14 clojurebot: #".*"

19:14 justin_smith: the source of that function reveals the source of my confusion (. java.util.regex.Pattern (compile s))

19:16 TEttinger: ,(java.util.regex.Pattern/compile ".*")

19:16 clojurebot: #".*"

19:16 TEttinger: I like re-pattern better :)

19:16 WorldsEndless: :)

19:17 jonathanj: ,(macroexpand-1 '#".")

19:17 clojurebot: #"."

19:17 jonathanj: can you expand reader macros?

19:17 justin_smith: ,'#(depends)

19:17 clojurebot: (fn* [] (depends))

19:17 TEttinger: that may be how it prints

19:21 justin_smith: is there something in plumatic/schema that turns off checks globally?

19:48 TimMc: I think regex literals are maybe special because they are cached statically in whatever class they end up as part of?

19:49 Unlike #( they don't just expand to more Clojure.

19:51 Hmm, can't back up that claim from reading code.

20:50 Trioxin: idk whether to keep learning clojure or just give in and use something like scala. I want to leverage the JVM and functional programming but clojure is so difficult to get used to coming from the likes of C#, javascript, and PHP

20:54 TEttinger: Scala's uh not that easy, having used both that and Clojure. Clojure's definitely different though

20:55 Scala seems like it should be simple to transition to from Java or C#, but there's a sort of internal conflict in the language between "should this be functional" or "should this be traditionally OOP"

20:56 Trioxin: hm

20:56 TEttinger: most developers in it seem to go the functional route even when OOP could be considered a better choice (for their application in Scala)

20:57 and the inheritance-swamped standard library is not terribly easy to navigate

20:58 Trioxin: meh

20:58 TEttinger: see the inheritance diagram for the List type. http://nurkiewicz.github.io/talks/2014/scalar/img/list-scala.png

20:58 Trioxin: why can't there just be a suffiently abstract cross development language that has horsepower and concurrency without having to jump into some awkward paradigm

20:58 TEttinger: concurrency seems to be the problem there

20:59 an unsolved problem. although depending on what you're doing, maybe consider IBM's X10 language, the winner of the DOD's challenge to make a better big-data-handling language

21:00 it's basically Java with good solutions for datacenter woes, like the locality of a computation (what machine is doing it and where) and of course the standard java++ things, like first-class functions and a lib that understands them

21:01 Trioxin: hm

21:01 TEttinger: it compiles to Java or C++ IIRC

21:01 which is nice, since it can be made to use either group of libs for the two platforms

21:01 it is bad for distributable applications.

21:01 it is not meant for that, it's meant for deployment on servers

21:01 Trioxin: meh

21:02 lol

21:02 TEttinger: its competitor in the last round was Chapel, by Cray and now open source

21:04 https://github.com/chapel-lang/chapel

21:04 Trioxin: i only need a new language for computationally expensive components. The rest I do in node and electron.

21:05 TEttinger: IMO chapel is a vastly better language design than X10, but because it doesn't have interop with any VMs, it's kinda limited compared to X10

21:05 Trioxin: so the jvm makes sense. i can package it in an installer if need be

21:05 TEttinger: hm

21:06 so if you're aiming for commodity-desktop-scale concurrency, I don't really know anyone targeting that currently, other than clojure to an extent

21:07 clojure can do well there, but with "only 4" or "only 8" threads, the speedup is not especially major compared to GPGPU stuff

21:08 Trioxin: I'll be forced to c++. i know it and then i'll have to code for each platform

21:13 maybe node can do it. there is forking and the cluster api. of course I have to consider mobile as well. maybe one day I'll create my own language.

21:21 tolstoy: Clojure seems so much more tractable, and much simpler than Scala (or similar). If you can see it as foo(a, b) rather than (foo a b) you'd think there's nothing to it.

21:21 But there's Frege for Haskell-likeness, or Groovy for dynamic-like, and Kotlin, for a simpler Java (I think).

21:22 TEttinger: yeah, I see more and more Kotlin projects

21:22 seen some interesting Frege stuff, I think it compiles to Java source

21:23 tolstoy: Kotlin has the Swiftian ?. suffix for nullable types? Huh.

21:24 TEttinger: Frege's compiled to byte code. Says so right on Wikipedia! :)

21:27 justin_smith: TEttinger: sadly, frege can neither implement nor define interfaces

21:27 (that was the deal breaker for me)

21:28 TEttinger: The compiler reads Frege source files and produces Java source files that are normally subsequently compiled to class files.

21:28 https://github.com/Frege/frege/wiki/Compiler-Manpage

21:28 Trioxin: I'm a big fan of jetbrains. I'd seen kotlin but question how much of following and contribution it will have.

21:28 tolstoy: Oh.

21:28 TEttinger: mwahaha

21:29 Trioxin: in the java circles I've been in people are switching fairly often

21:29 it helps that IntelliJ can convert java to kotlin

21:30 Trioxin: one thing missing I see.. ios

21:30 TEttinger: now that RoboVM is out for the count, that's a tricky one

21:30 Multi-OS Engine from Intel is the current thing in the works

21:31 Trioxin: hmm. kotlin might be the answer

21:31 if interop is super good

21:32 tolstoy: This seemed kinda interesting: some sort of Compile Clojure to ObjC or something: https://github.com/galdolber/clojure-objc

21:32 TEttinger: https://software.intel.com/en-us/multi-os-engine

21:33 Trioxin: yeah was just reading there

21:33 TEttinger: yeah from what I can tell kotlin can be translated to and from java automatically

21:33 not sure how well it does

21:33 they seem close for interop

21:33 I've considered changing some stuff towards it

21:39 oh, and jtransc I looked into, it seems very capable of an "interesting" build cycle.

21:40 it compiles jvm .class files to haxe source, where it can be compiled to many platforms including native stuff for phones (iOS and Android)

21:41 but it can also, if your haxe libraries of choice are roughly compatible with your java libs, run without the lengthy C++ compilation step and go directly run from the .class files

21:42 so in theory you only need to compile from (in clojure, it would probably be an uberjar) when you deploy or test on a device

Logging service provided by n01se.net