#clojure log - Oct 12 2010

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

0:01 amalloy: jkkramer: so the idea is to avoid creating a new future for every task?

0:03 kmc: is there a preferred pastebin here?

0:04 ohpauleez: jkkramer: kmc That gist is nearly identical to the code the source of pmap

0:04 jkkramer: amalloy: in that example, the idea is to create an optimal number of futures given a certain number of processors

0:05 amalloy: kmc: gist.github.com is nice, but we can live with anything

0:05 ohpauleez: ~source pmap

0:06 amalloy: kmc: and if you're using emacs (you sounded like a lisper), there's a plugin to automatically create gists from emacs

0:07 kmc: so pmap is already chunking by the number of processors?

0:07 ohpauleez: kmc: yes

0:07 you only need to junk if you abuse agents or you need to manually do the futures

0:08 otherwise pmap does 2 + num of processors

0:08 kmc: ok, so now i'm back to wondering why it's slower than map

0:08 if it's only making 4 futures

0:08 (i implemented my own batching, no change in runtime)

0:08 ohpauleez: the cost of starting threads, even pulling them from the pool

0:08 jkkramer: pmap doesn't create batches

0:08 ohpauleez: can be higher than the actual computation

0:09 jkkramer: as i understand it, pmap starts a future for each item in the collection

0:09 hiredman: ohpauleez: pmap does not chunk

0:09 * kmc is confused

0:09 jkkramer: but only processes them n (# of processors) at a time

0:09 hiredman: pmap tries to stay N ahead of the consumer of the pmap

0:09 kmc: ah

0:10 hiredman: but if you consume it eagerly

0:10 ohpauleez: ah, ok

0:10 hiredman: it will force the whole thing

0:11 kmc: i just want to compute these 60,000 function applications in parallel on a few threads

0:11 i'm fine waiting for that to finish before moving on

0:12 i don't need laziness

0:12 jkkramer: partition it into batches of whatever-size, then send those pieces to pmap or futures

0:12 kmc: i did that and it was still slower than map

0:12 (for 3 batches)

0:13 jkkramer: code?

0:13 clojurebot: http://homepages.inf.ed.ac.uk/kwxm/JVM/codeByNo.html

0:13 kmc: i don't need some runtime option to enable threading, do i?

0:13 ohpauleez: kmc: How many cores is it running on?

0:13 (do you have)

0:13 mabes: kmc: what do you mean enable threading? pmap uses a thread pool already

0:14 kmc: i have 2 cores

0:14 ohpauleez: hmm, you should see some difference

0:14 jkkramer: kmc: can you share the code?

0:14 kmc: yeah, sec

0:14 ohpauleez: cool, thanks

0:15 kmc: http://gist.github.com/621651 is my batching

0:16 jkkramer: it's worth noting that upcoming work leveraging fork/join may make this kind of thing easier

0:16 kmc: that's cool

0:16 hiredman: how are you timing this?

0:16 kmc: with /usr/bin/time -v

0:17 amalloy: i'd like to join in on this discussion as one of the clueless

0:17 hiredman: kmc: use the time macro

0:17 amalloy: ,(time (dotimes [_ 100000] 10))

0:17 clojurebot: "Elapsed time: 15.95 msecs"

0:17 TeXnomancy: clojurebot: clojurebot?

0:17 clojurebot: clojurebot is not a benchmarking platform

0:17 TeXnomancy: =)

0:18 hiredman: I think you'll find pmap is faster, the jvm just hangs around waiting for the threadpools to die

0:18 amalloy: damn, TeXnomancy, you're on the ball today

0:18 kmc: ah, weird

0:18 hiredman: you can call shutdown-agents to end the threadpools manually

0:20 amalloy: i'm performing some computations on a tree with smallish branching factor. i had assumed it would be faster to just make the recursive call use pmap; am i right in thinking that this discussion means i'd be better off calling pmap on the first N (for some N) levels, but doing the deeper levels with plain map?

0:20 hiredman: bench and see

0:22 amalloy: hm. currently my toy/test data is too small to bench, and it's not fast enough to do real data yet. i guess i have to write a function to generate specifically-sized data

0:24 kmc: amalloy, i know that's a common technique in Haskell

0:24 (parallelize first N levels)

0:25 amalloy: thanks kmc. i benchmarked pmap-only way at the beginning; it was slower, so i gave up and went back to map. glad i heard this discussion; i'm sure i can utilize pmap now, if i do it right

0:28 kmc: shutdown-agents helped

0:28 now the version with a batched pmap is only a few sec slower

0:35 i can share the whole program, if anyone's interested

0:36 i'd also be thankful for any general suggestions regarding style, libraries to use, etc.

0:40 ohpauleez: kmc, you might want to take a look at work: http://github.com/clj-sys/work

0:40 I have a similar, lighter-weight and naive project called tee

0:40 not sure what the scope of your project is

0:41 kmc: ohpauleez, looks cool

0:42 hmm, this is distributed too?

0:42 that's quite nice

0:42 amalloy: kmc: i don't have anything better to do than nitpick other people's code :) why don't you share it?

0:42 kmc: can you serialize closures in clojure?

0:42 amalloy, http://gist.github.com/621663

0:42 this prints a mandelbrot set on stdout in text PGM format

0:43 TeXnomancy: kmc: sorta; see http://github.com/Seajure/serializable-fn

0:43 obviously if you close over a non-serializable object it won't work

0:43 kmc: cool

0:44 hiredman: mmm

0:44 non-printable

0:44 kmc: is it recommended to use any particular jvm parameters? i note that the 'work' library ohpauleez mentioned suggests '-server'

0:45 my code for pmap-batched and -main has some doall which i think are unnecessary

0:45 i was testing to see if my performance problems were laziness-related

0:45 pmooser: I have a question ... is there any particular reason that clojure doesn't have any bitwise function corresponding to java's >>> operator (right logical shift) ? Does anyone know ?

0:45 ohpauleez: I use -server for everything when I'm not doing repl stuff. Server will be a slower startup, but possibly better runtime performance

0:46 pmooser: They exist, I think it's called bit-shift-left

0:46 and bit-shift-right

0:46 pmooser: Those are arithmetic shifts, if I'm not mistaken, rather than logical shifts.

0:46 kmc: ok, pmap is still slower even with -server

0:47 amalloy: kmc: (inc n) is more usual than (+ 1 n); you can use (println x) instead of (print x "\n"); you don't need to put spaces between the arguments to print. but mostly it looks quite nice

0:47 pmooser: The right logical shift (>>>) does a right shift with no sign extension ... ie, it fills from the left with 0's, rather than the normal rule of "fill from the left with 0 if leftmost bit 0, otherwise fill with 1" ...

0:47 kmc: thanks

0:47 pmooser: Since it's a fundamental java operator, I was hoping clojure would have some direct analog

0:48 and since JVM languages have no concept of unsigned primitives, it's pretty convenient when doing certain kinds of bitwise manipulations.

0:48 amalloy: pmooser: i remember reading something on the google group about someone wanting to add this feature to core

0:48 * kmc tests larger image sizes

0:49 amalloy: pmooser: http://tinyurl.com/24lzxgc

0:49 pmooser: amalloy: Ahh, thanks. Reading.

0:50 amalloy: Ah, OK. So I'm guessing that guy isn't a contributor (hasn't signed a CA) and he also called the function in his patch >>>, whereas I'm guessing in clojure it should probably be called something more like bit-shift-logical-right ...

0:51 In any case, thanks for the pointer ... Maybe it is just missing due to an oversight.

0:51 amalloy: heh, i dunno. from me, you get that link. for more details, consult google :)

0:51 pmooser: What's the procedure for filing an enhancement request ticket for clojure? Does such a concept exist?

0:52 TeXnomancy: pmooser: you need to discuss it on the mailing list before opening a ticket

0:52 amalloy: pmooser: i don't know. you could try http://groups.google.com/group/clojure-dev

0:52 TeXnomancy: then you wait. =\

0:53 pmooser: TeXnomancy: When you say the list, you mean the standard user list, as opposed to the developer list ?

0:54 kmc: pmap-batched is still slower. 'time' shows a lot of extra time spent in the OS, presumably waiting on locks?

0:54 TeXnomancy: a post to the dev list theoretically has a lower chance of being ignored, but I guess you need to request membership to it first or something.

0:54 pmooser: Thanks for the pointers. Maybe I'll send in a CA and then apply to that group.

0:54 kmc: in fact that accounts for about half of the difference in runtime

0:56 maybe i should give up on the pmap idea and have explicit threads write to a mutable array

0:57 amalloy: kmc: transients, maybe, as a compromise?

0:59 * kmc reads

1:02 kmc: i dunno

1:02 this is my first clojure program

1:02 maybe i should accept that parallel pure computation is not a beginner topic

1:02 amalloy: haha

1:02 you and me both

1:02 kmc: i was hoping i'd found a language where it is

1:04 pmooser: kmc, what is the computation you're performing?

1:04 kmc: iterating «z ← z² + c» until |z| > 2, or to a maximum number of iterations

1:05 for computing a mandelbrot set

1:05 http://gist.github.com/621663

1:07 amalloy: kmc: you might also consider creating a github account. i know you've got a lot to absorb already with clojure, so don't rush to do it; git takes some time to get the hang of, but it's worth it (as someone who is still using only a small subset of its features)

1:07 kmc: i've used git quite a bit, though not github

1:07 amalloy: ah

1:09 jkkramer: kmc: http://gist.github.com/621688

1:09 pmap-batched needed a doall

1:10 * kmc squints

1:10 pmooser: I'm squinting as well.

1:10 kmc: looks like the same pmap-batched i have at http://gist.github.com/621663

1:10 pmooser: Don't both bits of code have the same doall?

1:11 jkkramer: oh, so it does. didn't see that one. the original one didn't

1:11 kmc: yeah

1:12 the two performed the same on my mandelbrot program

1:12 jkkramer: that's odd

1:12 kmc: i'm not surprised it works on some functions though

1:12 is there any way i could be introducing locking / thread contention?

1:13 * jkkramer downloads the full code

1:13 kmc: i think my code is a pretty straightforward pure-functional mandelbrot, but i'm not familiar with clojure idioms and idiosyncrasies

1:16 pmooser: Is there a way to set things up so that lein will compile that code (from the mandel example) AOT,

1:17 without me directly doing some kind of "java -cp clojure.jar clojure.lang.Compile mandel" sort of thing?

1:18 TeXnomancy: pmooser: set :aot [mandel.core] in project.clj and do lein compile

1:18 pmooser: Thank you TeXnomancy. I use lein in very simple-minded ways.

1:19 kmc: on a side note, i am really enjoying vim's rainbow parentheses for Clojure

1:19 makes my code look so much happier

1:20 pmooser: Interestingly, when I try to do that AOT compilation, I get this error upon invoking lein compile:

1:20 Exception in thread "main" java.lang.ClassNotFoundException: clojure.contrib.math (core.clj:3)

1:20 kmc: you probably need a dep. on that package?

1:20 http://gist.github.com/621696 project.clj

1:20 pmooser: Hmm, I would have thought this would cover that:

1:20 [org.clojure/clojure-contrib "1.2.0"]]

1:20 kmc: yeah that's what i have

1:20 pmooser: Sorry, that is a :dependencies entry.

1:23 I think this is my fault (predictably). I think I know what I did.

1:24 TeXnomancy: pmooser: try the leiningen tutorial, it's pretty short and covers most of this

1:25 pmooser: Sorry, it's my fault - I flubbed the namespace declaration in a way that made it fail but not itself generate an error.

1:25 TeXnomancy, thanks for the tutorial pointer - I'll definitely read it again.

1:26 TeXnomancy: sure

1:27 and make a noise if there's something missing too; I want to make sure it covers all the bases for getting started.

1:30 pmooser: I have started using lein for some spare-time projects, but when I use clojure at work, I can't use lein because we have a monolithic build system of our own. So, unfortunately I haven't dug into it quite enough for me to have much facility with it yet.

1:41 jamesl: Hi, is there any function - e.g andf (andf f1 f2 f3 … fn x) will do something like (and (f1 x) (f2 x) (f3 x) … (fn x)).

1:41 Thanks.

1:42 jkkramer: kmc: replacing math/expt with Math/pow makes pmap behave as expected. i'm not sure if that messes up the numerical accuracy

1:42 rich_holygoat: jamesl: look at reduce and apply

1:43 kmc: oh, very strange

1:43 jkkramer: yeah

1:43 kmc: any idea why that matters, jkkramer?

1:44 jkkramer: kmc: no idea, just tried swapping out pieces until pmap-batched worked as expected

1:44 kmc: what version of clojure are you using?

1:45 kmc: 1.2.0

1:45 jamesl: rich, Thanks. I think about reduce, apply or partial. But ..:>

1:47 rich_holygoat: (reduce #

1:47 bah

1:47 raek: (every? #(% x) fns) ; maybe something like this

1:47 rich_holygoat: (reduce #(and %1 %2) (map #(apply % x) [f1 f2 f3]))

1:48 every? should work too

1:49 jamesl: Thanks.

2:03 yayitswei: what's a simple and quick way to persist data structures in clojure?

2:04 jacortinas: like a database?

2:05 yayitswei: yes, or even a file if that's simpler

2:05 just need to be able to (save data) and (load data)

2:06 jkkramer: (spit filename (pr-str data)) (read-string (slurp filename)) might work

2:08 yayitswei: jkkramer: thanks, trying that now

2:09 jkkramer: that should work with most of the basic data structures

2:14 pmooser: Thanks for the help, everyone. Beditme!

2:14 Goodnight.

2:15 yayitswei: jkkramer: that works, thanks! just needed a quick and dirty way to persist stuff while prototyping my webapp

2:16 LauJensen: Good morning all

2:17 notsonerdysunny: Good Morning LauJensen

2:22 kryft: Good morning, LauJensen. Any luck installing xmonad yet?

2:23 lpetit: Good morning all

2:25 LauJensen: kryft: Havent tried yet - Im feeling a little married to my awesome config

2:28 amalloy: speaking of which, i haven't found a description of monads that "speaks to me" - i don't really grok what they are

2:28 anyone have a favorite tutorial?

2:29 KirinDave: You just have to slog through

2:29 They're actually just a specification for functions to allow meta-functions to operate on them.

2:29 coldhead: mmm gonads

2:30 KirinDave: It's really more of a notational thing than complex implementation details.

2:31 amalloy: KirinDave: yeah, i grasped that it was "simple", but it was a high-level thing i *almost* followed :)

2:35 cpfr: hey, what's the best way to execute a compiled clojure project

2:36 yayitswei: cpfr: java -jar project.jar

2:36 cpfr: yayitswei, will this automatically call the -main function?

2:36 yayitswei: yes I believe so

2:36 cpfr: Failed to load Main-Class manifest attribute from

2:38 yayitswei: hmm. the jar file isn't compiled to be executed as an application

2:38 I think you will have more options with clojure.contrib.command-line

2:39 amalloy: cpfr: you have to set the main-class attribute (or something similarly-named) in project.clj

2:39 and then lein jar or cake jar should put in the manifest for you

2:40 cpfr: amalloy, how do I set the main-class attribute?

2:40 LauJensen: amalloy: The Wiki page seems good. Monads are a way of controlling state and wrapping side-effects, ie. not useful in Clojure

2:40 amalloy: cpfr: i'm not sure; it should be in the leiningen tutorial though

2:40 yayitswei: cpfr: in my project.clj, i have :main project.core

2:40 that works in lein

2:40 cpfr: ah ok

2:40 thanks!

2:41 LauJensen: cpfr: also works in cake

2:41 notsonerdysunny: http://gist.github.com/621773

2:41 cpfr: cake?

2:41 clojurebot: cheesecake is delicious.

2:41 yayitswei: cpfr: http://github.com/ninjudd/cake

2:42 KirinDave: LauJensen: The state monad is not a bad way to model some things, even in clojure.

2:42 notsonerdysunny: Hello everybody, I want to do some symbolic math using mathematica as the back-end-symbolic engine.. I have trouble converting a sexp returned from mathematica evaluation into a function via a macro .. however a small piece of it is pasted in the above paste .. can anybody help me fix this...

2:43 LauJensen: KirinDave: Can you give a convincing example?

2:43 KirinDave: LauJensen: There was a neat example for compojure awhile back.

2:44 cpfr: wow cake is like leningen on steroids

2:44 LauJensen: notsonerdysunny: Im not sure what you're trying to do. Are you looking to inject the values of x and y into the evaluation ?

2:44 cpfr: true.. :)

2:44 KirinDave: cpfr: No, it's just lein. With some stuff to help textmate achieve parity with slime.

2:45 kmc: LauJensen, amalloy, no, monads are not about state / side effects in general

2:45 F# has syntactic support for monads despite also allowing unrestricted side effects

2:45 and C#'s LINQ is quite close to monad comprehensions

2:46 KirinDave: C#'s linq. :\

2:46 kmc: ultimately "monad" is just the name of a small, very general API which is used by lots of stuff

2:46 LauJensen: kmc: Author of Haskell says "The primary uses of monads in functional programming are to express input/output (I/O) operations and changes in state without using language features that introduce side effects"

2:46 kmc: LauJensen, well that's weaker than what you said — "primary"

2:46 but also i disagree with that statement

2:47 even if it was uttered by Simon Peyton-Jones or Elvis Presley

2:47 notsonerdysunny: LauJensen: third expression is just a combination of the first and second .. I want the third one to work

2:47 LauJensen: I think if you disagree with Simon L Peyton Jones, you're likely wrong

2:47 notsonerdysunny: LauJensen: return the value I got in the second evaluation

2:47 kmc: common uses of monads in Haskell include IO, state, error handling, concurrency, parsing, code generators, logging, etc.

2:48 LauJensen: notsonerdysunny: Im guessing Variables is a macro that only accepts literals

2:48 kmc: anyway you can pop over to #haskell if you want some other people to tell you monads aren't just about state and IO

2:48 in fact the IO monad in Haskell is a weird, atypical monad -- not good for building intuition about what monads in general are

2:49 amalloy, http://byorgey.wordpress.com/2009/01/12/abstraction-intuition-and-the-monad-tutorial-fallacy/

2:49 amalloy: kmc: thanks. i'll check it out

2:49 notsonerdysunny: Actually math is a macro that calls the function corresponding to Variables in mathematica and returns the value

2:49 LauJensen: *

2:50 LauJensen: all this is happening via the Java Link that mathematica provides

2:51 I am using Clojuratica which brings the Java Link to clojure with additional syntactic sugar

2:52 raek: yayitswei: you might find this interesting: http://gist.github.com/606840

2:52 ohpauleez: kmc, can you better shape my personal definition of a monad, which I typically think of a way to do orderly functional combination with a contextual closure

2:52 raek: yayitswei: usage: (file-stored ref "path/to/file.clj")

2:52 KirinDave: ohpauleez: I don't think monads necessarily imply a shared closure

2:52 cpfr: yayitswei, I am getting java.lang.ClassNotFoundException: clj_termine.core

2:53 yayitswei: cpfr: what command are you using?

2:53 cpfr: java -jar clj-termine-1.0.0-SNAPSHOT.jar

2:53 yayitswei: raek: interesting. have you used this before?

2:53 KirinDave: Oh hell yes.

2:54 Oh _hell_ yes.

2:54 https://gist.github.com/3085f7636f6be32b2ef4

2:54 cpfr: generated by lein deps; lein compile; lein jar

2:54 KirinDave: Browser to jetty.

2:54 Or rather, browser to ring to jetty

2:54 ohpauleez: KirinDave: m-result isn't a shared closure?

2:54 isn't that the idea of monads, at their core?

2:55 KirinDave: I dont think it has to be?

2:55 yayitswei: cpfr: did you compile to uberjar? lein uberjar

2:55 ohpauleez: ahh ok

2:55 cpfr: yayitswei, i did not

2:56 is there a way that doesn't entail making an uberjar

2:57 yayitswei: someone else might have a better suggestion, but I think you have to set the classpath in your java -jar command if you don't have an uberjar

2:58 raek: yayitswei: actually, I made that when I was developing a web app too. I needed a quick and simple way to persist the state

2:58 also, when giving jav the -jar option, the -cp option is ignored...

2:59 *java

2:59 yayitswei: raek: nice. did you run into any performance issues?

2:59 cpfr: yayitswei, like java -cp .:classes -jar clj-termine-1.0.0-SNAPSHOT.jar?

2:59 raek: yayitswei: I haven't used it for serious things yet...

2:59 I will write something with agents that store the data every now and then

3:00 when a ref gets altered, an agent gets sent a fn that adds the ref to a "to-save" set

3:01 the agent sleeps for some minutes, then processes any changed refs and goes back to sleeping

3:01 this is just some idea I had

3:02 KirinDave: Why use agents for that?

3:02 yayitswei: raek: similarly for me, I assume I'll add a database and learn JDBC when my app grows to need it

3:02 raek: I don't want the code that alters stuff to block

3:02 but a BlockingQueue might make sense too

3:02 KirinDave: Okay.

3:02 yayitswei: although, does that mean the data has to fit in memory in its entirety?

3:02 raek: yes

3:03 KirinDave: Agent semantics are more than just non-blocking.

3:03 raek: I'm aware of that. this use case is probably very close to the border of agent-abusing

3:04 I'm not sure of which side of that border it is on... :-)

3:05 yayitswei: cpfr: sorry, I don't know the classpath syntax off the top of my head. what's the reason you can't build the uberjar? i'd try that first to see if it works

3:05 KirinDave: raek: Would future work?

3:05 cpfr: yayitswei, I can and it did work

3:05 I just like lean deployments

3:05 kmc: ohpauleez, each individual monad is a type. we could call values of that type "actions".

3:05 yayitswei: ah

3:06 kmc: so "IO actions" are recipes for doing IO, "parse actions" are parsers; "nondeterminism actions" are (lazily-deferred) lists of "possible results", etc.

3:06 note that the values making up monadic type A don't look anything like the values making up monad type B

3:06 ohpauleez: right right

3:06 kmc: they just share a common generic API

3:06 ohpauleez: like the sequence monad, etc

3:06 raek: KirinDave: I don't want to save the state each time it gets updated. I want something more like "sleep for 5 mins and check if anything has changed. in that case, store it"

3:07 kmc: the reason the IO type is special in Haskell has nothing to do with monads

3:07 ohpauleez: totally, I agree with that

3:07 kmc: and monads are useful in general even if you don't use them to do IO

3:07 ok

3:07 ohpauleez: I also agree with that

3:07 kmc: so this generic API provides something that looks a little like function application or function composition

3:08 raek: I think an agent holding a set of refs would solve this pretty neatly

3:08 kmc: you can formalize that by talking about the "Kleisli category of M" for some monad M

3:08 ohpauleez: I really want to use them more, I just think I have to force myself to do so

3:08 kmc: well, monads aren't really a language feature, but most languages don't have the right set of features to make them convenient

3:08 ohpauleez: right, I know most of this from the various tutorials I've read

3:08 kmc: one application i could see in clojure is

3:08 if you had to chain a bunch of actions, each of which can return nil

3:09 and you want to stop as soon as you hit nil

3:09 i bet there's already something built-in for that

3:09 ohpauleez: right

3:09 kmc: but that's essentially the Maybe monad from Haskell, one of the simplest monads

3:09 you could certainly implement Haskell-like "do" notation as a macro

3:09 or go without; it's not too bad

3:09 especially in a Lisp syntax where you're used to building lots of nesting

3:10 raek: just (send persist-agent conj changed-ref) and eventually it gets saved. the agent also handles a (fn sleep-and-store [refs] (doseq [r refs] (store r ...)) (Thread/sleep sleep-interval) (send *agent sleep-and-store) #{})

3:11 ohpauleez: kmc: cool, thank you

3:11 kmc: i can find plenty of stuff about monads in clojure

3:11 but i'm not sure if it's considered idiomatic

3:11 having only just started using the language

3:11 no problem ohpauleez

3:11 do you know any Haskell btw?

3:11 ohpauleez: enough to read and understand it.

3:12 raek: I guess -?> is very similar to the Maybe monad

3:12 Adamant: kmc: you might also want to look at Scala

3:12 especially ScalaZ

3:12 ohpauleez: I've never written more with it than a tutorial

3:12 kmc: yeah Adamant

3:12 Scala is an interesting language; it's definitely on my to-learn list

3:12 Adamant: kmc: I'm starting to look at both since they may be easier to get in the door at a business than Scheme or Haskell

3:13 kmc: yep

3:13 Adamant: and the only real suck I can see so far is basically the JVM's fault

3:13 ohpauleez: I've played around with the mondad library in clojure. Also fnparse uses it at its core, which I've done a lot with

3:13 kmc: i'm interested in Clojure for that reason; because of Java libraries; and because I like metaprogramming and find TH to be annoyingly difficult

3:14 Adamant: yeah

3:14 kmc: and because i want to avoid taking Haskell as a Blub language

3:14 Adamant: I still think Lisp is the best for metaprogramming

3:14 kmc: yeah

3:14 i like the idea of a Lisp-like variant syntax of Haskell for metaprogramming

3:14 Liskell did this

3:14 but is kind of a dead project, and not easy to use (it's a set of patches to GHC)

3:15 Adamant: yeah

3:15 kmc: i agree about things being the JVM's fault

3:15 basically every annoyance i ran into so far in setting up clojure and finishing one program

3:15 has been from Java stuff poking through

3:19 LauJensen: Adamant: Why do you find Scala interesting?

3:19 yayitswei: raek: what do I pass in for ref-type when calling file-stored?

3:19 KirinDave: raek: About your agent thing

3:19 Adamant: LauJensen: because it's a ML or Haskell for places that can't handle ML or Haskell

3:20 KirinDave: raek: You said the agent would hold the ref?

3:20 LauJensen: Adamant: Ah ok, so you like the functional paradigmes put on the imperative stack ?

3:20 Adamant: yes, the big attraction is a ML-like language that you can actually get companies to adopt

3:21 LauJensen: Adamant: This is probably a dumb question, but how much do Scala and ML have in common ?

3:21 Adamant: LauJensen: a fair amount

3:21 KirinDave: Adamant: You can get companies to adopt all sorts of things.

3:21 LauJensen: KirinDave: true

3:21 Adamant: ML is kind of the progenitor os such languages

3:22 KirinDave: I mean, I was a full time erlang programmer for nearly 2 years at a company that originally didn't do any erlang.

3:22 Adamant: KirinDave: sure, but Scala and Clojure are generally a easier sell than Scheme or Haskell

3:22 KirinDave: Those who dare; win.

3:22 LauJensen: Adamant: As they should be

3:23 raek: KirinDave: no, a set of refs.

3:23 KirinDave: raek: Why wouldn't it hold the file?

3:23 raek: That's what the agent is changing.

3:23 Adamant: LauJensen: I'm not sure about "should be", but they are.

3:23 raek: yayitswei: re, atom or agent

3:24 LauJensen: Adamant: Well. Clojure has more to offer in a business setting than Haskell, in no small part due to its integration with everything Java. Ditto for Scala. Clojure then goes the step further in that it builds incredibly robust and maintainable software. Which isnt the worlds hardest sell

3:24 KirinDave: Right.

3:24 We chose Clojure and Scala because we need to work with java but realize it's a lousy language for people who are not retarded.

3:25 LauJensen: KirinDave: Wow, and people call me harsh

3:25 raek: yayitswei: the agent things I mentioned were only ideas...

3:25 bartj: LauJensen, why doesn't your blog link work? http://blog.bestinclass.dk/index.php/2009/10/python-vs-clojure-evolving/

3:25 Adamant: LauJensen: from my perspective, it's more about being able to say "JVM-based language" repeatedly until it bores into the skull of people making decisions

3:25 LauJensen: bartj: The blog.bestinclass hasn't been active in over 12 months I think. Try www. instead of blog.

3:25 KirinDave: LauJensen: http://www.youtube.com/watch?v=iwGFalTRHDA

3:25 bartj: LauJensen, ah thanks

3:26 yayitswei: raek: i see, I'm just trying to understand what your function does

3:26 LauJensen: bartj: and notice the .php goes away automatically, nginx doesnt like it

3:26 KirinDave: LauJensen: Or perhaps: http://www.youtube.com/watch?v=ounTVG6paBM&feature=related

3:26 Adamant: I'd rather use either Scheme or Haskell, although I'm new at both Scala and Clojure so that may change.

3:26 LauJensen: KirinDave: hehe

3:26 bartj: LauJensen, yeah, saw your article when you re-vamped your site

3:27 LauJensen, would be good if you could handle the blog.bestinclass as well

3:27 LauJensen: Adamant: Well, Haskell has many virtues, though it still seems like a bit of an island. And also 'purely functional' is not a plus in my book, when building real software.

3:27 raek: yayitswei: it sets a watcher fn that is called every time the ref/atom/agent is changed, and stores the value it changed into into a file

3:27 bartj: LauJensen, found that link on HN

3:27 LauJensen: bartj: Why, many legacy links floating around?

3:27 kmc: Haskell is an island but that island is growing rapidly due to, uh, volcanic eruption?

3:27 * kmc has trouble with metaphors

3:27 LauJensen: Ah.. I heard a report that 6000 sites are linking bestinclass.dk, so if 10% of them is blog.* I guess I should fix it

3:28 raek: yayitswei: it also loads the contents of the file and uses that as the initial value for the ref/atom/agent

3:28 Adamant: LauJensen: understood, it takes a good long while to get used to IO, ST, etc. stuff to the point you can do things as efficiently as in an imperative language if you're doing a lot of imperative manipulations.

3:28 tobiasraeder: morning :)

3:28 LauJensen: Adamant: Oh dont get me wrong, I really dislike imperative programming. And I hate the resulting software, at least debugging it. But Clojures approach is ingenious if you ask me.

3:28 Adamant: efficiently in terms of programmer time.

3:29 LauJensen: yup, I generally agree.

3:29 kmc: i think the biggest barrier to widespread use of Haskell is not purity but laziness, and the tricky performance reasoning that comes with it

3:29 Adamant: agree there too

3:29 eager is easier for most programmers to reason about, including me

3:29 kmc: purity is great for concurrent and parallel programming; this is one point where Clojure and Haskell are philosophically very close

3:29 bartj: LauJensen, about 1250 I think, according to Google

3:30 LauJensen, do a "blog.bestinclass.dk" on Google

3:30 LauJensen: ok, I'll have a talk with nginx

3:30 kmc: 'pure functional' for real software is just another learning curve, as are 'functional' and 'not terrible' etc.

3:30 you can do all the same things

3:30 it's just a matter of what's taught and commonly practiced

3:30 bartj: LauJensen, also seems odd that the link: blog.bestinclass.dk points to Conj Labs

3:31 LauJensen: kmc: http://news.ycombinator.com/item?id=1531441

3:31 bartj: LauJensen, because Conj Labs is not a blog in itself :)

3:31 kmc: LauJensen, i've seen that troll-fest

3:31 KirinDave: LauJensen: It's too late for me to pull my punches on the subject.

3:31 LauJensen: bartj: Thats a barf in the way nginx handles sites. If there's no hit it just picks one :)

3:31 kmc: i'd like to point out that there's a number of PhD dissertations about Java too

3:31 bartj: LauJensen, oh! :)

3:31 LauJensen: KirinDave: You flamed in that post?

3:32 KirinDave: LauJensen: Oh, no, what I was saying earlier.

3:32 LauJensen: kmc: And many many more about Scala I think, but none of Clojure :)

3:32 KirinDave: ok

3:32 KirinDave: LauJensen: Java, these days, is basically run by people who think I need a UML diagram to successfully wipe my own ass.

3:32 It's really tedious.

3:33 LauJensen: hehe. To me Java is really a nutty language. Its amazing how it makes the simplest things incredibly verbose

3:33 KirinDave: Even worse because I know there actually are people who are that bad. I'd rather alienate them out of the industry rather than pander to them.

3:33 kmc: merits of individual languages aside, i'm disappointed that i keep seeing an anti-intellectual streak among certain communities of programmers online

3:33 LauJensen: KirinDave: Yea I totally agree

3:33 kmc: you mean #php? :)

3:33 KirinDave: kmc: Node.

3:33 LauJensen: No, man. Node.js

3:33 LauJensen: ?

3:33 KirinDave: Write once, rewrite for scale NEVER.

3:34 This idea that asynch is magic performance sauce.

3:35 tobiasraeder: is there a way to add static functions to a deftype? since it can't implement its "own" functions and interfaces cant have static functions i guess no, right?

3:35 kmc: KirinDave, how is Java "these days" different from before?

3:35 is it that they stopped innovating in the language design after 2004?

3:35 LauJensen: tobiasraeder: right. static functions are compiled to statics of their own classes IIRC

3:36 KirinDave: kmc: It isn't. The times are though, and Java hasn't changed much.

3:36 tobiasraeder: @LauJensen k crap :) thanks

3:36 kmc: or more recently that Oracle bought Sun and sees Java mostly as a source of lawsuit ammunition?

3:36 cool there's 2^8 people in this room

3:38 i hear Java will support λ by late 2012 now ;)

3:38 Adamant: LauJensen: public static void main()

3:38 I would appreciate it more if it supported continuations in the JVM

3:38 so the mini-interpreter could be dumped

3:38 KirinDave: Ha.

3:38 kmc: or just TCO (you can do CPS then)

3:39 KirinDave: Man, unlikely

3:39 Adamant: good point

3:39 kmc: i think learning Clojure or Scala would be good for my employability

3:39 makes a whole class of "JVM only" jobs tolerable

3:39 KirinDave: kmc: More salable than common lisp, anyways.

3:39 Adamant: maybe even fun

3:40 kmc: hehe

3:40 Adamant: and Scheme, as much as I still love it.

3:40 kmc: KirinDave, also a saner and prettier language, from what i see

3:41 (Clojure is)

3:41 Adamant: well, CL was a compromise language.

3:41 LauJensen: kmc: Sure, the Clojure Era is now

3:42 Adamant: the community also seems fairly nice so far.

3:42 that's always a plus.

3:42 LauJensen: Yea we're an okay bunch

3:42 notsonerdysunny: LauJensen: http://groups.google.com/group/clojure/browse_thread/thread/fcaffc66d5dbf053 describes the problem I was trying to solve in greater detail

3:42 LauJensen: :)

3:43 notsonerdysunny: I'm trying to look at it while compiling and deploying, its a little busy today :)

3:43 Adamant: LauJensen: #haskell has a crazy amount of people in it mostly because people are terminally nice there. it's more important for language communities than most people know.

3:44 notsonerdysunny: thanks LauJensen .. I just wasn't happy the way I described the problem before.. So I wanted to let you know ..

3:44 LauJensen: Adamant: Yea Ive always been very comfortable in here.

3:44 notsonerdysunny: thanks :)

3:45 amalloy: kmc: i am sad to discover that monads aren't something simple like burritos :)

3:46 KirinDave: amalloy: Burritos are a subtle and complex art.

3:46 amalloy: but in a way it's good news; now i won't stay up until i understand it

3:46 night all

3:48 kryft: LauJensen: You seemed to imply earlier that clojure would produce more robust and maintainable software than haskell; why is that, or did I just misunderstand you?

3:49 LauJensen: kryft: Yea you misunderstood, I think Haskell produces more robust software than Clojure. What Im saying is Clojure will always produce more robust software than imperative languages (php, java, scala, python, ruby, etc)

3:49 kryft: LauJensen: I'm only learning clojure and have no haskell experience, so I have no preconceptions about this, just curiosity. :)

3:49 LauJensen: Ah, ok.

3:49 LauJensen: I blame you because you were explaining why Clojure is an easier sell than Haskell. ;)

3:50 LauJensen: Ah ok. Well, honestly I havent tried to sell Haskell anywhere, but the benefits of Clojure are benefits that customers understand and relate to. Some devs might prefer Scala to Java because of style issues, like not having the 1 billion semicolons, but customers wont care

3:51 kryft: LauJensen: Right; I can see why clojure would produce more robust software than java. :P

3:51 LauJensen: notsonerdysunny: Am I correct in reading that (mathematica-eval "D[x*x+y*x,x]") => (+ (* 2 x) y) ;sexp1 and (math (Variables (+ (* 2 x) y)) => [x y] ;sexp2 both work, but (math (Variables (mathematica-eval "D[x*x+y*x,x]"))) is not working ?

3:52 kryft: Unless it's supposed to be maintained by an average java progammer? :)

3:52 LauJensen: kryft: Luckily Java programmers dont know how to maintain Clojure :)

3:52 Well. I guess Rich is actually a Java programmer :)

3:55 kryft: LauJensen: Precisely, which might make clojure a harder sell. I would expect that many companies like java because labor is cheap and plentiful. Then again, I guess those companies don't care about robustness anyway.

3:55 LauJensen: (That is, they like the fact that they can get something implemented in java now, and then later get some other code monkey to extend or maintain it.)

3:55 LauJensen: kryft: Oh right, to more exact: Innovative companies will buy it. The big corps who dont mind wasting 100 million USD on a dead end project, will still prefer Java or C++

3:55 kryft: LauJensen: Right.

3:57 LauJensen: But that might be changing. Nokia has a seat at the next Conj Labs for instance :)

3:57 Though I guess you could say they've always tried to be innovative

3:57 kryft: Here's hoping Nokia doesn't hang itself with Symbian first. ;)

3:57 LauJensen: No no, soon it'll all be Symbjure

3:57 kryft: Oo.

3:59 kmc: LauJensen, funny that you listed Scala as an imperative language

3:59 LauJensen: funny like if I said Java was a curly braces language?

3:59 kmc: 'imperative vs functional' is a silly distinction; every usable language supports both features, and they work great together

3:59 LauJensen: You need to look at little closer at both Clojure and Scala

4:00 Adamant: kmc: C doesn't really

4:00 kryft: LauJensen: So scala isn't as functional as clojure?

4:00 LauJensen: kryft: Not by a LONG shot

4:00 kmc: yeah, C gets a pass for being a low-level systems language and not general-purpose

4:00 kryft: C++ is finally getting lambda functions. =)

4:00 kmc: LauJensen, i'm aware that Scala is more liberal with mutation than Clojure, which is more liberal with mutation than Haskell

4:00 however all three support it

4:01 it's silly to draw this arbitrary line

4:01 notsonerdysunny: LauJensen: yes what you are saying is what I meant

4:01 kmc: and to act like imperative and functional programming are enemies

4:01 LauJensen: kmc: Not silly at all, its very important actually

4:01 kmc: when the best imperative code i've written is also deeply functional

4:01 LauJensen: notsonerdysunny: you didnt post the macro that works halfway did you ?

4:01 kmc: imperative by necessity, functional by design

4:01 LauJensen, so what's your criterion?

4:02 notsonerdysunny: LauJensen: I don't quiet get what you are saying

4:02 LauJensen: kmc: The default of the core data types must be immutability, otherwise you'll get in trouble

4:02 Chousuke: I'm not sure how imperative and (pure) functional programming work together.

4:02 notsonerdysunny: both of those are part of Clojuratica LauJensen

4:02 Chousuke: you *can't* do imperative programming with functional data structures

4:02 kmc: Chousuke, in Haskell you write pure functions which return descriptions of IO to perform

4:02 this is a powerful technique

4:02 Chousuke: yeah, sure.

4:03 kmc: you decouple execution order from evaluation order

4:03 and you can do imperative programming with functional data structures -- sometimes the most efficient mutable data structure is a ref cell holding a persistent data structure

4:04 Chousuke: my point is that the stuff you do in the IO monad is no longer functional

4:04 even though it integrates with the "outside" functional world.

4:04 kmc: Chousuke, that's not true. IO actions can produce functions which can return IO actions which produce functions ad infinitum

4:04 the idea that Haskell code separates to "pure functional" vs. "in the IO monad" is useful at a certain learning stage, but not really accurate

4:05 LauJensen: Its wrapping state, pretending its functional

4:05 kmc: no, it's not pretending anything

4:05 LauJensen: Though its cute, chousuke is right :)

4:05 kmc: it's *describing* IO without performing it

4:05 then passing that description off to a component of the runtime system to be performed

4:05 LauJensen: kmc: I think you need to square off your haskell-fu with Simon Peyton, then we can pick this up again :)

4:05 Chousuke: kmc has a point.

4:06 LauJensen: trololololo :)

4:06 kmc: the other day I solved a practical problem with a function of type «Int → IO (IO a → IO a)»

4:06 tell me that's not imperative functional programming

4:06 Chousuke: I suppose we have different ideas about imperative programming

4:06 kmc: of course the same can be done in Clojure or any half-decent language

4:07 LauJensen: so both Clojure and Scala?

4:07 kmc: yes

4:08 Haskell has first-class functions and first-class IO actions. in a language which does not distinguish between the two, the same tricks are still possible

4:08 assuming you have first-class functions which can also perform side effects

4:08 this is what is usually meant by "impure functional language"

4:12 Chousuke: I suppose it is true all programs contain some amount of imperative programming by necessity, but I still think the design has to be have a focus on either.

4:13 kmc: yes

4:13 Chousuke: In languages like Clojure and Haskell, the focus is on functional programming; and if you try to use imperative techniques with a functional design, you will run into problems.

4:13 kmc: the choice of defaults is very important

4:13 as are community norms

4:14 but we should not put the functional tools away when it comes time to interact with the outside world

4:14 LauJensen: kmc: Where Haskell typically uses monads, we have references types, have you looked at those yet ?

4:14 kmc: yes

4:15 and again, Haskell uses monads for a lot of things

4:15 not all of them have to do with state

4:15 Chousuke: Monads (and arrows) are a neat tool; it's too bad they pretty much require a static type system to be practical :P

4:15 kmc: Haskell has reference types too

4:15 Chousuke: there is a monad library for clojure but... no-one's using it. :P

4:18 kmc: i'm not sure why they require static types

4:18 like any generic API, the monad functions need to do type-dependent dispatch

4:18 but this is a standard thing to do in dynamically typed languages as well

4:19 monads in a statically-typed language require a pretty high level of type system sophistication, but that's not an issue with dynamic types

4:32 LauJensen: ,(java.net.URLEncoder/encode "x y")

4:32 clojurebot: "x+y"

4:32 LauJensen: Shouldnt that be "x%20y" ?

4:32 kmc: + is allowed too, i think

4:32 nlogax: yes

4:32 LauJensen: Well, Tomcat doesn't grok it

4:33 kmc: how does clojurebot know what parts of java are safe to expose?

4:33 LauJensen: kmc: Whitelist

4:33 kmc: cool

4:33 Adamant: kmc: also uses Java security stuff for the VM

4:33 kmc: ah, of course

4:34 is that using a class as a namespace to get at its static method?

4:34 LauJensen: Yep

4:35 esj: morning all

4:35 LauJensen: Morning esj

6:13 bobo_: oh, i can see conj-labs in "uppcomming events" in my calendar!

6:29 kryft: Chousuke: Why do monads require a static type system to be practical?

6:42 Chousuke: kryft: I guess my idea of monads is just haskell-centric, but they kind of feel out of place in a dynamic system.

7:02 lenw: hi all

7:03 whats an easy way to check if one map contains another map ?

7:05 LauJensen: ,(->> {:one {:map :in :another :map} :two 2} vals (some map?))

7:05 clojurebot: java.lang.VerifyError: (class: sandbox$eval9725, method: <clinit> signature: ()V) Incompatible argument to function

7:05 MrHus: (not (= 0 0))

7:05 LauJensen: -> (->> {:one {:map :in :another :map} :two 2} vals (some map?))

7:05 MrHus: ,(not (= 0 0))

7:05 clojurebot: false

7:05 LauJensen: lenw: well, that should work :)

7:06 lenw: LauJensen: digesting that

7:06 LauJensen: nom nom

7:07 lenw: LauJensen: thnks

7:08 LauJensen: Ok, you have a map with another map inside it. So you pass that to vals to get the values (a map and an int), you pass those values to (some map?) if asks... you guessed it, if any of them is a map. returns nil for false

7:08 carkh: hum that really should work =/

7:08 what's wrong with clojurebot !

7:09 ,(->> {:one {:map :in :another :map} :two 2} vals (some map?))

7:09 clojurebot: java.lang.VerifyError: (class: sandbox$eval9729, method: <clinit> signature: ()V) Incompatible argument to function

7:09 LauJensen: no idea

7:09 carkh: (doc ->>)

7:09 clojurebot: "([x form] [x form & more]); Threads the expr through the forms. Inserts x as the last item in the first form, making a list of it if it is not a list already. If there are more forms, inserts the first form as the last item in second form, etc."

7:09 LauJensen: $mail Raynes Where's your bot?

7:09 oh wait, its his bot that has $mail, haha :)

7:10 esj: hehe

7:30 jjido_: ,'foo

7:30 clojurebot: foo

7:30 jjido_: ,foo\'

7:30 clojurebot: java.lang.Exception: Unable to resolve symbol: foo in this context

7:31 jjido_: ,'foo\'

7:31 clojurebot: foo

7:31 jjido_: ,'foo'

7:31 clojurebot: foo

7:31 LauJensen: jjido_: That also works in private with the bot actually

7:31 and 'symbol' will work in 1.3, but not 1.2

7:32 jjido_: sorry for the noise heh

7:32 LauJensen: np

7:33 jjido_: laujensen: will it give a name ending in ' ?

7:33 LauJensen: yea. We'll have new functions called +' -' /' and *'

7:34 They will auto-overflow, as opposed to throw an exception like + - / *

7:37 sandGorgon: anybody using openbixo with clojure ? I cant seem to find any docs or how-tos on this.

7:49 rhickey: so, this seems promising: http://www.sutor.com/c/2010/10/ibm-joins-the-openjdk-community/

7:49 Adamant: will the openjdk finally have a TCO instruction?

7:49 rhickey: Adamant: as soon as someone does the work

7:50 Adamant: rhickey: my impression was the problem was political

7:52 rhickey: Adamant: the jdk is a large project with many consumers - it can't simply be about giving everyone whatever they want. So, yes, there will always be some aspect of convincing the majority that your minority feature is for the greater good. Or, if it's just politics, take your technical solution and put it in a fork of Java, then you'll just have the problem of convincing people to run it :)

7:53 on a positive note, it seems like Doug Lea could use TCO in his fork/join stuff. Requirements like these (that serve Java in general) are the best hope for these features

7:53 Adamant: rhickey: that sounds like another way of saying no :P

7:54 rhickey: Adamant: what do you want?

7:54 Adamant: rhickey: what I said.

7:54 rhickey: Adamant: go make it happen then

7:54 Adamant: rhickey: if I make it happen, will it get accepted?

7:54 rhickey: Sersiously, John Rose has asked for volunteers t help with these new features in MLVM, and has gotten few

7:55 Adamant: ok. what's MLVM?

7:55 rhickey: http://openjdk.java.net/projects/mlvm/subprojects.html#TailCalls

7:56 Adamant: rhickey: if there's a decent chance it may actually see the light of day, working on it makes sense.

7:56 LauJensen: Adamant: The fame is unlimited for the guy who gets TCO on the JVM :) If you're the lucky guy, please do FIXNUMS next :)

7:57 rhickey: Please do fixnums first

7:57 fhd: Hi. When declaring a bunch of things in a let block, how to best abort if some value isn't as expected?

7:57 LauJensen: hehe

7:57 fhd: I haven't run into this issue before for some reason, but I don't know how to solve it elegantly. Here's example code: http://paste.lisp.org/display/115434

7:57 If x is nil, I want to return nil and that's it. If it isn't, I want to continue with the other lets and the function's body.

7:58 mrBliss: fhd: http://gist.github.com/595634 lazy-let

8:00 fhd: Thats a pretty decent solution for the problem!

8:00 carkh: (doc nthnext)

8:00 clojurebot: "([coll n]); Returns the nth next of coll, (seq coll) when n is 0."

8:00 carkh: hum parameter order is not consistent for nthnext and take

8:01 or nth and take

8:03 fhd: mrBliss: Thanks, looks like a pretty good solution.

8:03 carkh: i remember there were talks about a threading macro where you could select the position of the threaded argument

8:03 did it eventually make it ?

8:05 LauJensen: Not that Ive heard of. Sounds scarcely useful as well

8:06 carkh: well there is your use case : you need to produce a opaged table for a web page : (-? customers (take 10 ?) (nthnext ? offset))

8:06 *paged

8:07 though i inverted the function calls =P

8:17 http://gist.github.com/622084

8:17 functional programming to the rescue

8:18 (doc trush)

8:18 clojurebot: I don't understand.

8:21 rhickey: wanted - better names than unchecked-* for truncating math ops. We have a new set of truncating coercions (to complement int/long/etc) that need names, and I'd like to do something else for unchecked-add etc

8:21 carkh: int-add long-add ?

8:22 always seemed like very long names those unchecked-*

8:22 rhickey: coercions need names first

8:23 carkh: do you mean for what is now (long value) ?

8:23 but truncating

8:24 rhickey: no, (int val) checks that val is in range, these new ones won't

8:24 carkh: i can see you going for unchecked-int =)

8:24 or truncated-int

8:24 but that's very long again

8:35 jarpiain: maybe (int! value) ?

8:41 rhickey: jarpiain: I like !, but overloads its current meaning

8:43 carkh: int!! keep the ! and show it's not your usual !

8:44 int\ : the \ cuts the int

8:45 ah the reader doesn't like it it seems

8:46 int| a vertical truncation

8:53 AWizzArd: (int: value)

8:59 Do we happen to have an expert for JEditorPanes here?

9:00 LauJensen: AWizzArd: More like a victim them of them, whats up ?

9:03 AWizzArd: LauJensen: I have a JEditorPane jep, set to "text/html" with a text set to "<font id='0' color='red'>hello world</font>". How can I get the font element itself, and how can I extract its color? I thought to do a (.getDocument jep) and then (.getElement doc "0"). But this seems not to work. Any ideas?

9:04 LauJensen: So you want "<fond id='0' color='red'>" and "red" ?

9:06 AWizzArd: LauJensen: yes.

9:06 The .getElement seems to give me what is *inside* the font tag.

9:06 I get an Element whose .getName ==> "content". I expected "font".

9:07 LauJensen: When you set the type to "text/html" that just means tht you get a wrapper around your actual content, with html/head/body etc. So why dont you just pick out what you want with an Enlive selector?

9:07 AWizzArd: And I can not call .setInnerHTML on it, because it is a leaf element.

9:07 LauJensen: you mean picking it out on the String that (.getText jep) returns?

9:08 LauJensen: yea

9:09 (select (-> t .getText html-snippet) [:font])

9:09 ({:tag :font, :attrs {:color "red", :id "0"}, :content ("hello world")})

9:10 AWizzArd: ^^ If there's a built-in way for the JEditorPane I would be surprised. Though that would ofc be easier

9:13 AWizzArd: LauJensen: yes, especially when I want to change it. Maybe I would like to change the color to blue, without generating&setting the whole html string again.

9:14 LauJensen: Yea. You still need a way of selecting that specific font tag though. Hard to make that part simpler than what enlive gives you

9:14 noidi_: has anyone here written complex, testable GUIs in Clojure?

9:15 LauJensen: noidi: Depends a little on what you mean by testable. I have written a complex GUI app in Clojure/swing. Which was detestable :)

9:15 (Swing that is)

9:15 noidi: hehe

9:15 I'm reading up on patterns like MVP and presenter first, which all make sense but unfortunately are very OO

9:16 and I'm trying to figure out how to get the same separation of concerns out of Clojure code

9:17 e.g. how one should convert this example to Clojure http://codebetter.com/blogs/jeremy.miller/archive/2007/05/23/build-your-own-cab-part-2-the-humble-dialog-box.aspx

9:17 LauJensen: Well. We're still breaking new ground. GUI design is usually inseperable from a lot of state. What I tried to do what separate everything into small logical units with no shared state. Cant say Im ready to write a book on the design pattern yet though

9:20 noidi: yeah, GUIs are pretty much just mutable state (all the components in a window) and side effects (showing pop up dialogs, etc)

9:21 bobo_: from my experience (in java though) the most important thing when testing GUI's is to ponder what your are actualy testing.

9:25 bmh: I'm trying to use some java code in a clojure project. I've chucked the java source into src/java and built it with lein-javac, but import can't seem to find it.

9:32 AWizzArd: LauJensen: yes, the enlive selectors would be very helpful I guess, especially when I can directly search for tags with specific ids.

9:55 lenw: ,(let [m {:one 1 :two 2}] (for [k (keys m)] (prn k)))

9:55 clojurebot: java.lang.VerifyError: (class: sandbox$eval9768, method: <clinit> signature: ()V) Incompatible argument to function

9:57 chouser: weird error

9:57 works fine here

9:58 lenw: why does that print nil nill at the end ?

9:59 chouser: for returns a sequence of the return values of its body

9:59 the body is (prn k) and prn returns nil

9:59 ,(prn :hi)

9:59 clojurebot: :hi

9:59 lenw: aah thanks

9:59 chouser: hm. clojurebot ate the nil.

10:00 bmh: so, as I asked a bit earlier. I'm trying to use some java code from clojure and the universe is exploding with classNotFoundException. I looked in classes in my source directory and everything seems to be there

10:01 chouser: so :one and :two are not in the sequence returned, they were just printed out

10:01 lenw: chouser: yes that makes sense now

10:01 chouser: (let [m {:one 1 :two 2}] (for [k (keys m)] k))

10:01 no nils there :)

10:02 chouser: bmh: that means your classpath doesn't have the .class files in it, or not in the right place

10:02 bmh: I would think lein should take care of that sort of thing for you, but I don't know lein well at all

10:04 bmh: chouser: That's what I would have thought too. I have a classes dir sitting at the root of my project, yet in the lein repl the universe explodes when I, say, type kylm.util.KylmMathUtils

10:05 chouser: you have a file classes/kylm/util/KylmMathUtils.class ?

10:06 bmh: classes/kylm/util/KylmMathUtils.class, yes

10:07 perhaps I should upgrade lein, I'm running 1.2.0

10:07 chouser: then you simply need to make sure that classes is on your classpath. If that's not a default for lein, I wouldn't know how to add it.

10:09 lpetit: bmh: yeah, upgrade lein first, you have a very old version, IMHO

10:11 bmh: lpetit: I'm on it. Let's see if it fixes anything

10:14 chouser, lpetit: wonderful! Fixed

10:14 lein 1.2.0 was bunging up the classpath

10:14 lpetit: bmh: happy for you !

10:27 LauJensen: AWizzArd: Ok great

10:27 AWizzArd: LauJensen: thanks for the ideas. Though I would really prefer reading/updating just that one node, and not mess with html strings.

10:28 LauJensen: AWizzArd: Well, with Enlive you can update/query that single node and then return the modified html. It doesnt change the fact that you'll be calling setText with a new body though. But is there a problem in that ?

10:32 AWizzArd: LauJensen: I don't know yet.

10:33 nollidj: for some bizarre reason, my repl says the fns union, intersection, and difference don't exist. what's going on?

10:34 are they in a namespace outside of core?

10:34 ah, they are...

10:50 LauJensen: AWizzArd: If its a problem, you could actually just diff the to strings and update on index.

10:50 to/two

10:57 pdk: just for the record

10:57 .bat file syntax is retarded

10:57 and fragile

11:04 LauJensen: pdk: why on earth are you using .bat ?

11:04 pdk: makin it so i can type clj on the command line to start a clojure session

11:04 and its less roundabout than writing a script in python or something for a simple task

11:04 LauJensen: pdk: why not just use cake?

11:06 pdk: hm looking into it

11:09 LauJensen: pdk: simply do this: http://github.com/ninjudd/cake/wiki/Cake-on-Windows, then type 'cake repl' and have fun

11:11 kryft: LauJensen: Would you recommend cake for OSX as well?

11:12 LauJensen: kryft: I havent tried it there actually.

11:13 lypanov: works for me.

11:13 briggs: I find that on OS X (or any *nix type system) it's just easier to create a shell script to fire off a repl, if that is all you need:

11:13 #!/bin/sh

11:13 java -cp jline-0.9.94.jar:clojure.jar jline.ConsoleRunner clojure.main

11:14 lypanov: thats much slower than cake.

11:14 LauJensen: and less tasty as well

11:15 pdk: like how it crashes to shell if you have any clojure syntax errors

11:15 LauJensen: pdk: what does?

11:15 briggs: Running a simple jline console?

11:16 pdk: nah doing it with jline and the bat seems fine

11:16 chouser: anyone know how to ask maven to build a jar containing just the uncompiled clojure code?

11:16 pdk: starting it with cake repl though any error in a line you write gets you a huge ruby stack trace and goes back to the shell

11:16 briggs: :pdk, ahh.

11:18 hugod: chouser: if you are not compiling at all, add your source directory to the build resources

11:23 chouser: hugod: then just mvn install ?

11:23 hugod: chouser: or mvn package, if you don't actually want to install it

11:27 tonyl: hello

11:27 chouser: hugod: thanks, but it still seems to compile the .clj and put the resulting .class files in the jar

11:27 hugod: do I need to exclude src/main/clojure from the build somehow?

11:28 tonyl: Does anyone know how to use the for form?

11:29 chouser: tonyl: ooh ooh, I do!!

11:29 * chouser waves hand urgently in the air

11:29 LauJensen: pdk: I cant reproduce that on linux, could you file an issue on github for it?

11:29 tonyl: thanks chouser

11:29 pdk: hm

11:29 tonyl: i have a question about the modifiers in the bindings

11:29 how is that expanded?

11:30 pdk: what sort of info would you need to make it a useful bug report

11:30 tonyl: like :while and :when

11:30 pdk: like the stack trace and the line causing it

11:30 chouser: tonyl: complicatedly

11:30 hugod: chouser: do you have packaging set to clojure? - if so remove it, or use compileDeclaredNamespaceOnly as described on http://github.com/talios/clojure-maven-plugin

11:30 tonyl: is it done in the inner loop

11:30 pdk: the short version is with ruby 1.8.7 + cake on windows 7 64 bit

11:30 chouser: tonyl: it's generally done at the point in the loop where you list it

11:31 pdk: something like say (prints "this will break") makes it dump a ruby stack trace then exit to console whereas you'd just get the exception message and chug along starting clojure the old "java -cp blah clojure.main" way

11:31 chouser: hugod: <packaging>jar</packaging>

11:31 ah, I see that in the docs now, thanks.

11:31 tonyl: ok so if a do it after the second binding it will run in the iteration of the second binding

11:33 chouser: ,(for [a [1 2 3] :when (== a 2), b [7 8 9]] [a b])

11:33 clojurebot: ([2 7] [2 8] [2 9])

11:34 LauJensen: pdk: Yes, all of the above sounds great, thanks

11:34 bmh: If I create an instance of a java class in Clojure and then invoke a method that mutates the instance, other references to the intance will refer to the mutates version, right?

11:34 tonyl: yeah i tested it out, great, so I can put multiple modifiers for each binding

11:34 hugod: chouser: remove executions/execution for phase/compile under the clojure-maven-plugin configuration (assuming it is there :)

11:34 pdk: would it help to get the actual stack trace

11:35 tonyl: for is awesome, thanks chouser

11:36 chouser: tonyl: yw

11:36 tonyl: why does for can't be expanded with the macroexpand, macroexpand-1 functions?

11:36 ,(macroexpand-1 for)

11:36 clojurebot: java.lang.Exception: Can't take value of a macro: #'clojure.core/for

11:36 chouser: hugod: oh!

11:36 lpetit: I'm getting crazy. 2 hours fighting maven 3 to get it accept a command line argument for filtering ... If there's any maven expert in there, could we talk in private (to not pollute the list, it's a little bit OT)

11:37 chouser: tonyl: that's not how macroexpand works

11:37 ,(macroexpand '(for [a [1 2 3] :when (== a 2), b [7 8 9]] [a b]))

11:37 clojurebot: (let* [iter__4059__auto__ (clojure.core/fn iter__9825 [s__9826] (clojure.core/lazy-seq (clojure.core/loop [s__9826 s__9826] (clojure.core/when-first [a s__9826] (if (== a 2) (clojure.core/let [iterys__4055__auto__ (clojure.core/fn iter__9827 [s__9828] (clojure.core/lazy-seq (clojure.core/loop [s__9828 s__9828] (clojure.core/when-let [s__9828 (clojure.core/seq s__9828)] (if (clojure.core/chunked-seq? s__9828) (clojure.core/

11:37 tonyl: ok makes sense now, i need to do some digging

11:37 thanks

11:37 pdk: reminds me what is the preferred way to quit a clojure repl session anyway

11:37 i'm noticing with jline included in -cp doing ctrl C won't work

11:38 so just (. System exit 0) which is kinda roundabout

11:38 lpetit: hugod: maybe you're the man ? :-)

11:39 hugod: you're too modest ;-)

11:40 briggs: pdk: Control+D

11:41 pdk: avast!

11:54 briggs: So, I am sure that it has been asked... but anyone else going to clojure-conj? I am wondering how many people are going.

11:57 hv: Is there a way to make clojure `require' a namespace when something from there is used? (purpose is convenience in a REPL)

11:57 * gary_poster wanted to go--45 min away!--but didn't have the vacation or conference days left to do so, and also couldn't convince my friend to join me anyway :-P

11:57 * KirinDave sighs

11:57 KirinDave: I wish I could go to conj

11:57 It's just, getting there is so ridiculous from sanfran

11:57 Like a 6000 hour flight. :\

11:57 gary_poster: heh

11:57 hv: do they up any podcasts?

11:58 KirinDave: And I found out my dog has cancer, so I'm staying around to help him through the chemo.

11:58 gary_poster: :-/ sorry, good luck

11:58 TeXnomancy: I thought only non-natives called it sanfran

11:58 yayitswei: morning everyone

12:00 KirinDave: TeXnomancy: if I called it "the city", would you know what I meant? :)

12:03 amalloy: KirinDave: speaking of which, how did your coffee shop thing on sunday go?

12:03 KirinDave: amalloy: No one showed. :)

12:04 I am going to go again today, i think someone from greplin is going to come pair with me

12:04 amalloy: Which is good, because clothesline is really flying along

12:04 amalloy: Last night I got requests through and through: https://gist.github.com/3085f7636f6be32b2ef4

12:04 ohpauleez: I had to cancel my conj plans for work. Life gets in the way of living I suppose.

12:10 tobiasraeder: is there a way to iterate over a seq and generate a function each named like the symbol in the seq? i tried it with doseq but it doesn't work out the way i thought it would

12:10 chouser: ohpauleez: :-(

12:10 KirinDave: tobiasraeder: Could you be more specific?

12:11 Chousuke: in a macro?

12:11 KirinDave: Chousuke: That'd only work if the contents of the seq are known at compile time.

12:11 ohpauleez: chouser: I wanted to stand up in the crowd and cheer finger trees into clojure.core

12:11 :)

12:11 chouser: ohpauleez: :-)

12:11 tobiasraeder: yeah in a macro

12:11 Chousuke: KirinDave: well in general generating named functions at runtime is not very useful :/

12:11 tobiasraeder: the contents are known at compile time

12:11 ill make a gist quick

12:12 KirinDave: Chousuke: Hum. Maybe.

12:12 Chousuke: ,(do ~©(for [s names] `(defn ~s ...)))

12:12 clojurebot: java.lang.Exception: Unable to resolve symbol: © in this context

12:12 Chousuke: ops

12:12 @ even

12:12 KirinDave: Sweet.

12:12 Chousuke: also should be `(do ...) of course

12:12 KirinDave: Chousuke: I think it could be useful in some cases.

12:12 tobiasraeder: ill try

12:13 KirinDave: Chousuke: Most of the cases in my head are compiler-ish though, a bit of the beaten track of daily use.

12:15 hv: Is it possible to install "hooks" into the REPL? the hook I am interested is something that require's missing namespaces before evaluating the form.

12:15 KirinDave: hv: Well you can't hook before evaluating the form any way but a macro, and even that is @ evaluation time.

12:15 hv: You can just replace require with your own.

12:16 tobiasraeder: Are you going to gist what you need, or should I get going? :)

12:17 tobiasraeder: @KirinDave i just tried Chousukes idea and it worked

12:17 was about to let you know

12:17 chouser: is it bad form to include test .clj in a lib's .jar?

12:17 tobiasraeder: but thanks a ton

12:17 KirinDave: Ah

12:17 tobiasraeder: So your seq's contents are known at compile time?

12:17 hv: KirinDave: I didn't mean before evaluating *literally*. They could be called pre-eval-hooks-list, or some such. Something that pre-processes the form, and then calls the normal eval in the REPL.

12:18 tobiasraeder: @KirinDave yeah

12:18 @KirinDave it's a huge java interop mess really which knows pretty much everything at compile time

12:18 hv: KirinDave: ummm, I cannot see how overwriting `require' can help. could you elaborate, please?

12:19 KirinDave: hv: Well, it's not like how things are loaded in a magical mystery. If you want to step in front of that then you could do so by just replacing forms like require and use (or load).

12:20 So, am I the only person who uses a macro like this all the time?

12:20 http://gist.github.com/622458

12:20 Should be standard. :)

12:21 jarpiain: hv: you could (defn custom-repl [] (loop (print (eval (preprocess (read)))) (recur))

12:22 Chousuke: rpepl :P

12:22 jarpiain: preprocess would walk the form and call require for namespace of each qualified symbol meant to be evaluated

12:22 KirinDave: Seriously, so useful.

12:23 hiredman: KirinDave: yes, you are the only person

12:23 KirinDave: hiredman: Why? :\

12:24 hiredman: because it's not needed

12:24 KirinDave: hiredman: Except that it is?

12:25 hiredman: the most names I've ever needed to forward declare in a file is four

12:25 ohpauleez: Yeah, I've only ever needed to forward declare when using fnparse

12:26 KirinDave: hiredman: You never had a situation like https://gist.github.com/793bda15a3b48b704cbf ?

12:27 hiredman: KirinDave: the bighttpgraph doesn't have any loops in it, so so I don't see why you would need to forward declare names

12:27 KirinDave: hiredman: Because otherwise I'd have to declare them backwards?

12:27 hiredman: Which would make reading it a huge pain in the ass?

12:28 hiredman: backwards in what sense?

12:29 hv: KirinDave: I would turn the states into keywords or numbers, not functions.

12:30 chouser: is it bad form to include test .clj files in a lib's .jar?

12:31 arohner: chouser: I don't think so

12:31 TeXnomancy: chouser: yeah, sorta.

12:31 chouser: awesome

12:31 TeXnomancy: I wouldn't sweat it unless it's an OSS thing though.

12:32 carkh: KirinDave: what's this defstate thing ?

12:32 KirinDave: hiredman: I need to declare the states at the bottom of the graph before the states at the start.

12:32 hiredman: If I didn't have that macro.

12:33 hiredman: Which was tedious, because then you read the state defs in a different direction from the graph.

12:33 hv: I did that, but then you're left to resolve them at runtime.

12:34 hv: So it still does that, but if you don't have it being a keyword it won't try.

12:34 hiredman: KirinDave: it's tedious no matter which order you do it in

12:34 anything where you end up def'ing a bunch of names like h13 is going to be tedious

12:35 hv: KirinDave: why wouldn't you have a map, e.g.: ({:b13 {:test (...) ...} ...} current-state) ?

12:35 KirinDave: hv: It still might be that under the covers.

12:35 Right now they get transformed to functions that call each other.

12:36 I confess, increasing the call stack depth by 35+ does worry me some.

12:36 But I dont' think it's much to worry about at this point.

12:36 hv: It's easier to read as it is now, and provides a lot of flexibility.

12:36 carkh: ah i like the idea of a map, then build an interpreter on top of that data

12:36 KirinDave: hiredman: The docstrings will fix that once I ad them.

12:36 carkh: Slow.

12:36 hiredman: no they won't

12:37 it will already have been tedious, unless your doc strings go back in time

12:37 KirinDave: hiredman: If I am explicitly implmenting from a reference graph, using those names.

12:37 hiredman: I know

12:37 KirinDave: hiredman: then it makes sense.

12:37 hiredman: I am not picking fault with you implementation

12:37 your

12:37 KirinDave: Well anyways

12:37 The pre-declaration stuff is necessary in this case.

12:37 I'm just surprised people accept that it's needed to care about order of definition in everyday use.

12:38 It's not a good thing. It's just an implementation detail

12:38 hiredman: I am saying that saying "oh that other way will be tedious" is ridiculous because the task is tedious no matter which way its done

12:38 KirinDave: hiredman: There are degrees of tedious.

12:38 Writing and reading that graph backwards would be at least 3.23 (repeating of course) times more tedious than forwards. :)

12:39 hv: KirinDave: I am not sure what is more efficient, and my hunch is that (get state-transistion-vector current-state) with states defined as numbers is faster. I would just add some macros to reduce verbosity ...

12:39 KirinDave: hv: Is faster than a ^:static call? It is certainly not.

12:41 hiredman: KirinDave: why do you say it's "just an implementation detail" is there a different implementation of clojure that does it differently?

12:41 amalloy: KirinDave: the tendency to build things "upside-down" for dependencies is not unique to clojure. i personally don't find it any more difficult to read the concrete layer first and then the abstract layer, but if you do then it's no problem to start reading at the bottom of the file instead of the top

12:42 pdk: moreso that it's a simple fact of how they chose to implement it

12:43 ohpauleez: KirinDave: Really? What's the use case that the map is too slow?

12:45 hv: KirinDave: I certainly believe there should be a builtin or standard way of building the fastest possible state machine (with minimal verbosity, of course). I am just not sure if your example achieves that.

12:46 carkh: well the fastest would be using gotos, but then you would be stopped by the 64kb limit at some point

12:46 so there's always a tradeoff

12:47 chouser: inline is faster, which can happen with java method calls and :static function calls

12:48 hiredman: there are levels of inlining

12:48 carkh: but wouldn't it also bump on the limit ?

12:48 or is it all taken care of by the jvm ?

12:49 hiredman: carkh: if you write code jvm can inline it doesn't have limits in its inlining

12:49 carkh: oh i see

12:49 hiredman: but clojure's inlining can run into those limits (inlining via definline)

12:49 also macro expansion, etc

12:49 carkh: right

12:50 hv: perhaps something like the way small maps start as vectors could be applied here. for small state-machines use static calls, for larger ones use transition matrixes, and optimize the keyword-to-number mapping.

12:50 hiredman: :static I don't think inlines, it just removes the overhead of var derefing

12:51 carkh: i guess it *might* inline if the jvm feels like it

12:51 chouser: right, it makes the fn call look like a java static method call, which the jvm should be able to inline if it wants to

12:52 hiredman: really? a static method?

12:52 dnolen: carkh: which it most definitely will if it's hot code. in my experience the craziest macro tricks, array tricks, what have you is pathetic to a whole series of static calls. your mileage may very.

12:52 yayitswei: KirinDave: what's this coffee shop thing?

12:53 hiredman: chouser: if it made it a static method call then :static "fn"s can't be closures, is that true?

12:53 chouser: hiredman: yup

12:53 (let [a 5] (defn ^:static foo [] a))

12:53 IllegalArgumentException static fns can't be closures clojure.lang.Compiler$FnExpr.parse (Compiler.java:3471)

12:53 hiredman: no kidding

12:54 chouser: I thought you might be kidding around, quoting the error word-for-word like that

12:56 hiredman: I have used any of the new stuff in 1.3

12:56 haven't

12:56 hv: is big-num promotion gone forever?

12:57 dnolen: hv: R.I.P.

12:57 ohpauleez: that's not totally true, right?

12:57 hv: any binding/sub-environment/whatnot you can do to get it back in a limited context?

12:58 ohpauleez: You can still signal you want promotion

12:58 amalloy: yayitswei: KirinDave is trying to get people to meet him at coffee shops in san francisco and do all his work for him :)

12:58 dnolen: hv: I believe there are auto-promoting variants like +'

12:58 KirinDave: hiredman: No.

12:59 hiredman: What I meant was, "It is not some important or interesting behavior of clojure that things have to be declared in order of dependency at compile time.

12:59 rlb: Why does string/join return "/" for (string/join [] "/")? The docs say it behaves like perl's, but at least taken literally, that's not correct.

12:59 hv: dnolen: I see, thanks. that's a relief

12:59 KirinDave: amalloy: When you're mirroring some other representation of the chart, I think it's better to have the code go in the direction of the chart.

13:00 rlb: $ perl -e 'print join("/", ()) . "\n";'



13:00 dnolen: ,(+ Long/MAX_VALUE 1)

13:00 clojurebot: 9223372036854775808

13:00 KirinDave: amalloy: And the cost is what? Controlled use of (declare ...)? I'm not sure why there is antipathy towards that approach.

13:00 dnolen: clojurebot is still 1.2.0 hv:, that would throw an overflow exception, +' would retain old behavior

13:00 rlb: ,join

13:00 clojurebot: java.lang.Exception: Unable to resolve symbol: join in this context

13:00 yayitswei: wow, I'd be down if it means learning clojure from the pros :) incidentally, just posted this question about cafes in SF on hacker news: http://news.ycombinator.com/item?id=1783882

13:00 KirinDave: yayitswei: Amalloy is correct.

13:01 I am extremely lazy and untrustworthy. I actually hope to rob people while they look at my code.

13:01 hv: dnolen: yeah, I just tried *' (1.3 here).

13:01 yayitswei: KirinDave: I'll have to remember not to bring anything of value

13:02 rlb: user=> (str/join [] "/")

13:02 "/"


13:02 clojurebot: <monads> is "yea, though I should walk in the valley of imperative code, I shall fear no evil, for your monad comforts me" - seen in #haskell

13:02 tomoj: aren't there any nice coffee shops that aren't starbucks?

13:02 KirinDave: tomoj: Yes.

13:02 rlb: tomoj: there are here.

13:02 tomoj: preferably with gelato?

13:02 KirinDave: tomoj: Esp in the city.

13:02 tomoj: Coffee Bar is great. Epicenter cafe is popular. There isn't much electricity at Ritual Coffee, but it's historical

13:03 tomoj: cool. plan to come to SF ASAP

13:03 amalloy: i'd love to get involved in an SF meetup of some kind

13:03 KirinDave: Four Barrel has no electricity, but it's gorgeous.

13:03 amalloy: Just so you know, I am not tring to make competition to runa's thing. :)

13:03 amalloy: I think hackfests and pair sessions would be a nice complement.

13:04 amalloy: i don't even know what runa's thing is. is that the bay area clojure group?

13:04 KirinDave: Yes.

13:04 amalloy: k. i found out about that just days after the one in SF :P

13:04 KirinDave: I just want to make it clear.

13:04 jkkramer: rlb: join takes the separator as the first arg

13:04 KirinDave: Runa is awesome and their meetups are cool.

13:04 ohpauleez: Is there anyone who hangs out here that is between Portland, OR and Eugene, OR?

13:05 amalloy: jkkramer: but it still does the weird thing with args ordered right

13:05 KirinDave: ohpauleez: My boss and co-worker are in portland and getting into clojure and scala.

13:05 ohpauleez: I really miss Philly Lambda and the philly clojure group

13:05 KirinDave: ohpauleez: Maybe I can convince them to begin something.

13:05 rlb: jkkramer: ?

13:05 amalloy: jkkramer: oh, i take it back

13:05 rlb: user=> (doc str/join)

13:05 -------------------------

13:05 clojure.string/join

13:05 ([coll] [separator [x & more]])


13:05 ohpauleez: KirinDave: Spread the word, I'll help out for sure

13:05 KirinDave: ohpauleez: You asked what the use case for a map deref + invoke being too slow.

13:05 amalloy: rib: the second arglist is the one youo're using

13:05 KirinDave: ohpauleez: I'm not really optimizing hard at this point, but

13:05 yayitswei: ohpauleez: not me, but aren't Portland and Eugene pretty far apart?

13:05 amalloy: separator coll

13:06 jkkramer: ,(clojure.string/join "/" [])

13:06 clojurebot: ""

13:06 KirinDave: ohpauleez: This graph is executed through jetty calls. I'd love to keep good performance for trivial responders.

13:06 rlb: Oh, right -- totally misread that.

13:06 KirinDave: ohpauleez: The more pre-compiled the graph is, the more the compiler can do, the less runtime work there is, the less overhead per request is incurred.

13:06 rlb: (wasn't thinking about parallel args, and of course "/" is a coll...)

13:06 ohpauleez: yayitswei: It's far apart in east coast terms, but not bad in west coast terms. I just hop on the train

13:06 yayitswei: KirinDave: will you be there tomorrow?

13:06 rlb: thanks

13:06 KirinDave: yayitswei: Where?

13:06 yayitswei: KirinDave: wednesday

13:07 KirinDave: at a cafe

13:07 KirinDave: Oh yes

13:07 Exactly where, I am not sure yet.

13:07 Probably epicenter or coffee bar.

13:07 ohpauleez: KirinDave: for sure.

13:07 KirinDave: ohpauleez: Eventually I'll perf audit the macro and make sure everything ends up being static calls and all redundancy is eliminated. That's the benefit of the macro approach.

13:08 Anyways, i should get to aforementioned cafe.

13:08 * KirinDave sighs off.

13:09 plathrop: Has the Clojure community settled on an idiomatic way to do unit testing?

13:09 dnolen: plathrop: clojure.test

13:10 ohpauleez: plathrop: You can also look at lazytest, which gives you a little bit more

13:10 it's like clojure.test 2.0

13:17 plathrop: Is there good docs / tutorials for those? Will a quick Google get me up and running?

13:19 dnolen: plathrop: clojure.test http://richhickey.github.com/clojure/clojure.test-api.html, lazytest http://github.com/stuartsierra/lazytest

13:22 replaca_: chouser: you're using showoff for your conj preso?

13:22 chouser: replaca_: that's the plan

13:22 I'm definitely using it for strange loop

13:23 replaca_: chouser: what are you doing for code formatting? Does it have support for that?

13:23 chouser: oh, I patched it

13:23 for syntax coloring

13:23 replaca_: chouser: wanna share? :)

13:23 chouser: I should put that somewhere. :-)

13:23 yeah, just a sec

13:23 replaca_: I would love it!

13:24 chouser: it's not much, but it's something.

13:24 plathrop: lazytest looks awesome

13:24 replaca_: That's more than I got!

13:25 I'm just trying to avoid <div> as much as I can nd stay on the playing field

13:27 chouser: replaca_: http://github.com/n01se/showoff

13:27 then @@@clojure blocks should get colored a bit

13:28 replaca_: chouser: you da man!

13:28 if I do more, I'll send it back

13:28 chouser: great, thanks.

13:28 there's actually a "source" for the .js.min files that I added. I wonder where I put that...

13:29 replaca_: I'm still trying to get the hang of showoff

13:30 we need to have an emacs "de-min" mode or something for working with js

13:32 chouser: Here's the file I used to generate clojure.js.min: http://gist.github.com/622574

13:33 I started with a lisp lang file or something and hacked it up pretty bad

13:33 I don't much like the syntax highlighting engines being used here, but they're ok for basic stuff.

13:34 I want map to be two different colors in (map (fn [map] ...) [{:a 1}])

13:35 replaca_: chouser: cool. I've used pygmentize (directly out of emacs) in the past, which is OK, but it feels wrorg in the context of showoff

13:35 *wrong

13:35 chouser: nothing is wrong

13:35 replaca_: well, wrong as in "likely to cause issues later on" :)

13:36 chouser: A presentation is one-time performance art, not software. Do what gets it done.

13:36 replaca_: yup

13:36 chouser: except

13:36 replaca_: ...

13:36 chouser: strange loop wants a 1-up pdf, so now I'm screwed.

13:36 printing from the browser appanretly only prints the one slide that's currently visible.

13:37 replaca_: there was code in their to generate pdfs, but I couldn't get it to run

13:37 chouser: oh, yeah. hm...

13:37 I looked but didn't see anything.

13:37 replaca_: but I didn't try real hard

13:38 chouser: oh, I see it now. hmmm...

13:38 replaca_: showoff static pdf

13:38 once you've installed princely

13:39 but I still got some error

13:40 I like to have a 1-up pdf as a backup in case of various catastrophes

13:40 chouser: yeah

13:41 I have a static .html and heroku install for contingency

13:41 paper would be nice

13:41 replaca_: yeah

13:41 that's what I was thinking too

13:41 is strange loop this weekend?

13:42 jamesl: How can I represent extremely big number(infinity) in clojure? Is Float/POSITIVE_INFINITY a right way to go? What if I want is infinity for integer?

13:47 rlb: How would you end up with an integer infinity?

13:47 Oh wait, I see.

13:47 (conceptually anyway)

13:51 chouser: replaca_: yep

13:51 well, late this week

13:53 replaca_: cool. Good luck! I wish I could be there, but I can't travel twice so close together

13:55 TeXnomancy: replaca_: have you seen epresent? it turns org-mode files into presentations. no extra render phase (don't even have to save); it just uses Emacs' font-lock rules directly.

13:56 replaca_: TeXnomancy: oh interesting. I haven't seen that, and I'm probably too far into showoff to change horses at this point

13:56 too bad too, since the source material is mostly in org-mode

13:57 TeXnomancy: yeah. there are other (possibly better) ways to get PDFs out of org-mode, but this is the simplest thing for my needs

13:58 replaca_: for general pdf or word, I usually just go to HTML and print or import

13:58 from org-mode

13:58 TeXnomancy: can't imagine keeping slides in something that couldn't go in version control though

14:00 replaca_: yeah, showoff is good that way (as you would expect from someone who works at github)

14:01 chouser: My favorite thing about showoff so far (and it's really just from using the browser to run to preso) is embedded svg that I can edit directly in inkscape and just reload to see.

14:01 most preso software chart-drawing tools just don't cut it

14:01 TeXnomancy: I really like having the whole presentation in a single file though. my last talk I had one per slide and it was a nuisance.

14:02 replaca_: showoff lets you choose

14:02 chouser: yeah, one file per slide is no good.

14:02 replaca_: as many slides per file as you'd like

14:02 TeXnomancy: nice

14:03 chouser: ok, I've got showoff onepage sorta working. 1-up pdf looks to be withing striking distance now.

14:03 replaca_: chouser: let me know the recipe when you peg it

14:03 chouser: will do

14:05 hm, the css being used for printing seems ... off

14:06 replaca_: :)

14:08 Drakeson: hmm, what is good about showoff? I was about to make a presentation.

14:08 do you build the pres in json?

14:10 replaca_: Drakeson: mostly in markdown with some extra stuff

14:10 there's a json file that points to the set of directories you want to use so you can easily enable/disable chunks of the preso

14:11 Drakeson: I see. I have been working on something that resemples slidy, but using clojure and based on ring

14:11 replaca_: cool.

14:11 Drakeson: I guess I should give showoff a try

14:11 (at least to see if I am missing something)

14:12 replaca_: showoff's big thing is that it's very interactive. No postprocessing cause it's based on a sinatra server

14:13 Drakeson: what is interactive? building slides or the show time?

14:13 replaca_: Drakeson: both

14:13 sorry, the show

14:13 but on both the client and server

14:14 Drakeson: is it ajax?

14:14 replaca_: authoring is mostly just like writing mardown

14:14 Drakeson: sort of, but no support for real live data

14:14 *markdown

14:15 it does pull a base page and then fills it in with content via ajax

14:15 it's built on top of jquery on the client side andyou can open that up if you want

14:16 Drakeson: but what about after that? what else is interactive after the slides are built up?

14:16 replaca_: just the way you can control them

14:16 and you can add your own js to the mix if you want

14:17 easy support for some kinds of incremental stuff

14:17 simpler than slidy, I think

14:17 Drakeson: I should give it a try, then.

14:18 personally, I prefer editing sexps with paredit over markdown

14:18 replaca_: Drakeson: I think that's going to be a tough sell in the wider world :)

14:19 Drakeson: lisp and clojure are also tough sells ;)

14:20 replaca_: do you have to edit any ruby to build up your pres with showoff?

14:20 replaca_: yeah, but to use showoff (or slidy or whatever) I didn't need to do any ruby hacking

14:21 no, though I had to read some

14:21 to overcome the light docs

14:21 more likely to end up writing css/js

14:21 I've already done some css and chouser did some js.

14:23 * replaca_ has to run

14:23 replaca_: bye, y'all

14:23 Drakeson: replaca_: thanks, bye

14:46 jjido: can you do "import" of a Java package?

14:47 jfields: I'm doing something with refs where I'm concerned about write-skew. I can't find any examples of using ensure. Do I just use ensure instead of deref or am I supposed to use it in some other way?

14:48 kumarshantanu: jjido: (ns xyz (:import java.util.ArrayList)) ?

14:48 jweiss_: does anyone here know of a way to get fp-like functionality in a unix shell? i'm aware of scsh, lush, eshell. They have little to no tab completion and/or paredit.

14:48 also there is rush (ruby) shell, but while it has some fp type stuff, i prefer lisp

14:48 jjido: kumarshantanu: looks good, thanks

14:50 klang: jweiss_: M-x bash followed by M-x paredit-mode .. I suppose ..

14:50 M-x shell (unless you have a bash setup)

14:51 chouser: jfields: doing the ensure once in the transaction is enough

14:51 you use it where you'd otherwise do a dummy write to avoid skew

14:51 klang: jweiss_: apart from that, the unix shell does let you pipe output from one function to the next ..

14:51 jweiss_: klang: how does that give me fp functions

14:51 klang: yeah, but where's filter and map?

14:52 klang: jweiss_: it doesn't .. it gives you paredit-mode, if you want it..

14:52 jweiss_: i suppose xargs is like map

14:52 klang: why would i need paredit for bash :)

14:52 ohpauleez: jjido: Just a comment, I love watching you really taking a hard grasp of Clojure

14:52 klang: jweiss_: not really ..

14:52 jweiss_: i meant i wanted paredit for lispy shells

14:53 jfields: chouser: so I use ensure to read the value, make a change to my other ref, then close the transaction, correct?

14:53 jjido: can I specify only one jar in the classpath? It does not find classes in the second jar

14:53 jweiss_: bash doesn't really let you write inline functions

14:53 ohpauleez: jjido: You do it like this onething:another_thing:last_thing

14:53 kumarshantanu: jjido: the classpath should be delimited by semicolon on Windows and by a colon on *nix

14:53 klang: jweiss_: I think you have to switch to the bash mindset if you want to do bash stuff .. :-)

14:54 jjido: ohpauleez: kumarshantanu: I think I have another problem

14:54 klang: jweiss_: but you could do a lot of things from within clojure

14:54 kumarshantanu: jjido: the CLASSPATH can of course have multiple JARs specified

14:54 jweiss_: klang: i don't want to do *bash* stuff, just shell stuff

14:55 scheme shell is awfully close

14:55 klang: jweiss_: is there a difference?

14:55 jweiss_: but no completion or paredit.

14:55 klang: of course there is

14:55 there are other types of shells than bash.

14:55 check out http://rush.heroku.com/

14:56 klang: jweiss_: maybe I am just too bash-centric. I'll crawl back under my rock.

14:57 jweiss_: klang: my desire to find a new kind of shell was from writing clojure code in emacs (with tab-complete and paredit). thought, "why am i not doing my command line stuff in a similar environment?"

14:57 and went off looking for one, and haven't found it

14:58 klang: jweiss_: you can do some commandline stuff from within clojure, but wouldn't that become tedious?

14:59 jweiss_: klang: yeah, clojure repl really isn't a shell - it's not that easy to connect unix command in/output, do process control etc from clojure, it's not really meant for that (although it may be possible to create that functionality)

14:59 klang: jweiss_: on rush .. well, it has the advantage of keeping you in the same mindset all the time .. I see your point

15:01 jweiss_: shell-out or pallet .. but not entirely what you are looking for..

15:12 d0m: A clojure shell would def. be awesome.

15:14 kotarak: d0m somehting scsh?

15:14 -.-

15:14 ohpauleez: d0m: zsh, plus a function to push to nailgun

15:14 kotarak: something like scsh?

15:14 d0m: Well a little bit as what jweiss_ was talking about with rush.heroku.com

15:15 jweiss_: i looked at scsh, which is almost perfect - except it breaks emacs paredit. and no tab completion that i can find.

15:15 chouser: I dunno. quoting filenames all the time sounds tedious

15:16 jweiss_: chouser: that's the nice thing, you don't quote file names

15:16 but no tab completion is still too tedious, i agree.

15:16 chouser: so -- custom reader?

15:16 kotarak: jweiss_: I guess that's backwards. paredit is "broken" in sense of not supporting scsh. Not the other way around...

15:16 chouser: or at least custom eval I guess

15:17 jweiss_: kotarak: well, i guess. paredit is not really meant for a shell prompt. i think it's designed for source files.

15:17 although it does work fine for slime

15:17 i think it's scsh's use of the pipe symbol that breaks paredit

15:17 d0m: [tab] could still work

15:17 it could even be improved by adding a little fuzzy matching

15:18 hiredman: chouser: well you need to model the filesystem as a set of namespaces and when in the directory of a namespace the symbols of the filenames are bound to the files

15:18 jweiss_: d0m, any idea how that would be done?

15:18 jjido: so the first jar was loading, the second wasn't. Turns out bash expansion of ~ does not work in the middle of the classpath.

15:18 chouser: hm. interesting. so, custom 'resolve'

15:18 d0m: Well, it depends of many things.. but I wouldn't be against using ncurses to be able to use clojure and [tab]

15:19 jweiss_: d0m: yeah i'd be all for that as well :)

15:19 although clojure is pretty heavy for a shell.

15:19 hiredman: chouser: right, being able to alter the behaviour of var resolution is really useful for sandboxing too

15:19 jweiss_: i'd still use it - just for interactive, not running scripts

15:20 hiredman: you could hook the resolve function, but the compiler doesn't use the resolve function

15:21 d0m: but that would kind of be ironic to use clojure ->> which mimic a shell instance.

15:21 chouser: rhickey wants the compiler to use a more flexible resolve policy for interop

15:22 hiredman: Arkham lets you change how var resolution happens so clojure.core/eval always resolves to #'arkham.evil

15:22 chouser: so the compiler doesn't have to load a class into the compiler's running jvm in order to compile calls to that class's methods

15:23 hiredman: that's hard, because is (foo.bar/baz 1 2) a static method call or what?

15:23 depends on what is loaded

15:23 chouser: well, it will examine .class files directly I think

15:23 hiredman: mmm

15:23 interesting

15:24 chouser: exactly what I thought

15:26 hiredman: http://github.com/hiredman/Archimedes/blob/master/src/Archimedes/compiler.clj

15:27 jjido: Clojure can't find my compiled class, though it is in the classpath: Unable to resolve classname: dodo0Lexer (runner.clj:5)

15:27 hiredman: I've been playing with defining a sort of abstract clojure machine as a protocol

15:28 http://github.com/hiredman/Archimedes/blob/master/src/Archimedes/compiler/jvm.clj implementation of the machine for compiling to java bytecode

15:28 jjido: ok it works with (ns (:import))

15:33 Can Clojure transform a String into a program?

15:33 ,(eval "[1 2 3]")

15:33 mrBliss: ,(doc read-string)

15:33 clojurebot: DENIED

15:33 "([s]); Reads one object from the string s"

15:34 kotarak: ,(eval (read-string "[1 2 3]"))

15:34 clojurebot: DENIED

15:34 jjido: mrBliss: thanks

15:34 mrBliss: yw

15:35 jjido: Wow that works! Clojure just ran my first dodo program :)

15:37 plathrop: Anyone using lazytest that can point me to some good examples? Do people tend to split their tests into separate files and/or namespaces?

15:37 ohpauleez: jjido: Congrats!

15:39 jjido: ohpauleez: I love that. Very limited at the moment but a good start

15:45 bhenry: is the 1st fibonacci number 0 or 1?

15:45 amalloy: 0

15:45 0 1 1 2...

15:46 bhenry: so (nth-fib 1) should be 0? i have (nth-fib 0) as 0 and (nth-fib 1) as 1 (nth-fib 2) 1 etc.

15:46 so it's 0 indexed i guess

15:46 but i want it to make sense

15:47 amalloy: i think your description is right. it's 0-indexed just like nth, no?

15:47 ,(nth 1 (range))

15:47 clojurebot: java.lang.ClassCastException: clojure.lang.LazySeq cannot be cast to java.lang.Number

15:48 amalloy: ,(nth (range) 1)

15:48 clojurebot: 1

15:48 amalloy: gets you the natural number at offset 1, whiuch is the second one in the list

15:49 bhenry: so (nth-fib 0) should be 0?

15:49 that does make sense

15:49 amalloy: yes

15:49 i agree whole-heartedly with that assertion/question

15:49 kotarak: Where it might be disputed whether 0 is a natural number..

15:50 amalloy: kotarak: sorry, i was compiled with --no-pedantic today. if you prefer, s/natural/non-negative/

15:50 coldhead: sup ChanServ

15:51 kotarak: amalloy: ;)

15:52 bhenry: amalloy are there any drawbacks to this? it took 400 msecs to find the 100th fib 1000 times. but i don't have anyone else's nth-fib function to compare. https://gist.github.com/8223ea8e8d2db70f54f2

15:53 amalloy|lunch: bhenry: check out rosettacode's fibonacci problem

15:53 the clojure implementation is very nice

15:55 bhenry: oh cool it's almost the same. except they are generating the list of fibs and i'm generating a way to find the nth fibs.

16:10 plathrop: I must be doing something wrong. I've defined a function with defn and a docstring, but when I do (meta #'myfn) the doc isn't included...

16:11 ohpauleez: plathrop: can you post a gist of your code?

16:11 also, does (doc myfn) show anything?

16:11 kotarak: plathrop: the string goes in front of the args

16:11 plathrop: ohpauleez: sure, 1 sec

16:12 kotarak: oh, that's probably it

16:12 kotarak: plathrop: usual suspect

16:12 ohpauleez: meta doesn't show the doc for me

16:12 plathrop: kotarak: yeah, that was it, now showing up in both meta and doc

16:12 thanks

16:13 hiredman: ohpauleez: meta of the var, not meta of the fn

16:13 kotarak: plathrop: np

16:13 plathrop: that kinda sucks, though, imho

16:13 for reading the code

16:13 kotarak: plathrop: it does not, because you can have multiple aritites

16:13 ohpauleez: hiredman: ah, I see that now

16:13 plathrop: I guess that makes sense.

16:14 I'm just coming from CL, so I guess it's "DIFFERENT IS BAD ARGH!" on my part

16:15 kotarak: plathrop: which is kind of a strange attitude, IMHO. Why learn something different if it's bad?

16:15 plathrop: kotarak: Was making fun of myself

16:15 My gut was that it was bad, but gut is often wrong

16:17 kotarak: plathrop: no offense intended.

16:18 plathrop: None taken

16:32 amalloy: bhenry: the rosettacode version is "better", though, because it lets you compute a range of fibonacci numbers, or keep around a local cache of them in whatever range you need, without inefficiently recomputing the whole thing every time

16:35 dpritchett: isn't there a clojure macro for applying a bunch of different setters to an object all at once without spelling out the object on each line?

16:35 amalloy: ,(doc doto)

16:35 clojurebot: "([x & forms]); Evaluates x then calls all of the methods and functions with the value of x supplied at the front of the given arguments. The forms are evaluated in order. Returns x. (doto (new java.util.HashMap) (.put \"a\" 1) (.put \"b\" 2))"

16:35 amalloy: dpritchett: ^^

16:35 * dpritchett hugs amalloy

16:36 amalloy: dpritchett: see also -> and ->>, which are different but in sorta the same vein of code restructuring

16:37 arkh: is there a function that will expand the following? [1 [2 3] [4 5 [6 7]]]

16:37 to this [1 2 3 4 5 6 7]

16:37 amalloy: ,(flatten [1 [2 3] [4 5 [6 7]]])

16:37 clojurebot: (1 2 3 4 5 6 7)

16:37 arkh: amalloy: thank you

16:47 lrenn: ninjudd: http://gist.github.com/622884

16:48 ninjudd: not sure if that is a concern or not as I switch around versions and branches fairly often.

16:48 ninjudd: lrenn: that is the bug i just fixed

16:49 amalloy: ninjudd: it's so exciting to be using a product maintained by someone with psychic powers, who can fix bugs before you submit them

16:49 ninjudd: heh

16:50 lancepantz: heh, his super hero is now totally jean gray

16:53 ninjudd: amalloy, made --no-destroy-host-system the default now too ;)

16:53 ohpauleez: ~seen ato

16:53 clojurebot: no, I have not seen ato

16:54 amalloy: ninjudd: was it a real problem, or something with kmc's setup?

16:54 astoddard: What is the "size" of the element of a clojure vector? Is it the size of an object reference?

16:54 chouser: astoddard: there is some overhead

16:54 arohner: a java box is what, 4 pointers?

16:55 hiredman: depends on the implementation

16:55 ninjudd: amalloy: a real problem, though he likely didn't have a lot of memory.

16:57 amalloy: there are two separate fixes in 0.5.0-SNAPSHOT that should help, one that reduces the default JVM memory usage and one that kills defunct JVMs better

16:59 astoddard: chouser: Thanks, so on a 64bit JVM I am looking at 24+ Gb for a 3 billion element vector (which just happens to be around the size of the human genome...) ?

17:00 amalloy: astoddard: why are you storing it in a vector? do you really need it all in memory at once?

17:01 arohner: astoddard: what kind of operations do you need to do on the vector? If it's read-only, you could use a java array

17:01 chouser: what are you storing in each element?

17:01 astoddard: amalloy: not necessarily but I was just quickly trying to work out what a naive implementation would come too.

17:01 amalloy: ninjudd: nice. this machine has plenty of memory, but if i'm ever foolish enough to run clojure on my home machine i need all the memory i can get

17:01 chouser: primitive vectors might be smaller

17:02 hiredman: you could use an array even if it is not read only, you just have to be careful

17:02 chouser: (vector-of :byte)

17:03 astoddard: chouser: that's one thing I was wondering. I only need 3 bits per element AGCT or N (for unknown).

17:03 AWizzArd: That has a good performance, as it uses real byte[] under the hood

17:06 chouser: astoddard: I doubt it's worth packing your bits in any kind of "naive" solution, but (vector-of :byte) will be more memory-efficient and just as easy to use as a vector of Objects.

17:07 when/if you're willing to write more complex code to gain performance or memory efficiency, packing bits into a Java array of bytes will be hard to beat

17:08 amalloy: chouser: except by lazy seqs, if he only needs chunks at a time

17:09 chouser: though ... it might be fun to write a (vector-of-nucleotides)

17:09 astoddard: amalloy: For my purposes I need index based access. So that excludes lazy seqs.

17:09 chouser: as an adapter on top of (vector-of :byte)

17:10 amalloy: chouser: if you're going to do vector-of-nucleotide you might as well go a bit further and layer huffman coding under it, or something similar

17:11 chouser: compression?

17:11 astoddard: Thanks for the suggestions, I had missed vector-of being added to 1.2.

17:11 amalloy: since i bet N is either quite common or quite uncommon in his data set

17:11 yeah, i guess any old compression would probably fit this task

17:12 astoddard: A amalloy suggested, there is a lot of repetition in genome sequence. Big runs of Ns being common in the reference assembly.

17:12 chouser: I don't know much about compression, but wouldn't it be hard to get good by-index performance with compression involved?

17:13 amalloy: chouser: blahhhhh, of course it would. stupid math

17:13 hiredman: it's a trade off, you can divy the sequence into chunks and compress chunks seperately

17:14 time (access speed) vs. space

17:14 chouser: packing 2 nucleotides per byte could likely be done with ~15 lines of clojure

17:14 and relatively little impact on read or write performance

17:15 amalloy: chouser: three nucleotides ought to fit in 7 bits, right?

17:15 without affecting indexability

17:16 5^3 possibilities

17:16 chouser: yes, just stumbling on that :-)

17:16 not neatly bit-partitioned, but a lookup table or some math should make it work well enough

17:17 amalloy: yeah, just (rem n 5) a few times

17:18 astoddard: Thanks for the suggestions.

17:19 amalloy: ,(take 3 (map first (iterate (fn [[n d]] (rem n 5)) [112 0])))

17:19 clojurebot: java.lang.RuntimeException: java.lang.IllegalArgumentException: Don't know how to create ISeq from: java.lang.Integer

17:19 chouser: but again that should be an invibible implementation detail under the IPersistentVector interface

17:19 astoddard: I was intrigued by using vectors as persistence would let me store a lot of variant genomes very naturally and efficiently as "mutations" of the reference vector.

17:19 amalloy: chouser: right

17:20 chouser: start with a (vector-of :byte) because it's there already and replace with your own if it ever becomes worthwhile

17:20 hm, except we don't have literal byte syntax in Clojure.

17:20 astoddard: And that then lead to the thought, could I just but the whole reference in memory?

17:21 amalloy: what's clojure's truncating division function? the complement of rem

17:21 chouser: quot

17:21 amalloy: thanks

17:22 chouser: seriously. 15 lines of clojure could get you vector-of-nucleotides that could store/retreive :A :C :G :T or :N (or maybe nil)

17:23 amalloy: are you writing it?

17:23 amalloy: heh, sorta

17:23 chouser: look at mk-am in gvec.clj

17:24 amalloy: i'm more interested by unpacking a byte into 3 nucleotides actually

17:24 chouser: I think you can write an ArrayManager for nucleotides and you'll be all set

17:24 put your packing code in aset and your unpacking in aget

17:24 amalloy: oh, no kidding? i didn't know that existed

17:24 ,(map first (take 3 (drop 1 (iterate (fn [[n d]] ((juxt quot rem) n 5)) [85 0]))))

17:24 clojurebot: (17 3 0)

17:25 chouser: it's not documented and therefore not really supported, but it sure would work today.

17:26 amalloy: hrm. that doesn't seem quite right, does it? i see

17:26 ,(map second (take 3 (drop 1 (iterate (fn [[n d]] ((juxt quot rem) n 5)) [85 0]))))

17:26 clojurebot: (0 2 3)

17:27 amalloy: there. 3*25 + 2*5 + 0*1

17:28 chouser: oh, a custom ArrayManager won't be enough

17:28 you need to muck with the index earlier than that would allow

17:28 I think you would actually need a full vector adapter

17:28 amalloy: chouser: now you're making me glad i didn't try to do that part first

17:29 chouser: heh

17:30 amalloy: hey, this could easily be turned into a generic bit-packer for encoding stuff in base N (here 5)

17:31 chouser: and since we don't yet have efficient partial implementations of the core clojure abstractions, a proper NucleotideVector deftype that handles equality, hashing, subseq, etc. will be quite a bit more than 15 lines.

17:31 ohpauleez: amalloy: that's almost an insult or a way to establish geekery rank

17:31 "I'm an n-5 bit packer"

17:31 or, "Quit being such a bit-packer and get it done"

17:31 amalloy: haha

17:32 you should have seen the bit-packer that guy was carrying

17:32 ossareh: in england we use pack to mean "stop". i.e. "pack it in"

17:33 amalloy: ossareh: we have that idiom, but don't use pack to mean stop in any other context i can think of

17:34 ohpauleez: in England, bit-packing is like "stop the presses" for the computer

17:34 :)

17:34 ossareh: amalloy: right - I was just thinking that - an habitual packer is not a constant stopper =)

17:34 ohpauleez: hahaha

17:35 * astoddard wonders what have I done...

17:35 ohpauleez: If there are ever Clojure Community awards, I really hope there's a category for, "most derailed conversations in IRC"

17:35 amalloy: haha

17:36 Adamant: they're just establishing a topic calculus. they can find the tangent to anything.

17:38 astoddard: Thanks for the suggestions, folks. For now I'll start exploring vector-of :byte

17:43 But that does leave me asking how to assign to such a thing without a byte literal...

17:44 Hm, looks like I can just conj any integer that fits in a byte. Well that was easy.

17:47 AWizzArd: à propos, there is also a java.util.BitSet

17:48 With it you could do 3 bits per entry.

17:48 amalloy: AWizzArd: yeah, i always hated that class, though it might be useful for this application

17:48 AWizzArd: http://download.oracle.com/javase/7/docs/api/java/util/BitSet.html

17:48 Don’t hate, learn to master it :)

17:48 amalloy: the must useful thing it could do is iterate over a collection of set-bits or unset-bits, but instead it will only iterate over all bits and return true/false

17:51 AWizzArd: This BitSet class could store your 3 milliard entries à 3 bit in around one GB of RAM.

17:51 amalloy: 3 milliard? i'm not sure what a milliard is, but he has 3 billion entries

17:51 AWizzArd: Yes, milliard = billion ;)

17:52 stain: and billion = trillion!

17:52 AWizzArd: An european milliard is an american billion

17:52 amalloy: man, is this a stupid english thing? i thought i knew all the stupid english things :)

17:52 AWizzArd: While a european billion is an american trillion

17:52 stain: that's how the bankers managed to fool everyone in the credit crunch

17:52 AWizzArd: :)

17:52 stain: UK is using billion = 1 000 000 000 like the US - they changed it in the 70s or something

17:52 AWizzArd: At least meters kilometers miles foot and inches have very distinct names.

17:53 yes, amazing job

17:53 They should switch on a regular basis in every country

17:53 stain: perhaps at almost the same time as daylight savings

17:53 AWizzArd: yes *sigh*

17:53 alsocasey: languages will make fools of us all

17:58 AWizzArd: Anyway, the BitSet should be able to store your whole genome in around 1 GB of RAM.

17:58 hiredman: but BitSet is mutable and not threadsafe

18:00 AWizzArd: Could be okay for his use case.

18:02 if he puts a :byte vector into a single ref then hammering that from multiple threads will totally kill the performance

18:08 amalloy: ohpauleez: now look what you've made me do: http://github.com/amalloy/bit-packer

18:08 ohpauleez: haha

18:09 YES!

18:09 amalloy: now *everyone* will know that i am...a bit-packer

18:09 AWizzArd: For example http://shootout.alioth.debian.org/u64q/performance.php?test=knucleotide :)

18:09 ohpauleez: soon technomancy is going to be coming to me to name his projects

18:09 amalloy: yeah, just work your way up the scale of interesting people, from me all the way to technomancy

18:10 AWizzArd: sbcl eats 170 mb ram and runs only one of the 4 cores, takes 37 seconds. Clojure eats 1200 mb ram and runs all 4 cores at 100% and takes friendly 12 minutes ;)

18:14 kmc: ,`(foo# bar ~`(foo# bar))

18:14 clojurebot: (foo__9899__auto__ sandbox/bar (foo__9898__auto__ sandbox/bar))

18:16 amalloy: hm. good question, kmc

18:16 kmc: heh i didn't ask the question yet but i guess it's obvious:

18:16 how do i refer to an auto-gensym from an outer quotation within an inner nested quotation

18:16 ,`(foo# bar ~`(foo bar))

18:16 clojurebot: (foo__9902__auto__ sandbox/bar (sandbox/foo sandbox/bar))

18:17 amalloy: ,`(foo# bar `(~foo# bar))

18:17 clojurebot: (foo__9905__auto__ sandbox/bar (clojure.core/seq (clojure.core/concat (clojure.core/list foo__9905__auto__) (clojure.core/list (quote sandbox/bar)))))

18:17 kmc: ahh

18:17 makes sense

18:17 amalloy: maybe? that has a different level of quoting on the outer form than you might want

18:18 but i think in general it will be what you want

18:40 KirinDave: Man, nested quote gensym hacking.

18:40 Prepare your butthole.

18:41 amalloy: KirinDave: a minute ago, this window was safe for work :)

18:41 KirinDave: amalloy: Oh come on. They say butthole on the simpsons

18:42 amalloy: *chuckle* i kid, i kid

18:49 duncanm: does anyone know why http://liebke.github.com/incanter/ doesn't actually list anything?

18:50 amalloy: um, what do you mean? i see a list of namespaces; there's just nothing helpful in any given namespace

18:51 http://liebke.github.com/incanter/api-index.html looks like the list of all the functions he's documented

18:52 or if you want the github repo it's at http://github.com/liebke/incanter

18:53 duncanm: amalloy: the 'old' API docs are here: http://incanter.org/docs/api/

18:53 amalloy: but all the links point to the new site

18:54 oh, i can use this: http://liebke.github.com/incanter/branch-1.0.x/index.html

18:54 * kmc decides to spare his butthole and use explicit gensym instead

18:55 amalloy: kmc: wuss

19:00 kmc: what's the standard way to have a function return a successful result or failure, when 'nil' is a possible successful result?

19:02 amalloy: ummmm

19:03 i don't know about standard, but you could return nil for failure, or [result] otherwise

19:04 kmc: yeah i can think of a lot of ways to do it

19:04 though i didn't think of that one; i like that particularly

19:04 maybe i should take a success continuation and a failure continuation ;P

19:08 amalloy: kmc: you can take your filthy haskell habits out of this channel :)

19:08 kmc: :P

19:08 no, in Haskell i would just return a Maybe value

19:09 jkkramer: people use locals bound to (Object.) as a sentinel value sometimes, but i don't think i've seen it as a return value

19:09 kmc: ah, that's odd

19:09 hiredman: there is clojure.contrib.monads

19:09 amalloy: kmc: go whole-hog java and throw an exception!

19:09 kmc: amalloy, heh

19:25 so i can define a variatic function with (fn [x y & zs] ...)

19:25 but i can't call it like (f x y & zs)?

19:25 amalloy: ,(doc apply)

19:25 clojurebot: "([f args* argseq]); Applies fn f to the argument list formed by prepending args to argseq."

19:25 kmc: is there a better way than (apply (partial f x y) zs) ?

19:25 oh, ok

19:26 amalloy: ,(apply + 1 2 [3 4])

19:26 clojurebot: 10

19:37 ossareh: apply is life.

20:42 yayitswei: LauJensen: in your Compojure/Emacs intro, you have Compojure logging displayed in the inferior lisp buffer. I don't see that in my Emacs, did you have to do some special configuration?

20:42 LauJensen: referring to the vimeo video, thanks for putting that up.

20:51 defn: is there a shortcut to get the most recent match from a regex

21:26 _rata__: hi

21:27 how do I change the way an object is printed by the repl?

21:28 dnolen: _rata__: print-method

21:28 ,(doc print-method)

21:28 clojurebot: "; "

21:28 dnolen: heh

21:28 amalloy: ~source print-method

21:29 not quite doc, but might be helpful

21:30 _rata__: thanks :)

21:40 * KirinDave sighs.

21:41 KirinDave: Man, this webmachine design is bugging me.

21:41 The erlang version totally embraces mutability.

21:43 TigerUppercut: how can i create a loop (like a for) in clojure, I would like to repeat a function 100 times passing as arguments to function ( myFunc(i) )

21:44 KirinDave: TigerUppercut: (dotimes ...) is a good start

21:44 ,(dotimes [n 3] (println n))

21:44 clojurebot: 0 1 2

21:46 amalloy: or:

21:46 ,(map #(* 2 %) (take 3 (rest (range))))

21:46 clojurebot: (2 4 6)

21:46 amalloy: depending on, among other things, whether you want it to be lazy

21:50 (and whether you want it to return a result or just produce side effects)

21:51 KirinDave: amalloy: You know what's what. Can I bounce ideas off you for a moment?

21:51 amalloy: sure

21:51 KirinDave: I'm trying to think my way around a problem.

22:01 TigerUppercut: ,(dotimes [n+1 5] (println n))

22:01 clojurebot: java.lang.Exception: Unable to resolve symbol: n in this context

22:03 TigerUppercut: tk

22:07 KirinDave: TigerUppercut: You need the index passed in?

22:12 TigerUppercut: I don't know what happen... (dotime [n 5] (myFunc n)) .. not yet

22:12 amalloy: TigerUppercut: that last form looks right

22:20 ,(let [[a b :as c] 1] [a b c])

22:20 clojurebot: java.lang.UnsupportedOperationException: nth not supported on this type: Integer

22:20 TigerUppercut: I pasted here http://pastebin.com/MabThXYP ... when I call "test 5" it returns nil , if a remove dotimes and call direct, works correctly. Could you see?

22:20 amalloy: ,(let [& [a b :as c] 1] [a b c])

22:20 clojurebot: java.lang.IllegalArgumentException: let requires an even number of forms in binding vector

22:22 amalloy: TigerUppercut: dotimes doesn't collect its results into a list; it just evaluates them for side effects

22:22 if you want it to print, then try wrapping a (print (if...)) around the if on line 11

22:25 TigerUppercut: :) it works. tks

22:29 _rata__: how do I create the symbol 'x_op' from the symbol 'x'? is there any function like Scheme's string->symbol and symbol->string?

22:29 amalloy: _rata__: symbol and str, respectively

22:29 _rata__: oh thanks :)

22:31 bhenry: TigerUppercut: dotimes is for side effects and will return nil every time.

22:31 amalloy: _rata__: http://github.com/amalloy/enum/blob/master/src/enum/core.clj is something i did a while ago that you might find useful

22:32 specifically lines 6-8

22:40 _rata__: yeah, thanks, I understand that part... but what does the 'key' function do?

22:41 chouser: key returns the key part of a MapEntry

22:41 ,(first {:a 1})

22:41 clojurebot: [:a 1]

22:41 chouser: ,(key (first {:a 1}))

22:41 clojurebot: :a

22:41 chouser: ,(avl (first {:a 1}))

22:41 clojurebot: java.lang.Exception: Unable to resolve symbol: avl in this context

22:41 chouser: ,(val (first {:a 1}))

22:41 clojurebot: 1

22:42 amalloy: ummm which part? chouser effectively explains (key), but i wonder if you mean what's key in my code for

22:42 chouser: sorry, I should know better than to answer without context

22:43 amalloy: heh, well your answer might well be the right one

22:44 cause it's looking like my answer will be "i'm using key in a way that is totally unrelated to what you're trying to do, but i'm happy to explain it to you if that's what you actually mean"

22:44 _rata__: i guess neither of us pinged you when we answered

22:45 _rata__: amalloy, no, I didn't know what the key function do in general... and the repl proved tricky at trying to understand it

22:45 amalloy: chouser: see? right again :)

22:45 chouser: lucked out

22:50 _rata__: which pastebin do you guys use? which one has clojure syntax highlighting?

22:51 amalloy: http://gist.github.com is pretty good

22:53 _rata__: http://gist.github.com/623339

22:53 amalloy: you get clojure highlighting iff you tell it the filename ends with .clj

22:54 _rata__: mmmm hahahaha ok

22:54 ok, now it works :)

22:56 TigerUppercut: , (dotimes [m 4

22:56 clojurebot: EOF while reading

22:57 TigerUppercut: , (dotimes [m 4] (print m "-"))

22:57 clojurebot: 0 -1 -2 -3 -

22:57 amalloy: ,(for [x (range 4)] x)

22:57 clojurebot: (0 1 2 3)

22:59 amalloy: or for extra fun:

22:59 ,(clojure.string/join '- (for [x (range 4)] (* 2 x)))

22:59 clojurebot: "0-2-4-6"

23:04 _rata__: is there a way to say ` not to qualify a symbol?

23:05 amalloy: _rata__: ' works, but it's usually a bad idea in a macro, and often actually illegal in a macro

23:07 ,`(~'r)

23:07 clojurebot: (r)

23:07 amalloy: ,'r

23:07 clojurebot: r

23:11 _rata__: thank you amalloy

23:12 I have these two macros: http://gist.github.com/623360

23:12 is it two bad to use the ' there?

23:13 they seem to work correctly

23:13 amalloy: well...i mean, it's fine so long as you know that you're messing around with any variables named r the user happens to have

23:14 but you probably want to use the automatic gensym# forms

23:14 ,`(let [r# 1] r#)

23:14 clojurebot: (clojure.core/let [r__10001__auto__ 1] r__10001__auto__)

23:15 amalloy: _rata__: the # magically creates a new variable name for you that it guarantees nobody else is using, so that you can't accidentally step on the user's variable named r

23:17 _rata__: oh yes, that was what I wanted... I couldn't remember how hygenie was done in clojure

23:17 thanks

23:17 amalloy: welcome

23:18 Lajla: ,(for [x '(\a \b \c)] (conj x "bla"))

23:18 clojurebot: java.lang.ClassCastException: java.lang.Character cannot be cast to clojure.lang.IPersistentCollection

23:18 Lajla: ,(for [x '("a" "b" "c")] (concat x "bla"))

23:18 clojurebot: ((\a \b \l \a) (\b \b \l \a) (\c \b \l \a))

23:19 amalloy: Lajla: conj takes its args in the other order

23:19 ,(conj "bla" \a)

23:19 clojurebot: java.lang.ClassCastException: java.lang.String cannot be cast to clojure.lang.IPersistentCollection

23:19 Lajla: ,(for [x '(\a \b \c)] (conj "bla" x))

23:19 clojurebot: java.lang.ClassCastException: java.lang.String cannot be cast to clojure.lang.IPersistentCollection

23:19 amalloy: hm

23:19 oh

23:19 Lajla: amalloy, you liar.

23:19 amalloy: ,(conj (seq "bla") \a)

23:19 clojurebot: (\a \b \l \a)

23:19 Lajla: ,(seq 3)

23:19 clojurebot: java.lang.IllegalArgumentException: Don't know how to create ISeq from: java.lang.Integer

23:20 Lajla: ,(seq '[vector I am])

23:20 clojurebot: (vector I am)

23:21 amalloy: ,(str (conj (seq "ola") \h))

23:21 clojurebot: "(\\h \\o \\l \\a)"

23:21 amalloy: lol, not quite right there

23:21 ,(apply str (conj (seq "ola") \h))

23:21 clojurebot: "hola"

23:21 amalloy: Lajla: ^

23:22 Lajla: ,(str '(this is a random list \a))

23:22 clojurebot: "(this is a random list \\a)"

23:22 Lajla: Weird

23:22 Why the double \ beore the char?

23:22 amalloy: so that if you copy/paste that back into the repl you get the same thing

23:22 ,"(this is a random list \\a)"

23:22 clojurebot: "(this is a random list \\a)"

23:22 amalloy: ,"(this is a random list \a)"

23:22 clojurebot: Unsupported escape character: \a

23:22 Lajla: ahhhh

23:22 escape

23:22 Yeah, I get.

23:33 amalloy: is there a function that combines predicates like and, but returns a function instead of evaluating something? eg, something equivalent to

23:33 (fn [& preds] (fn [& args] (every? identity (apply (apply juxt preds) args))))

23:38 i had in mind using this like (multi-pred integer? pos?) to define a function that tests for positive integers, but my naive implementation has some problems, so i was hoping someone else has done this

23:41 _rata__: amalloy, what's the problem with the anonymous function you write before?

23:41 amalloy: ,((fn [& preds] (fn [& args] (every? identity (apply (apply juxt preds) args)))) 'a)

23:41 clojurebot: #<sandbox$eval10078$fn__10079$fn__10080 sandbox$eval10078$fn__10079$fn__10080@4fdbd6>

23:41 amalloy: rgh

23:42 _rata__: the problem is if you pass it "a" it tries to call pos? even if the test for integer? failed

23:42 ie, it's not lazy enough

23:43 _rata__: ah ok

23:43 and #(and (integer? %) (pos? %))?

23:44 amalloy: _rata__: works, except i'm doing this in a function postcondition, which steals % from me

23:44 i wrote it as a (fn [x] (and...)), which does work

23:44 _rata__: ok

23:44 amalloy: but that lends itself to copy/paste instead of code reuse

23:45 so i was hoping someone had written a better version

23:45 _rata__: and you could write a macro multi-pred to write that function for you

23:45 let me try

23:46 amalloy: hmmm, interesting suggestion. i don't think we need a macro, though: can't this be done with a function that's like my naive one but more careful/lazy?

23:46 maybe the macro is easier, i dunno

23:47 Lajla: ,[+ - * /]

23:47 clojurebot: [#<core$_PLUS_ clojure.core$_PLUS_@2dacc6> #<core$_ clojure.core$_@84d6c2> #<core$_STAR_ clojure.core$_STAR_@e5691e> #<core$_SLASH_ clojure.core$_SLASH_@736f7e>]

23:54 _rata__: amalloy, http://gist.github.com/623401

23:54 TigerUppercut: how can i make a "new java.util.Date().getTime()" in clojure?

23:54 amalloy: if i (defn - [] 1), (defn _ [] 2), then both _ and - evaluate to #<user$_ user$_@xxxxxx - how can they have different code if they're the same class?

23:54 ,(.getTime (java.util.Date.))

23:54 clojurebot: 1286942392870

23:56 amalloy: _rata__: args should be args#, but otherwise it looks pretty spiffy

23:56 hiredman: http://gist.github.com/623413

23:57 _rata__: =)

Logging service provided by n01se.net