#clojure log - Feb 11 2011

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

0:09 TimMc: ,(update-in {:foo 5} [] identity)

0:09 clojurebot: {nil nil, :foo 5}

0:09 TimMc: That's annoying.

0:10 Shouldn't update-in pass the whole collection in to the function in that case?

0:10 (I see why it *doesn't*, reading the source, but I'm wondering if there's a good reason for it.)

0:13 rata_: TimMc: why should it do that?

0:14 amalloy: TimMc: update-in is effectively (assoc m (some-magic-stuff))

0:14 TimMc: rata_: 1) Consistency, 2) it would be damn useful in my code. :-P

0:17 rata_: TimMc: but normally the function you pass to update-in is expecting a value, not a map

0:17 amalloy: TimMc: how would your behavior be any more consistent?

0:18 TimMc: rata_: The value could be a map.

0:18 amalloy: Because ##(update-in {:foo 5} [:foo] identity) gives you back the thing unchanged.

0:18 sexpbot: ⟹ {:foo 5}

0:18 rata_: yes, but a "value-map", not the whole map containing that map

0:19 TimMc: rata_: What's the difference? update-in can handle 1+ levels.

0:19 I just think it should also handle 0 gracefully. :-)

0:19 rata_: TimMc: but not the top level

0:20 amalloy: TimMc: get back to us when you've gotten division to handle 0 gracefully too

0:21 rata_: what update-in is interpreting there is that you want the nil key to be modified, because you gave it the nil key implicitly in []

0:24 I see your point now... you want that to mean "no go any deeper, stay here at the top level of the map"

0:25 s/no /don't /

0:25 sexpbot: <rata_> I see your point now... you want that to mean "don't go any deeper, stay here at the top level of the map"

0:28 tomoj: I found a good source of random names for projects

0:29 I have a bunch of empty lein shells sitting around, and no clue what they were going to be or how I came up with their names

0:31 amalloy: &(take 5 (repeatedly (partial apply str "cloj" (repeatedly #(char (rand-int 0xff))))))

0:31 sexpbot: Execution Timed Out!

0:31 amalloy: hm. i guess not, huh?

0:31 oh heh

0:32 &(repeatedly 5 (partial apply str "cloj" (repeatedly 8 #(char (rand-int 0xff)))))

0:32 sexpbot: ⟹ ("clojÜ7OtÁt" "clojÜ7OtÁt" "clojÜ7OtÁt" "clojÜ7OtÁt" "clojÜ7OtÁt")

0:32 amalloy: man, that didn't work at all. but tomoj, that's a good source of names if you get it right :P

0:34 tomoj: I saw "compojure" is now allowed by lein

0:35 the issue I think suggested getting rid of the restriction with "compojure" as an example, so "compojure" was special cased :)

0:36 but there are so many terribly punny names it still allows

0:36 s/still//

0:36 sexpbot: <tomoj> but there are so many terribly punny names it allows

0:36 * tomoj counts to ten

0:38 tomoj: I think I'm just going to stop using sed style altogether

0:39 amalloy: tomoj: it wouldn't be too hard to add a "don't sed these users" list if it bugs you

0:41 TimMc: rata_: Exactly, I just want it to do nothing when there's nothing to do. :-P

0:42 tomoj: I should be able to remember to use different delimiters, and it shouldn't bug me anyway

0:42 _mst: time for a delimiter-changing erc extension? :)

0:42 rata_: TimMc: no, when you say it so, it doesn't make sense to me

0:43 TimMc: hah, OK

0:43 But yes, "don't go any deeper" is what I mean.

0:48 rata_: TimMc: you could easily do a wrapper fn around update-in like (defn my-update-in [m ks f args] (if (empty? ks) (apply f m args) (apply update-in m ks f args))

0:48 TimMc: I'll probably do that.

0:49 rata_: sorry, I missed a & before args

0:49 ossareh: woo @ wine and code.

0:49 dnolen: TimMc: but you have to ask yourself, why would you pass an empty seq of keys to update-in ?

0:49 (empty? ks) is less idiomatic than (seq ks)

0:49 TimMc: dnolen: I already have a need for that in my code.

0:50 dnolen: TimMc: why would want to propagate empty seqs around. Why do you need that?

0:51 TimMc: dnolen: I have a function that takes in another function that can change the state of the userdata, and also the level at which it knows how to change it.

0:52 Some functions operate on the entire state, some on just pieces of it.

0:52 update-in would be a *perfect* call to make if not for that flaw.

0:53 dnolen: TimMc: only if you think letting empty seq float around through your code instead of filtering them out seems useful.

0:54 TimMc: dnolen: [] is a perfectly valid selector. It's not floating around, it is being used in this one corner of the program.

0:54 rata_: dnolen: I prefer empty?, it's clearer... and it's the schemer way at the same time =P anyway, seq is not more idiomatic than empty?, but more than (comp not empty?)

0:55 dnolen: rata_: Clojure isn't Scheme.

0:55 rata_: dnolen: that's not the point, just a joke

0:56 the point is seq is not more idiomatic than empty?

0:56 dnolen: TimMc: sure, I'm just saying you're ok with running an operation that doesn't do anything, when really you could just filter it out.

0:56 rata_: it's come up before, seq as far I can tell is considered more idiomatic.

0:57 rata_: I have been here for those discussion as well, and it's not

0:58 TimMc: dnolen: I'd prefer to have consistent behavior in a library function than to add a conditional in my own code.

0:59 rata_: doing (empty? ...) is idiomatic, doing (not (empty? ...)) is not

1:01 dnolen: rata_: ah yes, it depends on how you do you branch, I tend to do (if (seq x) ...)

1:02 rata_: yes =) for me it depends on which case comes first to my mind, the empty or non-empty case

1:10 amalloy: tomoj: sexpbot should refuse to sed you now

1:11 tomoj: :O

1:11 amalloy: tryyyyy it plz

1:11 tomoj: s/:O/thanks/

1:11 amalloy: coolio

1:11 s/o/q

1:11 sexpbot: <amalloy> cqqliq

1:11 tomoj: it's not a hardcoded list, is it?

1:11 amalloy: tomoj: it's in the config file

1:12 :dont-sed #{"tomoj" "hiredman"}

1:13 was like a two-minute fix, plus fifteen minutes of trying to find a bug that wasn't there because i was testing wrong

1:15 tomoj: I'll buy you a beer at the next mutual clojureconj :)

1:16 amalloy: deal

1:16 hardcoded list, indeed. i'm insulted :)

1:17 brehaut: amalloy: at least its a hardcoded set rather than a list

1:18 amalloy: brehaut: config file! if you're suggesting i should let users opt-out without asking a sexpbot admin, then...well, i invite you to fork sexpbot :P

1:18 brehaut: haha

1:19 im fine; have enough unfinished code on my plate ;)

1:19 amalloy: (the gauntlet is down)

1:20 Raynes: tomoj: I am convinced that some people are born with a gene that causes them to have an involuntary and negative reaction to a bot doing something that they didn't actively want it to do. Thus, it is impossible to satisfy everybody with stuff like s/// replacements and title scraping.

1:21 But, because of that gene, you are forgiven. amalloy and I <3 you.

1:21 Especially amalloy. :>

1:21 amalloy: Raynes: actually, having a config area for user preferences is an interesting idea

1:21 but i guess he can only really control who he responds to, not who hears him

1:22 Raynes: amalloy: Actually, having decent and consistent configuration in general would be a nice idea.

1:22 Something I'm still thinking about.

1:22 Anyways, back to fringe.

1:25 brehaut: what you should do is create a custom filesystem like database, and let plugins stash things wherever they want, optimally with random UUID keys

1:26 amalloy: brehaut: you laugh, but sexpbot is running on top of mongodb

1:26 brehaut: ahahaha :(

1:27 amalloy: you don't approve?

1:27 brehaut: i actually have no opinion on mongo

1:28 ive only heard the hype and horror stories

1:29 amalloy: brehaut: it's okay

1:29 nothing special, but perfectly usable

1:30 brehaut: and as a bonus, its web scale!

1:30 amalloy: i certainly had a much easier time getting the hang of mongodb than cassandra, probably because it's more like sql

1:31 brehaut: i dabbled with couchdb

1:31 amalloy: that one scares me

1:31 brehaut: yeah im… ambivilent about it

1:31 amalloy: but hey, couchbase should be available soon, or something like that

1:31 tomoj: I miss the mapreduce looking at cassandra

1:32 amalloy: tomoj: what do you mean, miss it?

1:32 brehaut: however futon, couch's webbased admin interface, is pretty nice

1:33 tomoj: amalloy: coming from couchdb

1:34 amalloy: oh. i piled hadoop on top of it for m/r

1:34 didn't really know anything about couch at the time, and maybe it would have been a better choice

1:36 tomoj: maybe I just haven't wrapped my head around hadoop yet

1:36 brehaut: im going to head off. night everyone

1:37 tomoj: I feel like there are neat things couch's mapreduce does well that are hard in hadoop, but I can't think of a single example

1:37 amalloy: i doubt you are wrong

1:37 everything is hard in hadoop

1:38 tomoj: were you using clojure with this too?

1:38 amalloy: no

1:38 tomoj: shucks

1:38 amalloy: yeah, the clojure libs i looked at didn't look very good at the time

1:38 tomoj: I haven't liked clojure-hadoop at all

1:39 but I think part of the problem is just the way I use it, and part is just that it's still hadoop, after all

5:08 TobiasRaeder: morning

5:24 ejackson: yo

5:43 carkh: Hello

5:44 Did anyone manage to set gzip compression for jetty using compojure ?

5:50 xkb: hi

5:51 which lib should I use for OAuth? Clojars shows quite alot of em

5:52 ejackson: xkb: I'd go with mattrepl's version

5:52 i think its the original

5:53 xkb: Ok, ill tinker around with it

5:54 ejackson: cool

6:40 bartj: ah, bitten by this:

6:40 , (flatten #{1 2 3 4 5})

6:40 clojurebot: ()

6:40 bartj: what gives ?

6:44 ejackson: bartj: i don't think set is a sequential thing ?

6:44 ,(flatten (seq (#{1 2 3 4 5}))

6:44 clojurebot: EOF while reading

6:45 ejackson: bah

6:45 ,(flatten (seq #{1 2 3 4 5}))

6:45 clojurebot: (1 2 3 4 5)

6:45 bartj: ,(flatten (seq #{1 2 3 4 5}))

6:45 clojurebot: (1 2 3 4 5)

6:45 ejackson: yeah.

6:50 bartj: ejackson, is there any way I can check if something has multiple values ?

6:50 ejackson: is a composite value ?

6:50 bartj: for eg: "abc" is a single value and '(1 2 3) are multiple values and so is [1 2 3]

6:50 I was hoping to do a (seq? ) and check it

6:51 mrBliss`: bartj: sequential?

6:51 ejackson: yeah, as good as a say

6:51 bartj: I also have the type #{1 2 3}

6:51 which for all practical purposes are multiple values

6:51 , (sequential? #{1 2 3})

6:52 clojurebot: false

6:54 bartj: anyone ?

6:55 mrBliss`: ,(map (partial instance? java.util.Collection) (list '(1) [1] #{1} {1}))

6:55 clojurebot: 1

6:55 solar_sea: what's the best way to create a list/vector of n items ?

6:55 mrBliss`: #(map (partial instance? java.util.Collection) (list '(1) [1] #{1} {1}))

6:55 &(map (partial instance? java.util.Collection) (list '(1) [1] #{1} {1}))

6:55 sexpbot: java.lang.ArrayIndexOutOfBoundsException: 1

6:55 bartj: solar_sea, vector

6:55 ,(vector 1 2 3 4 5)

6:55 clojurebot: [1 2 3 4 5]

6:55 solar_sea: I currently use loop, recur and conj, but this doesn't seem right

6:56 oh well, n is defined later :)

6:56 mrBliss`: solar_sea: repeat

6:56 bartj: ; (vec (range 1 n))

6:56 , (vec (range 20))

6:57 clojurebot: [0 1 2 3 4 5 6 7 8 9 ...]

6:57 mrBliss`: ,(repeat 5 'x)

6:57 clojurebot: (x x x x x)

6:57 solar_sea: ah, repeat does the job fine, thanks :)

7:11 Can I add documentation to defstruct ?

7:14 raek: solar_sea: don't think so. I usually put documentation regarding data conventions and contracts in the ns docs

7:22 solar_sea: is there any guide about a proper coding style ? I'm just starting with clojure, doing a simple connect 4 playing app to get my feet wet :)

7:26 however, the repeat way of creating a vector creates a lazyseq, which I can't use assoc later on ..

7:26 ejackson: solar_sea: the quick workaround is (into

7:26 which will put the seq back into a concrete type

7:27 TobiasRaeder: http://www.assembla.com/wiki/show/clojure/Clojure_Library_Coding_Standards

7:27 its a bit older but seems fine on a quick look

7:28 solar_sea: thanks both of you

7:28 ejackson, I got around it by (vec (repeat ..))

7:28 ejackson: yeah, vec is the same as (into []

7:44 solar_sea: how can I get the size of a vector / list, so I can avoid an index out of bounds exception ?

7:45 opqdonut: count

7:46 solar_sea: or should I use get instead of nth and just check for nil ?

7:46 clojurebot: ⟹ "Returns the metadata of obj, returns nil if there is no metadata."

7:53 hoeck: solar_sea: nth does also support a default

7:53 ,(nth [] 100 :default-value)

7:53 clojurebot: :default-value

7:54 solar_sea: damm the cheat sheet explains none of this, looks like I'll have to (doc check every one of these functions :D

7:55 khaliG: i'm after a small project to look at how files and code are laid out in a typical clojure project

8:02 Cozey: Is there a function doing this: (fn [d kw f] (assoc d kw (f (d kw)))) in standard library? what's it's name?

8:04 Mange: Cozey: If the kw arg is instead a vector you can use update-in: (update-in d [kw] f)

8:04 Cozey: thanks!

8:48 pdk: ,(re-seq #"[t[we]]+" "twisters")

8:48 clojurebot: ("tw" "te")

8:48 pdk: ,(re-matches #"[t[we]]+" "twisters")

8:48 clojurebot: nil

8:48 pdk: what's the story here

8:51 incandenza: pdk: from the java docs, looks like the matches one has to match the entire string

8:51 ,(re-matches #"[t[we]]+.*" "twisters")

8:51 clojurebot: "twisters"

8:52 pdk: regexes

8:52 one day i will master your dark arts

8:55 fogus`gone: incandenza: sweet nick :-)

8:55 incandenza: heh, thanks :)

8:56 fogus`gone: I try to read that once every 5 years

8:56 That is, it takes that long. :-O

8:57 incandenza: right :) I read it in like '97, so if someone asks me some followup question, I'm like, "uhh... I don't remember"

9:34 clgv: how much would you estimate the impact on performance of using a map as a datastructure in a place where an array could be used? if there is pretty much read access to it?

9:39 jweiss_: is there a full-featured repl for the command line? paren matching would be great, but i'd settle for color highlighting

9:40 Fossi: yeah, it's called "emacs" :>

9:40 jweiss_: i'm trying to take it easy on my co-workers and not make them use emacs :)

9:41 clgv: Eclipse with CCW is working well for me ;)

9:41 cemerick: jweiss_: netbeans and eclipse both have good plugins

9:41 raek: syntax highlighting and paren matching sounds like a feature for the text editor for me...

9:41 jweiss_: clgv: which version? the official one doesn't have paren matching on the repl

9:41 the RC seem to but keeps popping up error messages

9:42 (although they don't seem to hurt anything)

9:42 cemerick: jweiss_: RC6 was released yesterday…maybe that'll resolve any issues you had?

9:42 raek: what editors beside emacs (and eclipse, I've heard) has convenient key bindings for evaluating an expression (from the source file) in the repl?

9:42 clgv: oh right. you just meant the repl and not the editor. well it has nothing except copy&paste... :(

9:42 jweiss_: cemerick: yeah that's what i'm running

9:42 cemerick: jweiss_: that's the refresh folder error?

9:42 jweiss_: cemerick: no, it's a project build error on labrepl

9:43 cemerick: ah

9:43 clgv: I am using the latest stable version.

9:43 cemerick: jweiss_: have you sent a msg to the list?

9:43 jweiss_: i'm trying to point my coworkers at labrepl but the instructions are a bit out of dat

9:43 e

9:43 try-clojure.org is down

9:43 arohner: clgv: from my benchmarks, maps are about 4x slower

9:44 but who knows how similar my workload and yours are

9:44 clgv: arohner: thanks for that fact.

9:44 cemerick: jweiss_: I know Laurent is working towards a final 0.2.0 release, so now's the time to get your issues in

9:44 clgv: records/types should be a fair bit faster than maps

9:44 clgv: I have around 5 Million accesses in a small run

9:45 fliebel: clgv: Still optimizing that loop?

9:45 solar_sea: java.lang.IllegalStateException: Nested #()s are not allowed - is this by a technical reason, or to force a coding style ?

9:45 fliebel: solar_sea: How would you match the arguments?

9:46 jweiss_: cemerick: any idea what this error means from CCW? seems to be labrepl related, but i'm not sure why CCW is trying to build the project over and over

9:46 http://www.fpaste.org/cIO0/

9:46 clgv: fliebel: another part now. I ordered the possible performance bottle necks by total time consumption starting with the biggest ;)

9:46 cemerick: solar_sea: parameters would be ambiguous given nested function literals

9:46 jweiss_: yuck. No idea. It only happens with labrepl?

9:46 Chousuke: solar_sea: I think it's both easier to implement and prevents people from writing confusing code.

9:47 fliebel: clgv: Can we see teh codez somewhere?

9:47 raek: solar_sea: having nested map + #()s? if so, consider 'for'

9:47 jweiss_: cemerick: no idea, i use emacs. I am just trying eclipse to work out the kinks before i let my coworkers try it.

9:47 Chousuke: every time you'd like to nest #()s there is a better way to write your code.

9:47 clgv: fliebel: nope. it's my current research project. code might be released after the first couple of publications

9:48 cemerick: jweiss_: I use the RC full time. *shrug* It may be a simple issue. Definitely worth pinging the ML.

9:48 solar_sea: raek, precisesly, iterating over a 2d vboard :)

9:48 jweiss_: cemerick: k thanks

9:48 fliebel: raek: Using for would give you a 1D seq, how would you use for in a place where you'd need nested #()?

9:48 clgv: I see...

9:48 raek: hrm.

9:49 anyway, (for [x xs] (do-complicated-stuff ...)) looks better than (map #(do-complicated-stuff ...) xs)

9:50 especially if the fn spans multiple lines in the source code

9:50 this would be my main point.

9:50 fliebel: raek: Very true. Let me dig up some example...

9:53 &(map (fn [k] (map #(* 2 %) k)) [[1 2 3] [4 7 2] [2 5 2]])

9:53 sexpbot: ⟹ ((2 4 6) (8 14 4) (4 10 4))

9:55 raek: yes. see what you mean. I would like to write at least one of those maps with a for

9:56 &(let [m [[1 2 3] [4 7 2] [2 5 2]]] (for [row m] (for [cell row] (* 2 cell))))

9:56 sexpbot: ⟹ ((2 4 6) (8 14 4) (4 10 4))

9:56 raek: &(let [m [[1 2 3] [4 7 2] [2 5 2]]] (for [row m] (map #(* 2 %) row)))

9:56 sexpbot: ⟹ ((2 4 6) (8 14 4) (4 10 4))

9:57 raek: I'm inclined to the symmetry of the for-for one...

9:57 fliebel: Okay, I must agree with you that it looks cleaner.

9:58 * fliebel wonders why he never uses for much

9:59 raek: yeah, I hardly used it at all during my first 6-8 months of clojure

10:00 fliebel: raek: I won't take that as an insult ;)

10:00 &(clojure.walk/postwalk #(if (number? %) (* 2 %) %) [[1 2 3] [4 7 2] [2 5 2]])

10:00 sexpbot: ⟹ [[2 4 6] [8 14 4] [4 10 4]]

10:01 raek: fliebel: hrm. let me put it this way: at the point where I felt that I knew about most of the stuff in the language, I had not begun to use 'for'.

10:03 it wasn't meant an insult. I just begun using 'for' relatively late

10:05 fliebel: raek: That still sounds pretty smug, because it implies you felt you knew the whole of Clojure in 6-8 months. I knew it wasn't an insult, I just realized you could interpret it as one.

10:05 oh, well, 6 months is a long time, actually...

10:07 Hm, is there any case where one would prefer prewalk over postwalk, or the other way around?

10:08 raek: hrm. "knew about" might not be the exact word either. more like "having a feeling for what exists in the language and what does not"

10:08 fliebel: raek: Never mind, it's alright. :)

10:10 But it's fun how some things in Clojure have always been there right in front of you, and only after a long time you start to use them. I guess for is one of them, amongst things like multiple arguments to a lot of functions tat take only 2 in most languages.

10:11 * fliebel discovers macroexpand-all

10:13 clgv: lol ;)

10:13 it's pretty short written for its effect. clojure.walk is definitely interestign.

10:16 fliebel: hrm… "XML reading/writing." Where is the writing part? http://clojure.github.com/clojure/branch-master/clojure.xml-api.html

10:17 There is emit still, but it's not listed… https://github.com/clojure/clojure/blob/master/src/clj/clojure/xml.clj#L111

13:59 kryft: amalloy: Well, like you said, I don't even see my parents

14:00 chouser: I wonder if it would be more clear for stack traces to be printed as root cause, rethrown as, rethrown as ... instead of final cause, caused by, caused by...

14:00 markskilbeck: chouser: definitely

14:01 amalloy: chouser: maybe

14:01 dsantiago: I've always wished the stack traces were upside down, since you've always gotta scroll upwards to see what caused them.

14:01 chouser: java prints them half-upside-down

14:01 amalloy: chouser: yes, that's what i was about to say

14:02 only i was going to be more verbose and less clear

14:02 markskilbeck: amalloy: would (vec (concat ... )) work then?

14:03 Even if it did, it feels dirty having to change the type.

14:03 amalloy: markskilbeck: it feels dirty for a reason :P

14:04 markskilbeck: Le sigh.

14:04 amalloy: markskilbeck:

14:04 er

14:04 * amalloy loves the enter key a little too much

14:05 * fliebel hates the position of the enter key relative to keys used to correct nonsense.

14:05 amalloy: markskilbeck: anyway, you can surely do all this with vectors if you want

14:06 use subvec instead of take, pass around two separate vectors instead of concat'ing them, and so on

14:06 chouser: fliebel: heh. good point.

14:09 markskilbeck: amalloy: thanks for the pointers

14:10 fliebel: Talking about subvec… say I have 2 vectors named a and b, made from c by subvec. They now share structure with c. Now we delete c, will all nodes not in a and b be GC'd?

14:11 amalloy: no

14:11 they keep a pointer to c, with no special information that lets the gc know only some of its objects are needed

14:12 fliebel: :( So this has the same problems as taking a substring from the works of Shakespeare.

14:12 chouser: yes

14:13 fliebel: Does the same solution apply? (vec (subvec))

14:13 amalloy: fliebel: i was just about to suggest that

14:13 (the answer is yes)

14:13 semperos1: any way to "reset" Clojure's memo cache while working at the REPL?

14:14 chouser: semperos1: re-memoize the function

14:14 fliebel: So, I guess we have arrived at the reason that vec takes linear time, even if the thing is already a vector.

14:14 technomancy: semperos1: you need to use an alternate memoization implementation.

14:14 amalloy: fliebel: not necessarily the reason, but at least a nice side effect

14:14 semperos_: technomancy: yeah, I was just reading about them

14:15 the function isn't one I wrote

14:15 fliebel: amalloy: You know *the* reason then?

14:15 semperos_: chouser: not sure I understand what you mean by re-memoize

14:15 chouser: if you have (defn foo* ...) (def foo (memoize foo*)), just rerun the def foo

14:15 mattmitchell: how can i get the first 2 chars of a string?

14:15 semperos_: ah

14:15 amalloy: mattmitchell: substr, or take

14:15 &(take 2 "hey dude")

14:15 sexpbot: ⟹ (\h \e)

14:15 mattmitchell: amalloy: thanks

14:15 excellent

14:16 amalloy: &(subs "hey dude" 2)

14:16 sexpbot: ⟹ "y dude"

14:16 amalloy: i guess that's the opposite. but you can adjust args to subs to make it work

14:16 fliebel: &(subs "hey dude" 0 2)

14:16 sexpbot: ⟹ "he"

14:49 mattmitchell: how can i turn [:one 1 :two 2] into a map like {:one 1 :two 2} ?

14:50 dnolen: ,(apply hash-map [:one 1 :two 2])

14:50 clojurebot: {:one 1, :two 2}

14:51 mattmitchell: dnolen: thanks!

15:07 dnolen: anybody read through Art of the Propagator and applied it's ideas to Clojure?

15:08 fliebel: dnolen: Not me, what is it about?

15:10 dnolen: fliebel: a very interesting model of computation (useful for constraint based programming, as well distributed search) http://lambda-the-ultimate.org/node/3250

15:13 fliebel: Prolog-style search is useful, but you want to constrain the search space very quickly before committed to a real search, propagators can help you do that.

15:13 cemerick: dnolen: I stole some ideas from it for a constraint-based system I built last year. Was a great perspective.

15:13 dnolen: cemerick: nice did you put anything into a library?

15:14 cemerick: Alexey gave a talk based on that paper at ILC 2009, was very compelling. Sadly, no video. :-(

15:15 dnolen: hrm, nothing I would inflict on anyone at this point. It was pre-Clojure 1.0 code, IIRC.

15:15 dnolen: cemerick: heh

15:15 cemerick: The implementation of it is very straightforward, really. Translating from the scheme impl to something reasonable given what we have now warrants some thought though.

15:16 dnolen: cemerick: was your implementation concurrent?

15:16 fliebel: dnolen: http://lambda-the-ultimate.org/node/3250#comment-47804

15:16 cemerick: dnolen: yeah, used refs extensively.

15:17 Which meant that it was dog slow for what I was using it for, unfortunately.

15:17 dnolen: fliebel: of course Peter Van Roy will say that, but the the paper is done in a approachable tutorial-style.

15:19 cemerick: I wonder if agents are a better fit, tho I imagine even they would have a sizeable overhead.

15:19 fliebel: http://lambda-the-ultimate.org/node/3250#comment-47997

15:20 cemerick: dnolen: a lot of my data was very fine-grained numerics. I never really profiled it (dog slow and working was good enough for me at that point), but I suspect the boxing was brutal.

15:33 CaseyS: quick question regarding a lein uberjar error I'm getting: LEIN_SNAPSHOTS_IN_RELEASE, how can I set this?

15:34 technomancy: CaseyS: $ LEIN_SNAPSHOTS_IN_RELEASE="I am responsible for my own actions" lein uberjar

15:34 it's just an environment variable

15:35 CaseyS: better yet, switch to using locked number snapshot versions if available ("1.0-20110121" instead of "1.0-SNAPSHOT")

15:37 CaseyS: thanks - it's just a toy project, so I'm not too concerned. I'll try to sanitize my project.clj of snapshots eventually though...

15:37 tomoj: is it possible to `:omit-default-repositories true :repositories {}` without changing project.clj? :(

15:38 oh, maybe some more settings.xml magic will help

15:48 TimMc: OK, unit testing question.

15:49 My program has a bunch of (def foo (ref ...)) and I want to write tests for some functions that read those refs.

15:50 Should I refactor my code to use helper functions that pass refs in to combinators?

15:51 mefesto: TimMc: maybe using binding to override the refs for the test?

15:53 something like: (binding [myns/foo (ref 1)] (some-func))

15:53 TimMc: Oooh, I can do that?

15:54 tomoj: your idea sounds better to me

15:54 CaseyS: technomancy: your suggestion to use locked number snapshot versions - am I cheating if I used a 1.0-SNAPSHOT when running lein deps then switched to the locked number version once I had the jar in my lib/ directory?

15:55 TimMc: tomoj: I like the idea of state-locked helpers that call combinators... but the binding macro is pretty seductive.

15:56 It also means I wouldn't have to create extra helpers.

15:56 tomoj: with binding, won't you have to start worrying about state leaking out of the tests?

15:56 oh, no, not at all

15:56 mefesto: well you could do the binding with :each fixtures

15:56 they are setup/torndown on each test

15:57 but still, if your functions just need a snapshot of the value of the ref then you should just pass that to them

15:57 testing becomes much easier then :)

15:57 TimMc: Crap, have to run... will read backlog later.

15:57 mefesto: (my-func @myns/foo)

15:58 TimMc: I really should not miss the talk my girlfriend is giving.

16:00 chouser: One should also no preceed such a statement with "Crap"

16:00 ;-)

16:08 fogus-: It seems that people (cough... me) are interested in AOP facilities in Clojure.

16:10 https://github.com/fogus/clojure-aop

16:16 cemerick: fogus-away: I've never thought AOP in clojure needed much of anything special.

16:16 * cemerick missed the "away"

16:16 cemerick: or, rather, that the *aims* of AOP needed anything special

16:17 qed: sorry for all the join/part noise.

16:26 fliebel: dnolen: Why does an unsuccessful statement return an empty seq rather than nil, as is common in Clojure, I believe. An empty seq would make sense in Scheme because it is falsey I think. < Lots of thinking and believing there… I should do my research before uttering things.

16:36 dnolen: fliebel: I could do that, but the results are simply a lazy-sequence - I'd need to hear more compelling reasons.

16:36 qed: dnolen: i missed this discussion

16:36 fliebel: dnolen: So, if I do (take 5 (run*)) on an infinite computation, it'd work?

16:37 qed: whatjoo talkin bout?

16:37 brehaut: fliebel dnolen: thats consistent behavior with other operations on lazy seqs that dont return anything

16:37 dnolen: fliebel: yup.

16:37 and it's truly one at a time lazy.

16:38 brehaut: eg (filter (constantly false) (range 1000)) => ()

16:39 fliebel: Okay, you are totally right. Only rest and seq return nil, that I know of.

16:40 or was it next… ##(rest [])

16:40 sexpbot: ⟹ ()

16:40 * fliebel crouches back in his cave

16:41 bytecolor: is there a latest and greatest blog for getting clojure+slime up?

16:42 I just installed lein. I'm assuming that's a piece of the puzzle.

16:42 technomancy: bytecolor: just the boring old swank-clojure readme

16:45 qed: would anyone mind parting/joining #clojure to test out something for me?

16:45 when you're done just say: yeah!

16:46 companion_cube: hello back!

16:46 qed: :( i dun configured incorrectly

16:51 * qed is highly annoyed that irssi is not paying attention to his activity_hide_level

16:57 fd: I've a question about ->

16:57 sarcher|work: ask away :)

16:57 fd: trying to wrap my head around this..

16:58 I have some functions that return functions

16:58 I'm trying to chain them together with ->

16:59 it works but the resulting function calls the functions in the chain in reverse order

16:59 I understand why that is, but is there a way to have the functions be called in order that I pass them?

16:59 brehaut: fd, first question, you understand that -> rewrites forms, rather than performing function compositions?

17:01 fd: brehaut: ah.. perhaps it is function composition I am after?

17:01 brehaut: fd perhaps

17:01 they perform two distinct roles

17:02 bytecolor: well, at least I can kill a program withough killing clojure now. That was worth the price of admission ;)

17:02 brehaut: and a -> that threads backwards (say (defmacro -< [& body] `(-> ~@(reverse body))) ) gains little compared to the actual form

17:02 fd: brehaut: I probably need to explain better what I am trying to achieve

17:03 technomancy: bytecolor: suggestions for improving the docs are welcome of course

17:03 brehaut: eg (-< inc (* 3) 4) and (inc (* 3 4))

17:03 fd: always good practise

17:03 fd: I have handlers which take other handlers as a parameter and return a function. in that function, I do something and I may or may not invoke the next handler.

17:04 amalloy: oh no, now brehaut will start talking about maybe-m :)

17:04 fd: I want to chain these handlers together. if somewhere down the chain, the handler doesn't invoke the next one, the chain just stops.

17:04 brehaut: amalloy: i was going to suggest -?> first ;)

17:05 fd: -?> is in clojure.contrib.core and it is like -> except that if any form results in nil, non of the following forms are evaluated

17:06 fd: brehaut: it is not the abortion of the chain that is the problem, it is the order. if I list in reverse order, it all works as expected.

17:07 I just find it counter-intuitive to have it work that way. maybe I should just try your -<

17:07 brehaut: my -< is horrible. i wouldnt recommend it

17:07 amalloy: bwagh no do not try his -<

17:07 brehaut: it merely existed to prove a point

17:07 if you really are just dealing with functions use comp

17:08 amalloy: granted any macro that looks like an electric guitar is appealing, but this one is evil

17:08 fd: heh

17:08 brehaut: its worse than evil, its maliciously stupid

17:09 fd: ok

17:09 brehaut: -> is designed to thread forms so that the inside most form is on the left and you read left to right rather than right to left

17:10 turning it round so that you can read right to left is self defeating

17:10 and being a rewriting operator, provides more room for error

17:10 amalloy: fd: why don't you put together an example of a few functions you have, and how you would chain them together manually

17:10 fd: for example, (defn handler1 [handler] (fn [ctx] (if something (dosomething) (handler ctx))))

17:11 brehaut: are your parens wrong there?

17:11 amalloy: brehaut: they look right to me

17:11 fd: also (defn handler0 [handler] (fn [ctx] (let [start (System/currentTimeMillis) _ (handler ctx) end (System/currentTimeMillis)] (println "that took..."))))

17:12 brehaut: ah i missread handler as handler1

17:12 fd: and so on.. so I want to chain handler0 handler1 handler2 into one function.

17:12 raek: fd: if these are Ring handlers, I'd suggest taking a look at Moustache

17:12 amalloy: so you want your end result to be (handler0 (handler1 handler2))?

17:13 raek: maybe it could be interesting anyway, since it composes middleware functions (which have that exact structure) in this way

17:13 fd: yes, but the end result has to be a fn [ctx]

17:13 raek: yes it is very similar to ring middleware

17:13 amalloy: fd: it is

17:14 my example above resolves to a function of ctx, so what's the problem with writing it that way?

17:14 fd: amalloy: oh, you're right. so yes that is what I want.

17:15 amalloy: gee you're right (I think). is there a nicer way to chain them so that with 10 functions I don't have a ton of nesting?

17:15 amalloy: fd: reduce comes to mind but i can't get it quite right

17:15 fd: something along the lines of what (.. obj getA getB getC getD) solves

17:15 amalloy: something like (reduce #(%2 %1) handlers)

17:17 the trouble is i think you want reduce to fold in the other direction. brehaut, do you have foldl/foldr implementations in clojure lying around somewhere?

17:17 brehaut: i dont sorry

17:19 fd: there's gotta be something to call (f0 (f1 (f2 (f3 (f4)))))

17:19 brehaut: comp

17:19 oh no i see

17:21 you'd have to do a filthy ((comp f0 f1 f2 f3) f4)

17:23 amalloy: brehaut: that doesn't solve the problem. comp goes in the wrong order

17:25 brehaut: i must have missed something

17:26 fd: this has helped a lot, thanks very much

17:27 brehaut: wow really? im more confused now than i was before!

17:29 amalloy: brehaut: oh no i'm just dumb

17:29 brehaut: phew

17:30 amalloy: that's what i get for trying to do actual work while i'm in #clojure

17:30 brehaut: hah

17:32 fd: ha! seen in moustache: middlewares (reverse middlewares)

17:32 quack

17:34 semperos_: using clj-time and joda time, trying to simply print out a DateTime with a specific format *and* timezone

17:34 but all printing with formatters changes the timezone to UTC by default

17:34 anyone know how to print the date with a specific format and timezone?

17:39 tomoj: semperos_: with-zone

17:40 semperos_: tomoj: thank you

17:42 bytecolor: technomancy: I've got an older version of slime I installed for sbcl, could I grab *only* slime-20100404.1.el and slime-repl-20100404.el from your emacs repo and install them manually without any other dependencies? I tried package.el, but my emacs is too old: 22.2.1. It craps out on the :risky keyword in a defcustom.

17:42 technomancy: bytecolor: that should work; yeah.

17:42 I don't know if sbcl will like it though

17:44 bytecolor: ok, I'll give it a shot. Yep, getting sbcl *and* clojure running with slime/swank doesn't seem to want to work well. My old version of slime worked ok with clojure-swank, though.

17:44 I'll burn the other bridge when I get to it

17:45 technomancy: working theory is getting clojure working will be so awesome that you'll lose interest in CL

17:49 bytecolor: clojure has kept my attention for a couple months now. Don't really have any gripes. Even the extra [] {} are ok. They actually have semantics tied to them instead of what scheme is trying to do: make lisp more readable by adding [].

19:28 tomoj: wonder how I can figure out when I found clojure

19:28 ossareh: does anyone use the emacs starter kit?

19:43 tomoj: Raynes: missed your gene comment before. that explains it

19:44 mattdw: ossareh: yes

20:37 bytecolor: the emacs starter kit says run: M-x slime, but the swank-clojure README says run: M-x slime-connect. How is the swank server being started? If I run the shell script swank-clojure, then in emacs M-x slime-connect, everything is peachy.

20:37 technomancy: bytecolor: where does the starter kit say M-x slime? that's out of date.

20:38 bytecolor: oh? hrm... lemme look again

20:38 technomancy: the swank-clojure shell script or "lein swank" are both good ways to start a swank server, depending on whether you're in a project or not.

20:40 bytecolor: I was reading it from this blog: http://freegeek.in/blog/2009/08/setting-up-emacs-clojure-with-emacs-starter-kit/ which actually linked to your git repo

20:42 hiredman: never read blogs posts, they never contain correct up to date information

20:43 technomancy: hiredman: at least this one is up-front about containing out-of-date info.

20:44 bytecolor: yes, later in the blog. I'm playing catch-up! ;)

20:45 so, it seems you were using the common lisp swank backend, then ported it to clojure

20:46 technomancy: bytecolor: that would have been jochu

20:47 bytecolor: ah

20:47 TimMc: So here's my proposal for rewriting my ref-using code so that I can do unit tests: https://gist.github.com/823389

20:48 Alternatively, use the binding macro when calling update-stuff! from testing code.

20:48 clojurebot: peepcode is a commercial screencast series; see the Clojure one at http://peepcode.com/products/functional-programming-with-clojure by technomancy

21:04 TimMc: And if the first, is there a good naming scheme for all these extra functions? :-P

21:08 amalloy: TimMc: binding is a lot less gross than this

21:15 cheezey: im using leiningen and im trying to start a new project but for some reason, it can't download clojure.jar nor the cljoure-contrib saying they're nto found. im using mac os x (new machine) so i dont know if im missing something or what..

21:15 any ideas?

21:30 amalloy: cheezey: get an up-to-date version of lein. whatever version is easiest to get on the mac is way old

21:31 cheezey: amalloy: it's the most recent version

21:33 amalloy: no idea then

21:34 maybe gist an actual error message instead

21:35 cheezey: it just tries to download those jars from the repos, fails, then tells me the standard maven missing jars stuff (try to manually do it, etc)

21:35 tomoj: how could it be easier than wget + chmod?

21:35 cheezey: oh wells :_;

21:35 tomoj: I guess some crazy mac package system with one step is less than two steps if you've already got the crazy

21:50 TimMc: amalloy: It is certainly more succinct.

21:52 echosystm: so, i've started with some clojure tutorials

21:52 this will be the first functional language i have learned

21:52 cheezey: echosystm: nice =)

21:52 echosystm: i have a few questions...

21:53 is clojure a very "strictly functional" language?

21:53 ie. is it to functional programming what java is to OOP ?

21:53 TimMc: cheezey: You've done lein self-install, then lein new?

21:53 cheezey: TimMc: rofl i think ti's because mac didn't include wget by default

21:53 TimMc: cheezey: oh wow

21:54 cheezey: yeah im kinda angry now

21:54 hopefully that's the problem tho*

21:54 TimMc: echosystm: Clojure interoperates tightly with Java, you know.

21:54 echosystm: yes

21:55 tomoj: lack of wget => maven errors?

21:55 cheezey: tomoj: i don't know. it didn't fix it so ;_;

21:55 echosystm: so does that imply that it isnt very strictly functional? in terms of side effects and so on

21:55 TimMc: echosystm: Indeed.

21:55 echosystm: i dont really know much about functional programming, im trying to guage where clojure sits in comparison to others

21:55 tomoj: as amalloy said, you should gist the entire output with the errors

21:56 TimMc: You can do all the great functional stuff too, of course.

21:56 tomoj: most likely you're just depending on something that doesn't exist

21:56 amalloy: echosystm: you can make side effects whenever you want, but by default there are no side effects, and it's easy to manage them when they are necessary

21:56 Raynes: $wiki purely functional programming

21:56 sexpbot: First out of 409 results is: Functional programming - Wikipedia, the free encyclopedia

21:56 http://en.wikipedia.org/wiki/Functional_programming

21:57 Raynes: Purely functional programming is the most hardcore of functional programming. Like Haskell.

21:57 TimMc: echosystm: Clojure uses all sorts of immutable (persistant) data structures by default, which is awesome.

21:57 Raynes: Clojure isn't purely functional.

21:57 However, it strongly encourages functional programming and that is the predominate paradigm.

21:58 cheezey: tomoj: https://gist.github.com/823439 ( amalloy too)

21:58 tomoj: oh, I didn't realize clojure was the problem

21:59 echosystm: i often hear people talking about print/println in terms of side effects

21:59 tomoj: cheezey: you're just starting out, right? if so, try deleting ~/.m2

21:59 echosystm: can someone explain what they mean by that?

21:59 tomoj: i.e. rm -rf ~/.m2

21:59 then try again

22:00 cheezey: tomoj: nice that seems to have fixed it

22:00 weird, i must have a corrupted version of clojure or something

22:00 echosystm: how can you write software without side effects it you need to print something to the screen?

22:00 gregh: echosystm: it means that sending data to an output device is a side effect. If you have a pure function f(a) followed by g(b), the runtime could run them in whatever order is convenient. If they both also print some output, then it *does* matter what order they're run in.

22:00 tomoj: sometimes maven will do blacklisting if there's an error when it first tries

22:01 echosystm: ah

22:01 so how would you print something to screen without creating "side effects" ?

22:01 TimMc: echosystm: Monads!

22:01 gregh: if you want to drink the purely functional kool-aid *and* worry about IO, I recommend Haskell :)

22:01 cheezey: echosystm: issuing multiple commands?

22:01 TimMc: And you would use Haskell. :-P

22:01 tomoj: I don't really understand it but deleting the appropriate pieces of ~/.m2 (or the whole thing if you can afford to lose it) seems to get rid of the blacklists

22:02 cheezey: tomoj: heh, no worries. new install anyway so not much in there :D

22:02 echosystm: do you think haskell is a better language to learn as ones first functional language?

22:02 gregh: learning haskell will give you a solid foundation in pure functional programming, allowing you to easily evaluate and compare other languages with some functional features

22:02 TimMc: echosystm: Side effects are not inherently bad, they are just something to be aware of and avoided in certain scenarios.

22:03 cheezey: i think clojure is awesome for first language but i don't know haskell so :\

22:03 TimMc: echosystm: Scheme is a pretty standard first functional language. Lots of good teaching books.

22:03 gregh: most programming languages have *some* aspect of functional features (even C). However, different languages emphasize the functional aspect more strongly

22:06 Kowboy: is there a compelling reason to use keywords as map keys if you are eventually going to need them as strings anyway?

22:06 or is it better in that case just to use string keys?

22:07 echosystm: so, what is the equivalent of monads in clojure?

22:08 amalloy: echosystm: monads are the equivalent of monads :P

22:09 echosystm: so there is no way to do side-effect free IO in clojure?

22:09 TimMc: echosystm: It's probably not the Clojure way of doing things.

22:09 gregh: you can think of functions in haskell being so pure that when a function wants to make a side effect, it takes the whole universe as a parameter and returns a new copy of the universe with the side effect changed

22:10 TimMc: echosystm: Why do you want functional I/O?

22:10 echosystm: learning purposes i suppose

22:11 TimMc: Ah, then check out Haskell.

22:11 Nota Bene: I am mostly a Clojure n00b.

22:11 pdk: doesn't io imply side effects

22:12 gregh: yes, "side-effect free IO" is an oxymoron

22:12 cheezey: q

22:13 where can i learn all about leiningen's proejct.clj options?

22:14 amalloy: $google leiningen project.clj example

22:14 sexpbot: First out of 474 results is: sample.project.clj at master from technomancy's leiningen - GitHub

22:14 https://github.com/technomancy/leiningen/blob/master/sample.project.clj

22:16 cheezey: k remind me to scroll down in github next time cuz i was searching around in testprojects ;|

22:43 tomoj: how do you indent your arrows?

22:43 mattdw: echosystm: http://brehaut.net/blog/2010/welcome_to_the_machine is a look at monads in clojure

22:44 tomoj: to first-arg or defn style?

22:44 mattdw: ,(doc io!)

22:44 clojurebot: "([& body]); If an io! block occurs in a transaction, throws an IllegalStateException, else runs body in an implicit do. If the first expression in body is a literal string, will use that as the exce...

22:44 amalloy: tomoj: first-arg, personally, but defn style is probably nicer

22:44 mattdw: ^ io! might also be of interest to you

22:44 tomoj: my thoughts exactly

22:45 eh, I dunno

22:46 "->" is maybe a bit too short for defn style

22:46 looks kinda funny

22:46 mattdw: my problem with first-arg is that -> and ->> end up with different indent levels

22:46 (although it's what I tend to use)

22:47 also, first arg is treated differently to the rest, makes sense to keep it on the first line

22:47 amalloy: mattdw: of course first arg should be on first line

22:47 but how far do you indent second+ args is the question

22:48 mattdw: sure

22:49 tomoj: I feel like emacs is a tyrant when it comes to indentation

22:49 if I try to make a patch to a clojure project that wasn't made with emacs it will almost certainly be a nasty diff

23:13 cheezey: this is a really dumb question but im still messing around with leiningen. so i have a core.clj and i want to import another file (derp.clj) which has namespace derp.derp and soem function is declared in it, how does core.clj import and use that function (basically how do i do imports if the 2 files are in the same folder.. simple stuff)?

23:15 tomoj: namespaces and paths should correspond

23:15 technomancy: cheezey: (ns derp.core (:use [derp.derp :only [derp-fn]]))

23:15 tomoj: derp.derp should go in src/derp/derp.clj for example

23:15 technomancy: cheezey: but in general you should read more existing code probably if that isn't clear

23:17 tomoj: if your core.clj is derp.core then I guess you already knew that..

23:17 cheezey: technomancy: ugh that's what i did and it says the files are not in its classpath

23:17 i dunno i thought since core was found, it would be fine :|

23:25 tomoj: does anyone else find that zip-filter lacks composability?

23:25 xml-> in particular

23:27 hmm.. guess if I wait as long as possible to call node and accept mapping xml-> over intermediate results it will compose fine

23:27 amalloy: tomoj: xml-> is shorthand for some publicly exposed functionality

23:28 tomoj: oh

23:28 didn't think of trying that, thanks

23:29 actually mapcat-chain just looks less useful, still only takes a single loc

23:30 for obvious reasons I guess :(

23:34 anthony__: I have some utility functions in a Clojure project. I built a JAR out of it (non-runnable). I want to execute a script that uses some of those functions, but I can't get it to work. Is there a catch?

23:34 I'm using java -cp clojure.jar:my-utils.jar clojure.main myscript.clj

23:39 cheezey: technomancy: can you point me to a project that uses leiningen and is relativel simple? i honestly cannot find one; github just keeps finding stuff from leiningen itself :\

23:39 amalloy: cheezey: more or less every clojure project on github

23:39 hiredman: the lein repo includes some sample lein projects

23:39 amalloy: uses lein or cake, and the layout is similar

23:47 bytecolor: anthony__: do all those jars, have to be in ./ when you execute that?

23:48 * bytecolor is still java CLASSPATH st00pid

23:49 anthony__: bytecolor: Which jars?

23:50 bytecolor: -cp resets CLASSPATH, correct?

23:50 clojure.jar and my-utils.jar

23:51 so if not ./clojure.jar and ./my-utils.jar, it will fail, no?

23:53 cheezey: amalloy: i know i've been trying to follow them but nothing i do seems to work. https://github.com/cheeze/nom is the code. it's really simple :\

23:54 anthony__: bytecolor: True. But my JARs are in ./ Sorry about that

23:54 The problem is when I reference functions from my-utils.jar

23:54 How do I import that namespace? Do I need to do something special to load the my-utils.clj file?

23:54 So I can use the ns?

23:56 amalloy: cheezey: the code all looks fine to me, but i don't do much gen-classing so i dunno. you certainly shouldn't need to gen-class for any namespaces other thancore

23:57 and i sorta question why you're gen-classing there either. you can use clojure.main to launch if all you want is a main()

23:57 cheezey: oh i dunno i think there was a compiling issue earlier and i got lost in it

23:58 amalloy: http://pastebin.com/4QbcxiEw is the ouput when i lein compile so

23:58 i must be missing something really obvious

23:59 replaca: in any case, I gotta crash. G'night all!

23:59 amalloy: then those files weren't on your classpath. but stop trying to compile anything, you're just making life harder for yourself. take out the gen-classes, and play around in a repl

23:59 use clojure.main if you want to run it outside a repl

Logging service provided by n01se.net