#clojure log - Aug 30 2015

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

0:19 frefe: Can you use compojure contexts like this (defroutes approutes (context "/a" [] (context "/c" [] ...) (context "/c" [] ...) )

1:04 ben_vulpes: what's the hot jam for working on the clojurescript/browser part of a webapp while also working on the clojure/jvm part of the application simultaneously in emacs?

1:05 justin_smith: ben_vulpes: I guess cider has a thing, but I got fed up and I use terminal windows for repls like a cave man

1:16 ben_vulpes: what about compiling code into the running clojure/script 'images'?

1:16 (load-file 'wherever)?

1:16 justin_smith: that's what the :reload arg to require is for

1:17 see also :reload-all

1:17 ben_vulpes: how does that handle code saved in a useless state?

1:17 i write buffers when they lose focus, not when my code compiles.

1:17 justin_smith: it'll throw an error if the file needs fixing, you can require and :reload again later

1:17 ben_vulpes: I have a key combo that lists all unsaved buffers

1:18 so that I can usually keep files valid, without losing track either

1:18 ben_vulpes: i refuse to waste mental cycles tracking which files have not been written to disk.

1:18 justin_smith: ben_vulpes: I refuse to waste mental cycles figuring out how the hell cider is supposed to work - and like I said, it's a key combo, I hit the key, it tells me what is unsaved

1:19 ben_vulpes: that there is even a distinction between text in a buffer i'm working on and text on disk offends my sensibilities (dramatic exaggeration)

1:19 no i know i'm just being dramatic

1:19 justin_smith: and the worst case is clojure says "I could not compile that" and you fix the file and hit up arrow and require again - it's very straightforward

1:22 ben_vulpes: justin_smith: d'you use or eschew figwheel?

1:22 justin_smith: I use figwheel

1:23 inside a terminal with rlwrap

1:23 the same (require 'some.ns :reload) works there

1:23 it also auto-loads though

1:23 but I find sometimes it gets confused

1:28 ben_vulpes: justin_smith: do you use cider in any way?

1:28 justin_smith: no, I gave up on it, it was wasting too much of my time

1:29 ben_vulpes: raw lisp-mode buffers with paredit and actual terminals for clojure/script?

1:30 or do you SLIME at all?

1:30 justin_smith: clojure-mode with paredit, no slime, actual terminal

1:30 ben_vulpes: (i went on a common lisp sojurn recently and now want to make some changes to my clojure emacs setup is why i ask)

1:31 justin_smith: if you consider clojure-mode part of cider I guess you can say I use the parts of cider that don't do any magic and don't connect to clojure

1:31 yeah, the slime integration with emacs is pretty neat

1:33 ben_vulpes: 2000s-era ripoff of SMBX terminals

1:33 written in the post-dotcom doldrums

1:33 * ben_vulpes kids

1:34 Bronsa: justin_smith: setting up clojure with slime is still quite easy FWIW

1:34 justin_smith: Bronsa: that's good to know, maybe some day

1:34 ben_vulpes: STAND BACK I'M UNINSTALLING CIDER

1:34 Bronsa: I actually tried the new cider a few hours ago

1:35 seems like it become quite usable

1:35 justin_smith: how was it?

1:35 interesting

1:35 Bronsa: I might consider doing the upgrade

1:36 I then got sidetracked trying to switch auto-complete for company

1:36 and trying to use the emacs package managers rather than git submodules

1:36 broke everything and reverted to slime+auto-complete+git submodules

1:36 but maybe one day.

1:38 ben_vulpes: justin_smith: what are you using for running the browser repl?

1:38 justin_smith: figwheel

1:38 in a terminal, with rlwrap

1:38 ben_vulpes: right sorry sorry

1:40 justin_smith: ben_vulpes: this all became especially acute when I moved to a distributed onyx / kafka system for our computation intensive tasks - suddenly I have two clojure repls, and one clojurescript one, and it was so much easier to keep them sorted out, and isolated, in regular terminal windows as compared to juggling connections in emacs

1:44 ben_vulpes: how does kafka affect your dev loop?

1:44 justin_smith: it's another piece that can brak

1:44 *break

1:45 ben_vulpes: so cljvm crashes? myriad functions never return for want of a kafka connection?

1:45 justin_smith: also, unlike eg. http where you have request response, you have N messages from A to B followed by N from B to A

1:45 ben_vulpes: "Of course, you can concurrently take advantage of all of nREPL's other facilities, including connecting to the same nREPL server with other clients (so as to easily modify Clojure and ClojureScript code via the same JVM), and interrupting hung ClojureScript invocations: "

1:45 ^^ WANT

1:46 justin_smith: ben_vulpes: it doesn't crash things, but misbehaving (related eg. to sleeping the computer - kafka hates suspend) can cause delays and inactivity followed by piling on masses of activity all at once.

1:47 ben_vulpes: it ends up being one more factor that might be causing the odd behavior of an app

1:47 along side bad code, or network hiccups, whatever

1:47 ben_vulpes: I found when clojure was inside emacs that added a few other things that could go wrong

1:48 (eg. locking up the editor if I print certain kinds of values)

1:50 and locking up a clojure thread if it is trying to print faster than emacs is using its output... (also seen this problem with tmux - people running an app inside tmux, going into scroll-back mode, forgetting to leave it, the app stops doing anything when the tmux buffer fills)

2:07 ben_vulpes: https://github.com/cemerick/piggieback/blob/master/src/cemerick/piggieback.clj#L282

2:45 Bronsa: I finally managed to implement prefer-proto

2:52 oymyakon: hi! newbie question: what does it mean when the first element of a sequence is a keyword. For example: (:something 1)

2:53 Bronsa: oymyakon: what it always mean in clojure: a function invocation

2:53 oymyakon: keywords are also functions in clojure

2:53 oymyakon: Bronsa: thanks yes, so the keyword evaluates to itself right.

2:53 but the whole expresion returns nil

2:54 Bronsa: they look themselves up in the arg which should be an associative collection

2:54 oymyakon: I don't understand what the semantics of that is

2:54 Bronsa: ,(:foo {:foo 1})

2:54 clojurebot: 1

2:54 amalloy: the keyword evaluates to itself, and then when called as a function it looks itself up in its argument, expected to be a map

2:54 luxbock: ,(:foo #{:foo})

2:54 clojurebot: :foo

2:55 Bronsa: http://dev.clojure.org/jira/browse/CLJ-1807

2:55 luxbock: sets work as well I guess

2:55 Bronsa: yup

2:55 amalloy: anything that implements ILookup

2:57 oymyakon: amalloy: ok, so it means that when we have a keyword as the first element in a sequence the second element should be a map or an assoc data structure

2:57 yes?

2:57 amalloy: if you are evaluating that sequence, then yes

2:58 oymyakon: ok, I get it. Thank you

6:24 domokato: I have two lists of numbers. I want to create a seq that contains the averages of the elements at each index in the lists. Is there an O(1) space solution that doesn't require loop/recur?

6:31 tcrayford____: domokato: so like (my-fn [5 4 6] [5 6 4]) -> [5 5 5] ?

6:32 domokato: (map (fn [x y] (/ (+ x y) 2)) [5 4 6] [5 5 5])

6:34 domokato: ah, map can take multiple colls!

6:34 thanks

6:35 tcrayford____: welcome :)

6:48 jeaye: domokato: That's linear time, mind you. You need to traverse the full sequence once.

7:54 expez: why isn't splicing allowed at toplevel?

8:09 puredanger: Because reading a single form would then produce multiple forms and there is no easy way to push read forms back onto the stream

8:10 expez: aha

8:10 puredanger: any plans for clojure in terms of project jigsaw?

8:11 jar hell is by far my biggest gripe with the platform atm

8:25 zeroware_: Hello ! I have a quick question on core.async. Is this the right place ?

8:29 expez: zeroware_: fire

8:32 zeroware_: I'm looking at the pipeline async function. The docs says that only n operations will be executed. But looking at the code, I can see that the async fn will be called without waiting from the previous one when parallelism is set to 1.

8:34 For example : if I have a channel with filenames, and my async function is reading files. If I fire the pipeline async , all file will be read at the same time even if n is set to 1.

8:37 expez: zeroware_: n controls the parallelism in play, everything on the from channel will be consumed

8:39 zeroware_: expez: Okay , what should i do if i want to read the files with only one file opened at a time ?

8:40 expez: zeroware_: if n=1 then the files should be read sequentially

8:44 zeroware_: expez: Looking at the source code, the job channel will be read without waiting for the async function to complete.

8:46 expez: zeroware_: You're calling pipline-async so some async behavior is to be expected :) Still, the async processing is only happening on a single thread.

8:50 zeroware_: expez: i'm really new to clojure, maybe i'm reading the code wrong. Do you know where I can find some example of this pipeline-async function ?

8:55 expez: zeroware_: think of it this way: The from channel is read from and the data is put on a conveyor belt. When that is done the pipeline-async returns control to the caller. In some background threads, controlled by the value n, data is taken from the conveyor belt, given to the work function af, and then the result is put on the to channel.

9:00 zeroware_: expez: okay , but when the af function is called, the next value is taken without waiting for the af returned channel to finish

9:01 expez: if I open files into my af function , I will have all files opened sequentially but not in a serial fashion

9:01 expez: zeroware_: That makes sense, though, right? The af function is off in its own thread working as hard as it can to transform the data on the from channel and put it into the to channel.

9:02 zeroware_: expez: my use case is that in my af function i'm calling an API and I don't want to have 25 requests made at the same time… Maybe pipelin-async is not the function I need.

9:04 I could make the af function blocking but the docs says that the function has to return immediately

9:05 expez: zeroware_: do you want to make your requests in a blocking manner, sequentially?

9:07 zeroware_: expez: Yes, I thought that the n parameter would do this but apparently it's not designed that way.

9:08 expez: zeroware_: Just do your requests in a doseq loop over your URLs if you want sequential and blocking.

9:11 zeroware_: expez: I will do like this yes. Thanks for your answers !

9:55 ska-fan: How does https://gist.github.com/mbertheau/3fef571a1a5391387a75 look in clojure? Parens of the dead impressed me with clojures terse syntax for manipulating lists and maps. My day job is still Python and I'm trying to use a more functional, stateless, pure style. I wonder what the python in the link looks like in clojure?

10:14 broquaint: ska-fan: I added a thing.

10:26 spacepluk: can I use figwheel with clojure jvm?

10:31 broquaint: spacepluk: I don't believe so, what's your use case?

10:31 spacepluk: nothing specific, I just like the workflow

11:14 ska-fan: broquaint: Thanks. So a list comprehension with let. Awkward to do with python.

11:36 broquaint: function unfavourite(tweet) { let $tweet = (sel) => jQuery(sel, tweet);

11:36 $tweet('.js-actionFavorite:visible').click();

11:36 console.log(

11:36 "Unfavourited:\n",

11:36 $tweet('.tweet-text').text(),

11:36 "\nby ", $tweet('.username').text(), '[ ', $tweet('.js-permalink').text(), ' ]'

11:36 );

11:36 }

11:36 let tweets = document.querySelectorAll('#stream-items-id > li');

11:36 let step = 0;

11:36 for(let tweet of Array.from(tweets).reverse()) {

11:36 justin_smith: broquaint: don't do that

11:36 broquaint: setTimeout(function() {

11:36 unfavourite(tweet);

11:36 }, step++ * 500 );

11:36 }

11:36 justin_smith: A misclick in putty, apologies, could've sworn irssi would prompt me :/

11:37 justin_smith: broquaint: worst is erc in emacs, which has a special feature where it slows multi line pastes down to ensure all the lines go through and you don't get kicked

11:37 understood, just making sure you knew it's something we don't intentionally do here

11:38 broquaint: Yup, understood :)

11:39 Hrm, my paste_verify_line_count is at 5, wonder what happened there (mosh confusion maybe?).

11:40 * broquaint reengages lurk mode

11:50 broquaint: s/setTimeout.* );/setTimeout(unfavourite.bind(undef, tweet), step++ * 500);/s ; Couldn't let that bug just sit there looking daft.

12:00 expez: ska-fan: added another solution

12:11 ska-fan: expez: Isn't net unbound in line 5?

12:12 expez: ska-fan: yeah, that's actually true

12:13 updated :)

12:17 ska-fan: Ok, so now the difference to broquaint's solution is that you're getting gross by destructuring the argument of the anonymous mapping function, whereas broquaint uses an explicit let and a list comprehension. Both solutions calculate net with an explicit let.

12:18 I wonder if this can be done with some kind of threading macro?

12:18 I can't get my head around it though.

12:20 expez: No, you can't, because you have to refer to the map twice. Once to get the value of net out of it and once to assoc something new onto it. You could use the as-> threading macro to name intermediary value but it won't really improve readability imo.

12:47 ska-fan: Hmm, can (fn [discount] (as-> discount ...)) be shortened somehow?

12:48 justin_smith: #(as-> % ...)

12:49 I mean that's what it would need to be for that last exampleto actually work

13:21 jack0: Hi! Does anyone know the GSoCers from Clojure?

14:21 ska-fan: Hmm that's not too bad.

14:21 dnolen: jack0: yes

14:22 jack0: dnolen: Can I private message you?

14:54 expez: Bronsa: Is this not a valid token? ::str/bar (str is alias for clojure.string in the ns). I just bumped tools.reader to 0.10-alpha3 and it no longer allows this token.

14:57 Bronsa: false alarm, *ns* wasn't being bound properly when reading to do an API change in tools.namespace.

15:41 kanja: Is there a way to memoize on multiple items? Ie I pass in a screen name or an id and expect to get the same return value

15:41 where both values are in the RV

16:04 justin_smith: kanja: perhaps a pre-processor that produces equivalent input to a memoized function for a given id or screen name?

16:13 kanja: justin_smith: I'm pretty new to clojure - The only way I see doing that is storing a hash in memory of screen name to id mapping and mutating that after each call of the memoized function. isn't that a side effect/mutation/cardnal sin?

16:14 justin_smith: kanja: how do you find the screen name for a given id or visa versa?

16:14 kanja: justin_smith: api call - twitter lets you use id or screen name to pull user data, and the resulting hash has both parts included

16:15 hence why I want to memoize it and avoid extra http requests :)

16:15 justin_smith: OK so it's the same api call that you are memoizing

16:15 kanja: justin_smith: right but with different but equivant calling args

16:17 justin_smith: I'd put a map of unsername -> id or visa versa (depending on which should be "canonical") in an atom, and update the atom after getting the memoized result, and check the atom before calling the memoized function

16:17 kanja: ah and wrap the function in a non memoized wrapper

16:17 justin_smith: exactly

16:17 kanja: that way I can do the mutation outside the memoization

16:17 justin_smith: right

16:17 kanja: that makes sense

16:18 is there some good docs on atoms? I already read the clojure ref documentation but I'd love something with a little more exposition

16:18 justin_smith: atoms are different from refs, the clojure docs on them are the best source of information

16:19 the most important thing I see people forgetting is that swap! can retry so you should not have side effects inside swap!

16:19 kanja: ah sorry meant Reference Documentation not documentaion on refs :)

16:19 have not read the refrence documentation on refs :)

16:19 justin_smith: yeah, this is the best info http://clojure.org/atoms

16:19 kanja: yeah that's what I've red

16:20 ok cool

16:20 thakns

16:20 I'll give this a try

16:20 justin_smith: kanja: another thing to look out for is using deref / @ inside swap!

16:20 that can lead to trouble

16:21 kanja: that is above my head right now

16:21 I haven't read anything on refs/derefs or @

16:22 justin_smith: ,(def a (atom 0))

16:22 clojurebot: #'sandbox/a

16:22 justin_smith: ,a

16:22 clojurebot: #object[clojure.lang.Atom 0x75869acd {:status :ready, :val 0}]

16:22 justin_smith: ,@a

16:22 clojurebot: 0

16:22 justin_smith: ,(deref a)

16:22 clojurebot: 0

16:22 Rurik: can anyone explain what atoms are?

16:22 justin_smith: ,(swap! a inc)

16:22 clojurebot: 1

16:22 justin_smith: ,@a

16:22 clojurebot: 1

16:22 rhg135: ! Functions always make you so exciting

16:22 kanja: so you're implicly dealing with an object when working with atoms unless you deref them?

16:23 justin_smith: kanja: you need deref if you want the actual value in the atom

16:23 kanja: and mutation functions are smart enough to operate over the object

16:23 and then deref pulls out the value

16:23 justin_smith: Rurik: atoms are a mutable container designed to hold immutable data

16:23 kanja: right

16:23 kanja: right that makes sense becuase the atom itself is just holding a pointer right?

16:23 and mutating it is just switching out the pointer?

16:24 justin_smith: kanja: not just "smart enough" - they need the atom itself in order to change its state - the value inside would not be sufficient

16:24 kanja: right bad choice of words

16:24 justin_smith: kanja: pretty much that's it, yeah

16:24 kanja: which reminds me, the other gotcha is putting a mutable data type inside an atom

16:24 kanja: so what's special about using the atom then? gives you transactional assignment for thread safety?

16:25 justin_smith: because swap! can retry and that does not do what we want if the data in the atom is mutable

16:25 kanja: justin_smith: oh crazy yeah

16:25 Rurik: justin_smith, so if you apply a function on an atom the contents get changed permanently?

16:25 justin_smith: kanja: exactly - it calculates a result optimistically, and retries if there is concurrent modification

16:25 kanja: justin_smith: because you could swap the value and then attempt to retry against a totally different set of data

16:25 does it ever make sense to stick mutable data into an atom then?

16:26 that seems like a pretty strong anti-pattern

16:26 justin_smith: Rurik: swap! and reset! have the power to mutate an atom. The contents are still immutable, you are just putting new contents in.

16:26 kanja: I suspect there are no reasonable examples of putting a mutable object directly in an atom

16:27 TimMc: hmmm

16:28 justin_smith: Does this count? https://gist.github.com/samn/5843422

16:28 It's a delay inside an atom.

16:28 justin_smith: hmm - delays are in a liminal space re: mutation though...

16:28 TimMc: Eh, I suppose not. Delays only barely count as mutable.

16:29 kanja: what's the ~ operator do?

16:29 justin_smith: who was it who was saying case effectively compiles to a hash map lookup?

16:29 kanja: I've seen in it some code but have yet to figure out where the docs for it are

16:29 justin_smith: kanja: it's a special operator inside `

16:29 unquote

16:29 kanja: justin_smith: I have said that in the past w/r/t other languages but not on this room :)

16:29 justin_smith: where ` is known as quasiquote

16:31 kanja: justin_smith: ` != ' right?

16:31 oy that's kind of confusing

16:33 justin_smith: yeah, those are two different things - quasiquote and quote

16:33 TimMc: quasiquote is the cooler version of quote

16:34 kanja: reading a message board posting on it now

16:34 it's used for delaying the execution of macros?

16:34 justin_smith: quotation is used as a tool to simplify constructing the value returned from a macro

16:34 a macro needs to return the form that will replace it

16:34 (its expnsion)

16:35 fancy kinds of quoting make generating a specific form simpler

16:35 TimMc: &(first `[a b c])

16:35 lazybot: ⇒ clojure.core/a

16:35 kanja: yea that makes sort of sense

16:35 TimMc: kanja: ^ You can use it anywhere.

16:36 kanja: so the quasiquote return is namespaced?

16:36 TimMc: It namespace-qualifies symbols, yes.

16:36 kanja: is (first '[a b c]) == (first `[a b c])

16:36 TimMc: try it

16:36 kanja: good point :)

16:37 no

16:37 TimMc: My main use of it outside of macros is with ~@ like so:

16:38 &`[1 2 3 ~@(map char (range 40 50))]

16:38 lazybot: ⇒ [1 2 3 \( \) \* \+ \, \- \. \/ \0 \1]

16:39 TimMc: but even that is very, very rare

16:40 kanja: haha I'm a little confused still! If I quote that rather than quasiquote it, the inner function isn't evualuated

16:40 does quasiquote force evaluation of everything inside of it?

16:41 but then when that first example wouldn't that throw an error since a b or c isn't defined?

16:41 &'[1 2 3 ~@(map char (range 40 50))]

16:41 lazybot: ⇒ [1 2 3 (clojure.core/unquote-splicing (map char (range 40 50)))]

16:42 kanja: I might just need to read up more on macros

16:42 justin_smith: kanja: quasiquote prevents evaluation, just as quote does. It also adds namespaces to symbols (even if the symbols are not currently available bindings)

16:42 kanja: I am weak on them

16:42 justin_smith: this is not about macros at all (yet) - it's a tool that makes macros easier to write, but can be used outside macros as TimMc shows

16:43 kanja: got it

16:43 so why did the example with the quasiquote get evaluated and the one w/ a quote not?

16:43 justin_smith: quasiquote is a version of quote that namespace qualifies symbols and allows controlled unquoting via ~

16:43 what got evaluated?

16:44 kanja: the (map char (range 40 50))

16:44 justin_smith: that was inside a form expanded via ~

16:44 well, ~@ more specifically

16:44 so it was explicitly unquoted

16:45 kanja: but isn't that true for the quoted version as well?

16:45 justin_smith: kanja: ' does not allow unquoting

16:45 kanja: oh which brings us back full circle to ~

16:45 justin_smith: ,'(:a ~@[:b :c])

16:45 clojurebot: (:a (clojure.core/unquote-splicing [:b :c]))

16:46 kanja: ~ only makes sense in a quasiquote because it's an unquote?

16:46 clojurebot: Cool story bro.

16:46 justin_smith: yes

16:46 kanja: ok well now I have to figure out how to use them :)

16:46 what does @ do in this example?

16:47 justin_smith: ~@ is unquote-splicing

16:47 clojurebot: Roger.

16:47 kanja: which is a different operator than @

16:47 which is deref

16:47 got it

16:47 justin_smith: ,`[:a ~[:b :c]]

16:47 clojurebot: [:a [:b :c]]

16:47 justin_smith: ,`[:a ~@[:b :c]]

16:47 clojurebot: [:a :b :c]

16:47 justin_smith: thats' what ~@ does

16:47 kanja: oh awesome

16:48 Rurik: justin_smith, it yanks stuff out of a data structure?

16:49 justin_smith: it effectively concats into the thing surrounding it, yeah

16:49 kanja: without breaking it out of the quoting right?

16:50 justin_smith: well, what's inside is evaluated

16:50 kanja: but only what's unquoted right?

16:50 justin_smith: ,`[(+ 1 2) ~@[(+ 1 2)]]

16:50 clojurebot: [(clojure.core/+ 1 2) 3]

16:52 Rurik: ,`[(+ 1 2) ~@[(+ 1 2) (+ 1 3)]]

16:52 clojurebot: [(clojure.core/+ 1 2) 3 4]

16:52 Rurik: cool

16:52 justin_smith, what if I wanted to get it out unevaluated?

16:53 justin_smith: ,`[(+ 1 2) ~@['(+ 1 2)]]

16:53 clojurebot: [(clojure.core/+ 1 2) (+ 1 2)]

16:53 justin_smith: or even...

16:53 ,`[(+ 1 2) ~@[`(+ 1 2)]]

16:53 clojurebot: [(clojure.core/+ 1 2) (clojure.core/+ 1 2)]

16:57 Rurik: ah

17:14 kanja: is there a way to test a private function?

17:14 I

17:14 'm not seeing it in the testing namespace

17:14 which makes sense since it's private

17:23 tcrayford____: kanja: yeah you can just refer to the var

17:24 like (is (= 2 (#'clojure.core/+ 1 1))

17:25 Rurik: hmmn

17:25 what if

17:25 ,(def a '( (+ 1 2) (+ 1 3))

17:25 clojurebot: #<RuntimeException java.lang.RuntimeException: EOF while reading>

17:25 Rurik: ,(def a '( (+ 1 2) (+ 1 3)))

17:25 clojurebot: #'sandbox/a

17:25 Rurik: , `(1 ~@a)

17:25 clojurebot: (1 (+ 1 2) (+ 1 3))

18:11 supremekai2: hi

18:20 justin_smith: hello

19:38 simon1234: Hi there! I was wondering, is there such a thing as datascript but in clojure? (and not clojurescript?)

19:38 Hm that would be core.logic maybe

19:57 Trioxin: has clojure implemented user defined reader macros?

20:05 dnolen: simon1234: datascript already supports Clojure(Script)

20:05 Trioxin: no, and probably never will

20:08 simon1234: dnolen: oh great, thanks! (and btw, thanks so much for your work, it's awe-inspiring)

20:15 crazydiamond: Hi. Is there an efficient algorithm to invert "multivalue map"? I.e. for {:a [1 2 3] :b [3 4]} it should return {1 [:a] 2 [:a] 3 [:a :b] 4 [:b]}?

20:16 mdeboard: Isn't there a groupby like that

20:16 for map

20:16 hashmap*

20:17 There is something in the stdlib I do believe for it

20:17 crazydiamond: I've implemented it like (defn maplist-invert [m] (into {} (map (fn [[k v]] [k (map second v)]) (group-by first (mapcat (fn [[k v]] (map #(do [% k]) v)) m)))))

20:18 but doesn't seem to finish :P

20:18 Trioxin: dnolen, why not? it's useful

20:18 crazydiamond: (on huge map)

20:19 dnolen: Trioxin: go through old IRC logs and the mailing lists on this topic to figure out why they aren't ever going to get included into Clojure

20:19 simon1234: np

20:20 Trioxin: "Since most users won't be aware of the meaning of reader macros one has created they are rarely used and to avoid the confusion altogether Rich Hickey decided to remove the ability to have user defined reader macros in Clojure"

20:20 seems like a lame reason

20:20 simon1234: Yeah, I guess you hear that all the time, but I feel obliged :)

20:24 amalloy: crazydiamond: (apply merge-with into (for [[k vs] m, v vs] {v [k]})) would be the easiest way i think

20:26 rhg135: But that's not very efficient I think

20:27 amalloy: rhg135: why would you think that?

20:28 i mean certainly you can use more efficient operations if you want to write a longer function, but the complexity is as good as you can do

20:28 rhg135: Apply X into, amalloy, but then again I can't think of a better way

20:28 amalloy: huh?

20:30 rhg135: Not sure why actually

20:32 crazydiamond: amalloy, thanks. I'll try that!

20:34 rhg135: I suppose apply is actually quite efficient on functions of varargs

20:52 Bronsa: Trioxin: we have tagged literals

20:56 Trioxin: does clojure have solid/vetted mobile development for android & ios?

20:57 just trying to pick a lisp and I'm stuck between CL, clojure, and racket

21:01 dnolen: Trioxin: for iOS people use ClojureScript (via React Native or other embedded JavaScriptCore thing). On Android a lot of progress has been made - though in theory React Native could also work there eventually.

21:08 shiranaihito: Trioxin: i bet Clojure is the most practical Lisp for getting stuff done

21:09 hfaafb: john carmack uses racket

21:09 shiranaihito: hfaafb: so? :p

21:10 Trioxin: to me, the JVM and scripting make it both attractive and repulsive at the same time

21:11 rhg135: http://www.reactnativeandroid.com/

21:13 shiranaihito: Trioxin: the real problem with Java is the shitload of pointless libraries just about everything depends on

21:13 commons-<whatever>.jar

21:15 Trioxin: clojure obviously shares that aspect then

21:34 kanja: I can't figure out why my inner function isn't getting called in this snippet http://pastebin.com/pLWqdtpr

21:35 the log at the end is missing the "sending tweet" text but the above and below calls are working right

21:35 because I'm shadowing it with the passed in arg

21:35 UG

21:37 how do I test a function that only has side effects?

21:42 shiranaihito: Trioxin: yeah, sadly Clojure comes with Java's baggage

21:45 talios: java doesn't ship with any commons-*.jar - mind you - if you removed the JVM from Clojure, you'd have every other lisp on the planet - a dead language

21:45 Bronsa: shiranaihito: you're painting a picture of the clojure ecosystem that doesn't match the one i know

21:46 shiranaihito: i'm not sure what you're arguing against

21:47 most widely used Java libs depend on a shitload of jars, so if your Clojure project depends on them, then you're carrying Java's baggage

21:49 Bronsa: you have the choice to use those libs or to not use them

21:50 to me it matters a whole lot more that I have the option to depend on those libs if I need to than how many jars a dependency depends on

21:56 shiranaihito: dude, sometimes you just need a specific library, even if it does depend on a shitload of jars..

21:57 but people in the Java and Clojure ecosystem don't seem to have seen this stuff as a problem

21:57 we've got Maven and Lein to deal with scraping together that steaming pile of jars, after all

21:57 Trioxin: is there a prolog implementation for clojure?

21:58 Bronsa: shiranaihito: are you complaining about package managers? I don't understand. Most languages have those

21:58 Trioxin: there's core.logic, not a prolog implementation but a logic engine nonetheless

21:58 shiranaihito: Bronsa: ok, now i think you're trolling me, so i'll just stop here

21:59 Bronsa: that's the first time I've been accused of trolling, nice

21:59 shiranaihito: you're welcome! :p

21:59 talios: shiranaihito - bloat of distribution is definitely a problem IN GENERAL, but in the scheme of things - of getting a working solution, someones extra bytes is better than reimplementing everything all the time

21:59 dnolen: shiranaihito: can't remember the last time I used an actually popular Java dep that pulled in tons of deps. The popular ones don't do this for the obvious reasons - you actually want people to use it.

21:59 Trioxin: silly arguing. I think if you learned clojure because you're a java fanboy you did it for the wrong reason

22:00 talios: dnolen - obviously never had to pull in a CXF dep then :)

22:00 dnolen: talios: emphasis on "popular", is it Jetty / Netty / Joda / Guava popular ?

22:00 shiranaihito: talios: yes, in general.. but i think the problem has been largely caused by people thinking they should always just get a lib from somewhere instead of implementing even a little thing by themselves

22:01 talios: dnolen - yep - its pretty much the only game left around if you need to interact with SOAP on the JVM

22:01 dnolen: talios: wow ok SOAP

22:02 talios: dnolen - yes sad. We had to intergrate with something recently, sadly their SOAP API wraps their RMI API - goood lord the classes that got generated ;p

22:02 Trioxin: this seems to be the most popular Lisp around. Hopefully not just because of Java coders who decided to have some extra fun.

22:02 hfaafb: Trioxin: is there a wrong reason to learn a new language?

22:02 * talios runs off for some lunch

22:03 hfaafb: you can love the jvm and hate java, that's a legal thing to do

22:03 Trioxin: hfaafb, if you've ever started in a language and then stopped before getting to know it well you'd know the correct answer to that.

22:05 hfaafb: you could be learning clojure right now... it doesn't take a whole lot of investment

22:05 learn a few lisps

22:05 go for it

22:05 macromancer: learning intercal to learn how to be more polite might count as the wrong reason

22:06 justin_smith: learning forth because you want to be more like yoda

22:06 Trioxin: i think i'll go watch farscape and think about how lame java can be before I decide to commit to clojure

22:07 languages almost always get popular for the wrong reasons

22:07 macromancer: platforms aswell

22:08 popular because of "popularity"

22:08 hfaafb: what a bizarre mindset, to only want to learn something if you think the few days diving into it are going to be somehow wasted

22:09 or rather not wasted

22:09 Trioxin: hfaafb, learn brainfuck then

22:09 your time won't be wasted

22:09 i promise

22:11 Bronsa: Trioxin: why would java be a factor in deciding whether or not to learn it?

22:12 we share the jvm with java, as an alternative language with entirely different principles

22:13 Trioxin: but you're all pink on the inside

22:14 Bronsa: what does that even mean?

22:14 Trioxin: lol

22:14 bytecode...

22:14 Bronsa: yes, that's a word we use

22:14 what about it?

22:15 Trioxin: you're all filled with toffee

22:15 Bronsa: are you just trolling now?

22:15 Trioxin: just tired

22:17 Bronsa: Trioxin: we're trying to be helpful and answering your questions, don't waste other people's time by trolling if you're tired please

22:18 hfaafb: never written a line of java in my life

22:18 use clojure semi regularly for hobby stuff

22:18 macromancer: i've never seen a one-liner in java before

22:20 Trioxin: other lisps arent JIT though

22:20 rhg135: I have, but it was very long

22:21 Trioxin: not in the traditional sense

22:21 macromancer: trioxin: looks like racketlang may be run on a JIT compiler

22:22 justin_smith: yes, racket has jit

22:22 macromancer: trioxin: sbcl seems to be JIT, if you call it that. You type code into the REPL and it produces machine code.

22:22 Trioxin: that would make sense with what it claims to do

22:23 justin_smith: macromancer: I'd call that a compiler hooked up to a repl, I think jit promises a bit more

22:24 Bronsa: sbcl is definitely AOT

22:24 it just does "interactive" AOT compilation

22:25 macromancer: feels like a grey area, like saying javascript is an interpreted language.

22:25 Bronsa: macromancer: no, not really. once sbcl emits machine code it's done.

22:26 macromancer: bronsa: how would a JIT be different?

22:26 Bronsa: macromancer: compare with the jvm, which compiles the bytecode into machine code at runtime

22:26 Trioxin: CL is incrementally compiled

22:26 Bronsa: macromancer: compilation happens during execution

22:27 macromancer: bronsa: why doesn't the REPL count as "at runtime"?

22:27 Trioxin: during runtime. and is there garbage collection?

22:27 i think so

22:27 Bronsa: macromancer: the jvm can compile the bytecode while it is executing it

22:28 macromancer: that's just compiling + loading in memory immediately after

22:29 macromancer: bronsa: what about a call to "eval"? sbcl will compile it, then execute it.

22:29 Bronsa: macromancer: right, you said it. compare then execute

22:29 justin_smith: macromancer: but it doesn't compile it in the midst of executing it

22:29 Bronsa: that's ahead of time compilation

22:29 just in time compilation means it will compile it or parts of it *while* it is executing it

22:29 justin_smith: macromancer: the point of JIT is it uses some information only available when running the code to optimize said code

22:30 macromancer: you mean, it is executing it, and compiling it, and the on the second run through it will execute the compiled version, but interpreted it the first time?

22:30 Bronsa: that's one possible scenario

22:31 justin_smith: macromancer: it will take notes during the first 100 or so executions, and use that statistical data to decide if and how to produce a new optimized version

22:31 Bronsa: realistically it will be much more complex and require many executions

22:31 justin_smith: yeah

22:31 macromancer: so, if instead of running the 100 scenarios, it executes zero of them, is it still a JIT?

22:32 Bronsa: ff a tree falls in a forest and no one is around to hear it, does it make a sound?

22:32 macromancer: even if it regenerates the machine code every time through.

22:32 justin_smith: macromancer: no because it isn't using runtime data - it isn't just running 100 random calls, it is waiting for you to call the code so it can get real profiling

22:32 macromancer: bronsa: my point is, JIT seems like an overloaded word, which has dragged along new improvements in the technology with it, and called that the baseline for what a JIT is.

22:33 justin_smith: macromancer: as Bronsa already said what SBCL does has a name, it is AOT compilation

22:33 macromancer: It seems that all that is needed is that no code be interpreted, but there is no compile/link phase prior to interpreting the code.

22:33 ok

22:33 Trioxin: I was just making the distinction between JVM bytecode and CL machine code

22:33 justin_smith: if you aren't using profiling data to transform a function that is already running, that isn't JIT

22:33 Trioxin: OK, JIT generates machine code

22:35 Trioxin: bytecode... I've been coding c# for a long time and don't consider it to be native compilation

22:35 justin_smith: Trioxin: AOT generates byte code, JIT generates machine code

22:35 Bronsa: Trioxin: javac and the clojure compiler compile byte code, JVM's JIT compile machine code from that byte code

22:36 justin_smith: Trioxin: it's not a question of "what we consider machine code" the vm outputs machine code that replaces the byte code

22:36 Trioxin: o i thought you were trying to put one in place of the other

22:36 Bronsa: no

22:37 macromancer: justin_smith: by that definition, a C compile isn't an AOT compiler, because it produces machine code, assuming we differentiate between byte code and machine code

22:37 Bronsa: macromancer: AOT doesn't mean "compiler file; ./a.out",JIT doesn't mean a REPL

22:37 justin_smith: macromancer: there's more than one factor here, but no, a C compile is AOT

22:38 macromancer: according to "Aycock -- A brief history of Just in time", the original LISP paper described JIT compilation, which I imagine didn't include any profiling.

22:39 justin_smith: I wouldn't be surprised that the terms changed meaning, it wouldn't be the only CS term to do so.

22:40 macromancer: i don't think it has changed meaning... i think what you might actually mean is a tracing-jit

22:40 Bronsa: macromancer: from the abstract of that paper "Broadly, JIT compilation includes any translation performed dynamically, after a program has started execution"

22:40 macromancer: sbcl falls into that category

22:41 Bronsa: replace "program" with "compilation unit" for better clarity

22:41 no.

22:41 macromancer: yes

22:41 Bronsa: no

22:41 macromancer: :)

22:41 justin_smith: ~gentlemen

22:41 clojurebot: You can't fight in here. This is the war room.

22:41 macromancer: i have to politely disagree

22:42 Bronsa: macromancer: once you input an expression into sbcl, that gets compiled and only after it is executed

22:42 see my previous comment, "replace 'program' with 'compilation unit'"

22:42 macromancer: are you saying the jvm can execute code before it has been compiled?

22:42 Bronsa: yes

22:42 macromancer: and the sbcl performs no interpration?

22:42 Bronsa: it executes a whole lot of code before compiling it into machine code

22:43 macromancer: according the the docs, sbcl can interpret lisp code, and it can also compile code, at runtime.

22:44 i must be missing a nuance that just isn't obvious.

22:45 Bronsa: I don't know how else to explain this

22:45 macromancer: ok,... broken down: code is either interpreted or compiled (effectively interpreted at a hardware level).

22:46 we're arguing about when the interpretation by software or compilation/interpretation by hardware happens.

22:46 Bronsa: macromancer: it seems to me that you're drawing the distinction between AOT and JIT to whether or not it produces a compiled file

22:46 AOT doesn't imply output to file, outputting to memory is still AOT

22:47 macromancer: but if I interpret code, then partially compile some of it, without any profiling, according to the literature, that is still "just-in-time"

22:48 Bronsa: macromancer: if you do that compilation dynamically, while that code is executing, sure

22:48 macromancer: if "eval" compiles the code before executing it, that is just in time..

22:49 Bronsa: no

22:49 macromancer: to be clear, if it's not interpreted, then it must be compiled, otherwise it can't be executed

22:49 Bronsa: that just means there's an interpreter or resident compiler available at runtime

22:49 it doesn't tell you anything about the style of compilation that's going on

22:50 macromancer: there seems to be no difference between a JIT compiler and what I think you mean by a "resident compiler"

22:50 if its all in memory.

22:50 at runtime

22:51 this really just seems like a slider which moves the compilation step to an arbitrary point in time.

22:51 JIT just means "as late as possible"

22:51 it still has to be compiled.

22:52 Bronsa: I'm sorry, I give up

22:52 again, no.

22:52 justin_smith: if no code can run without being compiled first, I don't think you can call that JIT

22:52 macromancer: i'm sorry you couldn't convince me

22:52 Bronsa: the jvm will make no guarantee whether or not some bytecode will be ever compiled to machine code

22:53 macromancer: how does a JIT execute without compiling it first? it must be interpreting it

22:53 justin_smith: the vm interprets bytecode, some bytecode is eventually compiled for performance reasons

22:53 macromancer: i'm sure I could patch sbcl to randomly decide to interpret or compile a bit of code, during runtime, and fill the criteria

22:54 Bronsa: macromancer: the jvm will interpret some bytecode, compile some to machine code, recompile some to optimized machine code, recompile some to unoptimized bytecode and much else

22:54 macromancer: okay, the JVM does all this, but that isn't the minimum necessary condition for calling a thing a JIT compiler...

22:54 Bronsa: way after that bytecode has been loaded by the vm

22:55 macromancer: i'm arguing about the minimum conditions, not about the state of the art

22:56 ok, time for lunch. Good discussion, even if I'm not convinced. I'll do some reading, and make up my mind, somehow.

22:56 Bronsa: macromancer: look, you (eval '(defun foo )) in sbcl. if sbcl is done with foo after eval returns, that's AOT compilation. if sbcl some time after and during execution will recompile foo or do other stuff to it, that's JIT

22:56 will possibly*

22:58 tali713: yes, in sbcl eval is more or less (execute (compile ...)) the compilation will happen right then, before it is executed and will not happen again for that object. uiui

22:58 Bronsa: macromancer: I think the confusion arises in lisps because lisp usually don't really have the same notion of program as other languages -- usually a lisp program is a compilation unit

22:58 which can be any lisp form

22:59 tali713: in other words the moment you evaluate a function definition it is compiled, compilation is not deferred for when that function is called.

23:52 joness2: hi. what is the clojure's equivalent of famous haskell's fibonaci example? "fibs = 0 : 1 : zipWith (+) fibs (tail fibs)" I used to have it but I can't find it now

23:58 IIRC there's a lazy clojure equivalent that also does auto-memoization. anyone knows what i am takling about? or am i imagioning things?

23:59 justin_smith: ,(def fib-seq (lazy-cat [0 1] (map + (rest fib-seq) fib-seq))) ; joness2 is this the one you were thinking of?

23:59 clojurebot: #'sandbox/fib-seq

23:59 justin_smith: ,fib-seq

23:59 clojurebot: (0 1 1 2 3 ...)

23:59 joness2: ,(take 10 fib-seq)

23:59 clojurebot: (0 1 1 2 3 ...)

23:59 justin_smith: ,(drop 5 fib-seq)

23:59 clojurebot: (5 8 13 21 34 ...)

23:59 justin_smith: ,(drop 10 fib-seq)

23:59 clojurebot: (55 89 144 233 377 ...)

23:59 joness2: yes thanks! that seems to be it

Logging service provided by n01se.net