#clojure log - Nov 18 2012

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

1:06 Sgeo: Is it worth writing a macro instead of a function for the sake of avoiding some Java reflection?

1:07 bbloom: Sgeo: measure and find out

1:07 Sgeo: Well, not avoiding it for performance reasons

1:07 More "I understand how to write the macro better than how to write the reflection" reasons

1:31 hyPiRion: Sgeo: Okay, so you're writing a macro instead of a function because you're unsure how you should write the fn?

1:33 I would've made the function for knowledge's sake.

2:46 abp: ,'(:a :d/b :b/a :x)

2:46 clojurebot: (:a :d/b :b/a :x)

3:16 muhoo: any best practices on wrapping a json service in clojure (i.e. using cheshire)?

3:19 i guess i could copy the way clutch does it, since couchdb is basically a json service

3:20 but i'm wondering if there's a better way. lots of tuts on how to CREATE a json service in clj (using ring) but none on how to wrap one for access from clj

3:31 abp: muhoo: how about https://github.com/ring-clojure/ring-json?

3:34 dimovich: hey guys, how does one jump to next line (with proper identation) in Emacs Live?

3:34 C+j jumps without identation... Enter imediately evaluates (due to auto-closing of paranthesis)...

3:39 amalloy: i dunno what emacs live is/does, but i assume you're talking about a repl, and for me C-j is bound to slime-repl-newline-and-indent

3:41 dimovich: how do I see what a key combo is bound to?

3:41 amalloy: C-h k

3:43 dimovich: thanks

3:57 muhoo: dakrone: that was a cheshire question, actually :-)

3:58 abp: that's for CREATING a json service. not what i want. i want to ACCESS a json service, making a clojure wrapper for it

3:58 kind of like python's ServiceProxy, which is awesome.

3:58 i'm sure something in clojure could be awesomer

4:20 Apage43: I tend to wrap up clj-http's "request" method for simple API service wrappers https://github.com/dakrone/clj-http/#misc

4:21 that was @ muhoo

4:21 It can feed the response through cheshire automatically, if you pass the :as :json option

4:27 muhoo: Apage43: yeah, but this is nasty: https://www.refheap.com/paste/6804

4:28 compared to the python equivalent: proxy.getinfo()

4:28 so i'm trying to get to there :-)

4:28 Apage43: Right, but if they all follow that form you could wrap up something like

4:29 (def api-proxy (fn [method params] (client/post…))

4:29 or a fn that returns that fn

4:30 muhoo: that may work, thanks.

4:54 awesome. i need a cigarette: https://www.refheap.com/paste/6805

4:55 i'd forgotten how easy it is to do stuff in clojure. instead of having to fight the language to get the hell out of my way, it is actually HELPING me. what a joy.

5:04 Apage43: done! https://www.refheap.com/paste/6806

5:05 Raynes: My mother can move again! Weeeee

5:05 We might get to leave this God forsaken state some time this bloody year.

5:06 deg: Anyone around now who can answer a question about Clojure's binding model? (or too early on a Sunday morning??)

5:09 muhoo: Raynes: congratulations

5:09 Raynes: aren't you at the conj? :-)

5:09 scottj: deg: normally best to just ask

5:09 Raynes: muhoo: I was for the first day and about 5 minutes of the second before I had to get my mother to a hospital.

5:10 muhoo: holy crap, that sucks.

5:10 deg: Ok. I don't understand why this gives a sequence of nils, rather than 42s: (def ^:dynamic *x* nil) (binding [*x* 42] (map (fn [_] *x*) (range 2)))

5:10 muhoo: Raynes: so is her health the reason you didn't move to L.A. with the genii guys?

5:11 callen: Raynes: I'm sorry to hear that :(

5:11 Raynes: muhoo: Yeah, what sucks is that we have to miss our flight and Delta is a huge pain in the ass about giving us a credit for rebooking. I'm concerned they're going to kick her out of the hospital long before they give us the bloody credit so I'll probably end up having to pay for tickets out of here.

5:11 muhoo: No, I'll be moving sometime after the first of the year.

5:12 bbloom: deg: more likely to get an answer if you just ask

5:12 deg: Raynes: I've had that issue before (though with a different airline). It worked to speak to a human agent and tell the full story. I didn't get what I wanted, a full rebate on the change-of-ticket, but they did give me a $120 voucher (instead of $250 cash, but still...)

5:13 bbloom: see above. I did ask after scottj gave the same advice.

5:13 Raynes: The tickets are pretty cheap (about $160 each), so I can cover them if I have to. I just shouldn't have to.

5:13 bbloom: gah, sorry, must be too early in the morning to read IRC :-)

5:14 deg: :-) That's why I asked. ROTFL

5:14 bbloom: deg: the issue you're encountering is likely one of laziness

5:14 try mapv instead of map

5:15 deg: mapv worked, thanks.

5:15 bbloom: the issue is that the binding takes effect, map is called, the binding is popped off the stack

5:15 then the return value, a lazy sequence, is passed to the repl

5:15 who then prints it

5:15 deg: So, map's laziness causes the dynamic scope to exit before .... yup

5:15 bbloom: the printing happens AFTER the binding has been popped

5:15 deg: thx

5:15 bbloom: dynamic variables and laziness tend not to work out well :-/

5:15 muhoo: Raynes: airlines suck, but hospitals suck worse. i hope your family has insurance.

5:15 Raynes: She has medicaid, so we're definitely good on that.

5:16 muhoo: cool.

5:16 Raynes: We've done this exact thing before. Not the first time her potassium dropped to ridiculous limits.

5:16 bbloom: Raynes: hurray receiving useful government services in exchange for taxes!

5:16 Raynes: Yay!

5:17 deg: Raynes: lots of magic you can pull with medicaid, etc. Glad to hear you've got it under control now, but push hard if things go wrong.

5:17 bbloom: Raynes: also, here's a fun tip with airlines

5:17 gate agents and flight attendants are TRIVIALLY bribed with candy

5:18 gate agents actually have a lot of power to re-arrange flights for passengers

5:18 but it's a PITA for them generally

5:18 my girlfriend is a flight attendant, so we fly standby to some places

5:18 deg: We had similar issues with my mom, but finally got the the bureaucratic and financial issues to work out. (Ubfortunately, not the health issues.... she had pancreatic cancer; survived 16 months, which is only good in a statistical sense)

5:18 bbloom: she brings people cookies, and things just magically go our way every time

5:18 muhoo: oh, good point. my dad taught me how to kiss up to gate agents (he was a salesman). never heard of cookies tho.

5:20 Barkingdogs: Raynes, I forgot, can eval in clojure actually influence the scoping or not?

5:20 bbloom: you'd be amazed how many drinks a pack of twizzlers can buy you...

5:20 Barkingdogs: Well, a better quaestion would be, is it possible to implement eval as a non primitive?

5:20 deg: bbloom: Can I also count on dynamic bindings being visible inside a pmap, or does the threading get in the way?

5:20 Raynes: user> (eval '(def x 1))

5:20 #'user/x

5:20 user> x

5:20 1

5:20 Barkingdogs: ^ Does that answer your question?

5:21 bbloom: Duly noted. Will be sure to carry swag.

5:21 bbloom: deg: see bound-fn

5:21 Raynes: :p

5:22 deg: bbloom: nice. Thanks.

5:22 bbloom: deg: I'm not sure if pmap automatically does the binding tho

5:22 deg: some things do, like agents, etc

5:22 Barkingdogs: Raynes, no, try: (let [x 3] (eval '(def x 1)) (+ x x)) I guess.

5:22 amalloy: Barkingdogs: certainly you can implement eval if you want

5:22 bbloom: bound-fn basically captures the dynamic scope and then reapplies it later

5:22 Barkingdogs: Ah yes.

5:22 deg: bbloom: ok, I'll play and test. At least now I have the primitives I need.

5:22 bbloom: (def ^:dynamic *x* nil) (binding [*x* 42] (map (bound-fn [_] *x*) (range 2)))

5:23 as an alternative to mapv

5:23 Barkingdogs: amalloy, so it' s not like in say php or perl where it actually can alter the properties of shadowing based on runtime string data is what I mean?

5:23 amalloy: those are two totally unrelated statements?

5:23 Barkingdogs: Like you define a variable with eval that shadows a variable in an outer scope.

5:23 bbloom: deg: for a small collection (can fit in memory easily), use mapv, if you need the laziness, use map and bound-fn. you'll pay some overhead for capturing/applying the scope, but at least you can operate on an infinite set

5:24 Barkingdogs: Not as far as I know, that' s one of the major things that doesn 't allow eval to be implemented in either language were it not to exist natively.

5:24 deg: bbloom: Ok. I'll have to wrap my head around how bound-fn inside map overcomes map begin lazy. Time for macroexpand, I guess.

5:24 Barkingdogs: amalloy, consider: http://pastebin.com/BUw9miVg

5:24 bbloom: deg: use (source bound-fn) and then follow the bread crumbs :-|)

5:27 Barkingdogs: those inner curly braces don't do anything… javascript doesn't have true lexical scoping

5:27 Barkingdogs: hence the (function(x) { … })(x); idiom

5:27 dimovich: hey guys, how can I automatically add additional modes to nrepl?

5:32 deg: bbloom: Wow!! That opened up new views of map... Scratched my head a bit and then realized that the first arg to map does not need to be a function; it can be a clojure, etc. Wow, wow, wow!

5:33 bbloom: cloSure :-)

5:33 deg: welcome to functional programming. enjoy the ride

5:33 deg: yup! I've written clojure too much recently!

5:34 bbloom: thus begins the process of breaking down everything you know and rebuilding it all :-)

5:34 deg: Yup. Until now I've just been treating Clojure as Common Lisp on the JVM. Already pretty cool. And, to be fair, FP was perfectly possible in Lisp too. But, this is a whole new way of looking at it.

5:37 For any other newbie reading this: good articles at http://kotka.de/blog/2010/05/Did_you_know_IV.html and http://kotka.de/blog/2009/11/Taming_the_Bound_Seq.html

5:37 dimovich: thx

5:50 Barkingdogs: bbloom, ah yes, tat explais my confusion.

5:50 bbloom: Barkingdogs: also worth noting is that PHP's semantics are shit

5:51 Barkingdogs: everything about PHP is just a WTF when it comes to scoping, evaluation, etc. You shouldn't try to map any sane language's notions to PHP's. down that path lies madness

6:01 Barkingdogs: bbloom, well, I' m mostly interested in how clojure's eval functions

6:02 Because if it's just a normal function then it's not actually "evil"

6:03 bbloom: Barkingdogs: It's just a normal function :-)

6:03 at your repl, type (source eval)

6:03 note that it calls into java land

6:04 Barkingdogs: it takes a data structure, which internally is a java type, and calls the eval method

6:04 see https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Compiler.java

6:09 Barkingdogs: bbloom, yeah, that is what I wanted to know, it's not like with php and perl where eval($string); is actually just the same as string in actual code on that line I mean.

6:09 where the string can do things like define functions for you or mess scope up etc.

6:10 bbloom: Barkingdogs: well you can define functions in an eval

6:10 Barkingdogs: consider (eval '(defn f [x] (* x 2)))

6:10 Barkingdogs: bbloom, well, do those functions then suddenly turn up in the scope the eval is in?

6:11 bbloom: Barkingdogs: clojure has a sane notion of both dynamic and lexical scope paired with a sane namespace system

6:11 Barkingdogs: so you can't magically mess with the lexical scope

6:11 Barkingdogs: lexical names don't have namespaces, so eval can't break out of it's little box and mess with your lexical environment

6:11 Barkingdogs: schweet

6:11 bbloom: Barkingdogs: dynamic scoping is a different story, you can use def inside the eval

6:11 however, it won't ever really hurt you

6:12 Barkingdogs: so there's basically nothing evil about it whatsoever, it's a function that takes a datum as argument, has a side effect if need be and returns a value?

6:12 Well, existence of dynamic scoping itself is evil, but we'll live with that.

6:12 bbloom: well so what you need to understand is that the side effect may be to add something to the dynamic scope

6:12 Barkingdogs: paramatres are better and can achieve pretty much the same.

6:12 bbloom: no, dynamic scopign isn't evil :-P it's useful

6:12 parameters ARE dynamic scoping, same thing pretty much

6:12 Barkingdogs: Is there somethingf you can do with dynamic scoping but can't with paramatres?

6:12 bbloom: but the point i want to make is this:

6:12 Barkingdogs: Nope, you can implement paramatres in lexical scoping alone.

6:12 bbloom: namespaces are resolved at compile time

6:13 Barkingdogs: Schweet.

6:13 bbloom: so when you do (let [static 5] (* static dynamic))

6:13 you'll get something like (let [static 5] (* static my.namespace/dynamic))

6:13 assuming dynamic has been defined

6:14 so if you (def dynamic) inside your eval, you will CHANGE the dynamic name, but you can't break any references in the surrounding code b/c they have already been assigned a namespace

6:14 Barkingdogs: Eeexcellent

6:14 exactly as I planned.

6:14 Yeah, a sad side effect of dynamic variables, but nothing to bad.

6:14 Merely a minor setback.

6:14 bbloom: and let me clarify: did you mean parameters as in the literal arguments to a function sense? or did you mean it in the scheme sense?

6:15 scheme has a notion of "parameters" which are pretty much the same thing as clojure's dynamic variables

6:15 Barkingdogs: Oh no, as in the scheme sense.

6:15 Well, no they are slightly different, basically because it's lexically clear where they 'end'

6:15 bbloom: http://docs.racket-lang.org/reference/parameters.html

6:16 Barkingdogs: As in say you have (withparam [x 3] ...) you know that the param x is its original value outside of that block again.

6:16 bbloom: Barkingdogs: yes, clojure has a binding macro

6:16 ,(doc binding)

6:16 clojurebot: "([bindings & body]); binding => var-symbol init-expr Creates new bindings for the (already-existing) vars, with the supplied initial values, executes the exprs in an implicit do, then re-establishes the bindings that existed before. The new bindings are made in parallel (unlike let); all init-exprs are evaluated before the vars are bound to their new values."

6:16 Barkingdogs: bbloom, yeah, paramatres are I believe sctrictly less powerful than dynamic variables.

6:16 bbloom: scheme/racket's parameter objects are almost the exact same thing as clojure's "vars"

6:17 Barkingdogs: But they can basically do anything you conceivably want from dynamic variables but don't go into the nasty stuff of dynamic variables.

6:17 bbloom: which nasty stuff are you referring to?

6:18 Barkingdogs: The nasty stuff of having no idea when reading code what a variable is actually referring to.

6:18 bbloom: right, so scheme solves that problem by having a difference between top level declarations and parameters

6:19 clojure solves it by unifying the two ideas and then by resolving symbol names at compile time with the namespace system

6:19 &`(inc x)

6:19 lazybot: ⇒ (clojure.core/inc clojure.core/x)

6:19 Barkingdogs: Well, it's more that you know that nothing funky is happening when you call a function if you don't do it inside with-param.

6:20 bbloom: &`(let [x 1] (inc x))

6:20 lazybot: ⇒ (clojure.core/let [clojure.core/x 1] (clojure.core/inc clojure.core/x))

6:20 Barkingdogs: While with dynamic variables because they can potentially be altered beyond the scope of that you essentially have no idea, a dynamic variable can mean anything depending on what happens above in the call stack.

6:21 bbloom: Barkingdogs: clojure's dynamic variable bindings are thread locals

6:21 you can alter the root value, but you can't alter interum values

6:22 def and alter-root-var will change the top level value, similar to scheme's declare

6:22 but bindings are pushed onto the stack in a thread-local manner

6:22 and they can not be changed except via push/pop

6:22 so, generally, they are safe to use without fear of being mutated by somebody else

6:23 Barkingdogs: I have no idea what you're talking about right now.

6:23 raek: they can be changed from within the thread

6:23 bbloom: raek: i know they can :-P

6:23 Barkingdogs: You are giving me mixed signmals to drive me mad.

6:23 Mad I say.

6:23 bbloom: raek: but only if you explictitly call push-thread-bindings, etc

6:24 which, i guess, he's saying you can't do with parameters in racket

6:24 Barkingdogs: I have no idea what they are

6:24 or how dynamic variables exactly function in clojure

6:24 I do know how they function in Common and Emacs lisp

6:24 it's evil.

6:24 THey shall not get a praesent from santa claus this year.

6:24 bbloom: yeah, and i'm telling you: they aren't evil in clojure :-P

6:24 Barkingdogs: Maybe next year.

6:24 Then it's cool.

6:24 #benice

6:25 bbloom: clojure's features work together to make them reasonable, i'm trying to explain those features

6:25 raek: variables are always lexically _scoped_ in clojure, but the values of vars can be dynamically _bound_

6:25 that is, the question "which variables does this symbol stand for" is determined lexically

6:26 Barkingdogs: raek, ingruiging, explain further.

6:26 raek: but "which value does it have" can be determined dynamically for vars

6:26 mpenet: I am wondering why keywords aren't implemented via deftype in cljs, performance reasons?

6:26 Barkingdogs: So basically there aren't strictly speaking dynamic vars?

6:27 bbloom: mpenet: yes

6:27 raek: an example

6:28 mpenet: damn, I wish it could be a clj type, it leads to unexpected behavior with protocols: https://gist.github.com/4104635

6:28 bbloom: mpenet: keyword comparisons need to be 'identical? rather than '= for performance

6:28 mpenet: yes makes sense

6:28 bbloom: mpenet: please report that bug

6:28 mpenet: will do

6:29 raek: (def x 1) (defn f [y] (+ x y))

6:29 bbloom: mpenet: in the meantime, your workaround is to extend-protocol to String and then use 'keyword?

6:29 raek: x in that function always refers to the global var x

6:29 bbloom: mpenet: which is what the backend will probably do automatically after fixing the bug :-)

6:29 raek: if you would do (let [x 5] (f 2)) the f function still sees x=1

6:30 bbloom: js/String, more specifically

6:30 raek: in a language with dynamic variable scope, the let binding would have shadowed the x global

6:30 bbloom: i think

6:31 mpenet: bbloom: I use js/Object with a couple of other similar checks, I want to keep js/String clean since it will be what is used in 90% of the cases

6:32 raek: so lexical scoping means "to find what x means, look upwards in the code for a binding of that variable"

6:32 mpenet: but wait, that wont work

6:32 bbloom: your idea is better, thx

6:32 raek: dynamic scoping means "to find what x means, look upwards in the call stack for binding of that variable"

6:33 bbloom: mpenet: I have a hacky, failed attempt to reify keyword and symbol types here: https://github.com/brandonbloom/clojurescript/commits/keywords-and-symbols

6:33 mpenet: would also be a similar strategy for Character

6:33 mpenet: if you are feeling up to the challenge :-)

6:38 mpenet: I am not really familiar with the cljs compiler, but this could be an occasion to dive into it. I will have a look.

6:39 bbloom: did you benchmark your solution yet? This seems to be a really clean approach, I wonder what is the perf difference

6:39 bbloom: mpenet: it's dramatically slower :-P

6:39 mpenet: there is a benchmark script in there

6:39 https://github.com/brandonbloom/clojurescript/commit/05f457ad52ff884f945c549f5da2c3f634613e37

6:39 mpenet: bbloom: yeah I saw it

6:40 bbloom: it's also a pretty old branch

6:40 5 months

6:40 core has evolved a lot

6:41 mpenet: the core idea was to emit interned keywords and symbols statically as a whole-program optimization

6:41 mpenet: but also to NOT intern future symbols and keywords because javascript doesn't provide a concept of weak references

6:46 mpenet: thanks for filing that bug

6:48 mpenet: bbloom: You're welcome. It is an interesting problem.

6:48 bbloom: mpenet: for sure. also worth noting is that there are some potential perf gains to be had by eliminating changes to string.prototype

6:49 mpenet: yep I was thinking about that, now every string is checked for keyword type I guess

6:49 elimitating the kw problem would improve strings

6:49 if I understand correctly

6:49 bbloom: mpenet: yeah, well teh bigger thing is core.cljs line 1777

6:49 (set! js/String.prototype.apply

6:50 if you change the prototype of string, you muck with javascript engines' optimizations

6:50 not sure how big the impact is from that, but dnolen assures me it's why cljs' strings are slower than desired

6:50 generally, extend-type does not modify prototypes on built ins, instead relying on a fallback and a switch statement for protocols on primitives

6:50 but apply is a special case

6:51 b/c you want (:foo …) and ('bar …) to work, but same for (map :foo …)

6:51 so since you can get a keyword or symbol back at runtime, and because apply happens directly, without any protocol lookup, you need to modify prototypes

6:51 which apparently deactivates entire categories of optimizations

6:52 on strings of all damn things!

6:52 argh.

6:52 mpenet: :/

6:53 bbloom: actually

6:53 looking at this again

6:53 it seems like it's been reduced to just indexing

6:54 ("foo" 2)

6:54 &("abc" 1)

6:54 lazybot: java.lang.ClassCastException: java.lang.String cannot be cast to clojure.lang.IFn

6:54 bbloom: hmm...

6:54 oh dur, i must be tired

6:54 IFn right above it

6:54 extend-type IFn and -invoke

6:55 mpenet: why is the toString call necessary on -invoke, since the dispatch is on Strings anyway isn't it redundant? (perf again?)

6:56 bbloom: lines 1773 & 1775

6:56 bbloom: mpenet: i'm not sure

6:57 mpenet: maybe it's not :-P

7:00 mpenet: give removing them a try

7:00 be sure to run ./script/test and ./script/benchmark too :-)

7:05 mpenet: bbloom: js-shell is necessary to run test/benchmark?

7:05 bbloom: mpenet: https://github.com/clojure/clojurescript/wiki/Running-the-tests

7:05 mpenet: I am following that page :)

7:05 just wondering

7:06 bbloom: mpenet: you can run just one platform if you like

7:06 mpenet: but generally all patches should be tested on all platforms

7:06 mpenet: ok

7:13 bbloom: mpenet: each of the platforms have some unique performance characteristics (and bugs too)

7:27 mpenet: the webkit nightly dl is awefully slow (64 KB/s)

7:33 Barkingdogs: raek, so, essentially, clojure dynamic vars _are_ paramatres? They are just static variables which are mutable under exceptional circumstances?

7:34 raek: Barkingdogs: I'm not familiar with parameters...

7:35 Barkingdogs: raek, well, basically, just tell me if they come down to statically scoped varaibles that are mutable under certain circumstances essentially.

7:35 raek: yes, I think so

7:35 Barkingdogs: raek, excellent

7:36 then they are about as unevil as obamacare

7:36 a little bit evil, but a lot better than other stuff.

7:36 raek: they also obey that stack discipline

7:36 Barkingdogs: What

7:36 What is that stack discipline?

7:36 raek: 'binding's can nest dynamically

7:37 each time you enter a 'binding' block you get a new mutable thread local variable

7:37 and when you leave it the old variable is used again

7:38 Barkingdogs: Hmm, and the 'scope' of that binding is lexical or dynamic?

7:39 Like, how a paramatre work is that you basically have (let-params [x 3] ...), any code inside ... will use x as the value 3, for instances functions which have x in their body

7:39 raek: (def *x* 1) ...*x* var immutable here... (binding [*x* 2] ...*x* is mutable here... (binding [*x* 3] (set! *x* 4)) ...*x* = 2...)

7:39 Barkingdogs: So what if effectively does is (set! x 3) at the start and (set! x oldx) at the end.

7:39 ah yes, that is essentially a paramatre is it not?

7:40 raek: dynamic vars seems to be like parameters

7:40 Barkingdogs: Good

7:41 raek: but in clojure you must have the dynamic var before you write the function

7:41 Barkingdogs: raek, what do you mean with that?

7:41 raek: (defn [x] (+ x *y*)) ; <-- not allowed

7:41 (def *y* 0) (defn [x] (+ x *y*)) ; <-- allowed

7:41 Barkingdogs: In a proper use of paramatres I find that you have to use (param x) to access the value of a paramatre

7:41 Yeah

7:41 raek: because varaiable scope is static

7:41 Barkingdogs: First (defparam x), then acces it with (param x), itś different from a variable.

7:41 Yeah.

7:42 So def always creates a dynamic var? or only if you put *y* around it?

7:42 raek: but the "extent" of the bindings introduced by 'binding' is dynamic

7:42 oh, sorry. you have to add metadata too: (def ^{:dynamic true} *y* 0)

7:43 previously (in 1.2 and earlier) all vars were dynamic

7:44 Barkingdogs: Ah yes

7:44 raek, so, do you play StarCraft?

7:44 Because everyone here does.

7:44 raek: no

7:48 sg2002: Hi all. Can somebody assist me with examples from Joy Of Clojure book? I've been going through chapter 10, the one about mutation, and I'm having problems with ref alter.

7:49 It either throws a NullPointerException or just does not work in one case.

7:57 Natch: sg2002: have you checked the book's errata page?

7:58 sg2002: Natch: Yes. There's nothing there.

7:59 Natch: sg2002: are you using the same clojure version as the book?

8:00 sg2002: Natch: No, I think the book was written for 1.3, while I'm using 1.4.

8:06 Natch: Ok, switching to 1.3 helped.

8:07 But I'm still interested to know why that does not work in 1.4. What was changed concerning refs?

8:08 Natch: sg2002: you can probably find out if you check the 1.4 changelog on clojure.org

8:11 sg2002: Natch: Looking at it right now.

8:58 wingy_: how do i use :db.type/uri (Value type for URIs. Maps to java.net.URI on Java platforms.) in datomic

9:13 jonasen: wingy_: I'm not quite sure what you're asking. Can't you just do [:db/add entity-id :uri (URI. "http://clojure.org")] in a transaction (if the :uri attribute is of type :db.type/uri)

9:14 wingy_: jonasen: oh i forgot the URI.

9:14 jonasen: why would (java.net.URI. "http://clojure.org") be better to use than "http://clojure.org" in a string property

9:15 is it because then it would need to be an URI and not something else

9:17 jonasen: The URI class contains useful methods. If you don't need them then I guess a string is just as good

9:19 wingy_: jonasen: yeah

9:28 abp: The meta-api isn't quite comfortable :(

9:29 what's a good way to replace things in meta and the function body besides postwalk-replace etc?

10:06 Mr_Bond: I'm having issues with a 4clojure problem, if anyone has some brainpower to spare. http://www.4clojure.com/problem/166 : I don't understand how to grab the operator being used, from a anonymous function. Is there a way to see what function returned a variable?

10:07 (lastfunc myvar); -> ">" something like that?

10:08 I'm not looking for the entire solution though, I would like to try to write the rest my self :)

10:11 andrewmcveigh: Mr_Bond: I don't think you need the operator from within the fn, the fn as a whole is the "operator"

10:12 Or, I didn't understand what you meant...

10:17 tmciver: Mr_Bond: The signature of the function you need to write could look something like (fn [op arg1 arg2] ...) where you could call the operator normally like (op arg1 arg2)

10:19 Mr_Bond: tmciver: yeah, but I need to return :eq or :lt or :gt

10:20 don't I?

10:20 andrewmcveigh: Mr_Bond: yes, but you need to work that out from the "op" passed in.

10:20 Mr_Bond: andrewmcveigh: yes, my question was, how do I do that with an anomymous function

10:21 the op being an anonymous function, that is

10:21 some kind of hint, cause I'm a bit stuck on this one :)

10:21 andrewmcveigh: Calling the fn on the args will tell you if arg1 is less than arg2

10:22 Mr_Bond: it will just return true or false, without saying anything about the operator?

10:22 hmm, yeah. I think you are on to something. I'll try that.

10:22 thanks :)

10:22 andrewmcveigh: yes, you can work it out from there.

10:23 tmciver: Mr_Bond: the problem statement tells you that you're given some kind of less than operator (if (op arg1 arg2) :lt)

10:24 Mr_Bond: yeah, I have to work out the operator which is given

10:24 andrewmcveigh: Mr_Bond: not exactly... the operator is always means "less than"

10:25 Mr_Bond: I don't understand what you guys are talking about now, not quite following. But I understand how to solve it now, with the help you have given

10:26 I'll look at the result of the operator/function on the args, and compare it with the args

10:26 tmciver: Mr_Bond: we mean that the problem doesn't require you to figure out what kind of operator you were given; you can assume it is less than.

10:26 andrewmcveigh: > Write a function that takes three arguments, a less than operator for the data and two items to compare.

10:27 Mr_Bond: oh, I get it now. thanks :)

10:31 tmciver: Mr_Bond: you've inspired me to get back on 4clojure problems (it's been a very long time since I've done any). Here's my solution to that problem if you get stuck: https://www.refheap.com/paste/6815

10:32 Mr_Bond: cool :)

10:32 I liked this one: https://www.refheap.com/paste/6814

10:32 and the one for default values in maps

10:33 I allways struggled with understanding "reduce" properly before this

10:33 tmciver: nice solution :)

10:34 tmciver: Mr_Bond: probably not as short as some could make it, but clear, I think.

10:34 Mr_Bond: hehe, yeah and I'm a newb

10:34 it's not only good for learning clojure this, but also for programming in general

10:35 but I think a lot of the problems I face are related to functional programming, and immutable types

10:35 Clojure is my first attempt at functional programming, and I'm really liking it.

11:54 tenpn: hello all

11:55 just messing around with clojure and overtone for the first time

11:55 could someone explain why this line doesn't work?

11:55 (definst s [noteName :C4] (saw (note->hz noteName)))

11:55 I get

11:55 lassCastException clojure.lang.Keyword cannot be cast to java.lang.Number clojure.lang.RT.floatCast (RT.java:1162)

11:58 Mr_Bond: I'm guessing there is a more elegang solution to this: https://www.refheap.com/paste/6816 :P

12:03 tenpn: why does this overtone command (definst s [noteName :C4] (saw (note->hz noteName))) result in ClassCastException keyword cannot be cast to number?

12:03 I've defined note->hz. (note->hz :c4) produces 2616.

12:04 *261.6

12:06 Foxboron: Question for Sublime Text 2 users. Would anyone like the idea of adding lein support inside of Sublime? Basically mapping the different lein commands into the Command Palette?

12:07 actually, nvm. I see someone have already done this.

12:08 https://gist.github.com/4103540

12:11 deg: I'm seeing some strangeness with pmap. I understand that it is only supposed to parallelize to the extent that makes sense on my hardware. (The source for pmap suggests that it starts nCore+2 parallel executions, which seems quite reasonable). But, I'm seeing (in JVisualVM) that a couple of dozen threads seem to be started on my 4-core computer. Most of them are waiting for locks most of the time. Is this expected behavior?

12:13 AndR: Mr_Bond: ,(doc nth)

12:13 ,(doc nth)

12:13 clojurebot: "([coll index] [coll index not-found]); Returns the value at the index. get returns nil if index out of bounds, nth throws an exception unless not-found is supplied. nth also works for strings, Java arrays, regex Matchers and Lists, and, in O(n) time, for sequences."

12:13 Mr_Bond: AndR: you can't use nth

12:13 in the solution

12:13 AndR: oh i missed it

12:13 sorry

12:14 Mr_Bond: can probably do something fancy with recursion

12:15 AndR: And I suppose just doing (source nth) and using that is cheating too .. :P

12:15 Recursion would probably be better, as you'd only traverse the list once

12:16 Mr_Bond: yeah

12:16 and not have to assign the list in memory twice

12:16 or at least parts of it a second time

12:19 AndR: Mr_Bond: do you want me to give you an example or can you write it yourself?

12:23 fckw: Hi there.

12:24 I would like to write a very simple REPL that can parse Clojure like mathematical expressions such as "(+ 2 3)".

12:24 What would be the best way to achieve this?

12:24 Oh - it needs to be done in Java - not in Clojure.

12:25 I thought: First, I need some sort of lexer and parser.

12:25 AimHere: Well if you're doing reverse polish, or S-expressions, then it's just a stack setup

12:25 fckw: But are there some best practices?

12:25 AndR: fckw: there's a lot of reverse polish calculator examples online, I'm sure you can find one in java

12:25 AimHere: (+ 2 3) means push 2 on the stack, then push 3, then pop them, add them and push 5 on the stack

12:25 clojurebot: *suffusion of yellow*

12:26 AimHere: Parsing is for when you have 2+3 and want to turn it into (+ 2 3) to be dealt with!

12:26 fckw: Yes, I know how this can be written in code, but I don't want to rewrite all this by myself but rather use a parser generator.

12:26 I thought of using ANTLR.

12:26 Or maybe JavaCC.

12:27 AndR: I don't see how that helps

12:27 fckw: Why?

12:27 clojurebot: why is the ram gone is <reply>I blame UTF-16. http://www.tumblr.com/tagged/but-why-is-the-ram-gone

12:27 AimHere: Would be silly; you want to run what's more or less the output of a parser into a parser

12:27 fckw: Nope, I first want to create a quite simple grammar. From this grammar, I want to generate a parser.

12:27 tmciver: fckw: If you want to write a lisp interpreter, you might find this enlightening (if you know Python): http://norvig.com/lispy.html

12:28 fckw: Thanks. Once I have the parser, how would parser and REPL interact?

12:28 AimHere: You're parsing stuff like (+ 2 (* 3 5)) - the whole point of having a parser is to get your 2+3*5 INTO that format

12:28 deg: fckw: Also look at SIOD (scheme in one defun): http://www.cs.indiana.edu/scheme-repository/imp/siod.html

12:28 fckw: Sorry, i have to explain a little better:

12:28 AndR: Well, you could have a parser, give it the input, and then work on the AST

12:29 fckw: AST?

12:29 clojurebot: paste is not gist.github.com

12:29 AndR: but it seems like too much effort for such a simple syntax

12:29 AimHere: Abstract Syntax Tree

12:29 AndR: abstract syntax tree, the output from a parser

12:29 fckw: Ah, okay. Once I have the AST, then do what?

12:29 AndR: well, make the calculations, I assume?

12:29 AimHere: Then do the stack machine thing I was saying

12:30 Or something that does the same job

12:30 AndR: with an AST he doesnt need a stack machine, he can just do depth-first traversal of the tree and collapse the nodes until only the result is left

12:30 fckw: Alright: So I have an AST. I can then traverse it using some stack and then execute what's on the stack. Is that right?

12:31 AndR: no, you can either traverse the AST directly, or skip the parser and read the input, putting stuff on the stack as you go

12:31 (it's easier with reverse polish than s-exps, so you might want to build the AST for s-exps. Still easier to do yourself than use some grammar generator, I think)

12:31 fckw: Ok. The reason I wanted to use a parser generator is that in the future the grammar might grow more comples.

12:31 complex.

12:32 Thanks, guys.

12:32 deg: If you are working in the lisp s-expr world, grammar shouldn't be an issue.

12:32 AimHere: Well compilers and interpreters do a division of labour these days. You get a parser that makes an AST (similar to lisp code/s-expressions/reverse polish) out of complex syntax, and then the backend that deals with the AST

12:32 fckw: Well, I am quite unexperienced with writing lexers and parsers, even for simple S-expressions. That's why I asked.

12:33 deg: Seriously, take a good luck at SIOD (google for best copies of source; it is an old project). It is C, not Java, but is a very, very small implementation of a complete lisp parser and runtime.

12:33 AndR: fckw: you probably want to write your own for a s-exp then, it's not that hard. Using a complex one will not help you understand it too much

12:33 fckw: I wanted to have a clean design from the start.

12:33 AndR: That usually doesn't work :)

12:33 fckw: deg: Already looking at it.

12:34 AndR: Yeah, I fear you're right. :D

12:35 (What I'm actually trying to do is writing some sort of REPL, where a user can define simple tree like data structures inetractively. Like this: "(defn newCategory value)"

12:35 So, really very similar to how the Clojure REPL works - just much simpler, AND it needs to run in Java.

12:36 (Rather like this: "(def newCategory value)")

12:36 deg: Remember that Clojure compiles down to Java, so if you just need to inter-operate in Java, maybe you can use Clojure directly.

12:37 fckw: or "(def newCategory (def newCategory2 value))"

12:37 deg: I thought about it. But then I would always need the clojure.jar given to my users, too, right?

12:37 AimHere: If you need something off-the-shelf, there's always one of a million XML parsers

12:37 AndR: You can embed clojure in your jar

12:38 so you only give them that one jar with all your dependencies included

12:38 fckw: Yes, that's true. I'll think about this.

12:46 * Mr_Bond is not super happy with this one either: https://www.refheap.com/paste/6817

12:50 Mr_Bond: ah, you can do same with reduce

12:55 zilti: fckw: Or use webstart.

12:56 fckw: Using web start for what?

12:56 You mean, instead of making a JAR including clojure.jar in it?

12:58 Frozenlock: I have a java method to retrieve some info from the network. However the process can take a long time. Any advice on how to update the data only if there's a given of time since last update? I was thinking of using an atom: {:timestamp 'last-update-time' :value 'some-value'}, then compare with current timestamp to see if I should update.

12:58 zilti: fckw: Using webstart to "deploy" it to your clients

12:59 fckw: You'll need the clojure.jar anyway.

12:59 fckw: zilti: Thanks for the hint, but it's still too early to decide on deployment questions.

13:00 zilti: fckw: Well, I just thought because you asked about deployment. Webstart is an awesome thing, but very few know how to use it and rather make some almost-works installers.

13:02 fckw: zilti: Deployment in general is still a pain in the a*. But using web start, why not? It's a good idea.

13:02 yedi: is there a #clojure log online?

13:02 zilti: fckw: I can tell you it's not a pain in the ass with webstart and lein uberjar ;)

13:05 fckw: zilti: We once had a customer. When a new version of our program would come, all he had to do was taking 1 .jar-file and put it in a certain destination directory, overwriting the old version of the .jar-file. He complained that this was too complicated a process. (Don't forget: The guys were Computer Admins, so they should have at least a basic skill in deleting and copying a file.) We kindly explained our customer that we simply could not co

13:05 with an idea on how to simplify the deployment process any more...

13:06 Ok, bye guys.

13:13 * hiredman is all nrepled up inside in jenkins

13:17 hiredman: https://gist.github.com/4106618

13:20 tgoossens: in a game. A robot can have "items". a function must exist to check whether a robot has a certain item, remove it, use it etc

13:20 i'm thinking of whether i need identity for items here

13:20 my first guess is not

13:21 because i think it doesn't matter

13:21 if a robot has 2 batteries with the same values. then it doesn't matter which one gets chosen.

13:21 and if they differ, the problem is trivial

13:21 is there something i'm not forgetting here

13:22 or is my thinking right

13:25 yedi: this function: (fn [a [b c]] (do stuff)) takes two variables? one being a vector with two elements in it? you can have nested parameters in clojure like that?

13:25 tgoossens: yes

13:25 yedi: thats a neat feature in clojure called "destructuring"

13:26 yedi: and as you probably guessed. in the function you can directly used b and c

13:26 ekoontz: nice

13:26 tgoossens: yedi: and if the vector has more than two elements only the first two are kept

13:26 ekoontz: didn't know about destructuring

13:26 yedi: yea, that seems really useful

13:26 tgoossens: i'm playing with destucturing atm

13:26 it gives you the ability to do "polymorphism à la carte"

13:27 eg:

13:27 (fn [{:keys [position health]}] ...)

13:27 means

13:27 the function expects a map with two keys. :position and :health

13:28 you can see how this gives you extremely flexible polyphishm

13:28 just "a map"

13:28 with those two keys

13:28 i use it all the time

13:31 --

13:31 ekoontz: can you destructuring with maps? or only vectors

13:31 tgoossens: read my example above

13:31 with maps you can do it as well

13:31 extremely powerfull stuff

13:31 ekoontz: ah this one? (fn [{:keys [position health]}] ...)

13:32 tgoossens: yes

13:32 it is one way of doing it

13:32 ekoontz: yeah missed your conversation above

13:32 thanks, cool stuff

13:32 tgoossens: http://blog.jayfields.com/2010/07/clojure-destructuring.html

13:33 what would be the best way. a robot has a list of items. should i use a vector or a list?

13:34 implementation detail i know. But just wondering

13:34 mpenet: it depends on how you use it (insertion, retrieval etc)

13:35 some usefull info here: http://www.innoq.com/blog/st/2010/04/clojure_performance_guarantees.html

13:35 tgoossens: thanks

13:42 yedi: so how exactly do namespaces work in clojure? there's the clojure.core namespace, but also like clojure.walk and others. Are they all included in clojure's main library?

13:43 AndR: Many are, but in general they are like java packages - you have to have a jar with the namespace you want to use on the classpath

13:46 hiredman: jars are a collection of resources, and my contain 0 or more java packages, or clojure source files, or any other kind of bytes

13:46 clojure namespaces normally map 1:1 to clojure source files

14:07 yedi: how can i check if an element is in a seq? like python's 'in' operator?

14:08 AndR: yedi: (contains? col key)

14:08 yedi: thanks

14:08 AndR: hm, not quite, it only takes indexes

14:08 i guess (some (= item) col)

14:09 ,(doc some)

14:09 clojurebot: "([pred coll]); Returns the first logical true value of (pred x) for any x in coll, else nil. One common idiom is to use a set as pred, for example this will return :fred if :fred is in the sequence, otherwise nil: (some #{:fred} coll)"

14:12 mpenet: ,(some #{:a} [:a :b :c])

14:12 clojurebot: :a

14:12 mpenet: ,(some #{:z} [:a :b :c])

14:12 clojurebot: nil

14:13 mpenet: AndR: contains works with sets/maps too

14:13 ,(contains? #{:a :b} :a)

14:13 clojurebot: true

14:13 mpenet: ,(contains? {:a :b} :a)

14:13 clojurebot: true

14:14 AimHere: Hmm, is there a function like some, but which returns x instead of (pred x)? I keep rolling my own

14:14 mpenet: AimHere: (comp first filter) ?

14:15 AimHere: That gives me the heebie jeebies, perhaps because I'm never totally sure when something's lazy or not

14:16 But it's an option, as is (some #(if (pred x) x false) ...)

14:16 mpenet: AimHere: I don't think there is an alternative in core

14:28 yedi: what does #{:a} do/mean?

14:28 AimHere: It's a set with the keyword :a in it

14:28 dgrnbrg: that's a set with one element: the keyword :a

14:29 yedi: the # denotes a set?

14:29 ChongLi: #{} denotes a set

14:29 AimHere: #{ ... } denotes a set

14:31 bbloom: # denotes some kind of variation on the next thing consumed by the reader

14:32 #{ is a set, #( is a function, #_ is discarded, etc

14:32 they are documented here: http://clojure.org/reader

14:32 search "Dispatch"

14:34 yedi: cool thanks,

14:36 ChongLi: especially cool is the form for passing data in unevaluated to the relevant constructor

14:36 gfredericks: quote?

14:36 clojurebot: http://en.wikipedia.org/wiki/Lisp_%28programming_language%29#Self-evaluating_forms_and_quoting

14:36 muhoo: AimHere: the docs usually say, but it'd be great if there were some other way to tell. metadata, maybe, or something

14:36 ChongLi: no, I'm referring to this

14:37 #my.record{:a 1, :b 2}

14:37 gfredericks: ah

14:38 ChongLi: they're great for serializing without the security issues of code being evaluated from an untrusted source

14:40 gfredericks: woah

14:40 when I do that syntax at the repl it prints a ClassNotFoundException but then returns the constructed record anyhow

14:41 I wonder if this is due to my single-element namespace :)

14:41 ChongLi: it returns a map, not the record

14:41 gfredericks: ooh

14:42 so the exception printed is like a warning by the reader

14:42 well no it _is_ returning a record

14:42 zilti: I want to implement a lazy collection, but I'm not exactly sure what to search for to do this

14:42 ChongLi: lazy-seq

14:43 zilti: Thanks ChongLi

14:44 Foxboron: Any Sublime Text 2 users wanna help me fix some snippets i found so they work with Clojure?

14:46 gfredericks: reading it with read-string works without any problems though...

14:53 yedi: so i have a function that takes two arguments, I want to map the function to a collection of mine, while keeping the second argument the same. How can I do that?

14:54 Iceland_jack: &(map #(+ % 5) [1 2 3])

14:54 lazybot: ⇒ (6 7 8)

14:55 metellus: or ##(map + [1 2 3] (repeat 5))

14:55 lazybot: ⇒ (6 7 8)

14:55 Iceland_jack: yes

14:55 metellus: I don't know whether that's a good idea, though

14:55 Iceland_jack: (for [i [1 2 3]] (+ i 5))

14:56 &(for [i [1 2 3]] (+ i 5))

14:56 lazybot: ⇒ (6 7 8)

14:57 yedi: ah right, I can just wrap the func in an anonymous function

14:58 ChongLi: yedi: that's something you'll find comes up again and again

14:58 can't map a java method over a collection? wrap it in a lambda

15:01 yedi: another trick you can use to do a similar thing is partial application

15:01 &(map (partial + 5) [1 2 3])

15:01 lazybot: ⇒ (6 7 8)

15:02 Iceland_jack: That is far more natural in languages like Haskell

15:03 ChongLi: sure, but it's still useful in some situations

15:03 Iceland_jack: Yes

15:03 ChongLi: for example, if you're mapping across a whole bunch of collecitons and don't want to do %1 %2 %3 %4 etc.

15:04 * gfredericks would probably use partial more if it weren't seven letters long

15:04 ChongLi: (def p partial)

15:05 gfredericks: quite

15:05 ChongLi: the other good one to use is comp

15:06 though a lot of people seem to prefer the -> macro

15:08 unfortunately, the -> is not usable as a higher order function (since it's not a function)

15:08 comp takes care of that

15:12 callen: ChongLi: I think for lisp people, if they have a macro that is apt to the use-case, they feel silly if they don't take advantage of it.

15:12 yedi: anyone wanna code-review my first ever clojure program?

15:12 I wanna see if there are things I can be doing better/more functionally

15:13 ChongLi: callen: yeah, I'm aware of that

15:13 yedi: https://github.com/yedi/rhyme-finder/blob/master/src/rhyme_finder/core.clj

15:14 gfredericks: yedi: wrap the docstrings

15:15 yedi: what do you mean?

15:15 ChongLi: the lines are really long

15:15 callen: yedi: try to at least stay somewhere near 80 columns across in your code.

15:15 gfredericks: line 33 at least

15:16 yedi: oh right ok

15:16 callen: is it idiomatic to use an io/reader like that?

15:17 ChongLi: I just use slurp

15:17 callen: that's what I do, that's why I'm asking.

15:20 wink: yedi: easy wins can be found with kibit

15:22 yedi: kibit looks really useful for learning, ill def check it out

15:23 callen: yedi: some rhymes are pretty fuzzy/not exact. Do you plan to handle those cases?

15:24 a good example would be something like shakespeare, even accounting for the pronunciations of the time, his rhymes weren't exact all the time.

15:25 yedi: yea, ideally I'll be able to handle those cases

15:25 i have a plan for it, but im pretty far away from that right now

15:49 callen: http://wikirhymer.com/rhyme-types

15:52 callen: Is there something like this for Clojure+Lucene? http://pypi.python.org/pypi/Whoosh/

16:09 Foxboron: So, fixed a couple of snippets i found for Sublime Text 2, anyone would like to test them? https://github.com/Foxboron/SublimeClojure

16:13 callen: Foxboron: wow, I didn't know people used ST with Clojure.

16:14 Foxboron: Well, it might not be ideal. I am myself a newb in Clojure and its a harsh world with Sublime from time to time ^^

16:14 But the overall support was kinda poor with only a syntax file and whatnot.

16:14 So i found a Leining build system, and added a snippet collection i found.

16:14 dnolen: callen: with SublimeREPL, Clojure development is passable in ST2.

16:14 Foxboron: SublimeREPL is kinda buggy from time to time.

16:15 Mr_Bond: I feel stupid, when doing this 4clojure stuff. I think it's a bit above my current level.

16:15 Foxboron: Mr_Bond, how far are you :)?

16:15 callen: dnolen: that's pretty neat. I'll have to check that out sometime in case I need to onboard a Clojure programmer that doesn't have time for Emacs.

16:15 the last time I did an onboarding, I got a bunch of people (like...10) at the Clojure meetup in SF to start using Emacs by cloning my git repo, hahahaha.

16:16 Mr_Bond: Foxboron: I've done quite a few of them, I'm at 39 now. It's the first one I gave up on, and googled (after spending at least two hours trying to figure it out)

16:16 the solution was much simpler than I thought: #(flatten (map list %1 %2))

16:16 Foxboron: i am at 23

16:16 Mr_Bond: ah, disregard that :)

16:16 callen: meanwhile, my .emacs.d has 400,000 lines of lisp in it.

16:16 Mr_Bond: cool

16:16 Foxboron: I spent the whole day at 21 and 22 trying to figure out why my lambda didnt work

16:16 then i saw i had () around the whole lambda ._.

16:16 callen: Foxboron: what like (#())?

16:17 Mr_Bond: I've not done 23 yet

16:17 Foxboron: callen: yes....are they called lambdas?

16:17 I am actually not 100% sure tho i still reffer to them as lambda <.<

16:17 Mr_Bond: I don't get the difference between (func) and (#(func))

16:17 callen: Foxboron: seems a reasonable term. They're just sugar for anonymous functions.

16:17 Mr_Bond: but I see sometimes the latter works, when the first one doesnt

16:18 Foxboron: mmm, should i post those Sublime repo on reddit?

16:18 Just so people can find it?

16:18 callen: Foxboron: can't hurt.

16:18 Foxboron: Not familliar with the community there.

16:18 callen: r/clojure is kinda sleepy. Needs more posts like this.

16:19 Foxboron: having trouble really knowing how i should write the snippets

16:19 atm the triggers are (defmethod etc

16:19 Mr_Bond: Foxboron: yeah, me too :) But it's really fun when they are working

16:20 callen: are either of you into search stuff perchance?

16:20 Foxboron: Mr_Bond, not sure how you work atm

16:20 callen: I found something cool for people who are recently.

16:20 Foxboron: but i think you just use the REPL?

16:20 am i correct?

16:20 Mr_Bond: Foxboron: yes

16:20 Foxboron: THen, i suggest you go and try setup a project with leiningen and write tests

16:21 then you compile your funcs and try test them with the test snippets you get

16:21 that way you get exp with the workflow

16:21 lein compile, lein run, lein test

16:21 etc

16:21 Mr_Bond: I just did the tests in the browser on 4clojure

16:22 callen: Foxboron: Mr_Bond follow amalloy on 4clojure btw.

16:22 Mr_Bond: willdo

16:22 callen: he'll teach you a lot about abusing #() :)

16:22 Mr_Bond: I'm mrbond

16:22 hehe

16:22 I need that

16:22 Foxboron: i am foxboron

16:23 Mr_Bond: how do you follow people?

16:25 Ah, you have to enter the url. I get it now

16:35 mpenet: dnolen: Hi, I asked something earlier that you can probably explain to me: is the call to toString here really necessary? https://github.com/clojure/clojurescript/blob/master/src/cljs/cljs/core.cljs#L1773

16:36 small detail, but I am curious

16:37 dnolen: mpenet: hmm, probably not - but that code is pretty awful. it's probably nigh to time to write proper keyword & symbol types and do the necessary optimization work.

16:38 bbloom: dnolen: as you recall, i had tried a while back but my optimization-fu wasn't up to snuff

16:38 dnolen: my attempt is here: https://github.com/brandonbloom/clojurescript/tree/keywords-and-symbols

16:39 quite hacky

16:39 dnolen: bbloom: yes I remember. we need something less hacky :)

16:40 bbloom: a lot of talk at the Conj about bootstrapping CLJS, this is a requirement for that to go anywhere.

16:40 bbloom: dnolen: "bootstrapping" in what sense?

16:40 dnolen: bbloom: the compiler can compile itself into JS

16:41 bbloom: dnolen: heh, why was that an interesting topic?

16:41 dnolen: besides the novelty factor. what's the motivation?

16:42 dnolen: bbloom: just being able to remove the JVM dep - LightTable, Session and similar projects could really benefit.

16:42 hiredman: that requires the cljs compile to take on more optimization work, yes?

16:44 dnolen: hiredman: that would be nice but I don't think critical to reap some early benefits.

16:44 hiredman: certainly it would be a good time to talk about making it easy to plugin passes.

16:45 hiredman: compilation via folding, T style

16:47 bbloom: dnolen: I'm not familiar with Session. which one is that?

16:47 dnolen: bbloom: http://github.com/kovasb/session

16:48 bbloom: http://vimeo.com/44968627

16:48 bbloom: dnolen: i'll check it out. random aside, how is the NY clojure meetup? My GF and I are strongly considering a move to NY in a few months :-)

16:48 dnolen: bbloom: http://twitter.com/chrishouser/status/269692379156606976

16:49 hiredman: I wrote some code during the conj to generate bytecode from some of the output of the clojurescript analyzer (I can compile the first 3 defs in core.clj) but I don't really like the approach I have, I think some kind of zipper for traversing the analyzer output would be good

16:49 dnolen: bbloom: growing! lots of new faces there these days - which is a good sign.

16:49 bbloom: dnolen: cool :-)

16:49 dnolen: hiredman: neat

16:50 bbloom: dnolen: conj was good too?

16:50 hiredman: I wanted to do compilation via transforms, but the zipper approach didn't occur to me until later, so it is very similar to the cljs emitter, put instead of println to stdout it calls ASM methods on *code-out*

16:51 bbloom: hiredman: see also my js-ast branch https://github.com/brandonbloom/clojurescript/tree/js-ast

16:51 dnolen: bbloom: was great fun! I think you would have enjoyed it quite a bit. You should try to make it next year. I suspect CLJS will be boostrappable by then :)

16:52 bbloom: hiredman: notes here: http://dev.clojure.org/display/design/JavaScript+AST -- if you want to add some comments about applicability of the approach to jvm byte code too, that would be appreciated :-)

16:54 hiredman: bbloom: I dunno that I have any notes, "passes are a good idea, and maybe a good way to do that is with a zipper"

16:54 bbloom: hiredman: heh. passes are a damn good idea.. which reminds me:

16:54 dnolen: we really need a top-level compilation unit AST node….

16:55 dnolen: closure has Token.SCRIPT, which is used for whole files or eval fragments

16:55 hiredman: the jvm compiler needs more information about types for interop, doing that as a pass over top of the existing cljs analyzer output seems like a good idea

16:55 bbloom: dnolen: it would be basically just a list of top level forms, but would also include the info that's currently in some of those top level dynamics

16:55 hiredman: yeah, right now type inference is trivial and baked into the analyze pass

16:56 hiredman: would be nice have a full-on inference pass

16:56 maybe with some core.logic love :-)

16:56 hiredman: sure

16:56 bbloom: also worth studying is the LLVM design

16:56 hiredman: someone at the conj mentioned something about a tshirt "my programming would be better with core.logic … if I could just figure out how"

16:56 bbloom: they have analysis and transform passes and they distinguish between the two b/c analysis passes only ADD info, where as transform passes invalidate analysis

16:57 hiredman: interesting

16:57 dnolen: hiredman: heh, pretty funny quote that.

16:57 hiredman: :)

16:58 amalloy: that's the beauty of it, right? just input bad code and good code, and run a core.logic program "backwards" to tell you how to use itself to get you there

17:03 dnolen: bbloom: I'm hoping ambrosebs might try his hand at using core.logic to add inference for Typed Clojure - we'll see. Typed Clojure actually generates interesting information for the compiler - the occurence typing info is actually exactly the kind of thing that could be used to further optimize Clojure code.

17:11 mpenet: dnolen: about CLJS-421 something like this would be acceptable you think? https://gist.github.com/4107823 ?

17:13 bbloom: dnolen: watching the session video

17:13 dnolen: i was playing with mathematica last week. it is super interesting :-)

17:14 dnolen: bbloom: session is a pretty sweet idea

17:14 ordnungswidrig: dnolen: will this kind of optimization conflict with the openes of clojure at runtime? I mean adding additional implementations for a type etc.

17:14 bbloom: dnolen: i found the mathematical "notebook" idea to be pretty compelling

17:15 dnolen: of course, state, is what burned me :-) i kept getting symbols interned that i wanted to clear & only could figure out to reboot the app

17:15 dsevilla: bbloom: what session video?

17:15 bbloom: dsevilla: linked above: http://vimeo.com/44968627

17:15 dsevilla: bbloom: thanks, I catched up late

17:16 bbloom: i would *love* a mathematica-style notebook thing for clojure… which is what i assume this video is building to :-)

17:18 dnolen: ordnungswidrig: it might have issues during development - but I don't see how they would cause issues at runtime at the moment. occurrence typing is basically applying obvious type optimizations in then/else parts of the branch.

17:18 er I mean in the case of occurence typing - more accurate type information - but you could apply the same strategy for optimization.

17:19 ordnungswidrig: dnolen: so it's kind of like branch prediction?

17:19 dnolen: ordnungswidrig: from what I understand it's the kind of thing efficient Scheme compilers already do, and I'd considered something similar for uses of seq & satisifes? in the past for CLJS ...

17:19 ordnungswidrig: dnolen: not harmful (functionally) if take the wrong assumptions

17:19 is ee

17:19 i see

17:20 so now that cljs compiles to cljs can't we use a clj to scheme compiler to take advantage of… no, let's drop that :-)

17:23 muhoo: is this an unreadable mess, or is it OK? https://www.refheap.com/paste/6835

17:23 Raynes: muhoo: Use for instead of mapo.

17:24 amalloy: muhoo: somewhere inbetween

17:24 Raynes: map*

17:24 muhoo: the "partial partial" made me chuckle, but i thought, my god, how will anyone understand what this thing does?

17:24 amalloy: agree with Raynes: map=>for is the first change i would try

17:25 muhoo: thanks. it's a fine line between clever and stupid, as spinal tap said. not sure what side of that i'm on.

17:26 amalloy: i think if you replace instances of map with for, the partial/partial nonsense falls out as a consequence

17:28 muhoo: it's funny, after coming from python to clojure, i used list comps everywhere. then i learned map/reduce and started to use them instead. now it's hard to go back to list comps. but it does make it clearer. thanks.

17:30 Raynes: muhoo: I think amalloy and I both hold the opinion that in most cases where you have to pass an anonymous function to map (and especially multi-line ones and ones with destructuring) it makes more sense to use for.

17:32 muhoo: thanks, that's a good rule.

17:32 bbloom: dnolen: session thing: super cool.

17:32 muhoo: much less insane that way, though still with ugly indentation: https://www.refheap.com/paste/6836

17:32 * Raynes is working on refheap trying to forget he is doing so in a hospital room.

17:33 Sgeo: Raynes, o.O what's going on if I may ask?

17:34 amalloy: muhoo: (conj (for ...) x) seems nicer as (cons x (for ...))

17:34 bbloom: dnolen: I'm not sure how far you can push the mathematica-style rendering. it's clearly super useful for rendering some category of interesting things, but under the hood, each "view" is doing something imperitive in some way

17:35 Raynes: Sgeo: My mother's potassium dropped really, really low during the conj (second day, actually). She is recovering, but we had to miss our flight home and are stuck here for quite a while.

17:35 Foxboron: So, i am messing with 4clojure tasks, and i am suppose to find the odd numbers. I am doing this by using reduce, but i get the error "Wrong number of args passed".

17:35 bbloom: dnolen: it seems like you need a lower level framework for implementing new views. ie. the youtube view expands out to the html view, etc. but that will fall over too when you get to the point of having to re-render an entire app

17:35 Foxboron: code so far: (reduce #(if (not= (mod %1 2) 0) println %1) [4 2 1 6])

17:35 Raynes: Sgeo: This happened once before in February. Fortunately, we weren't, you know, in a different bloody state at the time. :(

17:37 dnolen: bbloom: kovasb has done pretty well so far w/ data literals - clients can interpret however they want. you should chat w/ kovasb about it he's thought about it more. I think doing an entire app is a bit much - but I don't think that's really a goal - and not necessary to be compelling useful.

17:37 muhoo: what about this ((lots of stuff here ) arg) construction?

17:37 it looks ugly and obscure to me, i've used it a lot, but i wonder if it's considered bad?

17:38 bbloom: dnolen: yeah, sorry, should explain where my head is at: i've been trying to come up with some pretty cool full-scale-app stuff in clojurescript. my approach is heavily influenced by microsoft's WPF. it's basically a property-model

17:38 dnolen: i love the idea of data as an input, but i'm trying to figure out kinda how to make it scale to a large app and be toolable, etc.

17:39 amalloy: muhoo: that's often hard to read. at least for the special case of juxt, you might turn that into a for as well

17:39 bbloom: dnolen: I just get jealous of how *easy* things like session (and mathematica) make UIs :-)

17:39 dnolen: so kovasb in NY, then? I'd love to meet him

17:40 dnolen: bbloom: yes he's in NY

17:40 bbloom: ah, i think i have some insights for him on the IDomable / IViewable stuff in teh design challenges section

17:41 dnolen: could you send me an intro email? i'd appreciate it

17:41 dnolen: bbloom: it's an old video, I'm not sure what his thoughts are on that now. His session presentation at the Conj was quite different.

17:41 bbloom: sure

17:41 bbloom: thanks

17:41 i'm eagerly awaiting the conj videos!

17:43 muhoo: amalloy: wow, huge difference: https://www.refheap.com/paste/6837 now it looks like python code :-O

17:44 and it's clear what the damn thing does. so, win. thanks.

17:44 ambrosebs: Raynes: ah, glad to hear that above normal potassium is a good thing! nvm my tweet

17:45 Raynes: ambrosebs: It can get too high, but there is a huge gap between too low and too high and she is right in the middle.

17:46 dnolen: mpenet: that looks pretty good, though I would have 2 protocols not one.

17:46 ambrosebs: Raynes: thanks for the update. Lynn is a boss.

17:46 Raynes: She sure is!

17:46 dnolen: ambrosebs: Typed CLJS on the plane? sweet!

17:47 mpenet: dnolen: one for js->clj and one for clj->js you mean?

17:47 dnolen: mpenet: yes

17:47 mpenet: dnolen: not sure about the naming, there are conventions for that I would guess, JSEncodable, ClojureEncodable ?

17:49 ambrosebs: dnolen: I can't access the CLJS compiler from CLJS right? So it seems like my only option is to type check the CLJS AST in Clojure

17:50 dnolen: mpenet: IEncodeJSON, IEncodeEDN?

17:50 mpenet: dnolen: sounds good to me

17:51 dnolen: same location as where js->clj is now?

17:51 or is there some more appropriate place

17:52 dnolen: mpenet: yes that works

17:53 ambrosebs: yeah for now - in future when CLJS compiler is bootstrapped you might be able to do your current approach.

17:54 ambrosebs: note macros can access the compilation environment since macros are in Clojure.

17:54 mpenet: dnolen: hmm about the naming, EDN and JSON are tied to ajax, but in theory these fns could be used outside of this context?

17:54 ambrosebs: dnolen: oh!

17:55 dnolen: so I could still initiate type checking from CLJS repl

17:55 dnolen: mpenet: I'm not that great at names - if you have something better I'm all for it. Or anyone else!

17:56 mpenet: IEncodeClojure IEncodeJS seems ok, but naming is difficult yes :p

17:56 dnolen: ambrosebs: yep, one CLJS enhancement that would make this more natural would be an analyze-path option you can give the CLJS repl.

17:56 mpenet: go for it.

18:09 ambrosebs: Typed Clojure slides for the conj https://github.com/downloads/frenchy64/papers/conj%20main%20talk.pdf

18:27 mpenet: Having a hard time installing the dependencies to run the tests :/

18:33 I do have v8 and SpiderMonkey, but spidermonkey fails with some cryptic error. JavaScript core I should install qt5 to build it. (I am on ubuntu 11.10) https://gist.github.com/4108054 . If anyone knows what is the issue with v8 at least, any help appreciated

18:39 I probably need to bootstrap it first... nm

18:39 cljsbuild has spoiled me

18:45 dnolen: mpenet: yeah, getting the testing environment setup is a bit arcane. if JSC is too much of a hassle, just verify it works w/ SM & V8 and I can verify JSC.

18:48 mpenet: dnolen: Will do. The tests are running now (on v8))

18:54 yedi: how do you do multiline strings

18:55 Apage43: press enter in the middle of a string

18:55 Bronsa: lol

18:55 yedi: oh lol, figured youd might have to do something special

18:56 Apage43: nope. Be aware it's not going to do any whitespace cleanup or anything, though.

19:04 gfredericks: what happened to lein interactive?

19:05 Raynes: gfredericks: Have you tried drip? It might help you some.

19:06 yedi: does filter only let through values in which the filter function returns true, or all non-falsy returns?

19:07 Urthwhyte: ,(doc filter)

19:07 clojurebot: "([pred coll]); Returns a lazy sequence of the items in coll for which (pred item) returns true. pred must be free of side-effects."

19:08 amalloy: Raynes: do you know what the deal is with the sudden resurgence of interest in drip?

19:08 Raynes: amalloy: Pretty sure it was on HN again yesterday.

19:08 Urthwhyte: amalloy: it was on HN

19:08 gfredericks: Raynes: okay I will try :/

19:09 Raynes: amalloy: I also helped a guy while at the conj.

19:09 amalloy: It was hilarious. I helped him, presumably from his room, and then he came down and shook my hand.

19:10 gfredericks: how do I make lein use drip?

19:10 Raynes: Set LEIN_JAVA_CMD=drip

19:10 gfredericks: that sounds SO EASY

19:11 dansalmo: what is the lein dependency vector for clojure.walk?

19:12 Raynes: It's built in.

19:12 Comes with Clojure itself.

19:12 amalloy: it's funny because just on thursday ninjudd was saying drip was evidence of his becoming more responsible: he only wasted a week on a side project, rather than the six months he spent on cake. and then the next day, dozens of github issues and mail and stuff

19:13 dansalmo: (clojure.walk/prewalk ....) this does not work for me

19:13 Raynes: (require 'clojure.walk)

19:14 dansalmo: When I try lein repl in the project it does not compile due to not finding clojure.walk

19:14 thanks, I will try it

19:15 That worked, thanks. I thought I had to add it at the poject level

19:15 amalloy: if it were a separate library rather than a part of clojure.core, you would

19:18 muhoo: heh, side projects are a way of life in a new language. i remember some customer project, i had to create 2 new libraries, and some debugging and contributed changes in like 2 more libraries, all off the clock, in order to have what i needed in order to get the job done.

19:20 could have done it in php instead, without any of that extra work... but then i'd have been doing in php

19:22 yedi: is there a function for applying a function to all the values of a dict()

19:22 map*

19:26 gfredericks: for getting a new map?

19:26 (instead of side effects)

19:26 yedi: yea

19:26 gfredericks: nope

19:26 zipmap makes it not-too-awful

19:27 yedi: i'm looking at the second line of http://blog.jayfields.com/2011/08/clojure-apply-function-to-each-value-of.html

19:28 gfredericks: i.e., (zipmap (keys m) (map f (vals m)))

19:28 yedi: and i'm confused about how he's destructuring

19:28 wouldn't that reduce function be looking for 2 arguments, one being a vector with 2 elements

19:28 but here he gives the function a map instead of a vector

19:29 (gonna check out zipmap)

19:29 gfredericks: um

19:29 his code looks good to me...

19:29 ,(seq {:foo 1 :bar 2})

19:29 clojurebot: ([:foo 1] [:bar 2])

19:29 yedi: oh i'm sure it's correct, I'm just having trouble understanding it

19:30 gfredericks: ^ he's reducing over the map's seq

19:30 that's why also the destructuring of [k v]

19:31 yedi: he doesn't need to explicitly do something to convert the map into a seq?

19:31 gfredericks: nope

19:31 yedi: ah ok

19:31 gfredericks: most seq-y functions do it implicitly

19:31 it's quite useful :)

19:31 amalloy: a seq is just: a sequential "view" of some collection

19:32 functions that expect seqs implicitly call seq to get such a sequential view of their argument

19:33 Raynes: &(into {} (map (juxt key (comp inc val)) {:a 1 :b 2 :c 3}))

19:33 lazybot: ⇒ {:a 2, :c 4, :b 3}

19:34 yedi: thanks guys

19:40 after understanding how each of those methods work, i think i like the zipmap strat the best

19:40 * gfredericks wins

19:46 dnolen: not sure if anyone else has run into the depedency order issue w/ incremental compilation - if you have it would be helpful to see if this patch fixes it: http://dev.clojure.org/jira/browse/CLJS-282

19:47 unnali: dnolen: sure have.

19:48 dnolen: unnali: ah! can you try that patch, I was trying to test your minimal case, but I wasn't able to recreate before or after the patch.

19:48 unnali: hm, ok. will give it a go tonight!

19:49 dnolen: unnali: thanks much.

20:00 * gfredericks is using drip and still waits 7ish seconds for a jvm

20:00 Raynes: If you do multiple invocations back to back, that'll happen.

20:00 dnolen: unnali: chime on the ticket when you get a chance. the dep order stuff is necessary for moving forward w/ source mapping as well.

20:01 mpenet: is there a way to "reliably" compare 2 js objects in clojuresript, my tests keep failing because in js {} == {} is false

20:01 Raynes: NaN

20:01 dnolen: mpenet: there is no way to compare that two objets are equal in JS, you'll need to write that yourself.

20:01 mpenet: allright

20:02 hfaafb: if you don't have circular references you can try comparing their stringify results

20:02 hughfdjackson: mpenet: if it helps, underscore has a deep-equals implementation: http://underscorejs.org/#isEqual

20:02 amalloy: that's a very poor substitute for equality, hfaafb

20:02 mpenet: hfaafb: not really possible in my case

20:02 unnali: dnolen: sure, will do. (re: ticket)

20:02 dnolen: hfaafb: that assumes the order of object keys are consistent, I don't believe there's any such guarantee.

20:02 mpenet: hughfdjackson: thanks, I ll have a look

20:03 dnolen: mpenet: Underscore.js deep equality test is pretty crazy :) I would just look explicity for values in your tests. Just keep them simple.

20:04 hughfdjackson: http://underscorejs.org/docs/underscore.html#section-80 if you wanna look at the fairly mental implementation ;) as dnolen suggests

20:04 mpenet: dnolen: oki

20:06 I bet closure has something for that

20:08 dnolen: mpenet: don't think so.

20:08 mpenet: apparently not :/

20:08 dnolen: mpenet: equality in JS is massively broken.

20:08 mpenet: not in object.js at least, wher I would expect to have it

20:08 indeed

20:09 hughfdjackson: talking of broken things in javascript

20:09 does clojurescript export its immutable object types for use in regular js?

20:10 dnolen: hughfdjackson: I started on this a while back http://github.com/swannodette/mori.

20:10 hughfdjackson: :D very cool

20:10 i can tell you're not yet confident in its production readiness ;)

20:10 dnolen: hughfdjackson: until you can easily extract a particular datatype you want to use I don't think it'll see much use outside of perhaps Node.js where you might not care. it's a big dependency.

20:12 hughfdjackson: part of the problem is that quite a large chunk of the implementations are concerned with satisfying Clojure's nice protocols.

20:14 hughfdjackson: dnolen: hrm; it would be by far enough to have just a reasonable suite of immutable types to work with

20:15 may be better to start seperately with that goal in mind :)

20:17 seangrove: Hey all, trying to use codeq as a library in a project I'm working in, but I'm getting a very strange error: https://gist.github.com/6efb9ae3f2456c114526#comments

20:17 unnali: dnolen: replied on the ticket; unfortunately it didn't do the trick.

20:17 seangrove: Maybe I'm requiring eit incorrectly?

20:18 dnolen: unnali: hmm so identical results?

20:18 unnali: yup.

20:19 dnolen: unnali: oh I see, :incremental false was committed to the project

20:19 unnali: is there anything special I should do after applying the patch? I reran script/bootstrap for good measure.

20:19 dnolen: yes! silly silly silly me.

20:19 dnolen: unnali: let's see if I can recreate original issue.

20:19 unnali: in the commit named "Explicitly set :incremental true." :|

20:22 dnolen: unnali: btw, thanks for the minimal case project + good instructions, so helpful.

20:23 unnali: dnolen: no problems! I spent long enough answering questions on SO to know how helpful a reproducing (or not) case can be

20:23 gfredericks: Raynes: I'm going to conclude that my hardware cannot handle drip

20:25 dnolen: unnali: bizarre, I cannot recreate it at all. setting :incremental to true boosts my compile time considerably so I know that the compiler option is working, but I can't get a list of deps that are incorrect.

20:25 unnali: weeeird.

20:25 dnolen: unnali: what kind of system are you on?

20:26 unnali: os x (10.7.5)

20:26 you?


20:26 unnali: ...

20:26 dnolen: unnali: 10.7.5 as well

20:26 unnali: hahaha, bizarre.

20:26 hmm.

20:28 dnolen: unnali: oops I didn't follow your directions as closely as I should :) i see it's important to stop lein cljsbuild

20:28 unnali: ah! yes.

20:28 it's only on the second invocation

20:28 dnolen: unnali: recreated

20:28 unnali: !

20:28 woot.

20:28 dnolen: unnali: k testing now w/ patch

20:30 unnali: k for me the patch seems to work

20:31 unnali: hm.

20:31 do i need to do anything special to get it to apply?

20:31 dnolen: unnali: so you created a checkouts directory, cloned clojurescript into it, modified project.clj, and applied the patch?

20:31 unnali: correct

20:31 mpenet: dnolen: hmm it seems I can't add patches on cljs jira, I ll just add it as a comment + link on github .patch

20:32 unnali: dnolen: i've got a clone here of the clojurescript i'm using: https://github.com/unnali/clojurescript

20:32 dnolen: mpenet: you've sent in your CA right?

20:32 unnali: dnolen: and the sscce now has the modifications made: https://github.com/unnali/cljs-sscce

20:32 mpenet: yes

20:33 dnolen: it has arrived, I am listed on the contrib page.

20:33 dnolen: mpenet: can you ping clojure-dev to ask for permissions?

20:33 mpenet: will do

20:33 dnolen: unnali: can you paste your project.clj somewhere?

20:33 unnali: dnolen: sure: https://github.com/unnali/cljs-sscce/blob/master/project.clj

20:34 dnolen: unnali: lein 1 or 2?

20:34 unnali: ah, got a work meeting now

20:34 lein 2

20:34 dnolen: unnali: that maybe it, I'm not sure about classpath guarantees in 2

20:34 unnali: just retried and got the same result, possibly stillmy environment to blame

20:34 will brb.

20:34 aaah, i see.

20:35 seangrove: Looks like swank-clojure is broken with clojure 1.5.0-beta1..

20:39 dnolen: Had a chance to watch your cljs talk yesterday, really enjoyed it - thanks for putting it together!

20:39 dnolen: technomancy: ping

20:39 seangrove: the Strange Loop one?

20:40 seangrove: Yeah, from quite awhile ago

20:40 dnolen: seangrove: thanks!

20:46 unnali: gotta run - I can confirm that Lein 2 will ignore the checkouts directory if it "doesn't have a project.clj" (not even sure what that means). You probably need to ask technomancy about this. I'm not sure what's the easiest way to test CLJS patches is w/ Lein 2. Hopefully there's something straight forward.

21:05 muhoo: gah, i'm so deeply trained in the rdbms way of thinking about data, it's damn near impossible to break out of it.

21:06 even when i start thinking about things as maybe an object model (protocols, records) i still keep thinking "well i'd need a foreign key here and a link table..."

21:09 bbloom: muhoo: it's really not all that bad tho … it's probably better to think relationally than with a dense object graph

21:10 ambrosebs: interesting convo on typed clojure in #racket :)

21:11 perhaps a bit technical tho

21:14 muhoo: bbloom: relational designs can get pretty dense too. it just frustrates me that my brain goes into this same rut all the time.

21:17 i came up at a time when the answer for just about any data storage question was sql. that problem had been solved. no need to reinvent that wheel. use db2 or oracle or informix or mysql or sql server or whatever, it was all basically the same. now there's all this freedom and i don't know how to use it.

21:18 /rant

21:18 hughfdjackson: :D the brain-breaking times are some of the best

21:18 at least, by the time you get to the other side of it

21:23 muhoo: good point.

21:23 seancorfield: ibdknox: thanx for the tips about themes in LT - i copied in the full set of CM themes, updated order.json to declare them and now have monokai etc available - nice!

21:24 also: set font-size 24 and set theme solarizedlight makes LT very projector friendly for presentations!

21:27 Wild_Cat: Is the Windows version of LT usable? I heard there were various bugs

21:28 seancorfield: the only bug i've encountered is it looks for java.exe in the wrong place which is trivial to fix (just copy it to c:\Windows\SysWOW64\ if i recall?)

21:29 jyu: is clojure better living in emacs than vim?

21:29 seancorfield: i've been using it on Windows 8 and it seems solid Wild_Cat

21:29 jyu: that's a religious question :)

21:29 Wild_Cat: seancorfield: cool. Gonna give it a spin, then.

21:29 also, I´ve been looking for 2 things in the OSX version:

21:30 1. How do I disconnect from a project? (apparently, you can connect to as many as you want simultaneously, but it´s only additive)

21:30 2. How do I get a REPL (in a Leiningen-backed project) that auto-reloads my modules whenever I hit save?

21:31 seancorfield: not sure what you mean by "additive" - you can connect to a specific project and switch instarepl between connections

21:32 so you can have three files open in one project (connected to that project) and two files open in another project (connectec to that project)

21:32 as for auto-reload, i think it's early days to expect that (and reloading namespaces in clojure is a difficult problem anyway)

21:32 you can also open issues: https://github.com/Kodowa/Light-Table-Playground/issues

21:34 Wild_Cat: seancorfield: well, the ¨additive¨ thing is just that -- you connect to two projects, and whenever you launch an instarepl it´ll ask you which project you want it in.

21:34 ...even if you close and reopen LT.

21:35 seancorfield: which seems perfectly reasonable behavior to me? am i misunderstanding you...?

21:36 Wild_Cat: seancorfield: well, no. I want a way to globally switch projects, or at least disconnect from one. Let´s say I´m done working on a piece of software, I want it *gone* from my IDE until I explicitly bring it up again.

21:39 seancorfield: if i restart LT it forgets all connected projects BTW

21:41 Wild_Cat: seancorfield: hmm. Interesting. I can´t check here, but on my work machine it didn´t. Maybe I have stuff from an old version still running in the background.

21:41 thanks for the info.

21:42 seancorfield: i had old versions lying around too - just double-checked i have the latest from lighttable.com

22:11 flying_rhino: hello

22:11 why are vars dynamically scoped?

22:11 seems like bad idea to me

22:12 Sgeo: They aren't unless for a specific var, you set it up to be.

22:12 bbloom: so i have a tree-like structure that's flattened into a map: {'foo {:children ['bar]} 'bar {}} ; is there a way to work with such a structure with zippers?

22:12 flying_rhino: ?

22:12 I was pretty damn sure they are

22:13 Sgeo: http://ideone.com/yiOP60

22:13 And let is for lexical scope

22:14 flying_rhino: yeah let is for a very local namespace

22:14 inside function

22:15 Sgeo: http://ideone.com/y0u7ko

22:16 flying_rhino: okay I see the point

22:16 thanks

22:16 Sgeo: You're welcome

22:16 flying_rhino: how's adoption of language looks like

22:16 ?

22:16 are there new guys using it?

22:17 is it growing?

22:18 yedi: why is liberal use of let bad code smell?

22:19 Sgeo: http://ideone.com/mEMaCw

22:20 flying_rhino, fwiw, earlier on, all vars used to be supported by binding

22:21 flying_rhino: Sgeo: I am reading older book about clojure

22:21 Sgeo: from 2011

22:21 Sgeo: Ah

22:21 flying_rhino: Sgeo: that must be it

22:21 but seriously how does adoption of language?

22:22 how many people use this thing?

22:22 * Sgeo has looked at Clojure before, but only really got into it this year

22:22 Sgeo: Don't know, maybe someone else will answer

22:23 flying_rhino: how well does clojure perform mutlicore? I know it is big selling point of it.

22:24 brehaut: languages dont 'perform multicore'; programs do

22:24 flying_rhino: brehaut: I know

22:24 muhoo: and who is "selling" clojure? it's open source

22:24 brehaut: then why did you ask

22:25 flying_rhino: to rephrase: How big advantage are immutable data types and STM when programming multicore compared to vanilla Java?

22:25 flying_rhino: and what are drawbacks

22:25 ?

22:26 brehaut: how does malloc and free compare to GC? its about the same

22:26 also: STM is only one tool; its not a panacea

22:27 xeqi: significant, I'd recommend reading http://www.amazon.com/Java-Concurrency-Practice-Brian-Goetz/dp/0321349601 to get some ideas of how much work it is in java

22:28 Sgeo: How is Clojure vs. Haskell in this regard?

22:28 Haskell threads are lighter, aren't they? :/

22:28 brehaut: Sgeo: i think they are comparable

22:29 xeqi: I thought both were OS level threads

22:29 well, thats not the right phrasing

22:29 brehaut: xeqi: haskell has an impressive IO system that maps lightweight threads ontop OS threads and async

22:29 flying_rhino: xeqi: thanks, I got rough idea how it looks in java (not gritty details however). I am more interested are there problems with clojure? Like GC somethimes pauses program to clean up. Are there some problems with Clojure?

22:32 xeqi: brehaut: ah, its been awhile since I've touched haskell

22:32 brehaut: xeqi: i only dabble, so take with salt ;)

22:34 flying_rhino: can I call Java to produce mutable number in clojure? (not saying that's a good idea)

22:34 brehaut: a mutable number‽

22:34 xeqi: flying_rhino: sometimes you must type hint to get fast interop, and its easier to churn memory

22:34 but if you profile and find a spot to be a problem you can always drop to java

22:35 in a python -> c or c -> asm type way

22:35 flying_rhino: brehaut: to produce plain integer

22:35 brehaut: ,1 ; ← plain integer

22:35 clojurebot: 1

22:35 xeqi: ,(class 1)

22:35 clojurebot: java.lang.Long

22:36 brehaut: im fairly certain javas numeric types arent mutable though

22:37 muhoo: performance is a pretty deep topic in general, and concurrency performance especially.

22:37 xeqi: (inc muhoo)

22:37 lazybot: ⇒ 1

22:37 flying_rhino: brehaut: you mean x = x + 3; won't cnage value of x?

22:38 *change

22:38 muhoo: xeqi: thanks

22:38 i didn't know i could get points for stating the obvious :-)

22:38 water... it is wet!

22:38 xeqi: gravity is heavy

22:38 muhoo: gravity is just a theory, mind you

22:39 flying_rhino: brehaut: that makes little sense to me

22:40 amalloy: flying_rhino: it changes the value of x, but not the value of 3

22:41 flying_rhino: amalloy: but that's what I want, mutable x. The question was can I use Java interop to get mutable x?

22:41 metellus: flying_rhino: I think for that you'd want to use an atom or a ref

22:42 flying_rhino: metellus: probably

22:42 metellus: I just want to know if such a thing was possible

22:42 xeqi: &(doto (StringBuilder.) (.append "I") (.append "am") (.append "being") (.append "mutated"))

22:42 lazybot: ⇒ #<StringBuilder Iambeingmutated>

22:43 amalloy: xeqi: sounds like a message that would be sent by someone trapped in a StringBuilderFactory

22:43 metellus: flying_rhino: you could definitely use Java interop to work Objects like Integer and Double

22:43 xeqi: flying_rhino: yes, java interop allows mutating java object

22:44 metellus: but I'm not sure how that applies to ex. the Java "int"

22:45 flying_rhino: metellus: how would you handle multidimensional java array in Clojure?

22:46 metellus: I don't really know enough to answer that, sorry

22:46 flying_rhino: metellus: specifficaly 2d array

22:46 metellus: thanks anyway :)

22:46 brehaut: if you mean literally an array, then just the same as in java: with array of arrays. but you probably want a vector of vectors in clojure

22:47 or perhaps a map of pairs to values

22:47 it would of course depend on the specific application what the best representation is

22:49 flying_rhino: I thought Java has real 2d array, like c++. A rectangular array.

22:50 it is possible I mixed something up

22:51 brehaut: if you mean my_array[x][y] in c++/java

22:51 flying_rhino: basically item on x y location would be array[x + y*length]; if written as 1d array

22:51 brehaut: then yes you can do that

22:51 flying_rhino: yeah I mean that

22:51 brehaut: well then yes. you can do that. thats an array of arrays

22:52 but its properly bounds checked in java, not a contiguous block of memory

22:53 flying_rhino: okay

22:53 brehaut: nevertheless, you would probably want vectors in clojure, not arrays

22:54 flying_rhino: to represent large rectangular board (thing heightmap) arrays are more lightweight.

22:54 *think

22:54 brehaut: they are also mutable, which is not the right default for idiomatic clojure

22:55 flying_rhino: it's not like anyone is going to mutate them, unles I want them to and I don't.

22:56 I mean what is practical difference if I never invoke mutation from code?

22:58 brehaut: very little

22:59 the vector will use more memory, and is nicer to access

23:00 ,(aget (to-array [1 2 3 4]) 0)

23:00 clojurebot: 1

23:00 brehaut: ,([1 2 3 4] 0)

23:00 clojurebot: 1

23:02 flying_rhino: brehaut: thanks

23:02 one more thing about it

23:04 let's say that I have this large board that consists of 2d vectors or arrays, whatever. What if I want to, under rare circumstances, change it? Can I tell all current threads working on board "drop what you are doing, we are mutating board, try again when we finish" ?

23:04 that's exactly the functionality I am looking for

23:04 nightfly_: refs

23:05 brehaut: or atoms

23:05 or agents

23:05 depending on the application

23:05 'drop what you are doing is harder

23:05 metellus: isn't that exactly what happens inside a dosync?

23:05 brehaut: refs will ensure that its always consistent, but you'll burn a lot of cycles waiting

23:06 i dont believe so

23:06 dosync has checks on read and commit

23:06 flying_rhino: brehaut: say I have pathfinding looking for nearest path on board. When board changes, it should discard half finished path and tr again since it is obsolete.

23:07 metellus: well it's really "discard what you are doing and try again later"

23:07 flying_rhino: *try

23:08 if there is a new wall or something path might not be valid any more

23:08 so it starts again

23:08 brehaut: remarkably, per program specific details still require per program design

23:09 flying_rhino: brehaut: well I gave you details :)

23:09 brehaut: flying_rhino: solve your own damn problems

23:09 \

23:09 this is #yourfunctionaprogrammingdesignbitch

23:09 s/is/isnt/

23:10 flying_rhino: I simply asked if you have data A and sybsistem B uses it, can I mutate A in such a way it restarts B?

23:11 *automatically restarts B

23:11 brehaut: the answer is surely yes

23:11 the specifics are up to your application

23:11 thread coordination is hard

23:11 immutability and sensible primatives make it reasonable, not magic

23:12 flying_rhino: brehaut: uh... okay :)

23:13 brehaut: if it were me, i'd probably start of using futures, and future-cancel

23:13 flying_rhino: brehaut: that's all I wanted to know ;)

23:14 brehaut: its not magic; you'll still have to build the communcation on top of that

23:15 flying_rhino: I'll try

23:22 Sgeo: If I think that I want to use an anaphoric macro, should I just go ahead and do so, or should I struggle to think of alternatives?

23:26 bbloom: Sgeo: what do you want to use it for?

23:27 Sgeo: Have a series of functions that will take an argument, and I'm going to call the argument the same thing each time. The macro should be emitting code that refers to that

23:28 bbloom: would it be reasonable to establish a named binding? something like with-open ?

23:30 Sgeo: Not entirely sure how, or in my use-case even why I'd want to bother

23:30 The macro is for my internal use, not as part of the public API

23:30 bbloom: Sgeo: do you even need the macro? a tiny bit of redundancy won't hurt you that much :-P

23:31 amalloy: Sgeo: i'm not quite sure what you're envisioning. your macro (m + -) is going to expand to something like (do (defn f [x] (+ x)) (defn g [x] (- x)))?

23:31 Sgeo: I hate tiny bits of redundancy :( lol

23:31 arrdem: bbloom: always macro...

23:31 lisp has tought me to do terrible things when I write C now to avoid such duplication

23:32 bbloom: Sgeo: it's taken me a bit of practice to avoid abstracting out a macro until i see a pattern 3+ times

23:32 Sgeo: makes development go smoother because I don't re-re-refactor things that weren't that redundant to begin with

23:32 Sgeo: (defn blah-blah [bot a b c] (m a b)) expands to something like (defn blah-blah [bot a b c] (foobar +BLAH+ bot a b))

23:40 ForSpareParts: Does Clojure have some mechanism for efficiently serializing immutable data structures that share data?

23:42 ivan: ForSpareParts: seems doubtful

23:42 consider LZMAing the output?

23:42 arrdem: ForSpareParts: how do you tintend to make the references to "shared data" meaningful on deserialization?

23:42 *intend

23:44 amalloy: that's what java's Serializable does

23:45 ForSpareParts: arrdem, I was thinking that perhaps the serialized data structures could refer to other partial serialized data structures, allowing the language to deserialize them in a way that doesn't duplicate data in memory.

23:45 arrdem: ForSpareParts: that would be really cute, and it is doable in theory however Java does not offer such a facility to the best of my knowlege.

23:46 as amalloy mentioned Serializable is the closest you get, and that will duplicate ref'd objects

23:46 amalloy: huh? no it doesn't

23:47 arrdem: please correct me if I'm wrong, the only time I used Serializable I found that it dumped all ref'd objects down the tree unless your implementation of Serializable called for other behavior.

23:47 Sgeo: ugh, I am writing effectively the same code two times in a row

23:48 And similar code two more times, but the code has differences such that it's less immediately obvious how to factor it out

23:48 brainproxy: in my deftypes, if I have fields that are functions (or that implement clojure.lang.IFn), is it worthwhile type hinting them with ^clojure.lang.IFn?

23:48 amalloy: brainproxy: no

23:48 ForSpareParts: Well, the full story is that I'm trying to record the state of a real-time Clojure application on each update. Obviously, that turns into huge data very quickly -- I'm pondering strategies for dumping old data to temporary storage on disk as I go.

23:48 brainproxy: amalloy: okay thanks

23:49 ForSpareParts: I've never actually worked on a problem that involved larger-than-memory datasets before, and while I (theoretically) know how to do it, I'm getting a bit hung up on putting the theory into practice.

23:52 arrdem: is an append-only transaction log an option? If you just want to know what changed, that would be the easy thing to do and you could recover all state at an arbitrary point by integrating as it were over the logged changes. Slow, but possibly easier.

Logging service provided by n01se.net