#clojure log - Aug 14 2011

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

0:11 solussd: Is there anything like doseq that executes each body in parallel, e.g. a pdoseq ?

0:15 drewr: solussd: pmap can have side-effects

0:17 solussd: drewr- pmap holds onto the head though. I'm not returning anything, I just want to wait until all bodies have executed… guess I have to hold on to something if I want to know. :D

0:18 amalloy: each body?

0:20 solussd: you can slap a dorun on front of a pmap if you want

0:21 drewr: or you could wrap each body in a future and let the threadpool throttle it out

0:21 you'd get some parallelization there

0:21 solussd: if I use futures, how can I join? I need to wait until all the futures have executed before I continue

0:22 drewr: I thought that's what you wanted

0:22 but they won't block anyway

0:22 solussd: (doseq [item items] (future #(do something item))) would return immediately. I'd like to block until all those futures finish

0:23 drewr: you could use a latch/await

0:23 solussd: ,(doc latch)

0:23 clojurebot: Excuse me?

0:23 solussd: ~botsnack

0:23 clojurebot: Thanks, but I prefer chocolate

0:23 drewr: http://download.oracle.com/javase/6/docs/api/java/util/concurrent/CountDownLatch.html

0:23 amalloy: drewr: that's so complicated. is there something wrong with pmap/dorun, or pcalls?

0:24 drewr: no, just giving options

0:24 there's also delays

0:25 amalloy: delay solves a different problem; how would you use it for this?

0:25 solussd: guess I might as well use pcalls- a throwaway seq of nil return values i lightweight enough. considering any other scheme would require some other way to monitor the completion of each thread/future

0:26 *is

0:28 drewr: amalloy: no, you're right

0:30 solussd: wonder how much memory a seq of 5 million nils takes up. :D

0:31 amalloy: about 64 bytes at any given time :P

0:31 solussd: ?

0:31 drewr: I didn't know about pcalls

0:32 amalloy: solussd: it's a lazy sequence that can get garbage-collected whenever

0:32 drewr: why doesn't this work?

0:32 ,(pcalls (fn [] 1))

0:32 clojurebot: (1)

0:32 drewr: ?

0:32 it gave me an exception locally

0:32 amalloy: so it's not like having a zillion of them takes up a bunch of memory

0:33 solussd: so, a map wrapped in a dorun could possibly be being deallocated as it is being churned out?

0:33 amalloy: 64 bytes is a number i made up, but the point is that it doesn't "take up" any memory. it might use some, if nobody else wanted it

0:34 solussd: ,(dorun (pmap #(* 2 %) (range 1000000)))

0:34 amalloy: &(nth (map inc (range)) 1e7)

0:34 clojurebot: Execution Timed Out

0:34 amalloy: aw

0:34 lazybot: ⇒ 10000001

0:35 solussd: lazybot?

0:35 amalloy: solussd: pmap is costing you time there

0:35 making all those threads is way more expensive than multiplying by two

0:35 solussd: sure- but for what I'm actually doing it is worth it. :D

0:36 more like this: (dorun (pmap #(process-items %) (filter #(not= % p) (keys prefs)))) and 'items' for each key could number in the thousands

0:38 amalloy: solussd: #(process-items %) is just process-items

0:38 and (filter #(not= % p) x) is (remove #{p} x)

0:38 solussd: ah, right-- I was using pcalls

0:38 didn't know that second though, thanks

0:40 hm, that made it faster

0:40 amalloy: what, my changes? i doubt that

0:41 solussd: well, I'm testing on very small numbers of items

0:41 maybe not creating the extra anonymous functions every time?

0:42 amalloy: solussd: that's a misunderstanding of how closures work. it doesn't have to create any functions at runtime

0:43 solussd: #(…) doesn't create a function?

0:43 amalloy: sure it does

0:43 at compile time, once

0:43 solussd: oh geez, right

0:44 amalloy: if the function is a closure, at runtime it needs a single constructor call to pass in the values it's closing around

0:44 but nothing expensive like compilation

0:44 solussd: all this clojure stuff makes my day job less fulfilling. :/

1:07 jli: I don't understand how to dynamically redefine clojure code in a running program

1:08 amalloy: don't

1:08 jli: why not? it's neat :/

1:08 amalloy: so is goto

1:08 jli: but it's REALLY neat

1:09 amalloy: *chuckle* WELL then, that's a convincing reason

1:09 jli: I got it working with Rich's ant simulation, but I can't get it to work with a tiny ring app

1:10 I'll redefine a part of the app, but it seems to keep calling the same old code

1:11 amalloy: are you talking about having the program modify itself, or you jump in at the console and type a (def) yourself?

1:11 it's only the former that's a terrible idea

1:12 jli: I included swank in the app, and I'm connected with slime

1:14 amalloy: you probably want to start-jetty with #'myfn, not myfn

1:15 jli: ohhh, hmmm

1:16 yay, that works

1:16 * jli goes off to read more about vars

1:20 jli: thanks amalloy

1:20 amalloy: the point is that the var is a mutable pointer to a function. when you send jetty "myfn", you deref the pointer and send it the current value. when you pass #'myfn, you give it the pointer

1:20 and, when called as a function, the pointer derefs itself

1:22 the last point is what makes the whole trick work

1:22 jli: right, awesome

1:22 amalloy: &(#'inc 1)

1:22 lazybot: ⇒ 2

1:23 jli: so, why shouldn't I do this now? :)

1:23 amalloy: feel free. but what you asked for was vague, and usually people who say that mean something dumber

1:24 jli: what's that?

1:24 amalloy: a program that modifies its code at runtime

1:25 they generally have wild fantasies of magic self-teaching programs based on a misunderstanding of "code is data"

1:25 jli: curious

1:26 I guess you could do that by calling def within functions?

1:26 amalloy: *nod*

1:27 certainly that sort of thing is possible

1:27 they generally combine it with eval to construct the functions at runtime. i typoed that as ruintime, and that seems appropriate

1:28 ANYWAY, short answer: redefining is great when it's something you do manually during development, as you're doing

1:28 jli: wow, "ruintime" - I'm definitely going to start using that

1:31 amalloy: ruintime: when management takes the gorgeous program you wrote and replaces it with something that breaks all the time?

1:34 jli: it has lots of applications

1:38 amalloy: btw i just copyrighted ruintime. for $20 i'll let you say it

1:39 jli: :(

1:41 Hodapp: goddammit amalloy

1:44 amalloy: what've i done now?

2:17 solussd: If I have a map of maps, e.g. {:a {:x 3 :y 4} :b {:z 5}}, and I will be updating the inner maps frequently and adding new maps to the outer map frequently, and I want to use transients… how do I 1. use (contains? outer-map some-key) to check if I need to create a new inner map transient if the key doesn't exist in the outer map; 2. turn the inner transient maps into persistent maps, followed by the outer map (that way I can take advan

2:17 of assoc! when reassigning the new persistent inner maps to the outer map keys) ?

2:19 of course, I'm doing this all within one function-- the function takes a map of maps and pulls some of the inner map keys out into an outer map and moves some outer map keys into inner makes. It's a map transform of sorts.

2:22 amalloy: solussd: i don't think you really want to be using contains

2:22 solussd: why's that?

2:23 amalloy: &(update-in {:x 1} [z] (fnil assoc! (transient {})) :a 10)

2:23 lazybot: java.lang.Exception: Unable to resolve symbol: z in this context

2:23 amalloy: &(update-in {:x 1} [:z] (fnil assoc! (transient {})) :a 10)

2:23 lazybot: ⇒ {:z #<TransientArrayMap clojure.lang.PersistentArrayMap$TransientArrayMap@1d3981c>, :x 1}

2:24 amalloy: that's probably not the most efficient way you could do it; probably faster is something like ##(update-in {:x 1} [:z] #(assoc! (or % (transient {})) :a 10))

2:24 lazybot: ⇒ {:z #<TransientArrayMap clojure.lang.PersistentArrayMap$TransientArrayMap@fdb3e8>, :x 1}

2:24 solussd: neat

2:24 didn't know about fnil

2:26 amalloy: the latter is just a reimplementation of fnil that avoids creating the new transient unless you're going to use it

2:26 solussd: ignoring my implementation for a bit, what I'm trying to accomplish, efficiently, is a transform like this: {:a {:x 3 :y 4} :b {:x 2 :y 8}} -> {:x {:a 3 :b 2} :y {:a 4 :b 8}}

2:27 with many more kvs in the inner and outer maps

2:28 and not all outer keyvals will have the same inner map keys

2:28 amalloy: you're just writing an index function, then? check out clojure.set; it has a lot of stuff that's at least similar to this

2:42 solussd: so, if the outer map is a transient as well, how do I iterate over the inner maps and turn them into persistent maps?

2:43 (no help from clojure.set afaict)

2:44 amalloy: transients don't really support sequential access

2:44 because seqs are immutable views over immutable data; if the underlying data can change, so can that view

2:45 solussd: well, my inner maps change the most while building the data structure, so I guess that's good enough.

2:47 amalloy: &(let [m {:a {:x 3 :y 4} :b {:x 2 :y 8}}] (apply merge-with into (for [[outer inner] m, [k v] inner] {k {outer v}})))

2:47 lazybot: ⇒ {:y {:a 4, :b 8}, :x {:a 3, :b 2}}

2:48 amalloy: now you can stop worrying about the internals and all the transients :P

2:50 solussd: well that sure is elegant

2:54 it's so simple, but I don't think I would have thought of, or even looked for merge-with

2:54 thanks!

4:00 jli: whoo, I just threw a memoize in front of the wikipedia-scraping portion of my little webapp, reloaded live, and it's way faster. go clojure.

4:18 amalloy: jli: if you use a permanent memoization cache, you'll run out of memory before too long, i imagine

4:24 jli: amalloy: yeah, that's on the todo

4:24 are there sweet things in core or contrib for LRU caches and stuff?

4:37 amalloy: no, but it's a topic that excites people all out of proportion so there are a number of non-core libraries to do it

4:39 like fogus's recent "unk". haven't used it, myself

5:00 jli: I don't understand how exceptions in clojurescript are supposed to work, and I can't find very helpful docs on it

5:00 it looks like (try ... (catch x y)) ends up compiling to "<exception> instanceof x"

5:01 what is a valid value for x then?

5:02 oh, I guess it's an Object.

5:13 justinus_: M-x clojure-jack-in not working for me after opening emacs in new lein project

5:14 it just says "Starting swank server....."

5:17 I just followed the steps under the Usage section https://github.com/technomancy/swank-clojure

6:24 raek: justinus_: try running "lein swank" in a terminal. hopefully this will give you some kind of error message

7:01 justinus_: "lein swank" works fine...and I am able to "M-x slime-connect"

7:04 is there any advantage of using "jack-in" over "slime-connect"?

9:10 pyr: record fields are immutable, just like map fields, right ? (i.e: no one can modify them from within protocol implementations)

9:11 hiredman: ~ping

9:11 clojurebot: PONG!

9:12 raek: pyr: yes, it's the same as with clojure's other data structures. the "modifying" operations have to return a new object instead of changing it in place.

9:22 pyr: raek: ok cool

9:23 changing some defmultis to defrecord + defprotocol

9:58 dabd: why does (apply str (interpose "," ["ab" "cd"])) outputs "ab,cd" while (apply print-str (interpose "," ["ab" "cd"])) outputs "ab , cd" (extra spaces surrounding the comma)??? Is this some bug in print-str?

10:03 upwardindex: Is there a clojure introduction article targeted for common lisp programmers?

10:03 tufflax: upwardindex there is a video...

10:03 upwardindex: Is it the 2008 Rich Hickey video?

10:03 tufflax: http://blip.tv/clojure/clojure-for-lisp-programmers-part-1-1319721

10:03 manuel_: boston lisp group video

10:03 tufflax: that one

10:03 manuel_: it's nice

10:04 thorwil: dabd: print-str uses print under the hood

10:04 upwardindex: Hasn't clojure changed substantially since then?

10:04 tufflax: not so much i think upwardindex

10:04 upwardindex: Ah great

10:04 thorwil: ,(print "a" "b")

10:04 clojurebot: a b

10:05 tufflax: dabd it's just how print-str works. print functions insert spaces between the arguments

10:05 thorwil: dabd: ^

10:06 tufflax: ,(pr-str "a" "b")

10:06 clojurebot: "\"a\" \"b\""

10:07 dabd: but I don't want the escape characters

10:07 tufflax: dabd hehe then don't use the "pr" version. I was just trying

10:08 dabd: yeah but "str" does not force the evaluation of lazy sequences...

10:08 tufflax: if you want to force evaluation use dorun or doall

10:10 dabd but, str should... what do you mean?

10:10 (should force, how else can it make a string)

10:10 dabd: tufflax:I am writing an example just a moment please.

10:11 tufflax: oh

10:11 i see what you mean

10:12 use doall

10:13 dabd: try this example (apply str (interpose "," (c/cartesian-product ["AB" "AC"] ["XX" "YY"])))

10:13 c is clojure.contrib.combinatorics

10:13 tufflax: hm, that didn't work as i expected...

10:14 dabd: doall does not work here

10:14 tufflax: noticed..

10:14 dabd: i guess cartesian-product returns a lazy sequence but doall is not realizing it for some reason....

10:16 tufflax: doall does, but it just doesn't print the way you want it still :p

10:17 it's still a lazy seq, but it has been realized

10:18 dabd: I was checking the docs. It produces each head but not the entire seq. How can realize the entire seq?

10:20 tufflax: doall realizes the entire seq, but the thing you get back is still of type lazyseq, so it prints like a lazyseq

10:21 dabd: I'm looking for a way to get a seq from a lazyseq....

10:22 tufflax: yes i know ;)

10:22 im trying to find a good way

10:25 pyr: hmm

10:26 so (new (Class/forName "something")) doesn't work

10:33 raek: pyr: new is a special form. it doesn't evaluate its arguments

10:33 well, the first one

10:33 jeremyheiler: pyr: (.newInstance (Class/forName ("java.lang.Object"))

10:33 pyr: yes

10:33 I figured as much

10:33 jeremyheiler: sorry, you were trying to create an instance of the Class object, werent you?

10:33 pyr: but newinstance doesn't work for records

10:34 raek: pyr: (FooRecord. a b c)

10:35 your problem (whatever it is) might be possible to solve with a macro that expands into a constructor call

10:35 (but since we don't know what you are trying to do, it's hard to tell)

10:35 pyr: yeah :)

10:35 so a bit of context]

10:36 i have an implementation of storage engine as a record implementing a protocol

10:36 i want the implementation to be specified in a config file

10:36 so what I read is a string

10:37 raek: in order to construct a record, you must know the number of fields it has

10:37 pyr: so this isn't possible ?

10:38 raek: I think some like this would be the simplest solution (def record-constructor-functions {"foo" #(Foo. %), "bar" #(Bar. %)}) (defn construct-record [t x] ((record-contstructor-functions t) x))

10:38 pyr: 'k

10:38 tufflax: dabd sorry, I can't find a good solution. (Anyone else?)

10:39 raek: pyr: if you have different kinds of records with different number of fields, you cannot cal their constructors with the same number of arguments

10:40 pyr: yes, that I get

10:40 raek: pyr: my suggestion is to create a function for each implementation whose purpose is to create a new instance of the record. these construcrtors would have the same interface.

10:41 then you can put those in a map and select the right one with a string

10:42 pyr: good enough for now

10:42 i thought i could do better :)

10:42 dabd: tufflax:thx. I am puzzled that this is so hard to do!!

10:42 raek: you can write a macro or call the constructor with reflection, but then you might get security issues

10:43 tufflax: dabd this works? (apply str (interpose "," (map (partial apply str) (c/cartesian-product ["AB" "AC"] ["XX" "YY"]))))

10:43 raek: pyr: you might be interested in this: https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Reflector.java#L153

10:43 it allows you to call a constructor with any arity (not just the zero arity one .newInstance exposes)

10:44 tufflax: dabd what do you want the end result to look like?

10:44 dabd: tufflax: that works fine.

10:44 anyway I will post the question again later to see if there are other ways... and understand why doall does not work...

10:45 thx

10:46 pyr: raek: ahah!

10:47 raek: but if you know the type at compile time, it is unneseccary to use reflection for that

10:47 dabd: is it a sequence of sequences?

10:48 pyr: no clearly i won't implement it like that

10:48 but it's cool to find out about these reflection features

10:49 raek: dabd: also, str is not the right function for turning clojure data structures into strings, use pr-str for that

10:49 dabd: raek: in the example above the output of cartesian-product is a sequence of strings which technically is a sequence of sequences. But I don't see how that helps

10:49 raek:but pr-str shows all the escape characters and I don't want that...

10:49 raek: dabd: in what way is the sequence not forced?

10:50 pyr: raek: invokeConstructor does the trick

10:50 dabd: with pr-str it is forced but shows all the escape chars

10:50 tufflax: dabd why doall doesn't work is this: You have a lazy seq, which prints in "the bad way". It doesn't matter if you do doall on it, it's still a lazy-seq, it's just that after doall it's realized in memory. If you did (iterate inc 1) and used 20 elements, then 20 elements are realized, but it's still a lazy-seq.

10:51 raek: yes, that's how clojure data structures look in string form. pr-str returns a string which can be read back again

10:51 dabd: tufflax: I understood that. The problem is how can I access the realized seq

10:51 raek: str is for concatenating strings and for turning numbers into strings

10:52 pyr: (defrecord

10:52 oops

10:52 raek: dabd: so you want to turn a sequence of sequences into a pretty string?

10:52 or concatenate all the elements or somehting?

10:53 I think your issue is related to formatting rather that laziness

10:53 *than

10:53 dabd: raek:yes I want to turn it into a pretty string

10:54 raek: so what does the resulting data look like? (if you just type it at the repl) and in what format do you wish to have it?

10:55 tufflax: raek I think he wants to make a string that looks like it's been printed with print or pr, but does not want the extra spaces.

10:57 raek: dabd: so you gave the data (("AB" "XX") ("AB" "YY") ("AC" "XX") ("AC" "YY")). what should the string look like?


10:58 dabd: raek: that would be fine

10:58 raek: that is what you get with pr-str

10:59 dabd: raek: but I get escape chars

10:59 raek: that's because you print it at the repl

10:59 try (println (pr-str (c/cartesian-product ["AB" "AC"] ["XX" "YY"])))

10:59 the backslashes are not part of the string

11:00 the repl prints your string as a string literal

11:00 dabd: raek:thanks

11:01 raek: dabd: "that would be fine" were you refering to (("AB" "XX")... or ABXX... ?

11:02 dabd: raek:the latter

11:02 raek: ok, I parsed it as the former... :)

11:03 then you need to concatenate all the subsequences and concatenate the strings

11:04 tufflax: my thoughts are not very clear atm but...

11:04 ,((juxt (partial apply str) (partial apply print-str)) [(lazy-seq ["a" "b"]) (lazy-seq [1 2])])

11:04 clojurebot: ["clojure.lang.LazySeq@fe2clojure.lang.LazySeq@3e2" "(a b) (1 2)"]

11:04 raek: (apply str (apply concat (c/cartesian-product ["AB" "AC"] ["XX" "YY"])))

11:04 tufflax: what if i wanted "(a b)(1 2)" (no space!)

11:05 raek: no spaces and no quotes?

11:06 tufflax: no spaces and no "LazySeq"

11:06 raek: then you can't use the clojure printer

11:07 (def x (c/cartesian-product ["AB" "AC"] ["XX" "YY"]))

11:07 (apply str (for [subseq x] (str "(" (apply str (interpose " " subseq)) ")")))

11:07 tufflax: hm

11:07 raek: "(AB XX)(AB YY)(AC XX)(AC YY)"

11:08 duck1123`: This is insane. There has got to be a way to get decent line numbers when exceptions happen in soy templates.

11:09 raek: tufflax: so if you have custom printing rules, you need a custom printing function... :)

11:09 tufflax: ok :p

11:12 dabd btw "<dabd> tufflax: I understood that. The problem is how can I access the realized seq" the realized seq is the lazy seq. If you don't want it to be a lazy-seq then (apply list ...) or something.

11:12 I think that is how it works anyway :p

11:13 upwardindex: Hey I'm watching the 2008 introduction to clojure and I was wondering if TCO made it to the JVM yet?

11:13 tufflax: upwardindex no

11:13 upwardindex: tufflax: any ETA?

11:13 tufflax: dunno :p

11:14 raek: I think some made a patch for TCO, but only for self calls, or something

11:15 tufflax: upwardindex but you don't need tco that often in clojure. The seq functions and recur takes care of most cases

11:15 duck1123`: I thought Rich said even if TCO was there, it won't replace recur

11:15 upwardindex: tufflax: ok, good!

11:15 dabd: tufflax: ok thx

11:16 tufflax: take* :p

11:16 upwardindex: well if tco is there recur is irrevelant no?

11:16 duck1123`: well, recur gives you that assurance that TCO is actually being used

11:16 tufflax: yes but recur is nice in other ways, the compiler makes sure its in tail position so u dont make mistakes

11:16 duck1123`: if you try to recur when you can't, you get an exception

11:17 and it's very rare that you need to call it directly anyway

11:20 tufflax: and recur works for anonymous fns :p

11:20 lucian: tufflax: you can just as easily do (fn bla []...)

11:20 tufflax: yes i know

11:20 lucian: but yeah, recur is great

11:20 tufflax: but that's one more symbol

11:20 :p

11:21 lucian: the only use-case for real TCO i can think of is mutually recursive functions

11:21 and that's just way too confusing for me

11:21 tufflax: hehe

11:23 duck1123`: tufflax: you can recur inside a named fn

11:23 tufflax: yes of course

11:23 lucian: duck1123: look up

11:24 duck1123`: ahh I read the works for as only works for

11:24 and that confused me

11:24 lucian: btw, fn names are only in the fn's scope?

11:24 tufflax: yes i think so...

11:25 hiredman: (fn foo [] ...) foo is the this pointer for the Fn object

11:25 lucian: hiredman: right, so it doesn't leak in the outside scope. implicit let

11:26 danlarkin: anonymous function name

11:27 tufflax: hiredman does that have any nonobvious consequences?

11:27 hiredman: nope

11:27 tufflax: ok :P

11:27 duck1123`: makes the class names nicer too

12:30 lobotomy: ,(vec {:a 3 :b 2 :c 12})

12:30 clojurebot: [[:a 3] [:c 12] [:b 2]]

12:30 lobotomy: what's a good way to turn [[:a 3] [:c 12] [:b 2]] back into a map?

12:31 ah, apparently into

12:31 ,(into {} [[:a 3] [:c 12] [:b 2]])

12:31 clojurebot: {:a 3, :c 12, :b 2}

12:31 lobotomy: yay

12:36 no_mind: how do I call the clojure code from other jvm languages ?

12:38 duck1123`: do you man running clojure fns, or are you looking to make a class in clojure that can be called from java?

12:38 mean

12:39 http://stackoverflow.com/questions/2181774/calling-clojure-from-java

12:43 no_mind: duck1123`: I have a package in clojure and some one wants to extend it using jython. So I need to provide an interface which will allow calling of clojure fns from clojure package.

12:44 duck1123`: I don't know much about Jython, but you can have clojure produce actual classes and interfaces that jython could then use

12:45 http://clojure.org/compilation

12:45 now, that assumes you're able to change this clojure lib

12:45 and it forces you into AOT compilation

12:47 that SO pages shows how to simply call clojure from java. I assume you could use Jython's interop to do something similar

12:48 no_mind: thnxs, I will try

12:48 duck1123`: If you're planning for interop, better to go the gen-class route

12:48 no_mind: ok

12:51 duck1123`: http://cemerick.com/2011/07/05/flowchart-for-choosing-the-right-clojure-type-definition-form/

12:52 that's more for working in clojure, but still a handy chart

12:58 paulK_: hi there, what's the easiest way to list all files in a directory with clojure?

12:59 technomancy: (.listFiles (clojure.java.io/file "/tmp"))

12:59 should work

13:00 paulK_: thank you technomancy

13:01 technomancy: sure

13:01 paulK_: works great

13:02 technomancy: also .list if you want strings

13:02 hiredman: file-seq

13:02 technomancy: yeah, also file-seq has the advantage of working from clojurebot

13:03 paulK_: clojurebot?

13:03 clojurebot: clojurebot is a cold unfeeling genderless mechanism

13:03 pschorf: :)

13:04 hiredman: ~botsnack

13:04 clojurebot: thanks; that was delicious. (nom nom nom)

13:07 paulK_: ah, sorry my connection went down (and is very flaky ... )

13:21 tufflax: paulK_ http://clojure-log.n01se.net/

13:21 might come in handy

13:22 paulK_: thank you tufflax

14:29 tnks: I'm new to Clojure, but keeping an eye on it for when Scala/Haskell stops consuming my bandwidth.

14:29 but I'm really intrigued by Clojurescript.

14:29 does that bring persistent immutable datastructures into the Javascript ecosystem?

14:30 fliebel: tnks: Yes, but they are not yet as efficient as Clojure's, they are just... immutable.

14:30 tnks: ah. . . I /might/ have /just/ found my answer. . . (not in the alpha, but soon)

14:30 fliebel: efficiency asside, are they persistent?

14:30 (meaning no exception throwing on attempts to mutate)

14:31 https://github.com/clojure/clojurescript/wiki/Differences-from-Clojure suggests they aren't yet.

14:31 (or not all of them)

14:31 maybe List was easy or something.

14:32 fliebel: I suppose...

14:34 tnks: It seems hash-map is implemented like array-map for now. https://github.com/clojure/clojurescript/blob/master/src/cljs/cljs/core.cljs#L2035

14:38 amalloy: tnks: "efficiency aside, are they persistent". the definition at your link says they're not all persistent, but only because they're not efficiently persistent

14:38 (which is the only meaningful definition of persistent)

14:50 eskatrem: hello, I have some problem to write a script to get the prime factors of an integer.

14:51 I knew http://pastey.net to paste the code I want to show but it seems to be down. anybody knows a better one?

14:51 amalloy: http://gist.github.com

14:52 eskatrem: thanks amalloy

14:52 I put my code here: https://gist.github.com/1145173 , if someone would be kind and explain me what's wrong with it

14:53 amalloy: that's a long list of things that are wrong. what language are you coming from?

14:54 eskatrem: hmm

14:54 I use mainly R this days, I learned a bit of C/C++ before

14:54 I was trying to do some problems from Euler project

14:55 to get a hack on clojure

14:55 amalloy: sure, it's a good approach

14:56 the three problems that stand out to me are (1) :while isn't a legal thing to do in a loop; (2) you group expressions like (do expr1 expr2), not ((expr1 expr2)); (3) you shouldn't be def'ing things in a loop, but instead supplying the right arguments to recur

14:56 eskatrem: I feel like an idiot with that piece of code, I dont understand why it doesnt repeat the step "divide by p"

14:57 for problem (1), I tried many "versions" of a loop, this one happens to be my last failure

14:57 amalloy: *chuckle*

14:58 eskatrem: Before I did stuff like (loop [p 2 n a-arg] (while (> n 1) ... ))

14:58 amalloy: the general structure of a loop is (loop [var-name init-val] (... (if done? (something) (recur new-value-for-var))))

14:59 &(loop [x 1] (do (println "x is" x) (if (even? x) :done (recur (inc x))))) ; for example

14:59 lazybot: ⇒ x is 1 x is 2 :done

14:59 eskatrem: hmm right

15:00 hang on, let me (try to) change my code accordingly

15:00 amalloy: stay far away from (while), which is for side effects, and just (recur) into the loop

15:00 eskatrem: thanks amalloy, come back to you in 5 mins

15:03 sorry, is this gonna be valid inside my loop; (if (= n 1) :done (something else))

15:04 Bronsa: yes

15:04 eskatrem: thank you Bronsa

15:10 amalloy: eskatrem: i forked and rewrote it at https://gist.github.com/1145191 - don't look unless you want spoilers

15:10 eskatrem: amalloy: I am rewriting my code now. I will try to make it work, and then compare with your version (unless I cant make it work and then come back for more help)

15:14 nollidj: hello. i've been wondering how in clojure to express custom numeric types; probabilities, for example, which are transparently stored and manipulated in log-space

15:17 the hitch is that i would like for built-in arithmetic functions to work properly, so i can easily do something like (* (my-numeric-type 0.1) (double 0.5))

15:18 alternately, if i'm doing computation with probabilities that have the potential to grow very small, do i need to worry about converting them to log-space if clojure automagically promotes them to bigdec when precision underflow becomes a problem?

15:20 amalloy: nollidj: just use ratios instead of floats and it's not a problem

15:20 &(reduce / 1 (repeat 100 4))

15:20 lazybot: ⇒ 1/1606938044258990275541962092341162602522202993782792835301376

15:22 nollidj: i'm not sure that works for the scientific computing i'd like to do

15:23 amalloy: really? how could that be?

15:23 sleepynate: heh

15:24 yea when are floats better than ratios for significant digits? :)

15:25 tnks: amalloy: ah. . . I see now, I missed the "copy on write" part.

15:25 clojurebot: amespaces are (more or less, Chouser) java packages. they look like foo.bar; and corresponde to a directory foo/ containg a file bar.clj in your classpath. the namespace declaration in bar.clj would like like (ns foo.bar). Do not try to use single segment namespaces. a single segment namespace is a namespace without a period in it

15:25 nollidj: can i exponentiate ratios?

15:25 st3fan: &(float (reduce / 1 (repeat 100 4))

15:25 lazybot: ⇒ 0.0 ; Adjusted to (float (reduce / 1 (repeat 100 4)))

15:25 clojurebot: amespaces are (more or less, Chouser) java packages. they look like foo.bar; and corresponde to a directory foo/ containg a file bar.clj in your classpath. the namespace declaration in bar.clj would like like (ns foo.bar). Do not try to use single segment namespaces. a single segment namespace is a namespace without a period in it

15:26 amalloy: clojurebot: what the hell, shut up. hiredman, can we muzzle him?

15:26 clojurebot: hiredman <3 XeLaTeX

15:27 amalloy: nollidj: isn't that what i just did? 1 * (1/4)^100

15:27 but if you want a rational power...i can see how that would be a problem

15:28 nollidj: yeah. sorry, i'm a bit distracted irl

15:29 what i mean is something like: keeping things in terms of ratios can do a lot for me, but i'm concerned that at some point i'll have to use a floating-point value of some sort and things will collapse to zero

15:31 eskatrem: amalloy: I couldnt find it by myself, so I peeped at your code. Really awesome

15:33 nollidj: also, i am generally wondering about the question of how to extend numeric types in clojure to do something like autodifferentiation

15:35 amalloy: clojure doesn't really have any nice built-ins for adding new numeric types. you can find a library for it at clojure.contrib.generic-math, or something like that

15:35 nollidj: ok, thanks

15:37 eskatrem: amalloy by curiosity, do you use clojure at your workplace?

15:38 amalloy: since i started the new job in june, yeah

15:39 Chousuke: nollidj: are you aware of incanter?

15:39 nollidj: it sounds like you might like it

15:39 eskatrem: wow quite recent then

15:39 amalloy: ah, good point

15:42 nollidj: Chousuke: i have heard of it, thanks

15:43 thanks, all.

15:49 sritchie: hey guys -- when making a leiningen plugin, is there a way to call functions inside of the existing project?

15:50 (:use my.namespace) doesn't seem to be allowed

15:50 amalloy: eval-in-project, i think? i don't really do that, but i've heard people talking about it

15:50 sritchie: I wanted to use lein and pallet to scp an uberjar up to a remote machine, then call an ssh command

15:51 that sounds like a good place to start, though, thanks

16:26 eskatrem: quick question: how do I compute the max of a list of elements? (max 1 2 3) works but not (max (1 2 3))

16:27 lobotomy: ,(apply max [1 2 3])

16:27 clojurebot: 3

16:27 Bronsa: reduce may be slightly faster

16:28 eskatrem: thanks lobo

16:28 how does reduce work?

16:29 Bronsa: ,(doc reduce)

16:29 clojurebot: "([f coll] [f val coll]); f should be a function of 2 arguments. If val is not supplied, returns the result of applying f to the first 2 items in coll, then applying f to that result and the 3rd item, etc. If coll contains no items, f must accept no arguments as well, and reduce returns the result of calling f with no arguments. If coll has only 1 item, it is returned and f is not called. If val i...

16:29 Bronsa: internally max with more than 2 args uses redouce

16:30 so using reduce isntead of apply you should avoid 2 function calls

16:30 *instead

16:31 Night-hacks: hi

16:31 eskatrem: thanks Bronsa

16:33 Night-hacks: code as data participates in clojure, does anyone knows why it's not possible in Java ?

16:43 currymj: this is sort of a broad question, but does anyone have advice on how to learn penumbra (the opengl library)? I know nothing of graphics or opengl, should I even be starting with this?

16:44 raek: Night-hacks: in Clojure you can do (defmacro unless [condition false-exp true-exp] (list 'if condition true-exp false-exp)). how would you do this in Java? :-)

16:45 Night-hacks: raek: yeah, want to know what makes this limitation to java

16:45 raek: for the user to invent a new control flow primitive (like "unless", which works like if but with a inverted condition), you would need a Java source code preprocessor

16:46 Night-hacks: currymj: first you should complete your knowledge on OpenGL

16:46 currymj: so like, learn it in C/C++? or Java or what? I know there are different libraries.

16:47 raek: Night-hacks: in Lisps, the compiler (or interpreter) can use the functions defined so far in the program to build the code for the following code

16:48 Night-hacks: currymj: JOGL is fine

16:48 raek: currymj: the Red Book uses the C API. APIs for other languages are probably translations of this API

16:49 I expect the Java API(s) to be very similar to the C API

16:50 currymj: so i should probably work through that, i guess in Java. then i suppose i'll be able to understand how penumbra works underneath all the abstraction. thanks!

16:51 Night-hacks: raek: but what makes such an ability in Clojure ?

16:51 raek: i wonder both are running on JVM

16:52 duck1123`: it's because of the parser (and the syntax)

16:52 raek: yes, the JVM can load code at runtime.

16:52 duck1123`: In clojure, all the code is in the same form as the data

16:52 raek: but you generally don't write java code that generates new java code

16:53 that would involve either a lot of string manipulation, or parsing and emitting ASTs

16:55 Night-hacks: maybe it's not really about an ability to do it, but about whether the languages are designed to make these things easy to do

16:56 runtime generation of code in Clojure is trivial, but is a lot harder in Java (and probably requires additional libraries)

16:56 currymj: Night-hacks: when you run Clojure code, it converts the source file (with all the nested parens) immediately into nested linked lists. then Clojure executes the nested lists. this means that data manipulation facilities for dealing with nested lists can also be used to write, rewrite, and modify code. that is much easier than having to write and rewrite text, which is how the C preprocessor works, and what you would have to

16:56 (this is only a little bit of an oversimplification.)

16:56 raek: in Clojure you have everything you need for that in the language from the beginning

16:57 duck1123`: another good example of homoiconicity is XSLT, which is both written and operates on XML

16:57 raek: Night-hacks: Rich Hickey talks about this stuff at 36:00 in this videohttp://blip.tv/clojure/clojure-for-java-programmers-1-of-2-989128

16:58 duck1123`: I used to write XSLT templates that produced XSLT. (I feel a bit ashamed of that fact now)

16:58 raek: And he has pretty diagrams too... :-)

16:58 duck1123`: how meta.. ;-)

16:59 Night-hacks: so clojure is not just a bytcode compiler, it has something on top of JVM.

17:00 raek: it has a runtime too. it contains data structures, functions and the concurrency primitives, among other things

17:00 but these are ordinary JVM classes

17:00 after they have been compiled from java or clojure code

17:01 Night-hacks: after compilation

17:01 upwardindex: What is the most common way to host a clojure webapp? GAE?

17:02 Night-hacks: thanks for helps

17:03 raek: Night-hacks: one could imagine a homoiconic version of Java. you would write code in a syntax for ArrayList literals. these literals would be read into ArrayList objects, which would then be compiled into JVM bytecode

17:03 duck1123`: upwardindex: I think it's more common to have your own server and Jetty, but GAE is fairly popular

17:03 raek: then macros would be methods that takes some of this data and returns new data, using the Java ArrayList operations

17:04 upwardindex: duck1123`: Interesting, thanks!

17:04 duck1123`: upwardindex: If you're just getting started on this, you'll probably want to look to Compojure

17:04 Night-hacks: yes, i think how this small feature of lisp is beautiful.

17:06 upwardindex: duck1123`: Yes, but there seems to have been split right? compojure now referes to a group of libraries is that right?

17:07 raek: upwardindex: http://brehaut.net/blog/2011/ring_introduction <-- this is a really good overview

17:07 duck1123`: Well, really Ring is the heart of it all, but Compojure will help you get up and running quickly

17:08 There are a bunch of frameworks that sit on top that privide different ways to build the app

17:08 upwardindex: raek: this seems to be exactly the article i need :D thanks

17:10 I gotta say I'm quite impressed with the quantity and quality of documentation related to clojure

17:42 tufflax: upwardindex finally, someone who doesn't whine about the docs :p

17:43 http://news.ycombinator.com/item?id=2880935 first comment: "I will say that the online documentation IS atrocious and basically impenetrable" hmm I dunno what he has been reading

17:45 duck1123`: Wow, that was only a day ago AND he read 2 of the published books?

17:45 technomancy: tufflax: wikibooks probably =)

18:11 duck1123: Wow, it takes a bit of time for that to show up

18:33 srid: duck1123 how do you know that he read 2 of the published book within days?

18:43 bpr: In gloss/lamina is there any way to call (decode frame channel) where channel is a channel containing ByteBuffers, and have it return the decoded value and only consume the number of bytes needed from the channel?

18:44 I see in gloss.io there's decode-channel-headers, but this wraps the channel with a new channel. I'm going to receive many messages, and I'm afraid of the memory consumption concerns.

18:45 gloss.io/decode-channel won't work for me because there are multiple message types that could arrive on the channel.

18:55 duck1123: srid: I don't know how long it took him to read them, I was remarking that comment was posted 2 days ago, not 2 years

20:23 jsoft: :(

20:23 Hate having to translate java (which I barely know) into the clojure equiv

20:24 amalloy: why not just use the java you already have?

20:25 clojure and java are buddies

20:26 jsoft: I dont _have_ any java

20:26 amalloy: you're translating something imaginary?

20:26 jsoft: I am meaning examples on how to do things. Ie, no clojure examples, so I google java examples of a specific thing.

20:36 amalloy: mmm. okay. anything in particular at the moment?

20:36 Allax: what is wrong in this code?

20:37 , (map (partial apply str) (map (fn [s] (sort-by #((zipmap (seq "tzpnfrvmjdsglcbqxkhw") (range)) %) s)) (map seq (string/split "pbxktvfb pqv pxwcnpl pkpqpz pkrb pkgdl " #" "))))

20:37 clojurebot: #<CompilerException java.lang.RuntimeException: No such namespace: string, compiling:(NO_SOURCE_PATH:0)>

20:40 amalloy: you're working too closely with primitives like map instead of factoring out into meaningful, abstract pieces, which makes it too hard for you to debug when something breaks :P

20:41 no opinion about what's actually broken, though

20:43 Allax: it was working. I get that code here. I don't know what happend when I saved

20:44 this code order each letter and each word with my own sequence (instead of abcde, it use tzpnf,,,)

20:51 amalloy: bug reports and requests for help have three components: what you did, what you expected to happen, and what actually happened. can't do much with just the first

20:54 budu: hi

20:57 is there someone there?

21:03 technomancy: everyone is being very quiet right now: http://thebigcaption.com/post/609996178/everyone-shhh-its-a-sneak-attack-original

21:05 Allax: now where is the error in this code?

21:05 , (string/split "q1w2e3r4t5y6u7i8o9p0" #"\d+")

21:05 clojurebot: #<ExecutionException java.util.concurrent.ExecutionException: java.lang.IllegalStateException: replace already refers to: #'clojure.string/replace in namespace: sandbox>

21:11 duck1123`: Allax: I get ["q" "w" "e" "r" "t" "y" "u" "i" "o" "p"] in my repl

21:11 assuming that string/ is clojure.string/ that is

21:12 Allax: probably you set a namespace, how do it?

21:13 that message is showed in clojurebot and local compiling

21:13 duck1123`: (:require [clojure.string :as string]) in the ns clause

21:14 but I just added clojure. when I pasted it into a clean 1.3 repl

21:14 leonid__: ,(clojure.string/split "q1w2e3r4t5y6u7i8o9p0" #"\d+")

21:14 clojurebot: #<ExecutionException java.util.concurrent.ExecutionException: java.lang.IllegalStateException: replace already refers to: #'clojure.string/replace in namespace: sandbox>

21:16 duck1123`: I wonder what's going on there. Seems bot-specific

21:19 Allax: weird, string/split works before

21:20 sritchie: technomancy: whoops, sorry

21:20 jsoft: Phew.

21:20 Man java seems to be verbose.

21:21 duck1123`: I find that I mentally convert java to clojure when reading java code sometimes

21:22 Allax: I'd consult a real repl rather that trust what clojurebot says

21:25 Allax: 1:6 user=> (clojure.string/split "q1w2e3r4t5y6u7i8o9p0" #"\d+") java.lang.ClassNotFoundException: clojure.string (repl-1:6)

21:26 duck1123`: What version of Clojure are you using?

21:28 clojure.string was added in 1.2

21:29 Allax: ah

21:30 duck1123`: and unless you have a really good reason, you should upgrade

21:30 amalloy: good reasons include: i have no fingers with which to type the upgrade command?

21:31 duck1123`: that's not even a good enough reason. Voice-to-text man

21:32 go to at least 1.2 but keep thinking about 1.3

21:32 the libraries are getting better on compatibility

21:33 as we speak I'm looking to see which of my patched dependencies I can ditch in favor of the mainline versions

21:35 leonid__: sudo apt-get upgrade clojure gets me 1.0.0

21:35 what am I doing wrong?

21:36 (linux novice)

21:36 duck1123`: what are you using for project management

21:36 you'd be better off with lein, maven, et al. than the one in apt

21:37 leonid__: hmm okay

21:37 duck1123`: I'm a big fan of Maven, but arguably lein is much easier

21:37 leonid__: gotta use lein then

21:37 technomancy: lein is in debian unstable and ubuntu oneric

21:37 duck1123`: so get the lein script, run "lein new <projectname>"

21:37 sweet

23:09 solussd: what's a good REST client framework for clojure?

23:13 running with clj-http, unless someone thinks they should stop me. :D

23:14 cheier: solussd: http.agent in contrib

23:16 solussd: cheier: doesn't seem to support basic auth

23:17 duck1123: I've been using Aleph's client, but I believe that just uses clj-http under the hood

23:18 cheier: apache commons httpclient

23:19 solussd: which is what clj-http uses I believe

23:20 another random question- after 'lein deps' is there something I need to do to make what I pulled in accessible in my repl via swank/slime (besides requiring it)?

23:21 duck1123: nope, just require your ns once you're in

23:22 solussd: weird. not working.

23:22 I don't need to restart swank / reconnect with slime?

23:24 leo2007: How to get the arg of doc eval'd?

23:25 solussd: doc is a macro

23:26 cheier: solussd: have you tried (in-ns <your ns here>) ?

23:28 solussd: cheier: I don't understand. :/

23:28 cheier: switch to you're ns in the repl

23:29 ,(doc in-ns)

23:29 clojurebot: #<ExecutionException java.util.concurrent.ExecutionException: java.lang.IllegalStateException: replace already refers to: #'clojure.string/replace in namespace: sandbox>

23:30 amalloy: ,1

23:30 clojurebot: #<ExecutionException java.util.concurrent.ExecutionException: java.lang.IllegalStateException: replace already refers to: #'clojure.string/replace in namespace: sandbox>

23:30 amalloy: &(doc in-ns)

23:30 lazybot: ⇒ "([name]); Sets *ns* to the namespace named by the symbol, creating it if needed."

23:32 amalloy: hiredman: clojurebot seems to be choking on every eval request

23:33 solussd: cheier: ok, inns allows me to switch to the clj-http.client namespace… wonder why I cannot require it

23:33 oh wait, it created it, didn't it

23:34 cheier: switch back to you're core ns

23:34 your*

23:36 solussd: gr. killing restarting 'lein swank' 'fixed' it

23:36 my repl was in 'user

23:36 c-c c-k would throw a compilation error -- couldn't find clj-http.client on the classpath

23:50 amalloy: solussd: you need to restart swank when you have new dependencies

23:51 solussd: :/ ok.

23:51 amalloy: the jvm gets sad when you try to change the classpath at runtime

23:51 solussd: as long as I can blame it on the jam

23:51 *jvm (stupid autocorrect)

23:53 amalloy: haha i wish i could blame more of my problems on the jam

23:53 sarcher: hey i'm just checking out clojure and functional programming (coming from java)

23:54 how do you handle configuration? are configuration parameters just additional function parameters?

23:55 amalloy: "sorry i'm late, there was so much dang jam"

23:56 sarcher: that's one approach. clojure makes it so easy to create and use hashmaps that you can just create one for your options

23:57 store it on disk as a text file for whole-program configuration, pass it to a specific function, whatever

23:57 sarcher: ah cool.

23:57 in java we use spring to configure an object and then just call the methods on it.

23:58 I'm trying to figure out how to make things more scalable.

23:58 if configuration is passed, then we could have multiple servers setup and call our code on either one.

23:58 I know we could do that with java too, but i'm trying to learn the functional way :)

Logging service provided by n01se.net