#clojure log - Aug 11 2011

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

0:02 amac: Even dumping into a template throws a 'let requires a vector for its binding' error

0:04 err, my original question should have said dynamic vector.

0:06 tufflax: what do you mean by dynamic vector?

0:08 amac: something changable, so I want a let binding where the bound values (and their bound symbols) would be different dependant on what was passed into the macro

0:09 (bleh [a 2]) -> (let [a 2] body), (bleh [b 3]) -> (let [b 3] body)

0:10 TimMc: Seems straightforward enough.

0:10 amalloy: amac: that's literally how the implementation you already gave actually works

0:12 amac: when I try to pass a vector into the let form it cries though, ex. (def a [b 3]) (let a body)

0:12 amalloy: that is 100% not what you said you wanted. macros just don't work that way

0:13 amac: yeah, I was having a hard time phrasing the question

0:14 amalloy: amac: the macro runs at compile time. it sees 'a, not '[b 3]. there's a few things you can do about that, but they're all evil and wrong

0:14 amac: hmmm...

0:15 tufflax: amac are you just playing or do you have a real problem? :p

0:15 amac: bit of both, mostly playing

0:15 :)

0:16 tufflax: ok, well if you want you could describe the problem and we might be able to help with that

0:16 amac: the problem is kind of evil

0:16 tufflax: hehe

0:17 clojure is the bane of all that is evil

0:18 amac: tell me about it, it certainly gets rid of bad habits quickly

0:19 the problem is actually that I want to capture a bunch of symbols and tie them to some fns, but the symbols I'm trying to capture aren't constant (they're generated into a binding-like vector based on a bunch of other stuff)

0:20 which is wrong in a few ways...

0:21 but handy (at least, I think it will be) for this bigger thing I'm building

0:21 amalloy: so you have to make sure that stuff happens at compile time

0:21 see http://hubpages.com/hub/Clojure-macro-writing-macros for one of my blog posts with stuff that might be related

0:22 amac: amalloy: whoa, that's going to take me some time to digest.

0:22 bbiab

0:28 tufflax: Couldn't a vector be built similar to what happens in when-let for example: (let [form (bindings 0) tst (bindings 1)]. Wouldn't that allow amac to do what he wants?

0:29 I'm not sure I understand what he wanted though

0:39 amalloy: tufflax: in fairness, neither does he

0:39 tufflax: hehe

0:42 ibdknox: warning to folks using CLJS

0:42 writing macros with let in them seems to not do what you would expect

0:46 I'm looking to make my remote calls in Pinot prettier

0:46 and I think the nicest way to do that is through a let syntax

0:46 thoughts on if it should be letr letrem letremote?

0:53 amalloy: ibdknox: i don't actually use any cljs, but i'm curious how let could break only from within macros

0:56 ibdknox: amalloy: I didn't look into it too deeply, but from what I can tell it was closing over a variable and trying to pass the closure into my form as opposed to passing the value itself

0:56 I'm not sure, what I know is that it worked fine in Clojure

0:57 and didn't in CLJS

0:59 amalloy: huh

0:59 chouser: ibdknox: I'd be interested to see a simple test case that demonstrates that.

0:59 ibdknox: chouser: once I get this working, I'll try and make it happen again :)

0:59 chouser: there was a fix for closures in loops not too long ago. Dunno if it would be related.

1:00 ibdknox: chouser: no loop here

1:00 it was a version of me writing this: https://github.com/ibdknox/pinot/blob/master/src/pinot/macros.clj#L17

1:01 chouser: loop and let implementations are closely related in Clojure and ClojureScript

1:02 ibdknox: ah

1:02 could be then

1:11 amalloy: ibdknox: uh, having func# not be a gensym is kinda bizarre, just fyi

1:12 ibdknox: amalloy: can you explain?

1:12 amalloy: (let [func# ...] `(... ~func#))

1:13 func# is just a regular symbol named "func#" in the scope of remote, not gensymmed at all

1:13 ibdknox: ah, whoops

1:14 that's from when I was doing it a bit differently

1:14 * ibdknox goes to fix it

1:48 ibdknox: chouser: ping?

2:26 fhd: Morning

2:26 So what's the testing framework to use these days? clojure.test? Midje? Lazytest? Something else?

2:31 thorwil: that may be the first time i hear of lazytest

2:32 i guess for both midje and lazytest, clojure.test was looked at and considered unsatisfying

2:36 from http://www.lispnyc.org/blog/ericlavigne/a-tour-of-the-clojure-landscape: Midje encourages a separation between the actual tests and "checkers" that determine whether a test passed. Lazytest can be set up to watch your project's files, and rerun the tests automatically whenever your source code changes.

2:43 Guest9666: just curious... are protocols in clojure somethign similar than in objective-c ?

2:49 fhd: thorwil: Doesn't sound like I really need the features of either framework. Was just wondering if nobody was using clojure.test anymore, considering the number of alternatives

2:49 thorwil: I personally like clojure.test, does the trick for me. Some stubbing would be nice, but I can do that with bindings.

4:18 thorwil: how do i make the repl forget things that were defined by compling previous versions of the files i'm working on?

4:32 fliebel: What would be the best way to keep track of libraries developed for ClojureScript?

4:36 Hm, maybe Github... https://github.com/search?type=Repositories&language=&q=clojurescript&repo=&langOverride=&x=23&y=19&start_value=1

7:29 manutter: Any Eclipse/CCW users on?

7:30 depywork: I've tried it but that's it...

7:30 manutter: Yeah, I'm just playing around with it myself, I was wondering how the day-to-day workflow goes

7:31 especially how you go about adding dependencies like compojure

7:31 depywork: I never got beyond simple clojure scripts... :/

7:32 manutter: I get the impression not many people actually use it--I've been asking this question at various times for the past 3 days and haven't found anyone yet who actually uses it on a day-to-day basis.

7:32 clgv: manutter: I use CCW.

7:32 manutter: whoa, a nibble!

7:32 :D

7:33 clgv: so how do you handle dependencies? Do you use lein, or the built-in Eclipse library functions?

7:33 clgv: you add dependency by just adding the jar to the classpath in eclipse

7:33 I download them via leiningen

7:34 manutter: ok, that makes sense

7:34 I'm guessing you omit clojure itself from project.clj, since Eclipse/ccw adds it in already

7:35 clgv: you could write a launcher for leiningen to be able to just click a button in eclipse but I didnt try that yet. since switching to console 3-4 times a day is ok

7:35 manutter: Yeah, I did get lein pom to work as an external command

7:35 clgv: manutter: no I have it in project.clj and change eclipse classpath settings to the lib/ location

7:36 manutter: Ah, ok

7:36 clgv: but since I am on clojure 1.2.1 it's not supposed to change anyway ;)

7:36 manutter: heh :)

7:37 Ok, that's the info I was looking for, tks much

7:44 thorwil: i get differing results depending on whether i call this from the repl, or use it via an url handler: http://paste.pocoo.org/show/456528/

7:49 manutter: hmm, my first guess would be that you're getting an error calling (ds/save! (Article....

7:49 and the error message is getting lost

7:50 but I'm only saying that because it's the only way I can see to interrupt the program execution before the second (ds/save!

7:50 thorwil: it's the second call ds/save! that doesn't work in the through-handler case

7:51 and the (ds/save! (Article. ... does exactly what it should

7:51 manutter: Yeah, so if there was some kind of post-success error in the first one, it would never execute the second one

7:51 Is there any other output from that function? Do you have any kind of logging installed?

7:52 I'd insert a debug logging statement before and after the 2nd (ds/save!) call to see which code snippet is failing to execute.

7:54 thorwil: no logging yet, ok

8:27 comes out i was calling a function with a similar name, instead 0.o

8:27 * thorwil sometimes wonders how he got to any functioning code, at all

8:27 gtrak`: programming by probability?

8:38 Hodapp: THORWIL!

8:38 you're still around?

8:39 thorwil: =8-D

8:39 Hodapp: why screaming?

8:39 Hodapp: where'd I run into you first anyway? #lad or something?

8:40 clgv: gtrak`: or theological computer science, i.e.e just writing the code and then praying that it works ;)

8:40 gtrak`: clgv, oh, I haven't tried that yet

8:40 fhd: Funny that I never needed this before, but there is a way to redefine globals created with (def), right?

8:40 opqdonut: yes, just def again

8:40 clgv: fhd: alter-var-root

8:40 fhd: I thought it was (set!), but I get a IllegalStateException (can't change/establish root binding)

8:40 thorwil: fhd: def again?

8:40 opqdonut: or alter-var-root, yeah

8:41 fhd: thorwil: Worked in the REPL, not in my code

8:41 clgv: def-ing again, seemed not to work in clojure 1.3 anymore, when I tried porting some code few weeks ago

8:41 thorwil: Hodapp: if not #lad, it could have been #ardour perhaps. i don't think i saw you in ubuntu channels?

8:41 Hodapp: It was probably #lad. I never hung out in #ardour.

8:42 haven't been there in awhile.

8:43 fhd: thorwil: Okay, I made a mistake, defing again works

8:52 * fliebel does not understand closure compiler

8:54 manutter: fleibel: what don't you understand?

8:55 fliebel: manutter: its dependency layer.

8:56 manutter: I'm trying to use it with CouchDB, so I can;t just compile everything into one big file.

8:58 So either I need to emit one big JSON file directly, or spit out the right bits to the right place, to let couchapp push it to the database.

9:05 So I guess the question is... How can I compile an application with multiple entrypoints?

9:06 As in, different views on CouchDB, and code running in the browser.

9:08 manutter: Yeah, I can see how that would be difficult, Closure is oriented towards producing one big (minified) JS file, for web optimization

9:09 You should be able to write independent libs with a formal API though

9:12 clgv: Is there already a tool out there, that can analyse my clojure sources whether they contain superfluous :require, :use and :import statements in my ns-statements?

9:19 joegallo: slamhound

9:19 https://github.com/technomancy/slamhound

9:21 clgv: joegallo: thx

9:23 devn: manutter: closure is not about minification. it's about advanced optimization, dead-code elimination

9:24 *and* minification

9:39 manutter: devn: yes, exactly

9:56 clgv: args! clojure's (rand) uses Math/random which is synchronized and slowas down my threads... :(

9:56 ok, one PRNG for each thread now...

9:58 indeed all I do is adding doubles and calculating random numbers... ;)

9:59 mattmitchell: how can i get the character in a string at a particular position?

9:59 for example... (str-at-pos 0 "TEST") would yield "T"

9:59 clgv: like this: ##(nth "TEST" 2)

9:59 lazybot: ⇒ \S

10:00 mattmitchell: agh right!

10:00 clgv: thanks

10:27 fliebel: How can I update a compiled Jar? I ran jar xf foo.jar bar.class, fumbled with bar.class and called jar uf foo.jar bar.class, but now I get a security exception.

10:34 nilsg: hello

10:35 I have a problem with the executor framework and getting back values from clojure fns used as Callables

10:35 i do: (def *pool* (Executors/newFixedThreadPool 2))

10:36 and : (.get (.submit *pool* (cast Callable #(+ 2 3))))

10:36 what I get back is nil, not 5 ... Any idea what I am doing wrong?

10:39 manutter: nilsg: I think what you're getting back is the result of the .submit operation, not the result of the function you submitted

10:40 (caveat: I'm not familiar with the executor framework, so I may not know what I'm talking about)

10:40 nickmbailey: all functions already implement the thread and callable interfaces so you don't need to cast it

10:40 but i don't think thats your problem

10:41 manutter: The way I get output back from threads is to define a global atom somewhere, and have the thread call (swap! *global-atom* my-fn)

10:41 nilsg: nickmbailey: I wanted to be sure it was not using Runnable interface instead

10:42 nickmbailey: oh that could be it

10:43 nilsg: manutter: yes I could do that, but this interop problem is bothering me, I'd like to understand :)

10:43 nickmbailey: the cast function will implement both so i'm not sure if casting will help, if thats the problem

10:44 i.e. the cast will be done inside the runnable

10:44 nilsg: hmm ok, I didn't know that

10:44 nickmbailey: i'm just speculating though

10:44 nilsg: maybe I can try to pass a proxy implemeenting only callable, just to be sure

10:46 raek: nilsg: hrm. weird.

10:46 manutter: Try (let [call-fn (cast Callable #(+ 1 2))] (.get (.submit *pool* call-fn)))

10:46 raek: the cast shouldn't be necessary

10:47 * manutter is reading up on Executor, submit, and Interface Future<V>

10:47 nilsg: manutter: still nil

10:47 nickmbailey: what version of clojure and java

10:47 just tried and I get 5

10:47 raek: nilsg: try adding a type hint instead

10:47 nilsg: raek: actually, I get the same result with and without the cast

10:48 raek: nilsg: (let [^Callable f #(+ 1 2)] (.get (.submit *pool* f)))

10:48 nilsg: raek: I tried this too: (defn submit [^Callable f] (.submit *pool* f))

10:48 then (.get (submit #(+ 1 2)))

10:48 but no luck either, still nil

10:48 raek: same result?

10:48 ok

10:49 nilsg: side-effects inside the fn are executed however

10:49 manutter: nilsg: what JVM ?

10:49 nickmbailey was saying it worked for him

10:49 nilsg: openjdk I think... Let me check

10:49 raek: ~source future-call

10:50 nilsg: Well, I've looked at it, that's how I thought about the type-hint :)

10:51 java version "1.6.0_22"

10:51 OpenJDK Runtime Environment (IcedTea6 1.10.3) (ArchLinux-6.b22_1.10.3-1-x86_64)

10:51 OpenJDK 64-Bit Server VM (build 19.0-b09, mixed mode)

10:51 raek: the implementation of future-call, which does exactly this thing, does not even type hint it

10:51 oh, it does...

10:51 but it's the same as your submit function

10:52 nilsg: does (deref (future-call #(+ 1 2))) return 5 on your machine?

10:53 nilsg: well it returns 3, but yes...

10:53 raek: nilsg: try typehinting *pool*

10:53 eh

10:53 (where did I get the 5 from?)

10:54 nickmbailey: his initial question did (+ 2 3) somehow we moved to (+ 1 2) :)

10:54 raek: (def ^ExecutorService pool (Executors/newFixedThreadPool 2))

10:54 wastrel: 2 plus 3 is 5

10:55 raek: the source of future-call accesses a java field, so the compiler probably gets the type from there

10:55 nilsg: (set! *warn-on-reflection* true) can be useful in these situations

10:56 nilsg: Yes I have a reflection warning

10:57 raek: so my theory is that while you hinted the function, you did not hint the executor sevice. because of this, the compiler could not figure out the type and generated reflective code instead (which does not use any of the typehints, apparently)

10:58 and the reflective code just picks the first matching method it finds

10:59 nilsg: does (def ^ExecutorService pool (Executors/newFixedThreadPool 2)) solve the problem?

11:00 nilsg: nope, actually I still get the reflection warning on both get and submit

11:00 howerver, now the cast is necessary, without it I get an exception about being more than one matching submit

11:01 (the one for runnable and callble i guess)

11:01 also I find the reflection message for get surprising: reference to field get can't be resolved.

11:02 perhaps I should hint FutureTask?

11:04 raek: probably

11:04 nilsg: even when doing this : (def f ^FutureTask (.submit pool (cast Callable #(+ 2 3))))

11:05 raek: but isn't it a Future? (at least by the interfaces definition)

11:05 nilsg: I get the reflection warning for reference to field get can't be resolved

11:06 hmm, yes I think Future is the interface, you're right

11:07 raek: (defn submit [^ExecutorService exe ^Callable f] (.submit exe f))

11:07 (.get (submit pool #(+ 1 2)))

11:07 nilsg: this returns 3 for me

11:08 nilsg: yes, this works for me too, thanks!

11:08 raek: and with this I don't get reflection for .get: (defn ^Future submit [^ExecutorService exe ^Callable f] (.submit exe f))

11:09 nilsg: iep, same here for me :) thanks a lot!

11:09 raek: nilsg: I also wrote this, but it seems that you are already familiar with how these classes are used: http://blog.raek.se/2011/01/24/executors-in-clojure/

11:10 nilsg: Yes, actually I found your post back in my bookmarks while working on the problem :)

11:11 Bronsa: Hi

11:11 I am reading core.clj

11:11 I cannot understand what this means

11:11 636 (defn ^:static ^clojure.lang.IChunk chunk-first ^clojure.lang.IChunk [^clojure.lang.IChunkedSeq s]

11:11 637 (.chunkedFirst s))

11:11 nilsg: raek: however you didn't seem to need the type-hints at the time to get it to work

11:12 Bronsa: what is the meaning of the second hint?

11:12 what does it applies to?

11:13 raek: nilsg: no, I realized I only used the .invokeAll method which only accepts Callables

11:13 I should probably add this to the post

11:15 nilsg: raek: Yes, that would be great. Thanks for your help anyhow, not understanding this was driving me mad :)

11:22 coopernurse: I'm reading the appengine-magic readme, and I'm confused about some syntax on the last line that inits the webapp

11:22 (ae/def-appengine-app simple-example-app #'simple-example-app-handler)

11:22 what does the #' signify to clojure?

11:22 does that invoke the function?

11:26 manutter: coopernurse: #' means "get the var itself, not the current value of the var"

11:27 so if the value of simple-example-app-handler changes after the def-appengine-app, it will use the updated value

11:27 coopernurse: manutter: ah, cool. ok, so in this case I'm trying to wrap the handler

11:28 using: (compojure.handler/api simple-example-app-handler)

11:28 so that POST data is decoded

11:28 but it's not working, presumably because of the line above.. would I need to somehow nest that?

11:29 something like: (ae/def-appengine-app simple-example-app (compojure.handler/api simple-example-app-handler))

11:29 I know that's incorrect, but I'm a little unclear on how to express it correctly

11:34 manutter: I think you want something more like (def wrapped-handler (compojure.handler/api simple-example-app-handler)) (ae/def-appengine-app simple-example-app #'wrapped-handler)

11:34 i.e. put it into a var first so that you can pass #'the-var to def-appengine-app

11:38 coopernurse: manutter: ah, thanks, I'll try that

11:44 leo2007: does clojure compile to java byte-code?

11:45 jonabbey: yes

11:46 leo2007: can that directly run on the jvm such as the one from android without installing anything else?

11:47 jonabbey: i expect so, though you'd need some clojure library classes installed

11:48 http://clojure.org/compilation discusses .class file generation using clojure

11:48 lnostdal: hm, i think the jvm bytecode needs to be translated into dalvik type bytecode

11:48 jonabbey: yeah, it would

11:48 but the android dev tools take care of that for you

11:48 http://www.deepbluelambda.org/programming/clojure/creating-android-applications-with-clojure

11:50 mattmitchell: anyone know of a way to capitalize a string, without lower casing the rest of the string like clojure.contrib.string/capitalize does?

11:51 or... is there a super useful string lib out there besides contrib?

11:51 arohner: mattmitchell: look at the source of that capitalize

11:51 it does

11:52 (str (.toUpperCase ^String (subs s 0 1))

11:52 (.toLowerCase ^String (subs s 1))))

11:52 jonabbey: so (str (.toUpperCase ^String (subs s 0 1)) (subs s 1))

11:52 ,((str (.toUpperCase ^String (subs s 0 1)) (subs s 1)) "helloMom")

11:52 clojurebot: #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: s in this context, compiling:(NO_SOURCE_PATH:0)>

11:53 jonabbey: ,(#(str (.toUpperCase ^String (subs % 0 1)) (subs % 1)) "helloMom")

11:53 clojurebot: "HelloMom"

11:53 mattmitchell: cool thanks!

11:54 lnostdal: is there some way of controlling how a structure, say a map, is printed -- or similar? .. i'm getting stack overflows constantly because i have nested structures that point to each other (circle)

11:54 arohner: mattmitchell: clojure.repl/source is extremely useful

11:54 mattmitchell: arohner: what does that do?

11:54 arohner: mattmitchell: it prints the source of the fn, if it can be found on the classpath

11:55 mattmitchell: and I assume you already know about doc?

11:55 jonabbey: that's handy

11:55 mattmitchell: arohner: yes, i probably need to use doc more :)

11:55 arohner: didn't know about clojure.repl/source though, that's awesome

11:55 arohner: yes it is

11:56 somebody should write the bytecode version of it. I think that's guaranteed to work, even when the source can't be found

11:58 jonabbey: it likely wouldn't be very satisfactory. there is a significant loss of information going from clojure source code to the compiled output

11:58 arohner: meh. JVM bytecode isn't that hard to read

11:59 especially java method calls

12:01 hugod: ritz contains a disassembler that can display the bytecode for a function

12:02 arohner: lnostdal: you can try binding/setting *print-length* and *print-level*

12:02 lnostdal: http://blog.n01se.net/?p=85

12:06 raek: lnostdal: you can set *print-level*

12:25 cemerick: hiredman: so are you preferring infinispan over e.g. hazelcast then?

12:25 * cemerick likes to continue conversations from hours and days prior with no warning :-P

12:55 jsnikeris: What's the idiomatic way for handling configuration parameters in Clojure? The kind of data you'd store in .properties files in Java.

12:56 technomancy: jsnikeris: (read-string (slurp (io/resource "config.clj"))) is common

12:58 jsnikeris: technomancy: alright, thanks

12:58 lnostdal: arohner / raek, thanks!

13:04 dnolen: hmm so I guess you could pattern match on Java types just by extending them to ILookUp and using a guard...

13:14 hiredman: cemerick: haven't really used either

13:24 b

13:51 TimMc: cemerick: You're WRONG! (re: last week's comment on macros)

14:03 cemerick: TimMc: link? I can't remember what I wrote yesterday, nevermind last week… :-D

14:22 amalloy: cemerick: i think that was TimMc continuing a conversation without warning

14:24 Hodapp: that was like a drive-by

14:24 ibdknox: chouser: ping

14:24 cemerick: aaach, burned by my own hand!

14:25 ibdknox: for those of you with CA's, were you notified when it was received?

14:26 technomancy: ibdknox: no

14:27 dnolen: ibdknox: nah, your name will appear on this list http://clojure.org/contributing

14:27 Scriptor: how long does it usually take?

14:27 ibdknox: should I just apply for clojure-dev then?

14:27 amalloy: ibdknox: i think he goes over them about once a month?

14:27 ibdknox: last time I applied I got rejected

14:27 dnolen: ibdknox: ?

14:28 ibdknox: dnolen: "Hello ibdknox@gmail.com, Your subscription to Clojure Dev was not approved."

14:28 technomancy: it helps if you slip a few $20s in with the paperwork

14:28 ibdknox: haha

14:29 I had assumed this was because they hadn't received my CA yet

14:29 or someone really hates me already :D

14:29 Scriptor: probably the CA thing

14:33 ibdknox: dnolen: speaking of clojure-dev, I would definitely love a watch in cljs, as a stop-gap I wrote noir-cljs, but that only really helps if you're using it on the web and don't mind having noir running.

14:34 dnolen: ibdknox: yup. would save a lot of time.

14:36 TimMc: cemerick: amalloy is correct. I guess the joke fell flat.

14:36 gtrak``: vectors aren't seqs?

14:36 Chousuke: nope. but they are seqable

14:37 cemerick: TimMc: See, I went for a run after my question to hiredman, so I had totally forgotten my own comment. :-)

14:41 TimMc: oh no!

14:41 I guess that teaches me about meta-humor revolving around lack of context.

14:42 s/meta-humor/using \1/

14:42 Guest95270: <TimMc> I guess that teaches me about using 1 revolving around lack of context.

14:42 TimMc: um...

14:42 gtrak``: ,(inc 1)

14:42 clojurebot: 2

14:42 TimMc: Guest95270: Is that you in there?

14:42 gtrak``: &(inc 1)

14:42 Guest95270: ⇒ 2

14:42 gtrak``: sexpbot?

14:42 clojurebot: sexpbot is not a clojurebot

14:46 ibdknox: wow

14:46 I just got denied again

14:47 Is there some thing I'm missing about Clojure-Dev?

14:47 cemerick: You need to be on the CA list to subscribe.

14:48 ibdknox: ah, so even more than just have it sent in

14:48 that sucks.

14:49 technomancy: yep.

14:50 pjstadig: remember there are classes of clojure users

14:50 cemerick: If that's even part of what keeps the signal/noise ratio up near 1, seems like a small price to pay.

14:51 gtrak``: say I have a map of keys to vectors of vals, is there a simple way to convert that to a map of key to vals if there's only one val in the val vector? I did some loop recur nonsense but it seems dirty

14:54 ibdknox: just use map and something like (if (second val) val (first val))

14:55 gtrak``: ah

14:57 cemerick: pjstadig: classes?

14:57 o.0

14:58 pjstadig: yeah?

14:58 should i have said castes?

14:59 cemerick: perhaps nothing at all if those are the two options

15:00 talking about classes or castes is pretty over-the-top when the subject is a *mailing list*

15:00 pjstadig: there are CA signers and not-CA signers

15:00 ibdknox: cemerick: my life's worth is attached to that list. Don't take this lightly ;)

15:01 cemerick: ibdknox: Same here, and I don't. I just don't think it's worth some of the rhetoric that's tossed about.

15:02 ibdknox: lol

15:02 pjstadig: what? should i have said "groups"?

15:03 i guess you're reacting to the connotation of the words i'm using, but the fact is the fact

15:04 cemerick: I presumed you were using those words precisely because of their connotation.

15:04 TimMc: clojurebot: Are you an Untouchable?

15:04 clojurebot: I don't understand.

15:04 cemerick: Yeah, there's people that have opted into the rules that have been set, and those that haven't. Constantly hurling stones because of it is silly.

15:05 And maybe worse than that depending upon the details.

15:05 gtrak``: how do I make a map from a seq of vectors ([:key val] [:key2 val2])?

15:06 cemerick: gtrak: see zipmap

15:06 hiredman: incorrect

15:06 (into {} ...}

15:07 gtrak``: ah

15:07 zipmap is for things that look like zippers

15:07 hiredman: cemerick: I don't think pjstadig is refering to those that have signed the CA vs. those that haven't

15:08 cemerick: gtrak``: sorry, I read your Q too fast :-|

15:08 gtrak``: hiredman, that's very succinct thanks

15:10 cemerick: hiredman: Fair enough; I thought it was clear, but OK.

15:11 We're in year X of this topic though, so I'm sure there aren't a lot of new things to cover.

15:12 gtrak``: hiredman, is there a shortcut for duplicate keys?

15:12 hiredman: shortcut for duplicate keys?

15:13 gtrak``: say I have that seq of vectors, but some keys are duplicate (multiple values), I'd have to fold the vals into a vector

15:13 basically the opposite of what I was trying to do before

15:14 hiredman: you'll want to map over the vectors turning them into {:key [:value]} and then merge-with into

15:14 arohner: first world clojure problems: my program is only pegging 2 of my 8 cpus

15:14 hiredman: perhaps you should do some more io

15:15 arohner: hiredman: actually, zipping my input would probably speed things up...

15:15 I'm parsing a 4 GB xml file

15:15 zippy314: Hi folks. This works to call all the key-value pairs of a map onto some two parameter function and return a list of the results: (map (fn [[x y]] (some-two-param-function x y) ) some-hash-map) But I'm wondering if there's a more ideomatic way of doing it. Suggestions?

15:17 hiredman: (map f (keys m) (vals m))

15:17 amalloy: arohner: you can also do the vector conversion with reduce/update-in

15:17 arohner: that's probably slower though, if speed is important

15:18 amalloy: vector conversion?

15:18 dnolen: ,(map (partial apply +) {1 2 3 4})

15:18 clojurebot: (3 7)

15:18 gtrak``: arohner, I think he was talking to me

15:18 amalloy: oh, sorry, gtrak

15:19 &(reduce (fn [m [k v]] (update-in m [k] (fnil conj []) v)) {} [[:a 1] [:b 2] [:a 3]])

15:19 Guest95270: ⇒ {:b [2], :a [1 3]}

15:23 amalloy: zippy314: fwiw i prefer your first way. map a destructuring function over the map, rather than a two-arg function over its keys and vals. i do prefer using (for [[k v] m] ...) rather than (map (fn [[k v]] ...) m), though

15:24 gtrak``: I think the simplest for my case will be using map and into

15:26 zippy314: amalloy: yah, I just saw that (for [kv some-hash-map] (apply some-two-param-function kv)) will work too. You like just because you don't have to declare the fn?

15:27 amalloy: it's not like functions are expensive. declaring them is easy. but for has better nesting properties if the algorithm isn't trivially simple

15:28 and it has nice built-in :let/:when options

15:30 zippy314: yah. That's nice

15:33 gtrak``: check it out: https://gist.github.com/1140545 they are equivalent

15:34 joly: is there a built in function for splitting a list into two based on a predicate? something like (f even? [1 2 3 4 5]) --> ([2 4] [1 3 5]) Hopefully in one pass if possible

15:36 amalloy: (juxt filter remove)

15:38 joegallo: my god, it's full of functions

15:38 pjstadig: hiredman: i was in fact just talking about the CA/non-CA split

15:38 joly: hmm, not one pass, but maybe laziness will help me more than I'm currently thinking

15:39 hiredman: pjstadig: pardon me

15:43 arohner: ,(doc partition-by)

15:43 clojurebot: "([f coll]); Applies f to each value in coll, splitting it each time f returns a new value. Returns a lazy seq of partitions."

15:43 arohner: hrm. not quite

15:45 ,(doc group-by)

15:45 clojurebot: "([f coll]); Returns a map of the elements of coll keyed by the result of f on each element. The value at each key will be a vector of the corresponding elements, in the order they appeared in coll."

15:45 arohner: ,(group-by even? (range 10))

15:45 clojurebot: {true [0 2 4 6 8], false [1 3 5 7 9]}

15:46 joly: arohner: thanks, that's what I was looking for :)

16:15 amac_: amalloy: figured out my problem from last night, your blog post helped -- thanks!

16:22 fliebel: &(+ 1 1)

16:22 Guest95270: ⇒ 2

16:22 fliebel: ??? Does Lazybot/sexpbot have a new name again?

16:25 amalloy: fliebel: when Raynes graces us with his presence he'll make lazybot identify, i suspect

16:25 well, whatever. i'll just restart him; i think that's what Raynes does anyway

16:26 fliebel: amalloy: Oh, right. I still need to catch Raynes in here somewhere anyway. I saw he wrote a memcached backend for Jiraph.

16:28 amalloy: &(+ 1 1)

16:28 lazybot: ⇒ 2

16:28 fliebel: &(print "good morning")

16:28 lazybot: ⇒ good morningnil

16:30 amalloy: fliebel: you wanted to use the memcache backend to interface with couchdb's memcache api or something?

16:30 fliebel: amalloy: You use Jiraph at that company of yours, right? Which backend do you use, just the cabinet?

16:30 amalloy: Right :)

16:30 amalloy: I suspect I'll have to add a JSON backend to careal to make it work properly, but I think it's a nice idea.

16:31 amalloy: fliebel: i mentioned your desire to ninjudd yesterday, he thinks it's kinda bizarre to try to do that instead of just writing a couchdb layer

16:31 Hodapp: hm, I should examine this NoSQL bandwagon

16:31 if for no other reason than to piss off the greybeard DBAs

16:32 fliebel: amalloy: Do you think you can get any decent query speed with http and platters? The memcached api is in-memory.

16:33 amalloy: dunno, man

16:33 i can barely use jiraph, myself

16:35 * fliebel is confused.

16:36 arohner: can you use type hints to make clojure pick the right method on a java class?

16:36 I have to call a java class, that has two methods: "Object foo(Object o)" and String foo (String s)"

16:37 I want to call the string version, and I pass it a string, yet I get "no matching method"

16:37 fliebel: amalloy: What was the name of your company again? (does ninjudd also work there?)

16:37 amalloy: geni. and yes, he's my boss

16:39 fliebel: amalloy: How comes you can barely use Jiraph? I imagine Geni as one massive graph application.

16:39 amalloy: meh. there's plenty of other stuff going on.

16:43 dnolen: arohner: type hints should work for that yes, but you need to type the Java class and the argument

16:43 arohner: dnolen: thanks, but I was just wrong. I was getting no matching method because I thought it was static, and it wasn't

16:52 fliebel: dnolen: What was stm-couchdb about? Links to your github, but leads to starwars.

16:55 dnolen: fliebel: an experiment with seeing how fast you could insert documents into Couch

16:56 fliebel: Couch does better with bulk inserts, so I setup a simple ref that would wait till it received at least 50 docs before doing the insert.

16:57 you could insert a million docs in about 3 mins.

16:58 probably better now, they've made a lot of perf improvements it looks like. those tests were from a year ago.

17:03 fliebel: dnolen: So, it only saves on HTTP overhead, right? Because CouchDB already has a 'lazy' setting.

17:07 dnolen: fliebel: yes, tho the http overhead seemed pretty significant, 1 million docs is ~5550 docs inserted a second.

17:07 fliebel: I tried different bulk insert sizes, 50 was optimal at the time.

17:08 fliebel: dnolen: Doesn't that depend on the size of the docs you are uploading?

17:09 dnolen: fliebel: of course.

17:09 fliebel: pure microbenchmark, I was just playing around.

17:10 fliebel: dnolen: I would go for the 0MQ approach: send inserts at maximum speed, but queue when waiting for the server.

17:11 dnolen: fliebel: waiting?

17:12 fliebel: dnolen: You can push only so much data over the wire. Let mee see if I can find the 0mq thing.

17:13 hiredman: thats just async io

17:13 dnolen: fliebel: my experiment seemed to suggest the limiting factor was disk write perf, not the network. but I didn't look into super closely.

17:14 fliebel: Clojure would be done sending the data over the network in oh I dunno like 30 seconds

17:14 fliebel: dnolen: Then why would bulk inserts be beneficial? Just the append-only b-tree characteristics?

17:14 dnolen: the 3 minutes was just Couch writing all the data to disk.

17:16 fliebel: none of this was scientific, just two hours of playing around on a AWS Computer Cluster instance.

17:16 Compute

17:17 fliebel: dnolen: yeayea, I know, I'm just curious what would be the most efficient way to insert loads of data.

17:18 dnolen: if anyone's in NYC next week, I'll be talking about match and predicate dispatch, http://www.meetup.com/Clojure-NYC/events/16166963/

17:19 fliebel: dnolen: I'm not even close. But I heard some people say it was a more important talk than ClojureScript.

17:21 dnolen: fliebel: ha! ClojureScript is much more important IMHO.

17:23 fliebel: It's comparing apples to peathers. But from what I understand, a predicate dispatch system that is okay with rhikey has a larger potential impact on the whole of Clojure.

17:24 I need sleep. Bye

18:11 Raynes: $mail fliebel The memcached backend isn't finished. I forgot why right now, but we abandoned it, at least temporarily.

18:11 lazybot: Message saved.

18:12 gfrlog: making a memoized recursive function hurts my head

18:15 maybe it's easier with letfn...

18:18 amalloy: gfrlog: memoization isn't really for that anyway. for what purpose do you think you need this?

18:20 gfrlog: amalloy: let's say for a simple example that I'm defining pascal's triangle recursively

18:21 I thought this would be easy but my the repl keeps complaining about my arg counts...

18:22 amalloy: you can do that with iterate, for example

18:22 gfrlog: oh I just realized why the arg count fails...I'm using (partial g g) where I would need (partial g (partial g (partial g (partial g....))))

18:23 amalloy: how would I do such a thing with iterate?

18:23 given that each call causes two recursions

18:24 omitting base cases, the function is essentially (fn f [n k] (+ (f (dec n) k) (f (dec n) (dec k))))

18:25 amalloy: gfrlog: https://gist.github.com/gists/1140970/edit

18:27 gfrlog: so you create that lazy structure and then make a function that indexes into it?

18:27 amalloy: and this is totally lazy, of course. computing the millionth row doesn't require you to hold any more than two rows in memory at once

18:27 gfrlog: uh, do whatever you want with it. this generates the triangle

18:27 gfrlog: right

18:27 amalloy: you don't say what you're doing

18:27 gfrlog: yeah

18:28 amalloy: thanks

18:28 dnolen: clojurebot: max people

18:28 clojurebot: max people is 317

18:29 gfrlog: clojurebot: min people

18:29 clojurebot: programming clojure is http://www.pragprog.com/titles/shcloj/programming-clojure

18:30 amalloy: i don't think he actually counts people. someone just told him once that "max people is 317"

18:30 technomancy: clojurebot: forget max people

18:30 clojurebot: max people is 317

18:30 technomancy: clojurebot: botsmack

18:30 clojurebot: clojurebot evades successfully!

18:30 gfrlog: clojurebot: min people is 5

18:30 clojurebot: c'est bon!

18:30 st3fan: wy does lein create directories with underscores? is that because windows can't handle hyphens?

18:30 amalloy: java can't handle hypens

18:30 technomancy: st3fan: it's a problem with the JVM, not windows

18:30 st3fan: ohh of course

18:31 too bad .. they are so ugly :-/

18:31 amalloy: poor java has a "lexer" because it can't handle real syntax trees

18:44 gfrlog: did a bit of double-checking, and my iterative/lazy solution blows the stack. concat/for is a tricky combination

18:48 stuck a (map doall) in there and tried to compute the hundred thousandth row. no stack overflow, but it's been at about 130% cpu for several minutes now

18:56 gfrlog: amalloy: fortunately those details got replaced by the details of my actual function

18:56 which, in case you're interested, is computing the catalan triangle

18:57 http://oeis.org/A033184

18:57 amalloy: $google catalan triangle

18:57 lazybot: [Catalan's Triangle -- from Wolfram MathWorld] http://mathworld.wolfram.com/CatalansTriangle.html

18:58 gfrlog: oh I should try that factorial equation

18:58 the OEIS link had a closed form, but either I did it wrong or it's wrong

18:58 amalloy: yes, if you're only looking for a single row

18:58 gfrlog: I'm looking for a single entry

18:59 I assumed that C(.., ..) in OEIS referred to the choose function, but when I implemented it it started spitting out rationals

18:59 amalloy: gfrlog: yeah, i don't know how you'd know whether you'd done it wrong, with that completely illegible formula

19:00 it is Choose, though, as you can tell because the Maple definition includes binomial(...)

19:00 gfrlog: amalloy: the one I was going off of was: T(n,k) = C(2*n-k, n-k)*(k+1)/(n+1)

19:00 maybe I did my choose wrong :/

19:01 (fn [n k] (/ (factorial n) (* (factorial (- n k)) (factorial k))))

19:01 that matches what I have in my head...

19:01 amalloy: gfrlog: they probably mean 2n - k, not 2*(n - k). the formatting makes it hard to parse

19:01 gfrlog: yeah that's how I interpreted it too

19:02 amalloy: your choose looks right

19:02 gfrlog: maybe math doesn't work as well today

19:02 * gfrlog googles the schedule for math-maintenance

19:03 amalloy: gfrlog: fwiw though, you could write that as (/ (! n) (! (- n k)) (! k)) - the extra * step is unnecessary

19:05 gfrlog: I didn't know / was vararg

19:05 nor was I clever enough to think of the obvious use of the ! symbol

19:05 you've learnt me twice

19:15 triyo: can one dissoc all non-required keys from a map passed in a function as an argument; meaning that the map argument should only contain keys I want.

19:16 dakrone: ,(doc select-keys)

19:16 clojurebot: "([map keyseq]); Returns a map containing only those entries in map whose key is in keys"

19:16 dakrone: triyo: ^^

19:17 triyo: right, but not possible as a fn arg destructuring capability

19:17 ?

19:17 dakrone: (defn foo [{:keys [:foo :bar :baz] :as argmap}] ...)

19:17 the :as is optional, only if you need the entire map for something

19:18 gfrlog: that wouldn't give him exactly what he was asking for though...

19:18 triyo: gfrlog, yup you are right, not quite what I want

19:18 dakrone: no, it doesn't

19:19 gfrlog: triyo: I don't know why you want it though :)

19:19 triyo: Ok let me explain.

19:19 gfrlog: sure

19:21 triyo: I have a function that receives a map; this map contains some keys that actually represent the values that are passed on to sql insert/update statement as a *record*

19:21 take note of *some keys(

19:21 *

19:21 gfrlog: right

19:21 so far this is a use-case for select-keys

19:22 triyo: So think of it as an html form with many fields. I don't want to send "submit" field, :submit key to the insert statement..

19:23 so yes, select-keys seems most appropriate.

19:23 So I was just saying that it maybe would be cool if you could destructure in to that directly at function arg level

19:24 gfrlog: :/

19:24 I guess it doesn't seem like it would save all that much

19:24 syntactically

19:24 triyo: I guess you right, well regardless select-keys is cool

19:25 gfrlog: yessir

19:28 amalloy: gfrlog: i just looked at my previous solution to pascal's triangle on 4clojure

19:28 i defined !, but i did (/ foo (* bar baz)). shame on me

19:28 gfrlog: :)

19:29 I like how (/ foo) parallels (- foo)

19:30 amalloy: hm? in that it's 1-x or 1/x?

19:30 gfrlog: 0-x, isn't it?

19:31 amalloy: right

19:31 gfrlog: it's different from + and * in that the one-arg case is special

19:31 but they're consistend with respect to each other

19:31 and more useful than if they acted like + and *

20:24 dnolen: or patterns, https://github.com/swannodette/match/blob/d19de55df925cc846e4946a4453521b95c72b724/test/match/test/core.clj#L102

20:28 now for :as and :when

20:38 hiredman: ooo

20:43 technomancy: dnolen: 1.3 only, or is there backwards-compatibility?

20:44 dnolen: technomancy: nothing in match requires 1.3.

20:44 technomancy: cool

20:44 have you tried the lein-multi plugin?

20:44 lets you do "lein multi test" across arbitrary dependency sets

20:44 dnolen: technomancy: nice! I'll check it out.

20:45 technomancy: I use it for swank (though the tests there leave a fair bit to be desired); pretty handy

21:31 dnolen: k, being able to pattern match Java objects is going to be kinda … awesome, https://gist.github.com/1141252

21:33 drewr: yes! (except that constructor to j.u.Date doesn't do what you think it does)

21:33 dnolen: drewr: ?

21:33 hiredman: dnolen: beautiful

21:37 semperos: dnolen: nice!

21:38 drewr: dnolen: hm, I guess it did do what you thought it does

21:39 ,(java.util.Date. 2010 10 1 12 30)

21:39 clojurebot: #<Date Tue Nov 01 12:30:00 PDT 3910>

21:39 drewr: ,(.getYear (java.util.Date. 2010 10 1 12 30))

21:39 clojurebot: 2010

21:39 drewr: ,(java.util.Date.)

21:39 clojurebot: #<Date Thu Aug 11 18:42:04 PDT 2011>

21:39 drewr: that 3910 threw me off

21:40 but getYear() returns the right year

21:40 *shrug*

21:54 scgilardi: drewr: all the years above are 1900 off because date is kinda crazy and most of its member functions and constructors are deprecated.

21:55 dnolen: huh, does Scala have or patterns as well?

21:56 drewr: scgilardi: I know about (most of) Date's funkiness, just surprised that the 1900 is added to the printed obj represenation

21:57 scgilardi: the year value is defined to be 1900 + whatever you passed in. that constructor call created a date object representing a date in the year 3910.

21:57 getYear for today should return 111

21:58 drewr: it doesn't, thus my surprise

21:59 scgilardi: ,(.getYear (java.util.Date.))

21:59 clojurebot: 111

22:02 drewr: oh, I was confused by my rabbit trail above

22:02 grumble

Logging service provided by n01se.net