#clojure log - Sep 13 2009

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

2:46 emma: Hi is anyone here awake?

2:47 arbscht: hi

2:49 emma: oh hai

2:49 I have learned a little bit of scheme, and a little bit of common lisp. Because I want to learn a programming language and I want the first one I actually know to be a lisp.

2:50 I wondered if anyone in Clojure had any good reasons why Clojure is a good lisp to learn or maybe the best.

2:51 arbscht: clojurebot: rationale

2:51 clojurebot: rationale is http://clojure.org/rationale

2:58 emma: so it seems to be a lisp that can be used in place of Java and have all the good things about lisp but all the good things about java?

2:59 arbscht: it combines some of the good things of other lisps, some of the good things of java, some from other languages, and some new ideas and features too

3:03 hiredman: ~blip.tv

3:03 clojurebot: blip.tv is http://clojure.blip.tv/

4:22 rys: It's such a forward-thinking, portable Lisp, never mind the interaction with other languages on the JVM

4:27 Add the community and the JVM to that, and the fact it's not a research-driven language, and you have a really brilliant place to be if you want to learn a Lisp. Plus, the Clojure core has made some pretty big strides in recent months, so it keeps getting better

5:14 angerman: can I "undef" something?

5:16 Ibex_twin: @angerman: (ns-unmap namespace symbol)

5:16 rys: ns-unmap will remove the def'd symbol from the namespace

5:18 angerman: thanks

5:41 crios: hello. Could someone clarify me the difference between ref and atom? In my understanding, ref lives inside a transaction, atom not. So updating an atom is like changing a static Java variable in a multithread (not safe) environment?

5:42 Chousuke: crios: an atom only guarantees an atomic change.

5:42 you can't coordinate changes between multiple atoms like you can with refs

5:45 crios: by "coordinating changes" do you mean making more-than-one update in an transaction way?

5:46 Chousuke: yeah.

5:47 crios: ok, thank you.

5:48 and a function ending with a '!' means what ? like reset! (http://clojure.org/api#toc497)

5:48 ! points to a function which changes shared state?

5:49 hiredman: it mutates something

5:49 crios: I don't understand why (alter does not end with '!'

5:49 hiredman: *shrug*

5:50 crios: I mean, both alter and swap alter a shared state

5:50 Chousuke: crios: alter can only be used inside a transaction, so it's "safe" I suppose

5:50 hiredman: ! is a convention, not something enforced anywhere

5:51 crios: so swap! is not changing an atom inside a transaction?

5:51 Chousuke: swap! works anywhere

5:51 hiredman: ,(swap! (atom 0) inc)

5:51 clojurebot: 1

5:51 crios: '(doc swao)

5:51 * hiredman eyes clojurebot

5:51 crios: '(doc swap)

5:51 Chousuke: (doc swap!)

5:51 clojurebot: "([atom f] [atom f x] [atom f x y] [atom f x y & args]); Atomically swaps the value of atom to be: (apply f current-value-of-atom args). Note that f may be called multiple times, and thus should be free of side effects. Returns the value that was swapped in."

8:17 LauJensen: Top 'o da top gents

8:26 drewr: hola

9:11 ole3: j

9:45 crios2: help on the :keys binding on the function: (defn move [{:keys [body dir] :as snake} & grow] ( etc )) see the code on: http://pastebin.com/d45e8b3d7

9:46 rhickey: crios2: what's the question?

9:46 crios2: the author says "The {:keys [body dir]} part makes the snake’s body and dir available as their own bindings"

9:47 on Programming Clojure book

9:47 I don't understand how :keys is binding [body dir]

9:47 is it a sort of "destructuring"?

9:48 rhickey: , (let [{:keys [a b]} {:a 1 :b 2}] [a b])

9:48 clojurebot: [1 2]

9:48 rhickey: yes

9:48 crios2: Where can I find it on the APIs ?

9:49 I've studied just the special form :as

9:49 rhickey: http://clojure.org/special_forms#let

9:50 crios2: ah ok, I see it

9:51 so "destructuring" is a sort of "anonymous let-ting"

9:52 thank you

9:52 by the way rhickey, I was asking myself what is the difference between (var and (resolve ?

9:53 both return the Var pointed by a symbol?

9:59 crios: when should one use the former or the latter? (I'm a newby)

10:01 rhickey: crios: you should rarely use either

10:04 crios: just trying to well understand what I'm reading in the book :)

10:05 rhickey: var is to get a var you know exists

10:05 ,(var rest)

10:05 clojurebot: #'clojure.core/rest

10:05 rhickey: resolve is to try to find out if a symbol has some meaning in the ns

10:06 ,(resolve 'fred)

10:06 clojurebot: nil

10:06 rhickey: (var fred)

10:06 ,(var fred)

10:06 clojurebot: java.lang.Exception: Unable to resolve var: fred in this context

10:06 rhickey: ,(resolve 'String)

10:06 clojurebot: java.lang.String

10:06 rhickey: (var String)

10:06 ,(var String)

10:06 clojurebot: java.lang.Exception: Expecting var, but String is mapped to class java.lang.String

10:08 crios: so resolve is best suited for runtime checks

10:08 ok

10:39 singhv: I wrote this Sudoku solver a little while back: http://github.com/vishsingh/lisp-toronto/blob/80ea008e80976d3ec08b9005ace7658ec5278472/meetings/04-2009/sudoku.clj

10:41 I enjoyed writing it.. most interesting was the "parse-block" function. It uses a construction I invented called "union-map". It takes the union of the results of a map operation.

10:45 What would be a more idiomatic way to do this sort of thing? I was thinking something like: (into #{} (mapcat ..whatever..)).

11:27 Chouser: singhv: 'for' would probably work nicely for your nested ranges, let, and if (for has a :when)

11:28 and since a false in the :when clause produces no output item at all, you don't need to use an empty set to skip things.

11:29 so maybe (into #{} (for [y (range y1 y2), x (range x1 x2), :let [elem (get-in mat [y x])] :when (set? elem)] elem))

11:30 Chousuke: singhv: also (doall (vec ...)) is redundant. vec is strict already

11:31 doesn't doseq also support multiple sequences like for?

11:32 ~def doseq

11:32 seems so.

11:33 I wonder why it's not just a wrapper for (dorun (for ...)) :/

11:34 I guess looping explicitly is more efficient than consuming a lazy seq

11:50 ankou: hi, the documentation says that clojure.contrib.test-is is just a compatibility layer on top of clojure.test but in clojure 1.0.0 there is no clojure.test, how can I use test-is?

11:52 Chousuke: ankou: use the 1.0.0 compatible branch of contrib OR use clojure master branch from git

11:56 ankou: works, thanks

12:09 triyo: hhm, how do I check if a vector of chars contains a specific char? thought I could say ([\a \e \i \o \u] \a)

12:22 ok it works on sets (#{\a \e \i \o \u} \a) ...why is that this works on sets and not vectors?

12:24 Chousuke: what do you mean?

12:24 ,('[a e i o u] 3); vectors take an index as their parameter

12:24 clojurebot: o

12:27 Chousuke: triyo: basically, maps, sets and vectors are associative things, and when used as functions take as a parameter a key and return the associated value. for vectors, this key is an integer; for maps, anything, and for sets, the key is the value

12:29 triyo: ohh I see so its integers are keys for vectors. Set suites me perfectly for what I'm trying to do. thx

12:39 singhv: Chouser: Thanks. That's clever, and it really simplifies the code. I was leaning towards using 'for', but didn't know that it was possible to use a ':let' clause inside it.

12:46 Chousuke: You're right. I feel like I still haven't fully grokked laziness and how it works with different sequence types.

12:46 Chousuke: singhv: there's only one lazy structure in Clojure: the lazy seq

12:47 lists, vectors, maps and sets are all strict

12:49 and the only clojure data structure that is also a sequence (besides lazy seqs, of course) is the list. for vectors etc. you get a "seq view" by calling seq on them

12:50 If I'm forgetting something, now's the time to correct me :D

12:52 Chouser: Chousuke: sounds right, though if finger trees are ever added, they'll be seqs too.

12:52 Chousuke: I wonder if the PersistentQueue type is a seq.

12:52 singhv: Is this "seq view" what clojure.lang.APersistentVector$Seq is?

12:53 Chousuke: yes.

12:54 singhv: gotcha. So when you call (rest ..) on a vector, you're not actually creating a new vector, but a new view into that same vector.

12:56 here's one of my other confusions: (type [1 2 3]) -> clojure.lang.LazilyPersistentVector. what's "lazily" about this type?

13:01 Chousuke: singhv: it's not actually a real PersistentVector

13:02 hmm

13:02 ,(type [1 2 3 4 5 6 7 8])

13:02 clojurebot: clojure.lang.LazilyPersistentVector

13:02 Chousuke: ,(type (conj [1 2 3 4 5 6 7 8] 1))

13:02 clojurebot: clojure.lang.PersistentVector

13:03 Chousuke: it's an optimisation for small literal vectors

13:03 ,(type (conj [1 2 3 4 5 6] 1))

13:03 clojurebot: clojure.lang.PersistentVector

13:03 Chousuke: looks like it transforms into a PersistentVector on first conj

13:04 rhickey: it's bad to care about or rely upon the concrete types of things

13:52 beutdeuce: How would i be able to perform stdin and out in clojure?

13:57 Chouser: beutdeuce: the JVM's in and out are bound to Clojure vars *in* and *out* respectively.

13:57 ,(.write *out* "hello")

13:57 clojurebot: hello

13:57 beutdeuce: thank you, what do the asterisks signify?

13:58 Chouser: that's a convetion for global vars that you're likely to want to set or bind thread-locally

13:58 for example, with-out-str binds *out* to a stringwriter, and then returns that string.

13:58 ,(with-out-str (prn "one") (prn "two"))

13:58 clojurebot: "\"one\"\n\"two\"\n"

14:00 beutdeuce: ah

14:00 ty

14:03 Chouser: a var like *out* isn't actually any different from a var like str, but it's much more likely you'll want to rebind *out* than str.

14:11 beutdeuce: k

15:19 mikehinchey: hi. I've written a bunch of enhancements to clojure.stacktrace. Should I submit a ticket and patch?

15:36 StartsWithK: when using clojure.main how can i pass arguments to my script?

15:37 i tried java -cp .. clojure.main -i @my/script.clj --help and i get clojure.main help screen

15:38 Chouser: --

15:41 LauJensen: Chouser, rhickey, can't someone answer mikehinchey on how to submit enhancements?

15:42 StartsWithK: Chouser: http://paste.pocoo.org/show/UiT6ju0nmDX0yGozy4aW/ fails from clojure.main, not my app

15:44 * hiredman doubts

15:44 hiredman: what does build.sh say?

15:44 StartsWithK: hiredman: http://paste.pocoo.org/show/h9amCLjkp3oiwWlKY4Ux/

15:45 without --, it takes --help as part of clojure.main arguments :/

15:46 hiredman: and main.clj?

15:47 StartsWithK: main.clj prints *command-line-arg* and starts my app, then ends

15:47 erorr message is then from clojure.main that scans for second -i (or other switch) as it consumed my @truba/main.clj

15:47 finds --

15:48 and throws a exception

15:48 hiredman: ah

15:49 remove the "-i"

15:49 StartsWithK: hiredman: thanks, that worked (no need for --)

15:55 Chouser: mikehinchey: it's good to get permission from a contrib commiter, best if from whoever has been most active in the lib you're patching. Use the clojure-dev or clojure groups to make contact.

15:56 (to answer your question)

15:59 hiredman: http://twitter.com/dysinger/statuses/3959082485

16:00 LauJensen: Thanks Chris

16:05 mikehinchey: Chouser: ok, thanks, I'll try that again

16:09 triyo: I came across this "CS Topic Generator" http://www.cs.purdue.edu/homes/dec/essay.topic.generator.html and thought I'd implement it myself for fun in clojure.

16:10 could anyone have a look at my clojure impl. and please comment? http://gist.github.com/186313

16:11 would this be the lispey way to write it? Could it be done better? thx

16:32 * Chouser found a 32% perf boost in finger tree

16:43 JAS415: 32% is a lot!

16:44 Chouser: yes, it has given me hope. :-)

16:49 fps: hi

16:51 somebody around here using slime+clojure? (don't worry: no setup question)

16:51 triyo: I have a function that can return a string or a char. Is that valid or should my function always return a same data type?

16:52 in terms of best practice that is

16:54 Chouser: triyo: clojure has dynamic typing. do what makes sense.

16:55 conj returns pretty much any kind of collection

16:59 triyo: Chouser: could you pls have a look at this piece of code I wrote and let me know if there is anything glaringly obvious that could be done better (clojure way) http://gist.github.com/186313

17:00 Chouser: (doc rand-int)

17:00 clojurebot: "([n]); Returns a random integer between 0 (inclusive) and n (exclusive)."

17:02 Chouser: why call toupper on \a, instead of just using \A /

17:02 ?

17:03 you can use (.charAt word 0) or (first word) instead of the .. expr you've got

17:03 nothing else there really jumps out at me.

17:05 triyo: "why call toupper on \a, instead of just using \A /" -> because sometimes \a must be uppercase if it is for the first phrase

17:05 thanks for the rand-int

17:05 also for you last comment... greatly appreciate it.

17:06 Chouser: (if capitalize? \A \a) wouldn't work?

17:06 triyo: hmm, blind :)

17:07 I like first word) instead of (.. ) call I have

17:08 (first word)

17:08 JAS415: (first word)

17:10 isn't there a built in java capitalizer

17:11 nope

17:11 looks like i was making that up

17:11 oh well

17:12 triyo: Chouser: now that I got rand-int, would it be a good idea to still keep the smaller ver of my random-word function?

17:14 hmm stupid question, sorry. I use it few places so makes sense to keep it as its on defined function

17:14 Chouser: (doc clojure.contrib.seq-utils/rand-elt)

17:14 clojurebot: "([s]); Return a random element of this seq"

17:14 Chouser: it makes so much sense, someone else already wrote it. :-)

17:15 triyo: hehehe, sure

17:26 technomancy: that didn't exist when I started... kids these days.

17:33 JAS415: lol

18:13 singhv: Modified my sudoku.clj based on your feedback: http://github.com/vishsingh/lisp-toronto/commit/34aea588b13812315477053ca83922461bef1f13

19:00 Nate75Sanders: has there been any talk of something like SRFI-38 for Clojure? ( http://srfi.schemers.org/srfi-38/srfi-38.html ) or does Clojure already have some method for externalizing shared structure?

19:03 hiredman: Nate75Sanders: since clojure's datastructures are immutable, there is no set-cdr!

19:03 Nate75Sanders: hiredman: You'll have to explain to me how that's relevant....I don't understand

19:03 quidnunc: Anyone know if whoever wrote date.clj plans on contributing it to contrib? https://gist.github.com/raw/49656/badd0039ca9d75402ce0cff54e0289955ca92225/date.clj

19:04 Nate75Sanders: hiredman: All I'm saying is that if Clojure is already handling these data structure diffs, we should be able to externalize them that way if we wish

19:04 hiredman: Nate75Sanders: a clojure list, cannot be made to reference ittself

19:05 it is possible to have an issue with circular refs or atoms

19:05 Nate75Sanders: hiredman: doing external representations of shared structure right now involve a copy of a string if I'm not mistaken

19:05 hiredman: ah

19:05 Nate75Sanders: hiredman: you'd be storing state as if it were not shared

19:05 hiredman: I misunderstood

19:05 Nate75Sanders: hiredman: I want the state to be shared on-disk as well

19:06 hiredman: :(

19:06 shared structure is an implementation detail/performance optimization

19:07 exposing it for munging with seems like a bad idea

19:07 Nate75Sanders: I don't share your opinion

19:07 hiredman: *shrug*

19:07 Nate75Sanders: I don't think "printed representation of" is the same as "munging with"

19:07 hiredman: quidnunc: there was a thread about it on the group

19:08 Nate75Sanders: Again, if clojure is already doing these diffs for us, that's powerful and something I'd like to harness

19:08 You could build a revision system/undo/redo/etc with the work that's already been done

19:08 hiredman: :(

19:08 eww

19:08 Nate75Sanders: not just on strings, but on pretty much anything as far as I can tell

19:09 hiredman: no

19:09 strings are java Strings

19:09 any "sharing" is a jvm implementation detail

19:11 and it's not mutating something and keeping a history of the mutation, it's creating new things that incidentally shares some parts with the old thing

19:11 Nate75Sanders: yes, i understand how it works

19:11 the history should be pretty easy to keep track of

19:12 quidnunc: hiredman: I searched for "date.clj" and turned up nothing on Google groups

19:13 hiredman: *shrug*

19:13 I think it was technomancy's baby

19:14 quidnunc: "date" turns up nothing in clojure-dev and nothing relevant in the clojure group.

19:15 hiredman: Do you know approximately when it was discussed?

19:17 hiredman: http://groups.google.com/group/clojure/browse_thread/thread/659503e698ede0b5/f38621b4816302b0?q=date+clojure+technomancy#f38621b4816302b0

19:18 technomancy is in here from time to time, so he would be the one to ask about it

19:18 quidnunc: hiredman: Thanks for the link

19:47 oyiptong: what's a good way to get into clojure coming from a mostly imperative/OO experience?

19:47 I want to use clojure for AI-related work

19:48 arbscht: I hear Programming Clojure is good

21:39 emacsen: is there a good uri construction/deconstruction library? I realize it's trivial but I figured I'd ask

21:52 hiredman: http://www.thelastcitadel.com/lab/deps.svg still a few bugs to iron out

21:53 I need to get dot to output a nicer looking graph

21:53 emacsen: good luck with that. dot's a beast

21:53 Chouser: I was just about to say the same.

21:54 hiredman: alternatively I could figure out some kind of java charting library

21:54 but I just got dot output working

21:55 there

21:55 much nicer

21:55 http://gist.github.com/186432

21:56 the ns form parsing is pretty primitive

21:56 and I should wrap it up in a nice script

21:57 and figure out why certain clojure files are not being recognized as such

22:08 http://www.thelastcitadel.com/lab/ring-deps.svg

22:19 lowlycoder: is there any reason to use latest clojure instead of clojure-1.0.0.zip ?

22:19 hiredman: test-is is now in core

22:19 uh, I'm sure there must be other stuff

22:20 chunked sequences is post 1.0

22:22 clojurebot: graph?

22:22 clojurebot: I don't understand.

22:23 hiredman: clojurebot: graph is <reply>http://github.com/hiredman/clojure-dependency-grapher

22:23 clojurebot: In Ordnung

22:53 emacsen: is there a straightforward way within clj to have something be both a struct and a function?

22:54 hiredman: eh?

22:54 strcuts are maps, and maps are functions of their keys

22:55 emacsen: well, here's what I want, and maybe there's another way to do it...

22:55 I have a structure called a bounding box, which is 4 geographic points

22:55 and I'd like to be able to take a set of points and filter it on that bounding box

22:56 so it'd be (filter bbox points)

22:56 hiredman: well, there is a function called filter

22:57 (filter (partial inside? bbox) points)

22:57 emacsen: I guess (in-bbox bbox) isn't TOO bad

22:57 what's the partial for?

22:58 hiredman: partial application

22:58 emacsen: ie why not #(inside? bbox %) ?

22:58 hiredman: because I use higher order functions in preference to anonymous functions

22:59 emacsen: I've never used partial. What does partial buy me here?

23:02 hiredman: what does #() buy you?

23:04 partial is a succint description of the function. it is the function you get from partially applying inside? to bbox

23:04 #() is just noise

23:04 emacsen: yeah I don't get what that means

23:04 "partially applying"

23:04 what does that mean

23:05 hiredman: so inside? takes 2 args, (partial inside? x) returns a function that takes one arg

23:05 albino: it means passing a certain number of arguments into a function and getting a function back out which expects the rest of the arguments

23:06 emacsen: Oh I see, sort of. I'll need to play with that. I do a lot of anonymous function calling in my filters

23:08 albino: (add 1 2) -> 3 ... (def add1 (partial add 1)) ... (add1 5) -> 6

23:08 * albino wonders if he got his clojure syntax right

23:08 hiredman: http://gist.github.com/184831

23:09 emacsen: albino: wow that's wild

23:10 albino: hiredman's paste means less to me, but I don't read clojure code often, much more use to python

23:11 hiredman: a lot of my code ends up looking like that

23:11 a big -> form

23:11 emacsen: yeah hiredman's code's very dense and w/o a lot of explanation

23:11 part of the problem with the clojure docs is they assume you know a lot of the terms

23:11 that is they're quite terse and use existing jargon

23:12 and you have to know what end of the thing to pull at

23:12 hiredman: it's more of a warning about following my advice in ragards to style

23:13 albino: well partial function application is a cross language concept

Logging service provided by n01se.net