#clojure log - May 28 2014

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

0:26 thecontrarian: anybody here use om?

0:27 i'm having some trouble with react's synthetic events and core.async

0:28 as in when i send the event through the channel it seems what i get out the other side has all its fields nulled out

0:33 tolstoy: I've been using Om lately. That's pretty strange.

0:33 akhudek: thecontrarian: I’ve seen that, never tracked it down. I just ended up extracting stuff before hand.

0:33 thecontrarian: looked it up. apparently its a react thing

0:34 react reuses its event objects for performance

0:34 probably has a pool somewhere

0:34 akhudek: makes sense

0:34 tolstoy: Oh! Right. I've seen that, too.

0:34 I ended up using goog stuff.

0:34 ddellacosta: thecontrarian: I've encountered similar things and find it's better to get the fields from the event at the point the event happens, and send those explicitly into the channel

0:35 thecontrarian: so theres probably some runtime business that recycles the events after the event handler finishes

0:35 ddellacosta: thecontrarian: presumably you don't need everything

0:35 thecontrarian: yeah, i'm just gonna write an extract func that makes a hash-map out of what i need

0:36 ddellacosta: thecontrarian: yes, and since your message is being sent asynchronously that event object has been cleaned out by the time you receive the message, most likely

0:36 thecontrarian: i tried into {} just for grins but it errored saying that [Object object] wasnt ISeqable

0:38 i wish i could get the list of topics that have been sub'd from a pub

0:38 that would help me out alot

0:39 ddellacosta: thecontrarian: you could write some wrapper that records them when a channel is subbed

0:39 thecontrarian: but without manageing one myself theres no way. the atom that the pub uses is closured in and unreachable

0:40 yeah i could but that would mean rewriting some of the sub methods

0:41 specifically sub, unsub, and unsub-all

0:42 i guess i could do that, but its just as transparent as i would like

0:42 just not, i mean

0:43 it just irks me that the data is right there and already being managed, i just cant get at it

0:43 i guess i could just rip out the pub method

0:43 thats something

0:43 hmmm

0:45 arrdem: so what's with Clojure's inline function support?

0:45 (dec so)

0:45 lazybot: ⇒ -23

0:45 clojurebot: excusez-moi

0:47 arrdem: ,(doc definline)

0:47 clojurebot: "([name & decl]); Experimental - like defmacro, except defines a named function whose body is the expansion, calls to which may be expanded inline as if it were a macro. Cannot be used with variadic (&) args."

0:50 hellofunk: arrdem that looks rather interesting

0:51 arrdem: hellofunk: I suppose... also experimental and something I'm probably not going to support.

0:54 hellofunk: thecontrarian ddellacosta I'm not sure this is what you were talking about (quite new to Om myself) but just read this: Cursors are only consistent during the application render phase - that is inside the life cycle methods. Callbacks on events handlers and core.async loops are not really a part of the Om/React render loop. Thus you are not allowed to use cursors outside of the render phase as this is almost certainly a concurrency bug!

0:54 ddellacosta: hellofunk: no, this was more an issue with the life cycle of React events

0:55 thecontrarian: yeah

0:55 hellofunk: ok, it's not quite clear to me yet where Om ends and React begins

0:56 ddellacosta: hellofunk: well, all the event handlers you use inside of Om are pseudo-events managed by React.

0:56 hellofunk: er, handlers managing pseudo-events I should say

0:56 hellofunk: by event handler, you mean thinks like onClick events?

0:56 thecontrarian: yeah

0:57 Frozenlock: There's also Reagent, if Om is too confusing

0:57 tolstoy: hellofunk :onClick (fn [e] (put! some-chan e)) ;; e turns into a null

0:57 thecontrarian: but only those that you assign through the props of a component like the div

0:57 * Frozenlock is a proud Reagent user

0:57 thecontrarian: lol, whats the difference?

0:58 Frozenlock: I find Reagent more clojure-y

0:58 thecontrarian: genuine question, i have been trying to figure out

0:58 what do you mean?

0:58 Frozenlock: You make a component just like you would a function, without reify and stuff.

0:58 thecontrarian: word

0:58 what about performance?

0:59 Frozenlock: Also, using multiple atoms is pretty much the norm. (Even single component atoms)

0:59 hellofunk: I think Om's claim to fame (and arguably the key reason a lot of non-Clojure people are looking at ClojureScript more seriously) is the remarkable bencharks it has shown -- up to triple the speeed of React by itself

0:59 Frozenlock: http://holmsand.github.io/reagent/news/reagent-is-async.html

1:00 hellofunk: I think Om's claim to fame is dnolen :-p

1:00 hellofunk: in fact, it is getting so well-known, that even non-developers are chanting its name. i was at a yoga class recently, and everyone was just sitting down saying its name over and over again

1:00 Frozenlock: Reagent also uses hiccup like syntax, like you would with Om+sablono

1:01 thecontrarian: dnolen is definitely a big part of its appeal

1:01 Frozenlock: And with that (which should work also with Om), you can synchronize all undos for all atoms :-p https://github.com/Frozenlock/historian

1:02 thecontrarian: Frozenlock that is really cool

1:03 Frozenlock: This might also interest you https://github.com/alandipert/storage-atom

1:04 thecontrarian: it does, but not as much

1:04 Frozenlock: Awwww

1:04 thecontrarian: its just that its not as directly useful at the moment

1:04 still really coo

1:04 cool*

1:05 i like the cross tab update feature, thats a nice addition

1:06 Frozenlock: It is! It's a nice abstraction because you only have to deal with your atoms.

1:07 Jaood: is it really to bad to use react directly?

1:07 Frozenlock: And if you are using React (om/reagent/other...), everything is automatically updated.

1:09 tolstoy: Is the difference that Reagent doesn't have the split between app state and component state?

1:11 Frozenlock: I'm not sure I understand what you are talking about.

1:11 Wait, I'm sure I don't.

1:11 tolstoy: In Om, a component has its own state which is not connected to the app-state.

1:12 I guess I'm just saying the same sentence over again. ;)

1:12 Frozenlock: Ah yes, there isn't such a distinction in Reagent (as far as I know).

1:13 But then again you can create an atom for a single component if you want.

1:13 tolstoy: When I first used Om, I just stored ALL state in app-state (including form stuff).

1:13 Right!

1:13 I can see the appeal of that.

1:14 Frozenlock: http://holmsand.github.io/reagent/ bunch of examples

1:16 thecontrarian: i sort of like the whole store all your state in app-state idea

1:17 i mean, yes, it can get sort of unweildy sometimes, but its the only real way i can figure to do true trickle-down views

1:17 tolstoy: It's clean. Just have all your components put events in a shared queue and process them all in one place.

1:17 thecontrarian: exactly

1:17 tolstoy: However, it's not great for "re-usable" components.

1:17 thecontrarian: i disagree.

1:18 Frozenlock: Everything in the same atom works well 'most of the time'

1:18 thecontrarian: each seperate component only sees a portion of the state, so theoretically the main state is a bunch of little states in a tree like form

1:19 Frozenlock: If you want to use storage-atom, you are screwed, because serializing everything can take a while.

1:19 tolstoy: By re-usable, I mean third-party. (But I don't know, I don't really care about re-usable because I'm just an app writer, not a lib writer.)

1:19 thecontrarian: i'm actually in the process of writing a lib, or framework i guess.

1:19 Frozenlock: thecontrarian: could you make a variable number of tabset in Om? (genuine question, I really don't know)

1:19 tolstoy: thecontrarian: I think the idea is, though, that some components have local state of no importance to the app itself. Implementation details.

1:20 Frozenlock: thecontrarian: See this example https://hvac.io/vigilia/v/5371147be4b0222b740851a2?tab=%3Adevices&bc%5B%5D=%3Aa10122..0.7..0.2..4.1 (click on the button 'split screen' at the bottom right)

1:21 I made sure that each tabset has its own atom, meaning I can spawn as many as I want.

1:21 thecontrarian: tolstoy yeah, more that the internal state is something that can be recalculated based on the cursor data

1:21 tolstoy but yeah, implementation details

1:21 blur3d: Hey, I’m trying to insert a row into a postgres table that has a UUID type column, using jdbc library, and I get the following error “java.util.UUID cannot be cast to clojure.lang.Named”. I can’t seem to work out how to give it what it wants

1:22 tolstoy: thecontrarian: Like this thing: https://github.com/arosequist/om-autocomplete.

1:22 thecontrarian: Frozenlock holy shit this is nice

1:22 Frozenlock: thecontrarian: The tabset part, or the whole? (thanks either way!) :-D

1:22 thecontrarian: the whole thing

1:23 what do you mean by tabsets?

1:23 Frozenlock: Controllers - timeseries - Analytics ---> 1 tabset (multiple tabs)

1:24 If you click on the button at the bottom right, it will create a second set of those tabs for you.

1:24 thecontrarian: and they are supposed to be of identical data?

1:24 blur3d: Does anyone have any experience with the postgres uuid type?

1:25 Frozenlock: Yes, but you can keep one tabset on 'Controllers', while the other is on 'Timeseries'.

1:25 (if you have a kickass big screen)

1:25 thecontrarian: yeah, you can totally do that with om

1:26 Frozenlock: What would be your approach, if everything is stored in the same atom?

1:26 Store a vector?

1:26 ddellacosta: blur3d: you probably need to create a custom Postgres object

1:26 blur3d: hold on, looking for appropriate javadoc

1:27 blur3d: ddellacosta: ok, thanks

1:27 thecontrarian: you'd just have the data that they are rendering from be in one part of the atom and then just have an array of screen keywords or whatever. you store the currently viewing tab for each tabset screen thing and have a sort of internal route based off of that

1:27 blur3d: I found https://github.com/impossibl/pgjdbc-ng which I might be able to switch to instead

1:27 ddellacosta: blur3d: yeah, I think you'll just need to create one of these: http://jdbc.postgresql.org/documentation/publicapi/org/postgresql/util/PGobject.html

1:28 thecontrarian: that make sense?

1:28 blur3d: ddellacosta: ok, i’ll take a look. Thanks

1:28 Frozenlock: Yes, that would have been my 'naive' approach without knowing too much about Om internals. Thanks!

1:28 ddellacosta: blur3d: you could, but it really should just be as simple as (doto (PGobject.) (.setType <whatever the uuid type is>) (.setValue <your uuid>))

1:28 thecontrarian: thats my naive approach as well

1:29 Frozenlock: Well hopefully not so naive, if you use Om ;-)

1:29 ddellacosta: blur3d: assuming you are using clojure.java.jdbc

1:29 Frozenlock: (dec so)

1:29 lazybot: ⇒ -24

1:29 blur3d: ddellacosta: yep, I am.

1:30 hellofunk: You guys using cljs in a browser, when writing a function, you wish to quickly evaluate and test it, how do you work? With regular Clojure, it's easy to compile just the one form you are working on and then test at REPL.

1:30 thecontrarian: well thats just kinda the way i would do it using plain react

1:30 ddellacosta: hellofunk: either austin/piggieback (https://github.com/cemerick/austin) or lein cljsbuild auto

1:31 Frozenlock: hellofunk: If it's just a clojure function, I would test it in a repl. If it touches the Dom, I compile and reload my browser. If it's a complicated mess, I start a browser-repl

1:31 ddellacosta: hellofunk: the former gets you a repl but is a bit more complicated. The latter just rebuilds your cljs when you update it, and is quite fast at this point

1:32 hellofunk: Well I am using lein cljsbuild auto, but to actually try out a function that is not yet wired up to anything on a web page, I'd enjoy not having to do a bunch of console log tests

1:32 thecontrarian: lighttable

1:32 its got a whole instarepl thing

1:32 its pretty nice

1:32 hellofunk: i am also trying lighttable a bit too, but i keep coming back to emacs due to some annoying glitches in its editor

1:32 Frozenlock: emacs powaaaaa

1:33 thecontrarian: i was never an emacs user so this seems fine to me

1:33 hellofunk: i really want to like lighttable. but it's just not as stable as emacs.

1:34 thecontrarian: hellofunk yes, it is not as stable as the 45 year old editor

1:34 ;P

1:36 tolstoy: I'd give LightTable a more serious try, too (I tossed in some kickstarter $), but I do other things in Emacs as well: org-mode, markdown, etc, etc.

1:37 Frozenlock: tolstoy: ERC?

1:37 tolstoy: Sometimes.

1:37 p_l: tolstoy: at least they learned how to have less annoying library deps in recent versions

1:37 tolstoy: Magit is pretty nice.

1:39 The mailing list had good things to say about: https://github.com/tomjakubowski/weasel/

1:40 Frozenlock: o_O

1:40 This looks amazing

1:40 I wouldn't need to start a ring server just for my browser repl

1:42 tolstoy: I've never been able to get a cljs repl working. Well, once, a long time ago.

1:42 I always get so far, and it locks up.

1:42 thecontrarian: this looks pretty neat

1:43 id love someone to host a tiny little site that just asks you for the websocket address

1:44 Frozenlock how did you implement the multiple tabsets using reagent?

1:47 Frozenlock: thecontrarian: Turns out it was a bad example... I only use a single atom for the tabs. (each tabset an element in a vector)

1:48 thecontrarian: word

1:48 Frozenlock: https://www.refheap.com/86006

1:48 tolstoy: Heh. required weasel.repl in my cljs file, get a "no such namespace". Ah, the luck.

1:50 thecontrarian: Frozenlock so you just have an atom that has the tab data and that just generates a tabset from it?

1:52 Frozenlock: Ah! I knew I something was amiss.

1:52 It's an atom of atoms :-p

1:52 (def tabsets-atom (r/atom [(r/atom (or (get-valid-url-tab) :devices))]))

1:54 tolstoy: It worked!

1:54 hellofunk: so much great practical info getting disseminated in here today

1:55 Frozenlock: #clojure has always great info. It's the official Clojure documentation! <---- lie

1:56 arrdem: Frozenlock: even if we aren't we're better docs than the official ones...

1:56 clojurebot is arguably a full documentation engine in and of itself..

1:56 tack on lazybot and all the major library devs that lurk in here... this is doc and stupid question heaven.

1:56 TEttinger: &help source

1:56 lazybot: java.lang.RuntimeException: Unable to resolve symbol: help in this context

1:56 TEttinger: hm

1:57 l1x: ,(re-pattern "\bword\b")

1:57 Frozenlock: arrdem: I don't know how someone can become good at Clojure without spending time here.

1:57 clojurebot: #"word"

1:57 l1x: ,(re-pattern "\bwo.d\b")

1:57 clojurebot: #"wo.d"

1:57 TEttinger: hm

1:57 ,#"\bword\b"

1:57 clojurebot: #"\bword\b"

1:57 TEttinger: I think \b is treated differently in the string

1:58 l1x: i want to generate a regexp from a string

1:58 TEttinger: ,(re-pattern "\\bword\\b")

1:58 clojurebot: #"\bword\b"

1:58 l1x: ohh

1:58 this is what i am looking for

1:58 thanks

1:58 TEttinger: no prob

1:58 Frozenlock: That escape

1:58 TEttinger: regexps are always fun

1:58 Frozenlock: At least it's not an Emacs regexp escape

1:58 arrdem: Frozenlock: I think it's an open question unfortuantely

1:58 Frozenlock: \\\\\\\\\\\\\\\\\\\\\\b

1:59 arrdem: also I just did a readme update and am open to comments https://github.com/arrdem/oxcart

1:59 Frozenlock: such escape wow very confuse what does mach much mistery

2:00 TEttinger: ##(re-seq (re-pattern "\\b\\w+\\b") "The quick brown fox jumps over the lazy dog.")

2:00 lazybot: ⇒ ("The" "quick" "brown" "fox" "jumps" "over" "the" "lazy" "dog")

2:00 Frozenlock: arrdem: I know nothing of compilation stuff, can't help you with that :-(

2:00 arrdem: Frozenlock: I'll take feature requests and readability comments too :P

2:00 TEttinger: so that shows that to use other regex escapes they need the double backslash too

2:16 hellofunk: When changes are made to the app state atom in Om, what is necessary for them to update on the page? I have a bunch of components setup and built in functions passed to om/root, and I can log the changes in state fine, but the on-page state never changes. where should I look?

2:18 tolstoy: Is the app state an atom (atom {....})

2:18 hellofunk: Yes, I can log it by deferencing it

2:18 and it shows my updates

2:19 tolstoy: Should work. Maybe a swallowed exception somewhere in there?

2:20 I've had issues when a component didn't return (om/component ...) or (reify om/IRender ..) or something. But I think the new version warns against that.

2:20 hellofunk: no exceptions showing in the chrome console. i'm basically following dnolen's example here: https://github.com/swannodette/om/wiki/Basic-Tutorial

2:20 tolstoy: I get swallowed exceptions in core.async stuff.

2:22 ddellacosta: hellofunk: use transact! or update! to update the app data

2:22 hellofunk: are you doing that?

2:22 hellofunk: if anyone can spare a minute of eyes, here it is: https://www.refheap.com/86007

2:22 ddellacosta I am, just exactly as nolen's example shows

2:22 ddellacosta: hellofunk: okay, looks like you are

2:25 hellofunk: weird, my println @app shows the correct new state changes, but the page never updates.

2:25 ddellacosta: hellofunk: neither deleting nor adding works? Do you get any errors whatsoever?

2:25 hellofunk: ddellacosta the deleting works fine.

2:25 ddellacosta: hellofunk: oh

2:25 hellofunk: ddellacosta no errors with either deleting or adding

2:25 ddellacosta: hellofunk: you are updating at :contacts in your transact! inside of add-composer

2:26 hellofunk: I guess you probably want :composers there

2:26 hellofunk: ahh!

2:26 ddellacosta thanks, the extra eyes helped

2:27 ddellacosta: hellofunk: yep, extra eyes is key

2:28 hellofunk: so i guess the idea is that these Om components have independent state as well as access to a global app state, and each has hooks into the lifecycle of their rendering, and each also can own other components with the same powers. Is that the general idea here?

2:37 locks: 5:49 AM <hellofunk> ok, it's not quite clear to me yet where Om ends and React begins

2:37 use React and you'll know ;P

2:44 thecontrarian: hellofunk seriously tho, use react

2:45 i played around with om, then did some basic stuff with just react, then went back to om and everything made ALOT more sense

2:45 Frozenlock: Using react? Directly? As in JS stuff?

2:45 thecontrarian: yes

2:45 Frozenlock: yuck

2:45 thecontrarian: :/

2:45 well at the very least read up on how it works

2:45 it would really do you good just to do some mock stuff

2:46 or at least look at others mock stuff

2:47 Frozenlock: I don't really see what there is to learn except the few 'component-did-mount' 'component-will-mount'...

2:47 Oh, and knowing it doesn't fully support SVG.

2:47 *rage*

2:47 thecontrarian: lol

2:47 svg sucks, imo

2:47 avoid it where you can

2:48 Frozenlock: o_O

2:48 thecontrarian: this is coming from a guy who made an app starting all svg, then some svg, then no svg, and it just got better each time

2:48 css3 transforms

2:49 of course, there are some nice things that svg can do

2:49 but its slow

2:49 Frozenlock: How do you let your user 'save as' with css3 transforms?

2:49 thecontrarian: which makes me rage

2:49 wha?

2:49 Frozenlock: save as png, svg, jpg...

2:49 thecontrarian: oooooh

2:49 Frozenlock: You know, outside the browser :-p

2:50 thecontrarian: well arent there render html to png libs?

2:50 <- ignorance

2:50 you do have a point tho

2:50 that is one place where svg is kind of nice

2:50 but thats an edge case

2:51 Frozenlock: ur... I'd say it depends on your users. Getting out of the browser to send an email or include a graph in a report is not really an edge case I'd say :-/

2:52 I'd say twice even

2:52 thecontrarian: yeah but arent you talking about editing the svg in browser then saving it?>

2:52 Frozenlock: I'd say.

2:53 thecontrarian: also i just found this https://developer.mozilla.org/en-US/docs/Web/HTML/Canvas/Drawing_DOM_objects_into_a_canvas

2:55 ok so maybe not an edge case, but for stuff like complex ui and animations and stuff, i prefer to use html and css3 when i can

2:55 but i concede that there are things that you cant really do with css and html that you can with svg

2:56 Frozenlock: http://d3js.org/ Do THAT in html :-p

2:57 locks: thecontrarian: +1 on using react itself

2:57 Frozenlock: But the web is doomed anyway. Mobile is destroying everthing. Soon websites will be in font 72pts with a single button that says 'click me'

2:58 thecontrarian: Frozenlock, actually thats what i was talking about, with the d3 thing

2:59 thecontrarian.github.io/Abacus

2:59 uses d3 for animations, but everything you see is html

2:59 Frozenlock: Wow, I like that side menu

2:59 thecontrarian: lol

3:00 Frozenlock: Well, on a mobile. On a 27inches it sucks :-p

3:00 thecontrarian: really? it should be the other way arround

3:00 and it was designed for ipa

3:00 ipad

3:00 Frozenlock: hmm let me test that

3:00 * Frozenlock takes his 7in tablet

3:01 thecontrarian: but its the stuff you drag out from the side menu that is important

3:01 follow the instructions

3:01 or dont, w/e

3:02 Frozenlock: Oh God

3:02 case sensitive

3:02 I hate you :-p

3:03 thecontrarian: is this written in cljs?

3:04 thecontrarian: no

3:04 just regular js

3:04 it was before i really got into clj

3:06 Frozenlock: Oh, I just now realized you could drag boxes out of the menu

3:07 thecontrarian: SIGH

3:07 did you read the instructions?

3:08 Frozenlock: I thought you said to not follow them ...

3:08 "follow the instructions... or don't"

3:08 thecontrarian: that was me saying 'its shit'

3:08 but yes, if you play around with it, you should read the instructions

3:09 p_l: ... did *anyone* ever document how gen-class deals with overloaded methods when extending classes?

3:17 michal2: Hi. Is it possible to return jsonp by luminus ? I would like to write my angular apps with clojure (now python). And it would be cool to have jsonp as a return from controller.

3:29 ddellacosta: m_m: presumably this would let you do it: https://github.com/qerub/ring-middleware-jsonp

5:07 * ddellacosta dances around with a lampshade on his head while no one is around

6:03 noncom: so i tried out emacs live and now trying out prelude. aside from the fact that it had many warnings and errors during the initial initialization (but worked at the end), the first inconvenience that i am to notice is that there is no in-place advices for M-x commands, only if I press TAB

6:04 is thre a way to enable it, as it is in live?

6:07 whilo: hi

6:07 is there a reason why https://github.com/clojure/clojurescript/blob/master/src/cljs/cljs/reader.cljs#L547

6:08 and *default-data-reader-fn* are not declared ^:dynamic?

6:14 noncom: whilo: heh, strange, they are earmuffed atoms .. :)

6:15 whilo: noncom: right, and i get warnings when rebinding them, although it works

6:15 noncom: maybe there is a reason, but i think it is a mistake since even the compiler would warn you to not use earmuffed names for not maken them dynamic

6:15 whilo: you may try asking again later in today when people who are more into cljs will be present here..

6:16 whilo: ok

6:18 trap_exit: are lazy sequences considered as seqable?

6:18 , (for [i (range 10)] i)

6:18 clojurebot: (0 1 2 3 4 ...)

6:18 trap_exit: , (seq? (for [i (range 10)] i))

6:18 clojurebot: true

6:18 noncom: well, likely...

6:19 sequable is something that can be turned into a sequence, and lazy seqs definitely are

6:25 ddellacosta: whilo: there are no vars in CLJS

6:25 earmuffs are just a convention, there is no special handling of them in the compiler as far as I know

6:26 whilo: ddellacosta: the problem is that the reader has these atoms in there and i cannot get a "clean" reader without rebinding these vars

6:27 ddellacosta: whilo: Is swap!-ing them like normal atoms causing you trouble?

6:28 whilo: ddellacosta: then i will reset the reader state for the whole runtime, possibly interfering with other users. clojure.edn allows to pass in tagged-reader-fns and the default-reader-fn as arguments, which imo is a lot better

6:30 tools.reader might solve this problem in a similar way, if it becomes the default reader for cljs and clj

6:30 ddellacosta: whilo: you need to use this I suppose, but I'm not sure you're going to find a way around it: https://github.com/clojure/clojurescript/blob/master/src/cljs/cljs/reader.cljs#L567-L572

6:30 whilo: but as I said, you don't have vars in CLJS so I'm not sure how else you'd handle it

6:30 whilo: ddellacosta: right, this is basically manipulating the atom

6:31 it will probably cause problems, because i want to read all tagged-literals as a map value through the default fn, disregarding custom tagged readers

6:32 ddellacosta: but rebinding the default fn seems to work through the binding form atm

6:33 ddellacosta: how does binding work then on cljs?

6:33 i mean the (binding [foo/bar 42] ...) form

6:34 ddellacosta: whilo: not sure, I'm a bit confused by that myself, reading through the code now

6:35 whilo: ah, it's wrapping with-redefs, that's what I suspected

6:36 whilo: ddellacosta: this is what i am doing: https://github.com/ghubber/hasch/blob/master/src/cljs/hasch/platform.cljs#L14

6:36 ddellacosta: uh, redef is ugly, isn't it?

6:36 Bronsa: whilo: if I'm not mistaken cljs.reader comes from a time where clojurescript didn't support dynamic vars yet

6:37 ddellacosta: Bronsa: does it now? I didn't realize that had changed

6:37 Bronsa: ddellacosta: since a couple of years :)

6:37 whilo: Bronsa: ok. so for now they could be declared ^:dynamic

6:37 ?

6:37 ddellacosta: Bronsa: jeez am I confused. Obviously ignore what I said whilo!

6:39 Bronsa: whilo: I suppose so

6:44 noncom: Bronsa: so is it a mistake that these vars are not dynamic or is it ok?

6:45 oh yu've already answered

6:45 sry

6:45 ddellacosta: whilo: interesting related conversation from a few years back: https://groups.google.com/forum/#!topic/clojure/6cmnkHmHBNw

6:50 whilo: ddellacosta: thx, i am getting something to eat

6:51 ddellacosta: whilo: cheers, enjoy. :-)

7:00 owl-v-: lol this guy wanted jvm-free >> http://danielkvasnicka.tumblr.com/post/54741297421/racket-on-raspberry-pi-the-importance-of-being-jitted

7:01 lintomas: hi, are data structures java objects at the point where the reader finishes parsing them?

7:04 Bronsa: lintomas: yes

7:04 ,(class (read-string "[]"))

7:04 clojurebot: clojure.lang.PersistentVector

7:10 lintomas: Bronsa, thanks. So in the moment the compiler starts treating the data structures, it sees them as the objects of java, true?

7:12 owl-v-: omg javascriptV8 is actually quite good in this test >> http://benchmarksgame.alioth.debian.org/u64/benchmark.php?test=all&lang=v8&lang2=sbcl&data=u64

7:12 much less code :-)

7:12 Bronsa: lintomas: I'm not sure what you mean by that, but both the compiler and the reader output clojure.lang.Persistent* instances

7:19 gfredericks: lintomas: clojure objects are also java objects -- there's not a sharp distinction

7:20 lintomas: Bronsa, I don't the main idea here, I suppose. User inputs so called reader forms ( [], (), {}, "string") which we consider data-structures. But for reader they just strings. Then there spits data structures. But in what forms, in java object or some internal clojure syntax representation for those data structures?

7:21 Bronsa, I don't the main idea here, I suppose. User inputs so called reader forms ( [], (), {}, "string") which we consider data-structures. But for reader they just strings. Then the reader spits data structures. But in what forms, in java object or some internal clojure syntax representation for those data structures?

7:22 Bronsa: lintomas: the reader creates concrete instances of the data structures, yes

7:22 lintomas: Bronsa and gfredericks , I don't the main idea here, I suppose. User inputs so called reader forms ( [], (), {}, "string") which we consider data-structures. But for reader they just strings. Then the reader spits data structures. But in what forms, in java object or some internal clojure syntax representation for those data structures? How can see the exact form of those concrete instances of data structure, their representation form?

7:22 Bronsa: lintomas: what you get as output from read/read-string is effectively what the reader produces.

7:24 gfredericks: ,(map type (read-string "( [], (), {}, \"string\")"))

7:24 clojurebot: (clojure.lang.PersistentVector clojure.lang.PersistentList$EmptyList clojure.lang.PersistentArrayMap java.lang.String)

7:25 gfredericks: huh. the difference beteeen Vector and List$EmptyList there is curious

7:30 Bronsa: gfredericks: not really. all empty lists are List$EmptyLists

7:36 lintomas: Bronsa, wow...then i don't understand anything. What the reader produces is what compiler sees and processes. The (read-string "[]") returns []. So what does compiler do with []? Does it parse it again, understand it is an vector, create a java object array ...??? Sorry for being so noob

7:37 Glenjamin: ,(eval (read-string "[]"))

7:37 clojurebot: []

7:37 noncom: ,(type (eval (read-string "[]")))

7:37 clojurebot: clojure.lang.PersistentVector

7:37 noncom: ,(type "[]")

7:37 clojurebot: java.lang.String

7:37 noncom: just the magic of toString() :)

7:37 Glenjamin: ,(= '[] (read-string "[]"))

7:37 clojurebot: true

7:37 Bronsa: lintomas: yeah, the compiler takes the output of the reader and dispatches over the class, for PersistentVector it creates a new vector evaluating the elements of the vector returned by the reader

7:38 Glenjamin: read-string isn't returning a vector, it's returning the tokens []

7:38 i think

7:38 maybe not

7:38 Bronsa: Glenjamin: not true

7:38 Glenjamin: i have confused myself now

7:38 isn't it just an expression until it gets evalled?

7:39 lintomas: Bronsa, ty. u're great person :D

7:39 Glenjamin: oh, right - because it's a literal its already a vector

7:40 ,(= '[] (read-string "(vector)"))

7:40 clojurebot: false

7:40 Glenjamin: ,(= '[] (eval (read-string "(vector)")))

7:40 clojurebot: true

7:40 Glenjamin: please disregard my earlier statement about what read-string returns

7:41 lintomas: Then the reader is useful in which ways. One would be: it expands reader-macros. Other: u can type text in repl or read text from file. Or is there something important reader exist for?

7:41 Then the reader is useful in which ways? One would be: it expands reader-macros. Other: u can type text in repl or read text from file. Or is there something else important reader exist for?

7:50 sandbags: am i getting it right that a particular method can only be defined by one (the first) Protocol?

7:57 szymanowski: Hi, how can i do something like this? (defrecord A []) (extend-type A clojure.lang.Named (getName [this] "A"))

7:58 It work inline but not with extend-type

7:58 s*

7:58 Bronsa: szymanowski: yeah, you cannot use extend with interfaces, only protocols

7:58 szymanowski: is there a way to do?

7:58 Bronsa: no

7:58 szymanowski: ok

7:59 thank you

7:59 Bronsa: you can only do it inline if it's an interface

8:00 m_m: I am searching simple web framework for clojure with ORM, MVC. I would like to use clojure only to receiving data from database, sessions etc. Rest of the job is for angular. Any clues?

8:01 gfredericks: Bronsa: but why are not all empty vectors Vector$EmptyVector?

8:02 Bronsa: gfredericks: because there's not $EmptyVector class :D there's no need for it

8:02 gfredericks: Bronsa: why? that's the discrepancy I was originally pointing out

8:03 Bronsa: gfredericks: implementation details, an empty list cannot be implemented as a PersistentList/Cons, an empty vector however can be represented as a PV just fine

8:03 gfredericks: Bronsa: okay that makes more sense

8:04 (inc Bronsa)

8:04 lazybot: ⇒ 20

8:06 gfredericks: lintomas: I think you've been noodling at the concept of homoiconicity this whole time: http://en.wikipedia.org/wiki/Homoiconicity

8:07 lintomas: the two biggest reasons why homoiconicity is useful in lisp is because it makes macros easy and paredit possible

8:45 ayia: hi! is it possible to import specific java static methods in clojure? I don't want to write each time MyClass at (MyClass/myStaticMethod ...)...

8:46 Bronsa: ayia: the only way AFAIK is wrapping them in a function

8:47 ayia: Bronsa: big thanks bro! I will...

8:48 peterdon: Maybe http://richhickey.github.io/clojure-contrib/import-static-api.html

8:48 Bronsa: clojure-contrib is dead

8:48 peterdon: ah

8:51 noncom: Bronsa: what if, in a case like this one, I will use the machinery from the contrib lib? will it be considered deprecated?

8:52 Bronsa: noncom: nobody is going to stop you from copying code from clojure-contrib if you need it, but being deprecated means that it's not guaranteed to still works

8:52 bbloom: amalloy_: can be either low or hight bits, but yeah, i think you're right. low bits are much more common these days

8:53 Bronsa: s/to/it

9:22 clgv: ever seen that one: "CompilerException java.lang.VerifyError: Unable to pop operand off an empty stack" ?

9:26 noncom: clgv: not recalling.. wow you seem be hunting comiler bugs all over the place :)

9:28 clgv: noncom: not intentionally

9:28 noncom: clgv: maybe you're born a natural compiler-bug-hunter

9:29 the ability you know, a trait so to say

9:29 and have a great mission

9:30 clgv: yeah born a "fuzzier" ;)

9:30 it has something to do with primitive functions, but I never encountered that weird error before

9:42 There is a minimal example of that weird bug: https://www.refheap.com/86018

9:42 Seems as if the :tag for the array causes problems

10:11 according to the source HostExpr.tagToClass should work for doubles though ... :(

10:17 mskoud: I have a structure like this : [({:auth true :b 5} {:c 4}) ({:auth false :b 6} {:c 5}) ({:b 7} {:auth true :c 6})]

10:17 and would like to return all list with :auth true. How do i do that?

10:19 gfredericks: (filter #(some (comp true? :auth) %) my-lists)

10:19 ,(def my-lists [({:auth true :b 5} {:c 4}) ({:auth false :b 6} {:c 5}) ({:b 7} {:auth true :c 6})])

10:19 clojurebot: #'sandbox/my-lists

10:19 gfredericks: ,(def my-lists '[({:auth true :b 5} {:c 4}) ({:auth false :b 6} {:c 5}) ({:b 7} {:auth true :c 6})])

10:19 clojurebot: #'sandbox/my-lists

10:19 gfredericks: ,(filter #(some (comp true? :auth) %) my-lists)

10:19 clojurebot: (({:auth true, :b 5} {:c 4}) ({:b 7} {:auth true, :c 6}))

10:19 mskoud: Thanks!

10:20 llasram: clojurebot: what I tell you two times is my-lits

10:20 clojurebot: In Ordnung

10:20 llasram: Oops. Oh well

10:23 hyPiRion: clojurebot: what I tell you two times?

10:23 clojurebot: what I tell you two times is my-lits

10:23 hyPiRion: tehee

10:33 gfredericks: clojurebot: what I tell you three times is my-vectrs

10:33 clojurebot: Ik begrijp

10:43 Bronsa: 15:17:03 <clgv> ever seen that one: "CompilerException java.lang.VerifyError: Unable to pop operand off an empty stack" ?

10:43 uuuh I want to see that

10:44 clgv: Bronsa: https://www.refheap.com/86018

10:45 Bronsa: oh, yeah

10:45 clgv: the correct way to do it is (defn a ^doubles [] ..)

10:45 clgv: Bronsa: huh? tags are always on the symbol and primitive types on the argument vector

10:46 or did that change with 1.5/1.6?

10:47 Bronsa: clgv: tagging the var sym with a primitive return value never made the fn exploit the invokePrim optimization

10:47 you have to tag the argvec

10:48 clgv: Bronsa: afaik ^doubles does not make a function primitive, mind the "s" at the end. I want to tag that this function returns a double array

10:48 Bronsa: also, metadata on the var sym will be evaluated see http://clojure.org/special_forms#Special%20Forms--(def%20symbol%20init?)

10:48 TimMc: peterdon: Or https://github.com/baznex/imports

10:49 gfredericks: so weird to see rhickey arguing on reddit

10:49 Bronsa: clgv: oh, right. my point still holds anyway

10:49 clgv: Bronsa: hu why?

10:49 hyPiRion: gfredericks: huh where

10:49 llasram: gfredericks: ditto

10:49 (the "huh where" part)

10:49 Bronsa: because metadata is evaluated on the symbol of def, you're not tagging with 'doubles but with the _function_ doubles

10:50 clgv: so either (defn ^{:tag 'doubles} a [] ..) or (defn a ^doubles [] ..)

10:50 clgv: Bronsa: so ^'doubles is correct?

10:50 gfredericks: hyPiRion: two years ago: http://www.reddit.com/r/programming/comments/lirke/simple_made_easy_by_rich_hickey_video/

10:50 Bronsa: I guess

10:50 llasram: *brain explodes* wrt `doubles`

10:50 Bronsa: clgv: probably it's '^doubles

10:50 clgv: Bronsa: damn someone should clean that syntax up.

10:51 Bronsa: clgv: nevermind, neither '^ or ^' works.

10:51 clgv: as a rule of thumb, always prefer tagging the argvec

10:51 clgv: Bronsa: at least some compiler errors would be good if strange stuff is added as tag

10:51 llasram: Actually, I think '^doubles means "quote the next form and attach {:tag doubles} as metadata"

10:52 ,'^double foo

10:52 clojurebot: foo

10:52 clgv: Bronsa: does tagging the argvec work for normal classes?

10:52 Bronsa: clgv: agreed. I've made it throw an exception in tools.analyzer.jvm

10:52 llasram: Oh, "neither"

10:52 hyPiRion: gfredericks: heh

10:52 clgv: Bronsa: what happens with different tags on multiple arity implementations?

10:52 Bronsa: clgv: what you'd expect

10:53 clgv: tagging the argvec has a shortcoming too though

10:53 clgv: Bronsa: humm how can the compiler infer the return type in case of apply?

10:53 gfredericks: hyPiRion: there's a long exchange with psnively further down

10:53 Bronsa: the class is not resolved so if you have (ns a (:import some.class)) (defn x ^class [] ..)

10:53 clgv: Bronsa: it cant right?

10:53 Bronsa: and (ns b (:use a))

10:53 (.someMethod (x)) will not works

10:54 hyPiRion: gfredericks: currently reading it. Interesting, as I've never really heard rhickey's argument on types

10:54 Bronsa: you have to either tag with the qualified tag or import the class in b too

10:54 clgv: no it can't

10:54 clgv: :(

10:54 Bronsa: that should be on the agenda for the next release...

10:56 gfredericks: hyPiRion: ditto; the most I've gotten from most clojure community folks is question-begging dismissal

10:59 I guess snively got the last word there

11:01 hyPiRion: gfredericks: on the Internet, the last one to bed is the winner

11:07 TimMc: hyPiRion: But the internet spans all time zones... Oh.

11:07 I see.

11:20 Glenjamin: wow, thats a fun exchange of views

11:38 szymanowski: Hi, what is the way to redefine assoc method for a record?

11:43 cbp: Maybe you want to use deftype instead?

11:50 szymanowski: yes I'm I will go with deftype

11:51 AWizzArd: cbp: And? Already tried out the slider?

11:51 cbp: AWizzArd: I left that aside for a bit. Can you link me? :)

12:00 AWizzArd: cbp: https://bitbucket.org/athieme/om-widgets

12:02 cbp: AWizzArd: thanks!

12:21 rasmusto: I'd like to host some jars on my own server, what's a good place to start?

12:22 ohpauleez: rasmusto: Like your own maven repo?

12:22 or just host them for downloads

12:22 rasmusto: ohpauleez: yeah

12:22 ohpauleez: hang on, grabbing a link

12:22 rasmusto: ohpauleez: something that I'd be able to point leiningen at

12:22 llasram: rasmusto: I have only good things to say about Archiva http://archiva.apache.org/index.cgi

12:22 ohpauleez: rasmusto: http://cemerick.com/2010/08/24/hosting-maven-repos-on-github/

12:23 You can follow that, or use the general idea

12:23 rasmusto: llasram: ohpauleez: thanks :)

12:23 ohpauleez: np!

12:23 totally welcome

12:24 technomancy: rasmusto: the simplest thing is to just serve jars with nginx if they're not going to be changing frequently

12:24 cemerick: ohpauleez, rasmusto: private s3 repos are fundamentally better https://github.com/technomancy/s3-wagon-private

12:25 ohpauleez: cemerick: rasmusto: That's a good point - recently, I've done that (used s3)

12:26 rasmusto: technomancy: at this point, it'll only be at most a few new releases a day

12:27 technomancy: rasmusto: that's kind of a lot; you probably need `lein deploy` support for that then

12:27 one thing I am curious about but have never looked into is how the scp transport for aether works

12:28 because theoretically you could use that without a bunch of new infrastructure

12:28 never really looked into it though

12:31 man, if you could just auth with your SSH keypair that would save a lot of headache with gpg

12:31 why haven't I tried this before

12:31 ssh-agent works basically everywhere

12:38 rasmusto: my "deployment" strategy right now for python stuff is to scp stuff to a server that serves it with httpd

12:39 technomancy: rasmusto: it should be possible to make `lein deploy` scp stuff to the right place where nginx can serve it up

12:40 rasmusto: technomancy: s/nginx/httpd ? It would be nice to not have to modify the server setup

12:40 technomancy: cemerick: does this look reasonable to you? (aether/register-wagon-factory! "scp" (resolve 'org.apache.maven.wagon.providers.ssh.jsch.ScpWagon))

12:40 rasmusto: sure, whatever

12:41 rasmusto: technomancy: awesome, I'd love to make this work. I assume I need pomegranate as a dep?

12:42 technomancy: rasmusto: lein has pomegranate already

12:42 rasmusto: ah, cool.

12:42 technomancy: registering the scp wagon with pomegranate seems to have no effect though

12:42 weird

12:47 rasmusto: technomancy: is the register-wagon-factory! something you are putting into project.clj somewhere?

12:48 technomancy: rasmusto: I added it to lein itself, but it's not working

12:48 Viesti: puuh

12:48 rasmusto: hm, gotcha

12:50 Viesti: caching with core.cache/core.memoize is turning out to be surprisingly hard, they are almost there but not quite... :/

12:50 rasmusto: Viesti: what specifically are you trying to cache?

12:50 Viesti: the composing idea with core.cache is neat, I needed TTL with a limit on items

12:51 but then it turns out that TTLCache has a performance issue

12:51 CCACHE-15

12:52 tried to fix it, but then turns out that the secondary structure it keeps doesnt keep up with the limit but eats everything until ttl expires

12:52 slightly gave up and looked at memcached clients

12:53 ran into mcache but it didn't seem to play nice with core.memoize, tried out spyglass and ran into same issue

12:53 "ClassCastException clojure.lang.ArraySeq cannot be cast to java.lang.String"

12:54 I'm caching queries from mongodb

12:54 maybe I'll get there, but thought that this would be easier... :)

12:57 the problem with memcached backend to core.memoize seems to be how arguments are handled: https://github.com/clojure/core.memoize/blob/master/src/main/clojure/clojure/core/memoize.clj#L145

12:58 the "[& args]" turns args into clojure.lang.ArraySeq

12:58 which gets passed onto some spyglass function that expects a string :P

12:59 sorry everyone, has to air out thoughts...

13:01 noncom: that's perfectly fine

13:01 rasmusto: technomancy: would it be (register-wagon-factory! "scp" #(org.apache.maven.wagon.providers.ssh.jsch.ScpWagon)) ?

13:02 technomancy: rasmusto: hah, literally just realized that like thirty seconds ago

13:02 rasmusto: technomancy: :)

13:04 mi6x3m: hey clojure, is there a web browser component for seesaw?

13:04 preferably something based on xulrunner

13:06 technomancy: rasmusto: this seems to do the trick: https://www.refheap.com/86021

13:08 we could get rid of the manual registering of wagons if we read plexus components.xml from lein

13:08 but that is probably a huge bucket o worms

13:08 rasmusto: technomancy: awesome, I'll give that example a shot

13:08 is "dh" a username?

13:09 technomancy: rasmusto: no, it's just the repo name

13:09 so you'd deploy with `lein deploy dh`

13:09 use "releases" to make it work with `lein deploy`

13:09 rasmusto: ah, okay. It'll just auth with the current user?

13:09 technomancy: rasmusto: usernames should go in .ssh/config

13:09 rasmusto: gotcha, thanks

13:10 PigDude: i wish there were something like epmd for clojure

13:10 is there?

13:12 cbp: $google epmd

13:12 lazybot: [EPMD - Wikipedia, the free encyclopedia] http://en.wikipedia.org/wiki/EPMD

13:12 PigDude: epmd is the erlang port manager daemon

13:13 technomancy: PigDude: running multiple clojure instances on a single machine doesn't really make sense

13:13 PigDude: for that kind of distributed workflows most people use a message broker like rabbitmq or something

13:13 PigDude: ok, thanks, i was just curious as it seemed a natural extension of the nrepl

13:13 technomancy: erlang is really good at that kind of thing; you can write application code in clojure and still let erlang handle message passing across a cluster =)

13:14 PigDude: true :)

13:14 technomancy: if you want to go nuts you could try mashing up erjang and clojure

13:15 PigDude: technomancy: hehe https://github.com/oubiwann/erlang-clojure-node/blob/master/src/clj_controller.erl

13:16 technomancy: hoo boy =) fun

13:16 PigDude: i was looking to see if somebody was making clojure ports for erlang

13:17 but clojure being on jvm, makes more sense to justuse the java api rather than to make a port

13:18 right now i am not looking to integrate them though, i just find myself only wanting to program in lisps now that i am using clojure professionally

13:19 technomancy: well there's nothing as nice as otp on the jvm except for maybe with erjang

13:19 it's pretty amazing the level of compatibility he was able to achieve as a solo hacker on that project

13:19 probably because erlang is a very small language

13:19 PigDude: well there's Pulsar and Akka i suppose

13:20 technomancy: yeah... ehrm.

13:20 they're a step in the right direction, but really nowhere near as nice

13:21 PigDude: i have no experience with either, but lots w/ otp and i too like it

13:30 elchaty: hi all

13:30 noncom: hi!

13:30 elchaty: in clojure if I have variable x how can I test to see if that variable is ISeq?

13:31 mi6x3m: elchaty: (seq? my-var) ?

13:31 gtrak: elchaty: no variables :-)

13:31 rasmusto: technomancy: I had to use ssh-agent/add /and/ tell `lein deploy serv` my username/password. Will this go away if I just add credentials somewhere?

13:31 elchaty: (seq? [1 2]) is false

13:31 forget about the variable thing

13:31 technomancy: rasmusto: the password prompt will go away in 2.4.0

13:31 gtrak: elchaty: sequential?

13:31 elchaty: how to test is somethig is collection or not

13:31 any

13:31 clgv: ,(seqable? [1 2])

13:31 clojurebot: #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: seqable? in this context, compiling:(NO_SOURCE_PATH:0:0)>

13:31 elchaty: sequential? let me try that

13:32 rasmusto: technomancy: ok, thanks again for your help :)

13:32 elchaty: (sequential? [1 2]) works!

13:33 mi6x3m: elchaty: see (doc seq?) it does exactly what you want (ISeq test)

13:33 or you just wanted a collection test?

13:33 elchaty: seq? with a vector returns false

13:33 sequential? is what I was looking for. Thanks gtrak

13:34 clgv: &(-> [] class ancestors)

13:34 lazybot: ⇒ #{java.util.Collection clojure.lang.IPersistentStack java.lang.Object clojure.lang.IPersistentCollection clojure.lang.AFn java.lang.Iterable clojure.lang.Reversible clojure.lang.IObj clojure.lang.APersistentVector java.util.concurrent.Callable clojure.lang.Indexed ja... https://www.refheap.com/86023

13:35 clgv: elchaty: vector does indeed not implement ISeq but Seqable

13:38 kwertii: Anyone use Friend-OAuth2? I’m setting it up as per the example code, but it’s redirecting unauthenticated users to “/login” (the default Friend URL) rather than to the 3rd party site. Is this what it’s supposed to do?

13:38 cemerick: technomancy: looks sane

13:39 elchaty: clgv I didn't know that vector didn't implement ISeq

13:39 technomancy: cemerick: my mistake was returning a class instead of a fn that calls the constructor

13:39 works fine now

13:39 cemerick: seems like with all the trouble people have with s3 creds, documenting ssh deploys could save a lot of headache

13:39 cemerick: oh, factory-fn

13:40 I guess so? I haven't had any stable deployment targets in years.

13:40 technomancy: what are the troubles?

13:41 technomancy: cemerick: mostly gpg being a pain on macintoshes

13:41 Pourletain: cemerick

13:41 what is your opinion on people who use 'who' in object position.

13:41 Like "These foolish children have no idea who they are dealing with."

13:41 clgv: elchaty: now you do :D

13:41 technomancy: there's just a ton more good tooling around SSH already

13:42 cemerick: technomancy: I don't recall having any trouble when I was in Mac-land, but I can imagine it.

13:42 Pourletain: My opinion is that anyone asking me that question is trolling. ;-)

13:43 Pourletain: I don't have any problem with that example sentence though. Why?

13:45 Pourletain: cemerick, because it should be "these foolish children have no idea whom they are dealing with."

13:45 In this case "who" is the object of "with".

13:46 cemerick: yeah, ok

13:46 Why, man, why?

13:47 llasram: I'd argue that pretty much any use of "whom" sounds stilted to the contemporary ear, outside of very formal contexts

13:47 gtrak: being pedantic about english grammar is like polishing a turd.

13:47 Pourletain: cemerick, because it's an object.

13:47 You don't say "he they are dealing with" but "him they are dealing with" do you not?

13:47 kwertii: Language and grammar are living and changing things; “whom” is now archaic and disused

13:47 Pourletain: llasram, I disagree.

13:47 erlis: speak clojure

13:47 llasram: To whom are you talking, my good sir? vs Who are you talking to?

13:47 erlis: not english

13:47 cemerick: Pourletain: no, I mean, why are/were you asking me?

13:48 Pourletain: Use of who in object position clearly betrays one as an uneducated snail who never went to oxford or something similar.

13:48 cemerick, I have no idea.

13:48 kwertii: the death of “whom” has been well studied by linguists

13:48 even “respectable” authors now routinely omit “whom”

13:48 cemerick: Pourletain: that's…bizarre?

13:48 Pourletain: Yes well, most people are then again cattle who didn't go to Oxford or Cambridge or something else awesome.

13:48 llasram: Down with "whom"!

13:48 Pourletain: cemerick, well, yes, I am kind of bizarre.

13:48 Never.

13:48 * llasram burns "Whom" in effigy

13:48 Pourletain: I shall stand as the last bastion of proper grammar.

13:49 cemerick, what is your opinion about people who say "I think you're taller than her.' rather than 'taller than she' though.

13:49 dbasch: (= :who (first bases))

13:49 Pourletain: It is truly a failing of the school system that I once heard a professional newscaster use the former.

13:50 llasram: Pourletain: You may need a hobby. I suggest Clojure! Well, unless you use professionally

13:50 cmiles74: I would say a failing of the culture. It is simply not valued.

13:50 kwertii: “proper” grammar is merely a psychological construct foisted by self-appointed prestige groups to promote their own superiority. Linguists almost universally rejected “prescriptive grammar” many decades ago

13:51 llasram: kwertii: But without class markers how will he know which people we're better than?

13:51 Pourletain: kwertii, I don't see how a linguist can reject that because it has nothing to do with linguistics.

13:51 llasram: s,he,we,

13:51 Pourletain: Linguistics is a descriptive science. This is like saying that psychologists reject the idea of the law.

13:51 gtrak: people still program in PHP, too. But I don't interop with them.

13:51 Pourletain: Psychology studies human behaviour, the law tells people how to behave, both are completely unrelated.

13:51 technomancy: llasram: that's why we have windows.

13:52 kwertii: Pourletain: well, there’s a huge body of work in the subfield of sociolinguistics that goes over that question in excruciating detail, if you’re interested

13:52 llasram: Nice

13:52 Pourletain: Also, the proper spelling is of course præscriptive.

13:52 The spelling you used is abomination indicative of never been educated in Latin.

13:52 Such atrocities need to be weeded out of course.

13:53 gtrak: http://www.oxforddictionaries.com/us/definition/american_english/twerk

13:53 kwertii: “The abuse of grammar is something up with which I will never put!”

13:53 rasmusto: gtrak: it's "twerkm"

13:54 cmiles74: Pourletain: You're fighting a losing battle on that one. They will not make the US English keyboard larger.

13:54 Pourletain: Dead keys are a convenience.

13:54 llasram: I think Pourletain has transitioned to pure trolling. Maybe started there?

13:54 maxmartin: transitioned to?

13:54 cemerick: Pourletain: I'm as much of a pedant as anyone else, but I wouldn't think less of someone for not using proper grammar. Anyway, not into OT grammar quizzes in irc. :-)

13:54 Pourletain: cemerick, pædant*

13:55 surely.

13:55 maxmartin: so glad I'm in this room to catch all the useful discussion about Clojure

13:55 Pourletain: Damn, I am good at this.

13:56 technomancy: Pourletain: either that or people in this channel are really bad at it

13:59 arrdem: Bronsa: ping

13:59 Bronsa: arrdem: pong

14:00 dbasch: I’ve been wanring to build an implementation of Shamir’s Secret Sharing Scheme in clojure for a while but my brain is not letting me get started

14:00 wanting

14:01 Jaood: dbasch: disconnect from the internet ;)

14:01 dbasch: Jaood: but then how can I steal other people’s code? :P

14:02 arrdem: Bronsa: so I just got lambda lifting working, but there's one dirty trick I'm playing I'd like to check with you. I replace lifted functions with a partial that takes the used locals and makes them explicit parameters. To do this I have to analyze the partial in the same environment that I lifted the inline fn out of, which means that I just steal the :env key and reuse that environment exactly. It works, but does that make sense to you?

14:02 Ex. (let [x 3] ((fn [y] (+ x y)) 4)) -> (def fn_9001 ([x y] (+ x y)), (let [x] ((partial fn_9001 x) 4))

14:05 Bronsa: arrdem: yeah, that's what :env is there for

14:05 arrdem: Bronsa: sweet, thanks.

14:11 Viesti: seems that Immutant has a workaround for use with core.memoize https://github.com/immutant/immutant/blob/1.1.1/modules/cache/src/main/clojure/immutant/cache.clj#L143-L149

14:12 Jaood: dbasch: so much dependence

14:12 !

14:19 jcrossley3: Viesti: the comment for that commit might help to clarify what it's doing: https://github.com/immutant/immutant/commit/d1bcbccbe1

14:19 it's not really a workaround. it's just storing the delay in ram until it's actually realized.

14:22 rasmusto: technomancy: artifact is gpg signed, and scp deployed to a directory that's symlinked into /var/www, love how easy that was

14:23 technomancy: rasmusto: yay!

14:23 rasmusto: technomancy: that's definitely wiki worthy

14:24 technomancy: rasmusto: rather have it in the official docs

14:25 rasmusto: that works too :)

14:26 amalloy: arrdem: i don't understand the value of doing this lifting and replacing with partial

14:27 arrdem: amalloy: it exposes otherwise closed over functions as top level defs that I can play with, merge and inline without introducing special case code to handle inline lambdas.

14:27 amalloy: no expected performance gain just from doing this, but it's a transformation enabler.

14:33 Viesti: jcrossley3: yep, the first time I looked at the metadata kept by the memoized function, was a little puzzled an kind of dismissed it but now I'm getting the hang of it

14:33 samrat: in this macro, https://www.refheap.com/86025 why does unquoting happen properly with the `filters`?

14:34 Viesti: really it seems that keys get stored as clojure.lang.ArraySeq instances and values are deferreds

14:34 jcrossley3: Viesti: yep

14:35 the keys correspond to the args passed to the memoized fn

14:35 samrat: damn, I meant "why does unquoting _not_ happen properly"

14:37 Viesti: yep so the "rest args" is neat in that case

14:38 using memcached with core.memoized would be more simplistic, keys would be just strings

14:38 but it's a little weird..

14:38 memoization is more generic thing

14:40 l3dx: how can I get the indices [x y] of a 2d vector where the "cell" value matches some predicate? is map-indexed the way to go?

14:40 rasmusto: l3dx: sounds like it

14:41 Viesti: or well, I could have function that takes any number of arguments, does something, and the value would be stored to memcached

14:41 dbasch: samrat: why do you say unquoting doesn’t happen properly? do you have an example usage for that macro? what do you expect it to do?

14:42 Viesti: the thing is to encode the arguments so that memcached is pleased

14:42 samrat: dbasch: when I call it like (test-macro my-filters), I get Don't know how to create ISeq from: clojure.lang.Symbol

14:42 dbasch: samrat: what is my-filters?

14:44 samrat: dbasch: just a var. something like (test-macro [{:term "a" :op "foo" :vals "bar"}] works

14:49 amalloy: samrat: the macro receives a symbol, not the symbol's value

14:49 dbasch: samrat: unquote works, it just evaluates filter to the symbol

14:49 amalloy: or rather, not the value of the var named by the symbol

14:49 dbasch: filters

14:49 (eval filters) would do it

14:50 amalloy: dbasch: :(((((

14:50 only in the most simplistic of circumstances

14:50 dbasch: amalloy: yeah, not the best way

14:51 what is the macro supposed to do anyway?

14:51 samrat: dbasch: its a simplified version of something else

14:51 dbasch: so that macro itself is pretty useless

14:51 gastove: o

14:52 samrat: amalloy dbasch : what would the right way to have this work then?

14:52 amalloy: samrat: it's impossible to say, since this macro is, as you say, useless. how can you make it work if it doesn't make sense?

14:52 instead, describe a real problem you're having, and then solutions to that will be helpful

14:52 dbasch: samrat: what do you want this code to look like after macro expansion?

14:55 samrat: amalloy dbasch: I'm writing a macro that generates a function that takes a list of filters described in maps, and returns a predicate function that will check for those filters.

14:55 dbasch: samrat: why does it need to be a macro?

14:56 samrat: amalloy: I've already written that macro however I cannot call it with symbols bound to filters, but I can use it with just filters

14:56 amalloy: samrat: that was dbasch, not me. but i agree with him: this should be a function

14:57 you've already written a macro which "works", except in the cases where you want it to work (ie, with def'd values instead of inline source code) - and it won't work in those cases, because that's what functions are for, not macros

15:02 {blake}: I am reconfused by this: https://www.refheap.com/86027 (It's an attempt to allow the caller to access a parsed/zipped xml through a series of tags.)

15:03 Aw...crap...

15:04 samrat: amalloy : alright I'm thinking about this. I now have a function that returns a list, which I can `eval` to get the predicate that I want. Is there a better way to get the function itself?

15:05 or do I need to eval it?

15:06 dbasch: samrat: if you have a list of functions you don’t need to eval anything, you can compose them or juxtapose them or whatever you need to do to create the function you want

15:08 samrat: dbasch: no. I am using the `reduce` to avoid having a list of functions. Only one function is returned. Hence, I need the `reduce` to run when `test-macro` is called

15:11 amalloy: {blake}: are you confused about anything in particular? it's tough to help with "this is some code, i'm confused"

15:12 dbasch: samrat: post the refheap

15:13 {blake}: amalloy, Yeah, it's a structural thing. I'm passing a vector of hashes, then I'm trying to take a vector of hashes out of that to pass recursively, but...I'm not. I think. That printout makes it look like I am. (But I think there's some laziness there, since it also looks like I'm returning the output of my printlns.)

15:14 The result of (by-tags sample :L1 :L2) should be [{:tag :L2 :content [{:data :stuff}]}]

15:15 amalloy: well, it's close to that; you just have an extra () at the end

15:15 samrat: dbasch: https://www.refheap.com/86028

15:15 {blake}: amalloy: Eh...no, I think that's just the result of the printlns. If I take the printlns out I get "(())".

15:16 amalloy: and why is that? the only obvious error, to me, is that you're calling by-tags incorrectly in the recursive case: it wants varargs

15:16 ah. well, that's what you get for putting all these printlns in the middle of lazy code :P

15:16 really, {blake}, i'd say just remove the & from by-tags's signature - it's not doing anyone any favors

15:16 {blake}: amalloy, That sounds promising. And, yeah, I realize I'm...either too lazy or not lazy enough. I'm not the precise amount of lazy.

15:16 amalloy: then call (by-tags sample [:L1 :L2])

15:17 {blake}: amalloy, Oh...have them pass in a vector?

15:17 'k lemme see

15:17 gfredericks: samrat: what happens when you write this as a function?

15:19 samrat: gfredericks: I get a list which I can eval to get the function that I want.

15:21 llasram: samrat: What if instead of `eval`ing something you just return a closure?

15:21 {blake}: amalloy, OK, thanks, that worked.

15:21 (inc amalloy)

15:21 lazybot: ⇒ 113

15:23 samrat: llasram: not sure what you mean. But I need some computation done when test-macro is called- the reduce needs to get evaluated.

15:24 {blake}: (I really thought I =was= doing someone favors with the whole "& tags" thing.)

15:25 llasram: samrat: sure, so do something like (defn whatever [filters] (let [fs (map ... filters)] (fn [obj] (every? #(% obj) fs))))

15:25 amalloy: samrat: you can write it easily enough as a function with the basic outline of https://www.refheap.com/01d532c4d8e897f3a23217243

15:26 which, not coincidentally, is what llasram just said, but more fleshed out

15:28 llasram: You can pump out code waaay faster when the code doesn't even need to parse :-D

15:28 gfredericks: downside to stuartsierra/component: wrapping a component is hard.

15:29 amalloy: llasram: 14 seconds is hardly waaaaay faster. i'll race you any day

15:29 llasram: :-)

15:32 amalloy: just edited the paste with a slightly more performant version, pre-caching the (set vals) version. <3 (fn (let (fn (let ...))))

15:32 gfredericks: amalloy: time to use the <<- from swiss-arrows

15:33 amalloy: wat

15:33 {blake}: Can "recur" only be used with loop? And is that the only form of tail recursion in Clojure?

15:34 amalloy: {blake}: loop or the start of a function

15:34 AimHere: Well recur recurs either to the enclosing loop, or to the enclosing function

15:34 There's also trampoline

15:34 gfredericks: amalloy_: https://github.com/rplevy/swiss-arrows#the-back-arrow

15:34 {blake}: amalloy_, AimHere: Thanks, that's what I thought, but all the examples I found only used recur with loop.

15:34 AimHere: ,(recur)

15:34 gfredericks: &(recur)

15:34 clojurebot: Execution Timed Out

15:35 lazybot: Execution Timed Out!

15:35 gfredericks: lazybot is more enthusiastic about timeouts

15:35 arrdem: gfredericks: why would you use that...

15:35 AimHere: You know, of the two, I'd think lazybot would be the least enthusiastic one

15:36 samrat: amalloy_: ok, thanks a lot for the help. I'll take a better look at it in the morning.

15:36 gfredericks: arrdem: why would you use swearjure?

15:37 {blake}: Swearjure: Befunge for a new generation...

15:40 gfredericks: we need a word like ninja or rockstar but for swearjure programmers

15:40 an anchor for recruiters to cling to

15:40 {blake}: H.P. Lovecraft might be a good source for that.

15:42 arrdem: 1% of the elder gods control 90% of the evil!

15:42 {blake}: Occupy Ryleh!

15:42 arrdem: how about we don't I like my sanity where it is thank you...

15:43 we'll all be cthulu snacks eventually but I'd rather postpone that fate if possible

15:51 arohner: are there any other core.async buffer implementations? I'm thinking I want a core.async buffer that uses a circular buffer (i.e. array) rather than a linked list

15:52 because I want to take > 1 value off a channel at once

15:53 arrdem: doesn't that violate the core async state machine structure? you can take multiple values, but each time you take a value you "block" on the channel to provide a value which is really a callback to the producer structure to emit values AFAIK.

15:54 arohner: though I guess things might work if I put byte[] as 'values' onto the chan

15:54 my goal is to take all values I can w/o blocking

15:55 gfredericks: hey rhickey is keynoting at lambdajam maybe he will prove once and for all that static types are the devil

15:57 arrdem: he's welcome to say that, but a lot of people myself included will disagree.

15:57 mskoud: ,(partition-by #(= % 3) [1 2 3 4 5 6 3 7 8])

15:57 clojurebot: ((1 2) (3) (4 5 6) (3) (7 8))

15:58 mskoud: but i really wanted ((1 2) (3 4 5 6) (3 7 8))

16:02 {blake}: OK, so, now my by-tags digs down and finds the path :L1 :L2 :L3 (etc) but of course it returns the answer nested for each layer (((L3-stuff))). I really just want "L3-stuff".

16:03 flatten?

16:03 clojurebot: flatten is rarely the right answer. Suppose you need to use a list as your "base type", for example. Usually you only want to flatten a single level, and in that case you're better off with concat. Or, better still, use mapcat to produce a sequence that's shaped right to begin with.

16:03 {blake}: heh

16:04 gtrak: arohner: cljs version uses circular buffers

16:05 https://github.com/clojure/core.async/blob/master/src/main/clojure/cljs/core/async/impl/buffers.cljs#L23

16:06 gfredericks: haha my such-that just blew up after 10 tries and I have no idea which one it was. thank you combinators and your useless stack traces.

16:09 gtrak: gfredericks: swearjure impressionists.

16:09 gfredericks: mskoud: might be easiest to just write your own recursive lazy function

16:10 gtrak: maybe not extreme enough.

16:14 swearjure radicals.

16:15 rasmusto: swashbucklers

16:15 gtrak: omg, pirates!

16:15 ninjas, rockstars, pirates.

16:15 obvz

16:17 gfredericks: gtrak: but still using the word "swashbucklers"?

16:18 TEttinger: code khans

16:18 digital spartans

16:18 joelkuiper: can't brain today. Say I have two vectors of maps [{:a 1 :b 2} {:a 3 :b 4}] and [{:a2 1 :b2 2} {:a2 3 :b2 4}] and I wish to merge them such that the result will be a new vector [{:a 1 :a2 1 :b 2 :b2 2} {:a 3 :a2 3 :b 4 :b2 4}]

16:18 what would be the easiest way to do so?

16:18 messed up the example, but you get the ide

16:19 rasmusto: ,(map merge [{:a 1 :b 2}] [{:c 3 :d 4])

16:19 clojurebot: #<RuntimeException java.lang.RuntimeException: Unmatched delimiter: ]>

16:19 rasmusto: ,(map merge [{:a 1 :b 2}] [{:c 3 :d 4}])

16:19 clojurebot: ({:d 4, :c 3, :b 2, :a 1})

16:20 joelkuiper: do totally forgot about the & cols on map, thanks rasmusto

16:20 rasmusto: joelkuiper: np

16:22 gfredericks: why on earth would you throw an ExceptionInfo with an empty map?

16:23 rasmusto: whom is throwing ExceptionInfo?

16:23 hiredman: you just want to watch the world burn

16:28 gfredericks: https://github.com/clojure/test.check/blob/master/src/main/clojure/clojure/test/check/generators.clj#L258-259

16:28 reiddraper: when I first saw the limit-10 on such-that I thought it was terrible and now that I've run into for the first time I think it's great

16:35 reiddraper: gfredericks: happy to hear that

16:48 whodidthis: http://docs.oracle.com/javase/8/docs/api/java/time/Instant.html#now-- how do i get one of these bad boys in clojure

16:50 dbasch: whodidthis: are you running java 8?

16:51 whodidthis: yes, am just confused how to interop one of them cool instants

16:51 dbasch: do you really need nanosecond precision?

16:52 whodidthis: well, that or localdatetime, more interested in minus/plus functionality without joda

16:53 dbasch: what’s the confusing part? can’t you treat them like any other java classes?

16:53 whodidthis: old style date thingie is (java.util.Date.), instant is (. now java.time.Instant) but that doesnt work cause im a bad

16:53 dbasch: (java.time.Instant/now)

16:53 it’s a static method

16:53 whodidthis: sweet, thanks

17:01 technomancy: whoa, somehow I missed that 310 made it in

17:02 makes it sting all the more than clojure ships with j.u.Date support by default =(

17:02 gfredericks: 310?

17:02 technomancy: jsr 310

17:02 temporal units that aren't a disaster

17:03 gfredericks: do we need a lib for setting #inst to the new stuff?

17:03 technomancy: I think it's just a data_readers entry

17:04 arrdem: gfredericks: you can't write a lib for that unless it crowbars into core..

17:04 only namespaced reader lits are user accessible.

17:04 technomancy: rich said he was debating having the default data_readers blow up if 310 wasn't available, but sadly that didn't happen =\

17:06 gfredericks: technomancy: you know I'm starting to wonder if you might have something against java.util.Date.

17:06 arrdem: Bronsa: ping

17:06 technomancy: gfredericks: "why should I change; he's the one that sucks", &c

17:07 arrdem: Bronsa: https://www.refheap.com/86030

17:07 gfredericks: arrdem: really? I coulda sworn you can do those things as long as you don't tell rich

17:07 arrdem: gfredericks: here take this crowbar it's dangerous to go alone

17:08 Fare: how do I use maths functions?

17:09 Bronsa: arrdem: ouch.

17:09 Fare: (use 'clojure.math.numeric-tower) => FileNotFoundException Could not locate clojure/math/numeric_tower__init.class or clojure/math/numeric_tower.clj on classpath: clojure.lang.RT.load (RT.java:443)

17:09 seancorfield: Fare: sounds like you didn't add the dependency to project.clj?

17:09 arrdem: Bronsa: T_T I'm getting started on dealing with letfn and that guy cropped up.

17:09 Fare: what project.clj? All I did was M-x cider-jack-in

17:10 seancorfield: Fare: to use anything other than core Clojure, you need a "project" (created by Leiningen) that lists dependencies

17:11 kenrestivo: clojurebot: java.util.Date is Michael Bolton

17:11 clojurebot: Ok.

17:11 Fare: ok. What if I'm not using leiningen?

17:11 warlock: clojurebot: crowbar is when all else fails just alter-var-root!

17:11 clojurebot: Ok.

17:12 Bronsa: arrdem: looking into it

17:12 arrdem: Bronsa: Thanks. I'm gonna reup on the coffee and take a look myself.

17:12 technomancy: rich said on an application level it would be OK to make #inst use something else

17:13 but that may have been before the design was finalized

17:13 kenrestivo: i was amused that in one of rich's projects, instead of fixing a bug in an upstream library and submitting a pull request, he just copy/pasted the function's code into his own project, fixed the bug, and alter-var-root patched it

17:14 arrdem: Crowbars: even the language designer uses them, why don't you!

17:14 seancorfield: Fare: what are you using for dependency management then if you're not using Leiningen?

17:14 Fare: hint: use Leiningen :)

17:15 hiredman: technomancy: well, that is sort of the point of data readers, to disentangle the semantics of serialized data from the actual type in memory

17:15 gfredericks: arrdem: now that technomancy mentions it I think changing the behavior of the core data readers was completely intended

17:15 ,default-data-readers

17:15 technomancy: yeah, one would hope you'd be able to reverse the brain damage of the defaults

17:15 clojurebot: {inst #'clojure.instant/read-instant-date, uuid #'clojure.uuid/default-uuid-reader}

17:16 gfredericks: arrdem: and I've definitely done this at an app level, e.g. with clj-time/joda

17:16 amalloy: Fare: if you're not using leiningen, use leiningen

17:16 technomancy: doing it in a library might be mildly sketchy? dunno.

17:16 amalloy: it's so much better than the alternative

17:16 PigDude: ,(defn update [m ks f] (let [v (select-keys m ks)] (merge m (zipmap (keys v) (map f (vals v)))))) (update {:a "2" :b "3"} [:a :b] #(Integer. %))

17:16 clojurebot: #'sandbox/update

17:16 PigDude: is there something like this in clojure.core?

17:16 ,(update {:a "2" :b "3"} [:a :b] #(Integer. %))

17:16 clojurebot: {:b 3, :a 2}

17:17 technomancy: PigDude: map-keys and map-vals are conspicuously absent for some reason

17:17 PigDude: ok, thanks

17:17 yea, those are better names

17:17 arrdem: PigDude: there is an open proposal for _a_ update function, but it behaves differently than what you described.

17:17 amalloy: technomancy: he actually didn't wriet map-vals, there

17:17 gfredericks: PigDude: they're conspicuously present in prismatic/plumbing

17:17 technomancy: amalloy: oh, hrm

17:18 amalloy: overzealous irc pattern matching strikes again

17:18 amalloy: PigDude: http://dev.clojure.org/jira/browse/CLJ-1251 is why it doesn't yet exist; https://github.com/flatland/useful/blob/develop/src/flatland/useful/map.clj#L127-L134 is an implementation in useful

17:19 PigDude: amalloy: is it better to use update-in than to just straight-away recreate the map?

17:19 amalloy: (using zipmap like mine)

17:21 Bronsa: arrdem: it's a bug in the collect-closed-overs pass

17:21 Fare: ok.

17:21 amalloy: PigDude: if you have a large map and you're updating each key in it, building a new map and then merging it is pointlessly expensive, compared to updating the existing one in place

17:22 PigDude: makes sense

17:22 my first one was using reduce like yours but i didn't like how it looked

17:22 arrdem: Bronsa: shall I kick off a ticket for it?

17:22 also looking into that pass because I just build something very like it...

17:23 Fare: How do I tell emacs which project to use?

17:23 do M-x cider-jack-in while the current directory is under the project?

17:23 technomancy: Fare: yeah, it's based on the current dir

17:24 Bronsa: arrdem: yeah go on open a ticket

17:25 amalloy: PigDude: i mean, you can write it differently if you don't like reduce: (into m (for [k ks :let [e (find m k)] :when e] [(key e) (f (val e))]))

17:25 but i don't think that reads better

17:25 seancorfield: Fare: if you have Leiningen installed, you could say: lein new mathtest - to create a project, then edit project.clj and add [org.clojure/math.numeric-tower "0.0.4"] as a dependency, then edit src/mathtest/core.clj and jack in and you'll be off to the races

17:25 storme: is there a way to assign arguments in clojure similar to the ||= operator in ruby?

17:25 vars*

17:26 amalloy: storme: there's no way to assign anything ever

17:26 but you can just use (or)

17:27 storme: (or something-that-might-have-been-defined what-it-will-be-defined-if-it-has-not)?

17:27 PigDude: ,(defn map-keys [m ks f] (reduce (fn [m* k] (if-let [v (k m*)] (assoc m* k (f v)) m*)) m ks))

17:27 clojurebot: #'sandbox/map-keys

17:27 amalloy: well, yes, modulo the weirdness of what it means to be "not defined"

17:27 PigDude: (map-keys {:a 1} [:a :b] -)

17:27 ,(map-keys {:a 1} [:a :b] -)

17:27 clojurebot: {:a -1}

17:27 PigDude: amalloy: that was my first one which doesn't pass nils to the fucntion, unlike update-in

17:27 amalloy: that's also why i use the select-keys view in the first code i showed

17:28 amalloy: PigDude: well, the one i linked in useful assumes you're passing keys that exist. but if it's important that you be able to "skip" keys that don't exist, the one i pasted in irc a minute ago does that

17:29 Fare: seancorfield, thanks

17:29 amalloy: yours has the serious issue that it doesn't work for maps whose values are nil or false

17:29 PigDude: i was just using it for strnig to integer conversion :P but fair point

17:31 amalloy: but i just change the if-let to contains? and i'm set

17:31 arrdem: Bronsa: merry christmas. http://dev.clojure.org/jira/browse/TEMJVM-6. let me know if there is anything I can do to help.

17:33 PigDude: ,(defn map-keys [m ks f] (reduce (fn [m* k] (if (contains? m* k) (assoc m* k (f (k m*))) m*)) m ks))

17:33 clojurebot: #'sandbox/map-keys

17:33 PigDude: ,(map-keys {:a nil :b false :c 4 :d 2} [:a :b :c] (constantly 5))

17:33 clojurebot: {:c 5, :b 5, :d 2, :a 5}

17:33 amalloy: sure, but now you're looking a key up in the map twice. it's harder than you think to write quality implementations of these basic functions

17:37 PigDude: ,(defn map-keys [m ks f] (reduce (fn [m* k] (let [v (get m* k ::empty)] (if-not (= v ::empty) (assoc m* k (f (k m*))) m*))) m ks))

17:37 clojurebot: #'sandbox/map-keys

17:37 PigDude: ,(map-keys {:a nil :b false :c 4 :d 2} [:a :b :c] (constantly 5))

17:37 clojurebot: {:c 5, :b 5, :d 2, :a 5}

17:37 PigDude: er i should include a nil key

17:37 ,(map-keys {:a nil :b false :c 4 :d 2} [:a :b :c :zzz] (constantly 5))

17:37 clojurebot: #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: map-keys in this context, compiling:(NO_SOURCE_PATH:0:0)>

17:38 PigDude: well that romance ended quickly

17:38 ,(defn map-keys [m ks f] (reduce (fn [m* k] (let [v (get m* k ::empty)] (if-not (= v ::empty) (assoc m* k (f (k m*))) m*))) m ks))

17:38 clojurebot: #'sandbox/map-keys

17:38 PigDude: ,(map-keys {:a nil :b false :c 4 :d 2} [:a :b :c :zzz] (constantly 5))

17:38 clojurebot: {:c 5, :b 5, :d 2, :a 5}

17:39 hiredman: (doc find)

17:39 clojurebot: "([map key]); Returns the map entry for key, or nil if key not present."

17:40 amalloy: hiredman: i already showed an implementation using find. i imagine he wants to do it differently

17:40 PigDude: thanks hiredman

17:40 hiredman: anyway, map-keys is gross

17:40 use something that isn't a map

17:50 Frozenlo`: Anyone familiar with nginx and ssl stuff? I have 2 website on the same server. I use clj-http to fetch some data. Doing (client/get "https://my-website-1") works fine. But (client/get "https://my-website-2") fails. ---> SSLException hostname in certificate didn't match <my-website-2> != <my-website-1> OR <my-website-1> OR <www.my-website-1>

17:50 I'm a little confused, because browsers don't throw this error :-/

17:54 noonian: frozenlock: it sounds like the ssl certificate is only valid for the domains my-website-1 and www.my-website-1

17:55 frozenlock: Sure, but each website has its own certificate

17:56 I suppose nginx is giving the wrong certificate to clj-http but not to browsers for whatever reason...

17:57 Bronsa: arrdem: https://github.com/clojure/tools.analyzer/commit/60e271ca7066c59d04d683c7c403045d3e048669

17:59 arrdem: Bronsa: Awesome thanks! Now to update oxcart to use your bindings collection code rather than mine...

18:00 Bronsa: arrdem: oh well wait. now it compiles but still fails ;-;

18:06 frozenlock: well, looks like I'm not alone O_o https://github.com/dakrone/clj-http/issues/202

18:07 dakrone: Ping! Could it be that clj-http doesn't support SNI (server name indication)?

18:13 gfredericks: man assembling symbols from other symbols is always a pain

18:13 catern: it should be a pain, though, because it's a dark thing to do, right?

18:14 frozenlock: Why would it be dark?

18:15 amalloy: it's something you should be careful about, anyway. most of the time you should regard symbols as indivisible, whereas strings are just a seq of chars in a pretty package

18:15 gfredericks: e.g., if in a def-style macro I want to make a symbol representing the fully-qualified name of the thing being defined

18:15 technomancy: there's a reason CL calls them "atoms"

18:16 gfredericks: I have to create a (symbol (name (.getName *ns*)) (name the-def-name))

18:16 dakrone: frozenlock: pong, I saw the issue you pinged on, I will look at it when I can (traveling now)

18:16 amalloy: gfredericks: (defn symbol* "Like symbol, but not as dumb." [& args] (apply symbol (map name args)))

18:16 gfredericks: amalloy: uh huh

18:17 amalloy: apparently my threshold for complaining about a problem is lower than my threshold for using a util library to solve it

18:17 frozenlock: dakrone: Awww... but I wanted it naow! :-p Perhaps you could point me in the good direction for a pull request? (if you know what the problem is)

18:17 bbloom: gfredericks: seems to me that the cost of utilizing a util lib is dramatically too high

18:17 amalloy: you don't even need a util library. just tattoo that snippet on your wrist so you remember to paste it into every app

18:18 bbloom: gfredericks: yeah, what amalloy said. copy/paste is a-ok

18:18 amalloy: anyway, i don't know of any util libraries that actually include symbol*

18:19 cbp: not even useful?!

18:19 * technomancy grumbles at appending * to the end of functions that aren't macroexpand targets

18:20 gfredericks: technomancy: yeah ' FTW

18:20 amalloy: well, i defined it once as a letfn for a function in useful.experimental

18:20 technomancy: actually that one especially. just call it useful.whatever/symbol

18:20 gfredericks: oh right of course

18:20 technomancy: gfredericks: http://p.hagelb.org/get-out.gif

18:20 gfredericks: bbloom: any speculations for how it could be easier?

18:21 technomancy: gfredericks: I had to remove a bunch of faux-prime marks from leiningen the other day

18:21 amalloy: i'm gonna define a library named *

18:22 the functions will just be named *, **, ***, ****

18:22 bbloom: gfredericks: automated copy/paste :-P

18:22 amalloy: what will they do?

18:22 frozenlock: Wait, there's an official usage of '*'?

18:22 Bronsa: arrdem: ok there was a bug on the tej side too, fixed that. looks like I forgot to test letfn w/ out-of-order deps

18:22 amalloy: bbloom: annoy technomancy

18:22 frozenlock: I usually append * to a function that shouldn't be considered complete - shoudn't be used directly. Any suggestion? :-/

18:22 bbloom: amalloy: seems like that belongs in useful

18:23 technomancy: frozenlock: that's what I interpret * as meaning, yeah

18:23 that you shouldn't be using it directly

18:23 frozenlock: ah ok

18:23 technomancy: but it can't be private because it's in macroexpansions

18:23 amalloy: frozenlock: that's one common use of *. technomancy thinks it should be the only use, but it's not really a language standard

18:23 esp given functions like list*

18:23 arrdem: Bronsa: cool.

18:23 technomancy: the other meaning is "I couldn't think of a good name for this" =P

18:23 Bronsa: arrdem: thanks for the report and sorry for the trouble :/

18:23 amalloy: where * just means "kinda like X but i couldn't think of a good name"

18:23 bbloom: technomancy: for that purpose, i use "blah"

18:23 arrdem: defn****

18:24 cbp: symbol++

18:24 amalloy: one thing about working witn ninjudd: he could *always* find a name he liked better than foo*. he programmed with a thesaurus in his hand

18:24 Bronsa: https://github.com/clojure/tools.analyzer.jvm/blob/master/src/main/clojure/clojure/tools/analyzer/jvm/utils.clj#L228-L233 get on my level.

18:24 arrdem: Bronsa: no worries, thanksf or the quick fix

18:24 bbloom: Bronsa: heh, i've done that

18:25 technomancy: amalloy: https://mobile.twitter.com/topfunky/status/466652171061436416?p=v

18:25 bbloom: Bronsa: actually

18:25 Bronsa: that looks silly

18:25 amalloy: Bronsa: there are so many nicer ways to write that (or)

18:26 eg, (#{mn mn* mn** mn***} name)

18:26 bbloom: Bronsa: and you can create that #{...} at once

18:26 Bronsa: amalloy: yeah, I'm not really sure why I didn't do that

18:27 arrdem: eh the jit'll probably throw away a set if you use one there and generate exactly that comparison code..

18:27 amalloy: arrdem: you wish

18:28 arrdem: amalloy: object elision is osum

18:29 Bronsa: heh using your collect-closed-overs makes this way nicer.

18:29 amalloy: arrdem: i think you actually get more efficient code if you close over the set, probably

18:29 as opposed to writing out four = comparisons

18:30 TimMc: What, an object creation and a hash lookup is faster than four equality checks?

18:31 *three, I guess

18:32 amalloy: TimMc: you can create the object once and use it many times

18:33 (let [matcher #{...}] (fn [name] (matcher (str name))))

18:33 and then you're only closing over one thing instead of four, so making the object is cheaper; and you only have to pass name once, and...

18:36 TimMc: But the hash lookup is faster?

18:36 Hmm... I guess JVM string hashes are pretty simple, and these are small strings...

18:38 amalloy: ,(class #{"x" "y"})

18:38 clojurebot: clojure.lang.PersistentHashSet

18:38 TimMc: When someone says "hash" I think "SHA1" or in general something more involved than a linear combination of the inputs. :-P

18:38 amalloy: i always forget we don't have array-sets

18:39 bbloom: amalloy: yup, no array-sets :-/

18:44 technomancy: poll: would you want `lein release` to run your tests for you before bumping your version number, tagging, deploying, etc? or would you be annoyed at it.

18:45 arrdem: +1 would want, or would write git hook to provide

18:46 technomancy: either way it'd be easy to add

18:46 catern: +1

18:48 shep-home: Hi all!

18:48 About how long does it take from me putting my CA in the mail and showing up on the CA list?

18:49 I've got some commits burning a hole in my pockets!

18:49 hiredman: technomancy: by "either way it'd be easy to add" do you mean it would be asy to remove if you don't want that?

18:50 technomancy: hiredman: yeah

18:50 well

18:50 you could provide your own :release-tasks vector

18:50 which is easy but verbose

19:22 kenrestivo: ,(def -_- 42)

19:22 clojurebot: #'sandbox/-_-

19:23 kenrestivo: ,-_-

19:23 clojurebot: 42

19:32 frozenlock: If I want to result of something sent to a writer, I can use `with-out-str' and *out*. Is this the best way?

19:34 kenrestivo: i guess, if the function you're trying to capture the result of, doesn't return it directly, but instead wants to poot it to *out* as a side effect

19:35 frozenlock: It does, which is kinda weird... Especially considering that similar libraries just return you the data. https://github.com/clojure/data.csv

19:35 kenrestivo: ,(def -_- (symbol ":-)"))

19:35 clojurebot: #'sandbox/-_-

19:35 kenrestivo: ,-_-

19:35 clojurebot: :-)

19:35 kenrestivo: clojure mood improvement

19:37 huh, i've used that library before, i don't remmmeber it being that annoying and insisting on *out*. huh. maybe i used it only for reading

19:37 dbasch: frozenlock: I see that the functions explicitly ask for a writer in the parameters

19:37 frozenlock: Yes :-(

19:37 I give it *out*

19:38 dbasch: is that a problem?

19:38 frozenlock: I don't know

19:41 dbasch: frozenlock: this library is meant to spit out csv files, using a writer is one way to do that

19:41 kenrestivo: thers's probably some plumbing with bufferedwriter or similar that could be done to create a writer you could pass to that function, and then pull the data out of into a string or whatever you like. been a while since i dealt with clojure.java.io though.

19:41 amalloy: dumping an entire csv into one string doesn't seem like a fun time. people make absurdly large csvs

19:42 frozenlock: https://github.com/clojure/data.json is pretty much the same thing, but gives the result back.

19:42 dbasch: but if you know you’re creating small csv files in your program, you can dump them into a StringWriter

19:43 not sure why you would want csv in memory as a string though

19:44 csv is a least-common-denominator export format

19:45 json is different because it’s meant to be passed over the wire

19:46 frozenlock: dbasch: I want to serve it throught liberator. I have some data in vectors form that I want to let the user download as a CSV.

19:48 dbasch: frozenlock: are they generated on the fly or are they worth caching?

19:48 frozenlock: on the fly

19:48 amalloy: yeah, definitely don't put that into a string

19:49 instead, create a Writer that pipes to a pipe that ring is reading from, so that the data streams straight from data.csv to the user

19:51 eg, use https://github.com/ring-clojure/ring/blob/bc4ddda43e68cc2117f73306d936555ac870239b/ring-core/src/ring/util/io.clj#L11 and java.io.OutputStreamWriter

19:52 frozenlock: Will try immediately, thanks

19:55 kras: Hi, I am reading an EDN file into clojure. It gives me an error saying there are duplicate keys. IllegalArgumentException Duplicate key: clojure.lang.PersistentHashMap.createWithCheck (PersistentHashMap.java:67)

19:55 How do I find out this duplicate key?

19:55 gtrak: sounds like EDN that was edited manually.

19:56 kras: I generated the EDN file from a python parsing program

19:56 gtrak: ohhhhh... :-

19:56 )

19:56 hiredman: how are you reading the file?

19:57 kras: (read-string (slurp "/Users/myself/gate_parser/hod.edn"))

19:57 hiredman: the easiest thing would be to put a check in the in the python program to make sure it doesn't output the same key twice

19:58 amalloy: kras: i mean, when you try to read a map with a duplicate key, the exception message contains the duplicate key

19:58 ,'{a 1, a 1}

19:58 clojurebot: #<IllegalArgumentException java.lang.IllegalArgumentException: Duplicate key: a>

19:58 amalloy: so, what is the duplicate key? look for that in the file

19:59 hiredman: kras: how large is the edn file? if it is small you should be able to read through it(if it is large you shouldn't be using slurp and read-string)

19:59 amalloy: it helpful prints nil as ""

20:00 amalloy: oh, no kidding? i was wondering why he didn't seem to have one

20:00 ,'{nil nil nil nil}

20:00 clojurebot: #<IllegalArgumentException java.lang.IllegalArgumentException: Duplicate key: null>

20:00 kras: amalloy: it doesn't print the key in my case

20:00 amalloy: hiredman: looks like null to me

20:00 hiredman: huh

20:00 noonian: sounds like a bug in the python program to me

20:00 amalloy: ,'{""""""""}

20:00 clojurebot: #<IllegalArgumentException java.lang.IllegalArgumentException: Duplicate key: >

20:00 noonian: ,{"" "" "" ""}

20:00 clojurebot: #<IllegalArgumentException java.lang.IllegalArgumentException: Duplicate key: >

20:00 noonian: lol

20:00 hiredman: heh

20:01 I guess " " would match the spacing

20:01 kras: java.lang.IllegalArgumentException: Duplicate key:

20:01 PersistentHashMap.java:67 clojure.lang.PersistentHashMap.createWithCheck

20:01 RT.java:1462 clojure.lang.RT.map

20:01 LispReader.java:1094 clojure.lang.LispReader$MapReader.invoke

20:01 LispReader.java:1148 clojure.lang.LispReader.readDelimitedList

20:02 noonian: so the python program looks to be outputing a map with two or more keys that are strings of the same length containing nothing but whitespace

20:03 how are you generating the edn in the python code?

20:03 kras: yeah looks to be the case

20:04 yeah I open the edn file, I see a lot of "" in there

20:05 I guess I need to work on my python edn_dump function

20:05 amalloy: hiredman thanks for the hints

20:06 noonian: if you are interested in the python edn_dump, here it is

20:06 noonian: try refheap or pastebin instead of pasting multiple lines in irc

20:06 https://www.refheap.com/

20:06 kras: http://pastebin.com/Qz6fPfVT

20:07 was going to do that :-)

20:10 hiredman: on the file size, it is a 5MB file, but this is just a testcase

20:10 my actual files can run into GB

20:11 amalloy: you plan to slurp a many-gig file into a single string, and then read-string it into a single object?

20:11 hiredman: gonna have a bad time

20:12 even if you aren't doing that, gigs of small edn maps in a single file are a bad time

20:13 kras: for the application I am building, I need that whole map in the memory

20:13 hiredman: have you considered a database?

20:14 kras: hiredman: never used one so far

20:15 noonian: i envy you

20:15 kras: basically, here is what the application is:

20:15 hiredman: anyway, we don't know what your requirements are, but slurp+read-string on a multi gb file is going to be slow

20:16 kras: I parse a verilog file using python and dump an EDN file. The goal is to read the EDN file which has all the sub-module information and build a graph out of it

20:17 then use DOT to generate a visaulization of that graph

20:17 dbasch: kras: you may want to check out neo4j

20:17 hiredman: at the very least I would dump pairs in to the file, so each pair can be read one at a time instead of dumping a multi gig map

20:17 dbasch: it may be overkill though

20:18 frozenlock: Wow. I'm so bad.

20:18 Behold, my csv! https://www.refheap.com/86033

20:19 dbasch: csv is supposed to stand for comma, not crap :P

20:19 kras: noonian: I am not a software engineer

20:19 frozenlock: dbasch: That's YOUR opinion! :-p

20:20 dbasch: kras: if you can write that code, you definitely can figure out a way to dump those values into a more efficient store

20:20 kras: hiredman: I achieved the same stuff in python, memory is not a very big concern here

20:21 this is a process of porting the idea using clojure

20:21 hiredman: kras: sure, if it works it works

20:21 kras: my finished python code looks like sphagetti and hence this exeercsie

20:22 dbasch: kras: I’m sure there are verilog parsers in Java you could use from Clojure instead of going through edn

20:23 kras: dbasch: antlr is on my mind

20:23 but as a first step I am using this approach

20:23 because antlr has a big learning curve if I am not wrong

20:23 noonian: like hiredman said, if it works it works; i'd stick with spit and slurp until it becomes a problem

20:24 i'm trying to figure out how many map entries you need for a GB+ file

20:25 hiredman: I wonder about the amount of garbage the reader will generate

20:25 kras: noonian: to give you an example, an average verilog netlist contains roughly 2.5M submodules

20:26 so each child modue corresponds to a key in the dictionary

20:27 frozenlock: amalloy: I get a bunch of garbage out... would you mind telling me if everything looks in order? https://www.refheap.com/86035

20:27 hiredman: you may even have better luck writing values to a local memcached and just passing a list of keys

20:30 kras: hiredman: since the hardware being equal and since it worked in python I am confident that this will work in clojure as well :-)

20:30 Jaood: sqlite could be a sane choice too but I hear sqlite java support is not that nice

20:31 amalloy: frozenlock: (a) please please include error messages when something goes wrong. it's tiring to use psychic powers. (b) you're passing data.csv an OutputStream, where it wants a Writer. that's why i said you'd need OutputStreamWriter

20:31 dbasch: Jaood: sqlite from java is no different than using any other sql db

20:32 Jaood: dbasch: I was actually referring to the sqlite java driver

20:32 noonian: if you're set on using file's i'd try putting each sub module on a line and maping read-string over (line-seq file)

20:32 dbasch: Jaood: I haven’t used it in maybe 5 or 6 years, it was fine back then. Has it gotten worse?

20:37 frozenlock: amalloy: (a) I did, I pasted it just a few lines higher. I guess I should have pinged you then.

20:37 l1x: has anybody used graphs with clojure?

20:38 amalloy: wait, that refheap was generated by your ring server? the code you pasted shouldn't even produce output at all; you should die quite quickly on a classcastexception

20:39 hiredman: l1x: what do you mean by that?

20:39 frozenlock: And there I was thinking making progress because at least my server was giving me something.

20:40 l1x: hiredman: i was wondering how could i have a very simple undirected graph in clojure, i need to be able to get the shortest path between two nodes

20:42 hiredman: l1x: https://github.com/aysylu/loom may be a good place to start, it is still maturing but it does have some path finding algorithms

20:44 l1x: hiredman: thanks!

21:14 tuft: i used loom in a project -- worked well

21:40 hellofunk: with cljs and getting DOM elements, it would seem wiser to leverage the built-in goog.dom library rather than the document.getElementById, is that right? or is there an even wiser approach?

21:45 beamso: it looks like goog.dom.getElement just calls document.getElementById anyway.

21:45 http://docs.closure-library.googlecode.com/git/local_closure_goog_dom_dom.js.source.html#line112

21:46 i have no idea what has changed but now my first om page using cljs-ajax is working now.

21:48 hellofunk: perhaps when working with Om, relying on the #js :ref for assigning and retrieving DOM ids is even better

21:48 because that should wrap everything in React, right?

21:51 storme: Would someone be willing to look at my binary search implementation in clojure and critique it for me please?

21:51 https://github.com/vincentstorme/clj-binary-search/blob/master/src/clj_binary_search/core.clj

21:54 dbasch: storme: it’s very inefficient to sort the collection just to check that it’s sorted

21:54 storme: dbasch, What would you recommend?

21:55 dbasch: storme: if you must check that it’s sorted, at least do it in linear time

21:57 storme: dbasch, Ah, so do the checks while it is searching by checking the neighboring elements if they are respectively higher/lower as they should be?

21:57 hellofunk: ,(= [1 2 3 4] [4 3 2 1])

21:57 clojurebot: false

21:57 hellofunk: Isn't it throwing an exception because sorting negates equality?

21:58 You are telling it if they are not equal, then throw an exception.

21:58 And you are making them non equal by comparing the original with the sorted version

21:59 storme: hellofunk, Thank you, I was assuming ascending sort

21:59 hellofunk: it probably is ascending sort

21:59 ,(sort [4 3 2 1])

21:59 clojurebot: (1 2 3 4)

21:59 hellofunk: ascending, right?

21:59 storme: hellofunk, Yep

22:01 dbasch: storme: but more importantly, it defeats the purpose of binary search

22:02 storme: i.e. if you’re going to check every element, might as well do a linear search

22:02 binary search assumes your collection is sorted

22:03 storme: dbasch, So I shouldn't even worry about checking if the collection is sorted?

22:04 dbasch: if you’re going to be using binary search for millions of queries with the same collection, it may be worth checking the first time depending on your application

22:04 beamso: the function str doesn't exist in clojurescript?

22:05 seancorfield: beamso: sure it does...

22:06 beamso: it's probably me stuffing something up. my apologies.

22:07 seancorfield: drop the code in refheap and show us?

22:08 beamso: i think it's more me strugging to construct a anchor link in om.

22:09 https://www.refheap.com/86037

22:10 storme: dbasch, Thank you

22:10 seancorfield: beamso: you have an extra set of parens

22:10 beamso: compare with this https://www.refheap.com/86038

22:10 storme: dbasch, Do you see anything else that you might have concern with/that could be improved?

22:11 beamso: seancorfield: i apologise for my stupidity. i think i may need food or coffee on that one.

22:13 dbasch: storme: it can be made more idiomatic and probably more efficient too, and also you want to check that you’re doing this on a collection for which counting is free

22:13 storme: e.g. not a linked list

22:16 seancorfield: beamso: it's easy to accidentally add parens and get a baffling error msg - esp. in clojurescript!

22:23 hellofunk: I am working on a library, CloError, for clojurescript, that will give you an exact explanation of all errors, but also fix them for you, and with optional config, it will write your program for you. More details closer to launch, circa 2019

23:16 Lemur: Is there a definitive source on operators? They're rather pesky to Google for.

23:17 such as ->> (which I assume is some form of pipe) and % (which is mod in some languages, args in others)

23:17 bbloom: Lemur: you can always try (doc ...)

23:17 (doc ->>)

23:17 clojurebot: "([x & forms]); Threads the expr through the forms. Inserts x as the last item in the first form, making a list of it if it is not a list already. If there are more forms, inserts the first form as the last item in second form, etc."

23:17 bbloom: works in your repl

23:17 Lemur: nifty

23:17 Slightly new to this area.

23:17 bbloom: there's also http://clojure.org/reader that covers the actual parsed syntax

23:18 those two things should get you started

23:18 if you don't find anything in either of those, you can ask here

23:18 Lemur: I know Ruby and a good amount of Haskell so shouldn't be too bad.

23:36 uvtc: Lemur, I've always found the [cheatsheet](http://clojure.org/cheatsheet) to be very helpful.

23:37 Lemur: Very nice indeed.

23:37 * Jaood tries to memorize the cheatsheet

Logging service provided by n01se.net