#clojure log - Oct 11 2009

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

0:04 * technomancy is surprised how many people miss the "add a call to clojure-slime-config" note

0:04 technomancy: I wonder if it should/could be made more obvious somehow

0:05 I guess it could write it automatically with the customize feature, but many people don't appreciate that.

0:07 jaiganesh: hi

0:07 can anyone explain whats happening in this piece of code (for [x (range 100 1000) y (range x 1000)] (* x y))

0:09 tomoj: x goes from 100 to 1000, and each time y goes from x to 1000

0:11 er, except 999 instead of 1000

0:11 ,(for [x (range 0 4) y (range x 4)] [x y])

0:11 clojurebot: ([0 0] [0 1] [0 2] [0 3] [1 1] [1 2] [1 3] [2 2] [2 3] [3 3])

0:11 jaiganesh: yeah thks

0:12 is this called List comprehension? can i produce similar list in a different way in clojure?

0:14 tomoj: it's list comprehension, yes

0:17 ,(mapcat (fn [i] (map (fn [j] [i j]) (range i 4))) (range 0 4))

0:17 clojurebot: ([0 0] [0 1] [0 2] [0 3] [1 1] [1 2] [1 3] [2 2] [2 3] [3 3])

0:17 tomoj: maybe there is a prettier way to do it besides using for

0:17 but why don't you want to use for? :)

0:21 for is faster, too

0:21 jaiganesh: k

0:21 tomoj: going from 0 to 1000, the for version above is over 3 times faster than the mapcat version

0:22 jaiganesh: hmm interesting

0:22 tomoj: it uses chunked seqs, maybe other optimizations as well

0:28 solussd: what is the difference between binding and let?

0:28 hiredman: let is lexical

0:28 twee: is there an easy way to get the namespace of a function parameter?

0:28 hiredman: binding is dynamic, and it only works if the names have already been created via def

0:29 twee: what do you mean?

0:29 (fn [x] x) x is a local name, there is no namespace

0:29 twee: at runtime i guess.. when you can the fn

0:29 call the fn

0:30 solussd: I see- So, binding will mask a defined value, but not define a new one?

0:30 hiredman: more or less

0:30 tomoj: all the code called from within the body of the binding will see the new value, as well ("dynamic")

0:30 hiredman: twee: what doe you mean by get the namespace of a function parameter?

0:30 binding is also thread local

0:31 solussd: isn't 'let' thread local?

0:31 hiredman: let is lexical

0:31 (let [x 1] (future (prn x)))

0:32 (def x 0) (binding [x 1] (future (prn x)))

0:32 tomoj: (def *foo* 3), (defn foo [] *foo*), then compare (binding [*foo* 10] (foo)) to (let [*foo* 10] (foo))

0:34 twee: something like what the namespace function does, except for arbitrary things i guess

0:34 (doc namespace)

0:34 clojurebot: "([x]); Returns the namespace String of a symbol or keyword, or nil if not present."

0:34 hiredman: arbitrary things don't have namespaces

0:35 solussd: I see. Thanks

0:35 twee: let's say i pass in (namespace map) i'd like it to say 'clojure.core'

0:35 hiredman: namespaces are a space for names, so the only things that have/exist in namepsaces are names like keywords and symbols

0:36 (def foo (Object.))

0:36 the Object is not in a namespace, the name bound to the Object is

0:37 tomoj: hmm

0:37 ,#'map

0:37 clojurebot: #'clojure.core/map

0:37 tomoj: how do you pull that out? maybe that's what twee is asking?

0:37 twee: yup it is

0:38 hiredman: you want to resolve a symbol to the var it is bound to

0:38 ,(doc resolve)

0:38 clojurebot: "([sym]); same as (ns-resolve *ns* symbol)"

0:38 tomoj: does resolve have an inverse, though?

0:40 ,(.ns #'map)

0:40 clojurebot: #<Namespace clojure.core>

0:41 twee: ah thank you, that's what i was looking for

0:41 tomoj: I dunno if you're supposed to use that

0:41 may be subject to change, I dunno

0:42 twee: i see

0:42 hiredman: what are you doing?

0:42 twee: some java interop stuff

0:43 hiredman: and what does that have to do with namespaces?

0:46 twee: have some stuff where it dynamically resolves the workflows to run, where workflow is passed in from cmdline, but for test-is code, i just don't want to deal with it. but if it doesn't work out, i'll just pass it in explicitly

0:46 hiredman: if you don't want to say, you can just say that

1:03 http://weblogs.java.net/blog/forax/archive/2009/10/06/jdk7-do-escape-analysis-default

2:31 arussel: I got some newbee question before I start learning clojure. How mature is the eclipse plugin ?

2:32 slashus2: arussel: Try netbeans with enclojure

2:32 arussel: (in term of debuggin, autocomplete, code browsing)

2:33 slashus2: I never used netbeans ... Then between emacs and netbean plugin, which one would you recommend ?

2:33 slashus2: I don't use emacs because I have never given it an honest try, so I can't really weigh those.

2:34 arussel: does the netbeans plugin has autocomplete, debugging and code browsing ?

2:37 slashus2: arussel: Yes.

2:39 arussel: nice. Apart from compojure, is there any other web framework known to run on GAE ?

3:43 gonzojive: does anybody have emacs configured for both Common Lisp and Clojure? right now I can only do one or the other

3:44 tomoj: I have both

3:44 but I still have a bit of trouble using both at the same time

3:44 gonzojive: http://gist.github.com/28a01c699b8afecc0750

4:10 G0SUB: what should be the clojure type hint for a Future<Object> object?

4:10 will #^Future<object> work? or should it be #^Future ?

4:11 LauJensen: Depends on what you're passing it to I suppose - I never had to type hint a future, why do you ?

4:11 G0SUB: LauJensen: I was just thinking. I am trying to use the spymemcached lib.

4:21 ambient: arussel neither netbeans nor eclipse plugins are something i'd call "mature"

4:21 they work, but that's about it

4:21 plenty of rough edges

4:38 Chousuke: G0SUB: typehinting Object is pointless, and if you want to tell the compiler it's a Future, just use #^Future

4:38 or at least, I hope typehinting Object is pointless, since all classes are supposed to be Objects ;P

4:39 G0SUB: Chousuke: OK.

4:39 Chousuke: if you still need to do the hinting, you'll need to do it when you dereference the future

4:39 eg. #^Object @future

4:39 clojurebot: Chousuke: the fn created by future (like all fns) doesn't close over dynamicly scoped stuff

4:44 hiredman: ~botsnack

4:44 clojurebot: thanks; that was delicious. (nom nom nom)

4:53 arussel: ambient: do you know where to get the sources ( hg clone https://counterclockwise.googlecode.com/hg/ counterclockwise is empty

4:58 ambient: arussel might be a problem with googlecode

4:58 they juse changed how their repos work iirc

5:00 hiredman: ~ccw

5:00 clojurebot: Counterclockwise aka ccw at http://code.google.com/p/counterclockwise/

5:01 ambient: hiredman if you browse she source from there, you will notice it is empty

5:05 hiredman: I was just checking

5:05 I know, uh, the guy that does the ccw stuff just stuffed a mess of urls into clojurebot the other day

5:06 kyromancer: arussel, http://github.com/laurentpetit/ccw

5:06 cgrand: ~ccw is http://github.com/laurentpetit/ccw

5:06 clojurebot: Ack. Ack.

5:06 cgrand: ccw

5:06 ~ccw

5:06 clojurebot: ccw is http://github.com/laurentpetit/ccw

5:06 hiredman: I think he was the one that set it to the google code url

5:07 kyromancer: github is just where the source is maintained, issues and wiki is on google code

5:07 hiredman: 2009:Oct:08:15:37:53 lpetit : clojurebot: ccw is <reply> Counterclockwise aka ccw at http://code.google.com/p/counterclockwise/

5:07 arussel: fatal: http://github.com/laurentpetit/ccw/info/refs not found: did you run git update-server-info on the server?

5:07 hiredman: oh

5:08 interesting

5:09 kyromancer: the clone url is different

5:09 git://github.com/laurentpetit/ccw.git

5:10 arussel: got it, thanks

5:13 I am not much of an eclipse coder, but it seams that the name of the folder in which we put the compiled class is hardcoded.

5:14 kyromancer: let me check

5:15 indeed, ClojureBuilder.java:124

5:16 arussel: I would like to be able to have them also in a war/WEB-INF/classes folder.

5:18 or to change the folder to war/WEB-INF/classes.

5:22 kyromancer: hmm thats gonna be a problem...

5:22 you try linking classes to war/WEB-INF/classes

5:23 *could

5:24 it's a workaround at least if your OS supports it

5:31 arussel: that looks like an ok workaround :-)

5:52 G0SUB: OK, so I have written a wrapper on top of spymemcached, and I need to write some tests. what's the best way to temporarily bind some vars just for testing purposes? (I need to bind the client obj to some var).

6:25 arussel: kyromancer: what action would compile a file into the "classes" folder. It seems I can manage to do once and that's it. If I clean the project, classes just becomes empty, and nothing is compiled into it anymore

6:25 kyromancer: yeah that is a bit of an issue atm

6:25 compilation needs the REPL to run

6:26 since that is where to compilation is performed

6:26 try starting it

6:27 then CTRL+ALT+K in the editor

6:27 (Clojure->Compile...)

6:28 arussel: I am currently working on ways to improve compilation and Java interop

6:29 The other day I was trying to mash up wicket and clojure using ccw, and it was quite difficult

6:29 Eclipse was spitting out errros about not being able to clean the classes folder because the REPL was running

6:30 so I stopped the REPL and did a "Clean"

6:30 that of course deleted all the classes generated from clj

6:31 so I restarted REPL, compiled, stopped repl, refreshed project...

6:31 Maybe theres a better way

6:31 ..but I haven't found it yet

6:54 Chousuke: G0SUB: (binding [thing someotherthing] ...)?

6:54 G0SUB: you need to be careful if threading is involved, though.

6:55 G0SUB: hmm

6:56 Chousuke: I wanted to know if clojure.test provided a similar but more sugared construct.

6:59 Chousuke: I need to write a function/macro similar to memoize which caches the return vals in memcached. any tips on how to write something like that?

7:04 Chousuke: G0SUB: well, clojure.test also has fixtures but I'm not sure how to use those

7:05 G0SUB: isn't memoize enough? :)

7:06 anyway, one way to do it would be to have the function close over an atom for example.

7:06 G0SUB: Chousuke: memoize, is not enough :) Really need to use memcached.

7:07 Chousuke: ah, I guess I misunderstood your question

7:08 G0SUB: Chousuke: so instead of storing the ret val in an atom, I store it in memcached.

7:08 Chousuke: that might work.

7:09 G0SUB: Chousuke: OK. What's the best way to convert a function's name to a string? I am using (str (val f)) right now.

7:09 (var f)

7:09 not val.

7:10 Chousuke: I think that's just fine

7:10 hmm

7:10 ,(.toString +)

7:10 clojurebot: "clojure.core$_PLUS___4443@1fce83e"

7:10 G0SUB: hmm

7:10 Chousuke: if you're going to use it as a memcached id or something, you might want to use that, too. it'll work for any function

7:11 G0SUB: yeah, for the memcached key

7:19 I am always getting confused with the syntax of :use inside the :ns macro.

7:19 (:use [clojure.contrib seq-utils :only (str-join)])

7:19 what's wrong wit that?

7:19 with

7:21 Chousuke: it's (:use (clojure.contrib [seq-utils :only (str-join)]))

7:22 G0SUB: ah

7:23 Chousuke: it takes a prefix list, which is a list containing the prefix and any number of library specifications (either plain symbols or vectors)

7:24 G0SUB: Chousuke: there seems to be a problem with var

7:24 (defn var-test

7:24 [f]

7:24 (str (var f)))

7:24 this gives an error.

7:25 Chousuke: that's because f is a local, and thus f names no var :)

7:25 G0SUB: dang

7:26 how do I get the name of the function then?

7:26 Chousuke: the function might not even have a name

7:26 but try the toString approach

7:26 G0SUB: right

7:26 ok

7:27 Chousuke: one concern is that the toString fn returns some extra stuff after the name of the function. I think it refers to the memory location or something.

7:28 as a result, it might not be the same for two different VMs running the same code.

7:28 Chousuke: hmm, yeah

7:28 it won't be :P

7:28 G0SUB: may be I can split the str at two underscores

7:29 Chousuke: how general do you need this memcache thing to be?

7:29 G0SUB: Chousuke: not a lot, really. but it should generate the same key for different VMs given the same fn and args

7:30 Chousuke: maybe the easiest solution would be to leave selecting a proper key to the user

7:30 G0SUB: Chousuke: hmm, you are right, I think.

7:30 Chousuke: so they could do (def memcached-foo (memcache "the.ns.foo" foo))

7:34 G0SUB: Chousuke: makes sense. thanks for the tip.

8:37 mrBliss: I've got a question about zippers

8:39 suppose you want to represent a graph as a zipper

8:39 much like http://projecteuler.net/index.php?section=problems&id=18

8:40 I only see a way to store values in the leaves, not in the branches

11:04 kyromancer: A question: Is there a particular reason that all the VARs in RT are static?

11:05 This makes cleanly separating independent clojure instances pretty hard...

11:06 Groovy and JRuby for example offer a runtime object that encapsulates the state so multiple instances don't step on each other's toes

12:58 raek: is there any difference between .. and -> besides that .. "adds dots" to the functions/methods?

13:20 chouser: raek: nope. if you look at their definitions in core.clj you'll see there are very similar.

14:46 itistoday: i'm looking through the code for compojure and I came across this:

14:46 (fn [param-map, #^DiskFileItem item]

14:46 what is that ',' doing there?

14:47 hoeck1: itistoday: commas are whitespace in clojure

14:47 itistoday: hoeck1: thanks

14:47 do you happen to know why they were added?

14:48 hoeck1: maybe to enhance readability in this arglist

14:49 itistoday: oh i mean in general

14:49 hoeck1: when printing maps, clojure puts commas between key-value pairs

14:49 tomoj: ,{1 2 3 4 5 6 7 8 9 10}

14:49 clojurebot: {1 2, 3 4, 5 6, 7 8, 9 10}

14:49 itistoday: ah i see

14:49 tomoj: much harder to read without commas

14:50 itistoday: so it's so that can be read back in?

14:51 Chousuke: nah, just for humans :)

14:51 the reader thinks commas are whitespace

14:51 itistoday: ah k, thanks

14:52 Chousuke: it's possible to abuse though :P

14:52 hoeck1: but it would be nice to have one more reader-macro character,

14:53 Chousuke: what for?

14:53 hoeck1: don't know (yet)

14:53 maybe for arrays?

14:54 itistoday: personally i hope clojure doesn't stray any further away from its lisp roots than it has...

14:54 syntax is the enemy ;-)

14:56 prishvin: Hello, I have netbeans repl saying "Unable to resolve classname: Color" when I have (import '(java.awt Color ) done,

14:56 what might be the reason?

15:07 any ideas? :)

15:12 chouser: prishvin: seems unlikely, doesn't it.

15:13 You're sure the file's getting saved and reloaded the way you think it is? No other errors?

15:17 prishvin: yes chouser, the file is saved and reloaded. it works if i use the full name like java.awt.Color

15:17 like if import does not work

15:30 LauJensen: prishvin, netbeans and vim have been replaced by something called Emacs - everything works in there :)

15:31 prishvin: LauJensen, :) I am not the emacs guy, btw do you have function browser/list in there?

15:31 I've had function browser when I used emacs for a while writing CL

15:31 LauJensen: yea sure, you mean by way of reflection for java stuff?

15:33 prishvin: no sorry, I must have said it wrong, I mean a list of functions, which are in the open source file, "source browser"

15:34 LauJensen: I think somebody made a speedbar integration, but Ive never looked into it

15:34 prishvin: well, netbeans has it, + its the best java ide, imo

15:35 LauJensen: k

15:35 prishvin: all works like a charm, except for (import...)

15:38 LauJensen: How about those JVM Summit videos, are they up yet ?

15:39 itistoday: rhickey: take a look at newlisp's documentation: http://www.newlisp.org/downloads/manual_frame.html

15:40 rhickey: can be auto-generated using newlispdoc command: http://www.newlisp.org/downloads/newLISPdoc.html

15:42 Chousuke: I wonder where the clojure-contrib doc generator is being hosted :/

15:43 itistoday: one other thing that i think clojure should borrow from newlisp is its strings ({}, [text][/text])

15:43 does clojure have escape-proof strings?

15:43 Chousuke: escape-proof?

15:43 itistoday: I.e. in newlisp this is a valid string: {hello "fool", I'm so "cool"}

15:43 Chousuke: they're java Strings

15:43 clojurebot:

15:43 itistoday: instead of: "hello \"fool\", I'm so \"cool\""

15:44 Chousuke: no such thing

15:44 itistoday: it would be *great* if it did...

15:44 Chousuke: it's a neat feature, yeah.

15:44 but what do you propose as the syntax?

15:45 itistoday: it's a problem for clojure to use {} of course

15:45 or []

15:45 or ()

15:45 so... i'm not sure

15:45 how about <>

15:45 i don't think those are being used for anything right?

15:45 it would be best for it to be one-character, whatever the delimiter ends up being

15:45 Chousuke: other than being valid in symbols, no ;/

15:46 how do you suppose we'd deal with (< 1 2 3)? :/

15:46 itistoday: good question

15:46 LauJensen: <> is xml property

15:46 itistoday: clojure might not be able to do it with only one char...

15:46 perhaps something like /* */ :-p

15:46 Chousuke: :P

15:47 LauJensen: How about #"" ?

15:47 itistoday: that's already used

15:47 for regex's

15:47 but good idea

15:47 LauJensen: yea, but for something as useless as regex

15:47 so scrap that

15:47 Chousuke: :P

15:47 LauJensen: Who would miss regex?

15:47 itistoday: lots of people :P

15:47 LauJensen: ~regex

15:47 clojurebot: Sometimes people have a problem, and decide to solve it with regular expressions. Now they have two problems.

15:47 LauJensen: See... :)

15:47 itistoday: haha

15:48 LauJensen: According to my last blogpost, regex is for dweebs :) We have to go by that

15:48 itistoday: i like the idea though

15:48 some other char though

15:48 and we can't use "

15:48 it can't be #"" b/c we can't use # or "

15:48 and it can't be #{} because that's already used too

15:49 so how about #[] ?

15:49 Chousuke: I'd rather save that for some data structure

15:49 itistoday: k...

15:50 Chousuke: something like #rDfooD where D is the delimiter wouldn't be too bad

15:50 itistoday: well whatever it ends up being another constraint is that it has to play nice with regex's

15:50 in newlisp {} are used all the time for regex's

15:51 so that you don't have to do extra escaping

15:51 Chousuke: the regex literals have different escaping rules from plain strings

15:52 itistoday: right, but it's handy nonetheless, as it does let you avoid escaping a bunch of stuff

15:53 [t]my text[/t] ?

15:53 Chousuke: [t] is a vector :P

15:53 LauJensen: Still looks good though

15:54 itistoday: running out of symbols

15:54 s/symbols/characters/

15:55 s{my "escaped" string?}

15:55 Chousuke: needs the # prefix

15:55 itistoday: can't have it

15:55 that's a set

15:55 Chousuke: no, I mean #s{...}

15:55 itistoday: oh

15:55 Chousuke: as I suggested earlier :)

15:56 though a bit more general

15:56 itistoday: :-)

15:56 so #s{blah..} is good?

15:56 it seems to fit clojure's use of #

15:57 Chousuke: that would be easy to implement and wouldn't reserve any very important characters.

15:57 itistoday: where should I send the recommendation?

15:57 bzr-dev?

15:57 (list)

15:57 errr

15:57 lol

15:57 Chousuke: the list, yeah. :P

15:57 itistoday: clojure-dev list

15:58 Chousuke: not the developer list though. the public list :)

15:58 itistoday: just wondering, but why?

15:58 isn't this a dev decision?

15:59 Chousuke: the dev list is for discussing the implementation mostly

16:00 itistoday: rhickey: when you get back, check out the discussion above on #s{ ... }

16:00 Chousuke: a raw string reader macro would be quite useful for docstrings

16:00 which often contain bits of code

16:00 itistoday: that's true

16:01 that way you could easily include sample code, something that the docs desperately need

16:01 Chousuke: you can include it now, too, but writing strings is a bit ugly.

16:02 itistoday: btw, can i join the clojure group without a gmail account?

16:02 (if so, how?)

16:03 Chousuke: you need a google account I think

16:04 itistoday: not cool google...

16:04 Chousuke: hmm, I can send invitations it seems

16:04 I don't know what that actually does, but give me your email address and I'll send you one :P

16:04 rlb: itistoday: you don't have to have a gmail account, just a google account -- though I agree, still unfortunate for a list.

16:05 itistoday: rlb: the invitation should work?

16:05 Chousuke: pm sent

16:05 Chousuke: I have no idea if the invitation does anything special

16:05 or if it's just a "plz join" spam message :P

16:06 but sent it anyway

16:06 rlb: itistoday: you don't need an invitation -- you can create an account for this purpose yourself.

16:07 itistoday: Chousuke: i got the invite, thanks, it contained a link, i seem to have been subscribed, might take a bit to see if it actually worked though

16:07 Chousuke: itistoday: I wonder if you'll be able to post without a google account though :/

16:08 itistoday: Chousuke: have you noticed anyone on the list without one?

16:08 i seem to recall on another list people doing so

16:08 so i think it's possible

16:09 Chousuke: itistoday: http://groups.google.com/support/bin/answer.py?hl=en&answer=46438

16:10 hiredman: it's not actually mailing list, it is a google group, which needs a google account, you just have the option of using it via email

16:11 Chousuke: you can post by sending mail to clojure@googlegroups.com apparently

16:11 itistoday: cool, thanks

16:11 although i was expecting an email to arrive saying "you've joined! here's what you can do:..."

16:12 someone should post to the group though and i should get the email though, if that doesn't happen within 4 hours i'll just sign on via gmail

16:13 hiredman: the first message to the group requires a moderator to sign off on it

16:14 itistoday: hiredman: that doesn't affect receiving emails though right?

17:39 fyi i've sent an email to the clojure group regarding the #s{ ... } construct, hopefully a mod will approve it soon

17:40 spaceman_stu: I'd like write a macro that would generate a few helper functions. defn'ing them from within the macro seems problematic - what's the right approach there? maybe return a hash with the funcs as keys?

17:42 Chousuke: keys? you mean values? :P

17:42 spaceman_stu: details =]

17:43 but yeah, so would something along those lines be the preferred appraoch?

17:43 Chousuke: do you need to generate these functions at runtime?

17:43 spaceman_stu: no

17:44 I know them beforehand

17:44 Chousuke: then I guess macros might be a better choice

17:45 you can have a (defmacro gen-funcs [some params] (list 'do `(defn firstone ..) `(defn secondone ...))

17:45 the (list 'do ..) because nesting ` is a bit icky :)

17:45 spaceman_stu: hm, yeah, that could the reason it's not working now

17:54 itistoday: ~seen rhickey

17:54 clojurebot: rhickey was last seen joining #clojure, 623 minutes ago

17:54 itistoday: ,(/ 623 60)

17:54 clojurebot: 623/60

17:54 itistoday: ...

17:54 ,(int (/ 623 60))

17:54 clojurebot: 10

17:55 itistoday: ,(float (/ 623 60))

17:55 clojurebot: 10.383333

18:03 itistoday: how do i check if a symbol is bound?

18:03 i.e. (def x)

18:03 then what to check if it's bound?

18:04 (as that will leave it unbound)

18:04 Chousuke: (try x 'BOUND (catch SomeException e 'UNBOUND)) :P

18:05 itistoday: ok, then i should change my question as that's not the solution i'm looking for

18:06 how do you create a closure that increments a counter?

18:06 i.e. (defn counter ... )

18:06 (counter) => 1

18:06 (counter) => 2

18:06 etc.

18:06 Chousuke: that's bad style :)

18:06 itistoday: that's a common thing to do

18:07 Chousuke: not in clojure though

18:07 itistoday: can clojure not do it?

18:07 Chousuke: but, (let [ctr (atom 0)] (defn counter [] (swap! counter inc)))

18:07 you're strongly encouraged not to do this though :P

18:07 clojurebot: this is not a bug

18:08 Chousuke: rather, have the counter in an atom or a ref and increment it explicitly :)

18:08 itistoday: k... but what is that code doing..?

18:08 where is ctr used?

18:09 Chousuke: whoops

18:09 the first argument to swap! should be ctr

18:10 ,(let [a (atom 0) b (fn [] (swap! a inc)] [(b) (b) (b)])

18:10 clojurebot: Unmatched delimiter: ]

18:10 Chousuke: ,(let [a (atom 0) b (fn [] (swap! a inc))] [(b) (b) (b)])

18:10 clojurebot: [1 2 3]

18:11 itistoday: ok cool, thanks

18:11 and why an atom and not a var?

18:11 Chousuke: a var is usually not intended to be changed

18:11 locally rebound, perhaps, but not changed

18:12 itistoday: hmm.. thanks, i'll wrap my head around this soon...

18:13 how does one create a local var?

18:13 Chousuke: (doc with-local-vars)

18:13 clojurebot: "([name-vals-vec & body]); varbinding=> symbol init-expr Executes the exprs in a context in which the symbols are bound to vars with per-thread bindings to the init-exprs. The symbols refer to the var objects themselves, and must be accessed with var-get and var-set"

18:13 Chousuke: but that's almost never used.

18:13 in fact, I can't think of any good use for it :P

18:14 itistoday: well, i was looking at the docs on var

18:14 http://clojure.org/vars

18:14 and it says that set! can't be used to change a root binding

18:14 so how do i create a var that is not in the root binding?

18:14 Chousuke: you don't. :)

18:15 you use the binding macro to rebind it locally

18:15 itistoday: so when is set! used?

18:15 is it used often?

18:16 Chousuke: within a dynamic scope where a var has been thread-locally bound

18:16 eg, (binding [*someglobal* 4] (foo))

18:16 now foo can be a function that uses set! on *someglobal*

18:17 itistoday: that seems like it would be a very rare thing to do

18:17 or at least in poor taste

18:17 i.e. foo would require that it be run inside the binding macro and nowhere else

18:17 right?

18:17 Chousuke: well, using set! is fairly rare, but binding stuff like that isn't

18:17 set! is thread-safe though. :)

18:17 because var bindings are thread-local

18:18 the root binding isn't, so that's why you can't use set! on it.

18:18 itistoday: is 'binding' used often?

18:18 i can't imagine a situation where i'd want to use it

18:18 Chousuke: pretty often I think.

18:19 itistoday: can you give an example? sorry if i'm asking too many questions btw

18:20 Chousuke: itistoday: well, you could have some code that depends on a database being specified, and you could use a global *db* that is initially unbound, but when you actually call the database functions, you bind it with (binding ...)

18:20 usually wrapped with some macro magic so that you can use (with-database-connection conn (some-db-stuff) (more-db-stuff)))

18:20 itistoday: does that mean you'd have to establish a db connection each time you want to do something?

18:21 Chousuke: itistoday: no, you can establish the db connection beforehand

18:21 and just bind *db* to that whenever you use the db functions

18:21 itistoday: why not have the *db* always bound?

18:22 Chousuke: will you always have a connection? :)

18:22 you might also want to have multiple connections

18:23 itistoday: ok, so you're saying that functions can reference *db* and just require they be called in a binding on *db*

18:23 where is the actual connection stored though?

18:23 Chousuke: yes.

18:23 itistoday: on another var?

18:23 or an atom?

18:23 Chousuke: wherever you like

18:23 raek: when is var-quote useful?

18:24 in (send *agent* #'do-stuff) ?

18:25 itistoday: actually, that's another question i had, what is the purpose of #'blah

18:26 i.e. the var function?

18:26 ,(doc var)

18:26 clojurebot: Titim gan éirí ort.

18:26 itistoday: wtf

18:27 raek: that's var-quote

18:27 itistoday: ,(doc var-quote)

18:27 clojurebot: No entiendo

18:27 Chousuke: ,'#'foo

18:27 clojurebot: (var foo)

18:27 raek: it gives you the var bound to the symbol

18:27 Chousuke: itistoday: var is a special form, no doc string for it :)

18:28 #'foo is identical to (var foo)

18:28 raek: so, when should one use var-quotes?

18:29 do they force a lookup when they are evaluated?

18:29 Chousuke: when you want the var named by a symbol :/

18:29 which does happen sometimes

18:29 itistoday: http://gist.github.com/207927

18:30 whoops

18:30 typo in comment.

18:30 the first one of course results in 15 :P

18:31 itistoday: thanks

18:31 i see that now

18:31 i'm trying to reconcile my existing knowledge with clojure

18:31 and it's hurting

18:31 heh

18:31 Chousuke: dynamic scope is a bit weird :)

18:31 itistoday: well i know dynamic scope

18:32 raek: if I run (send-off some-agent some-fn), will some-fn be looked up only once?

18:32 itistoday: i'm trying to figure out how to do lexical scope to create a counting function

18:32 raek: *if I run .. from "some-agent"

18:32 itistoday: and i take it that i need to use an atom, but if i'd rather use a var

18:33 raek: that is, do I have to use var-quote if I want to be able to "monkey patch" the code?

18:33 Chousuke: raek: hm, I'm not sure about that actually.

18:33 try it and see :)

18:34 raek: it looks like #'some-fn and some-fn doesn't make any difference

18:34 Chousuke: it sometimes does though IIRC.

18:34 maybe only if you're storing it in a data structure.

18:35 itistoday: Chousuke: how do i make a correct version of this: (defn new-counter [] (binding [x 0] (fn [] (set! x (+ 1 x)) x)))

18:35 i'm pretty sure that i'm using binding incorrectly

18:35 but all i want is a variable with that closure

18:35 that the function can manipulate

18:35 or is that not possible in clojure?

18:36 Chousuke: itistoday: you need an atom

18:36 or a ref, or an agent, but an atom is simpler

18:37 itistoday: (defn new-counter [] (let [x (atom 0)] (fn [] (swap! x inc) x))) ?

18:37 that seems to work

18:37 Chousuke: yeah, it closes over the atom

18:37 the x at the end is redundant though

18:37 itistoday: oh, didn't know

18:37 Chousuke: actually, it's wrong. you meant @x :)

18:38 x is the atom, @x is its value

18:38 itistoday: gotcha

18:38 getting the hang of this... thanks :-)

18:38 Chousuke: but in any case, (swap! x inc) returns the new value

18:38 itistoday: right

18:39 is there anything in clojure that is not thread-safe?

18:39 Chousuke: java interop :P

18:39 itistoday: gotcha, so using a value from a java object could be unsafe?

18:40 Chousuke: in clojure parlance, a "value" is an immutable things.

18:40 -s

18:40 but Java objects are not necessarily values

18:40 they might change, thus rendering them unsafe.

18:40 itistoday: a java object that has a public int x; using that x is unsafe right? and uh... what do i call that x if not a value?

18:40 or a variable?

18:41 Chousuke: x is a variable I suppose, but the int is its value

18:41 an int is immutable

18:41 5 is 5, no matter what you do :)

18:42 itistoday: right, ok, i'll learn to use the terms correctly too ;-)

18:42 but the *variable* is unsafe?

18:42 Chousuke: yeah.

18:42 itistoday: what do people do about that?

18:43 Chousuke: you could do (def foo (YourObject.)), and depending on what happens, (.x foo) may return different values

18:43 so foo is not a value

18:43 itistoday: usually, people are very careful when dealing with mutable java things :)

18:44 immutable java things are safe of course, so not all interop is dangerous

18:44 itistoday: well i mean say they have a java object written to by multiple threads, do they wrap it in a clojure actor?

18:44 Chousuke: that's one way I guess.

18:44 itistoday: with my limited knowledge of clojure, that's what i'd do. ;-)

18:45 Chousuke: there's also the locking macro, but that's pretty rare :/

18:45 I don't think I've ever seen it used :P

18:45 itistoday: it's like a mutex lock?

18:45 Chousuke: ~def locking

18:46 itistoday: pretty much a mutex i guess

18:46 Chousuke: I guess it's whatever the java synchronisation system uses

18:46 itistoday: monitors are similar to mutex locks no?

18:47 `(let [lockee# ~x]

18:47 is that # on the end doing anything special?

18:47 Chousuke: yes. it's an autogensym

18:47 itistoday: or is that just some bizarre naming convention

18:48 ah, gotcha

18:48 so that's how they're used

18:48 Chousuke: it can be used to avoid multiple evaluations of x

18:48 itistoday: i thought it was used to prevent name clashes?

18:48 Chousuke: that, too

18:48 itistoday: gotcha

18:48 well, i think i've used up enough of your time :-p

18:48 thanks for all your help

18:49 Chousuke: (let [x '(some-expensive-computation)] `(let [x x#] [x# x# x# ~x ~x ~x]))

18:49 ,(let [x '(some-expensive-computation)] `(let [x x#] [x# x# x# ~x ~x ~x]))

18:49 clojurebot: (clojure.core/let [sandbox/x x__4470__auto__] [x__4470__auto__ x__4470__auto__ x__4470__auto__ (some-expensive-computation) (some-expensive-computation) (some-expensive-computation)])

18:49 Chousuke: oops

18:49 forgot to unquote the first x

18:49 and got them the wrong way around too

18:49 ... I guess I shoudl go to sleep :)

18:49 anyway, you get the idea.

18:50 ,(let [x '(some-expensive-computation)] `(let [x# ~x] [x# x# ~x ~x]))

18:50 clojurebot: (clojure.core/let [x__4474__auto__ (some-expensive-computation)] [x__4474__auto__ x__4474__auto__ (some-expensive-computation) (some-expensive-computation)])

18:50 itistoday: yeah, i originally thought it was to be used the way you had it the first way around

18:50 because I thought it was like (gensym)

18:51 so, (let [x (gensym)] ... )

18:51 i figured it'd be (let [x x#] ... ) , or something like that

18:51 but that wouldn't make sense

18:51 Chousuke: autogensyms are so much nicer than using gensym directly though

18:52 in the cases that you can use them, which is most of the time.

18:52 itistoday: right, i thought it was nifty when i saw it, and seeing it used now makes sense, i just never would have thought that code would work because i'd thought calling x# multiple times the way it does there could create multiple symbols

18:53 somehow it doesn't though

18:53 Chousuke: ` contains a lot of magic

18:54 itistoday: ,`(let [#x 0] (println #x))

18:54 clojurebot: No dispatch macro for: x

18:54 itistoday: why fail?

18:54 Chousuke: huh

18:54 ah

18:54 x#, not #x :D

18:55 itistoday: ,`(let [x# 0] (println x#))

18:55 clojurebot: (clojure.core/let [x__4478__auto__ 0] (clojure.core/println x__4478__auto__))

18:55 itistoday: lol

18:55 hehe

18:55 Chousuke: if you want to see sq implemented in clojure, search http://github.com/Chousuke/clojure/blob/sq-macro/src/clj/clojure/core.clj for syntax-quote

18:56 itistoday: k, think that's too advanced for me right now though

18:56 btw, how do i get that thing to print 0?

18:56 ,`(let [x# 0] (println x#))

18:56 clojurebot: (clojure.core/let [x__4482__auto__ 0] (clojure.core/println x__4482__auto__))

18:56 itistoday: instead of that

18:56 Chousuke: eval it :)

18:57 macros in the end are just functions that produce data structures just like that.

18:57 the compiler just runs eval on it afterwards

18:57 itistoday: ,(eval `(let [x# 0] (println x#)))

18:57 clojurebot: DENIED

18:57 Chousuke: heh ;(

18:57 itistoday: that would have worked though right?

18:57 Chousuke: yes.

18:57 itistoday: k

18:58 Chousuke: it was a small epiphany for me when I finally understood macros.

18:58 itistoday: that happened to me as well, but that was a year ago when i was learning scheme

18:59 Chousuke: when I tried to learn CL I saw the backquote as some kind of magic that's macro only :/

18:59 itistoday: since them i've forgotten about them because i've been using newlisp's fexprs

18:59 that's about the stage that i'm back at right now too ;-)

18:59 Chousuke: heh.

19:00 but it really helps to realise that the backquote is just a convenience tool to replace a lot of manual calls to list and quote :P

19:00 itistoday: right

19:00 i'm going to go back to that scheme tutorial and read about it, it had an excellent explanation

19:01 http://www.ccs.neu.edu/home/dorai/t-y-scheme/t-y-scheme-Z-H-10.html#node_chap_8

19:01 btw, i love clojure's logo, i just noticed the yin-yang in it

19:02 Chousuke: yeah, it's great

19:03 itistoday: ah, looks like my suggestion for #s{ ... } made it into the clojure list

19:07 kmurph79: is there a function that returns true/false based on whether a regex matches a string; like: (re-match #"(9)" "298") => true

19:07 Chousuke: (doc re-match)

19:07 clojurebot: excusez-moi

19:07 Chousuke: hmm

19:07 ,(re-matches #"foo" "bar")

19:07 clojurebot: nil

19:08 Chousuke: ,(re-matches #"foo" "foo")

19:08 clojurebot: "foo"

19:08 Chousuke: maybe that's good enough?

19:08 kmurph79: yeah

19:08 itistoday: ,(if (re-matches #"foo" "foo") "yes" "no")

19:08 clojurebot: "yes"

19:08 itistoday: ,(if (re-matches #"foo" "fzo") "yes" "no")

19:08 clojurebot: "no"

19:08 itistoday: yay

19:08 raek: ,(boolean (re-matches #"foo" "foo"))

19:08 clojurebot: true

19:09 raek: if you don't want to "leak" any details

19:09 kmurph79: thanks

19:13 raek: is (doseq [x xs y ys] (fn-with-side-effects x y)) the same as (dorun (for [x xs y ys] (fn-with-side-effects x y))) ?

19:31 kmurph79: what does the _ symbol do?

19:32 dreish: raek: They expand to different code, but as far as I know they're effectively the same thing.

19:32 kmurph79: nm i think i got it

19:33 raek: (try (foo) (catch SomeException _ (bar)))

19:34 in that case, you are not interested in the value that would have been assigned to the symbol in the place of _

19:34 (defn foo [_] (bar))

19:35 a function that takes one argument and discards it

21:00 steiger: hey guys. i'm trying to create my own data structure in clojure by using :gen-class and extending clojure.lang.ASeq (like StringSeq does). but, how should I call the superclass (ASeq) in the -init method?

21:03 arbscht: steiger: -init returns a vector including arguments for the superclass constructor, and your own state. the superclass constructor is called automatically with those args

21:04 if you want to call any other overridden methods, use :exposes-methods

21:05 steiger: arbscht: oh, i see

21:06 arbscht: thank you

21:18 zaphar_ps: why does recur not work in an if expression?

21:18 it's still a tail call but if I put the tail call in an if expression it doesn't work

21:19 chouser: ,(loop [a 1] (if (< a 10) (recur (inc a)) a))

21:19 clojurebot: 10

21:19 chouser: works fine

21:20 zaphar_ps: hrmmm must have a paren out of place then :-)

21:20 * zaphar_ps goes back to staring at his code

21:20 itistoday: zaphar_ps: i hear it needs to be in the "right place"

21:21 i.e., near the end

21:21 zaphar_ps: heh

21:21 found it

21:21 I hate it when you lose track of one. It's such a pain to track it down again

21:31 ynniv: hiredman: Does the XMPP code in clojurebot currently work? I'm having some trouble.

21:35 steiger: is it possible (if so, what is the best way) to implement a map structure that has different behavior on (first) (rest) and (seq), returning something like: (first {1 2 3 4}) -> {1 2} instead of [1 2] ?

21:39 ynniv: I don't know the answer to your question, but your question seems odd. Why would you want a dictionary from (first)?

21:40 itistoday: i think it makes sense, he wants the first key/value pair

21:40 oh wait

21:40 no, it is odd

21:40 ynniv: heh

21:40 itistoday: he's getting that already

21:40 hehe

21:42 steiger: ynniv: i'm just experimenting

21:42 hiredman: ,(key (first {:a 1}))

21:42 clojurebot: :a

21:42 hiredman: ,(val (first {:a 1}))

21:42 clojurebot: 1

21:42 ynniv: you're probably looking for "(apply hash-map (first { 1 2 3 4 }))"

21:42 steiger: hiredman: i'm aware you can do that

21:43 ynniv: is the goal to make a new data type that has an alternate definition of #'seq?

21:43 steiger: the focus of my question is: how to create a custom data structure with a custom (first) and (rest) semantics

21:43 ynniv: something like that, yes

21:45 think of the string data type: (seq str) returns a StringSeq, which is a string of chars

21:45 ,(type (seq "abc"))

21:45 clojurebot: clojure.lang.StringSeq

21:46 steiger: and (first "abc") returns \a

22:17 ynniv: steiger: that seems surprisingly difficult to accomplish. maybe I'm following the wrong trail?

22:17 but I'm knee deep in Java, and not seeing a clear path out

22:21 seq seems to operate on ISeq, which is a java interface that has more methods than I expected (through inheritence)

22:43 steiger: (defn make-data [d] (proxy [clojure.lang.ISeq] [] (first [] (apply hash-map (first d))) (next [] (next d)) (more [] (rest d)) (cons [o] (cons d o)) (count [] (count d)) (empty [] (empty d)) (equiv [a] (= d a)) (seq [] (seq d))))

22:44 I only modified "first" to return a map

22:46 actually, this might do it:

22:46 (defn make-data [d] (proxy [clojure.lang.ISeq] [] (first [] (apply hash-map (first d))) (next [] (make-data (next d))) (more [] (make-data (rest d))) (cons [o] (cons d o)) (count [] (count d)) (empty [] (empty d)) (equiv [a] (= d a)) (seq [] (map #(apply hash-map %) (seq d)))))

22:47 which would look really snazzy in a paste, but i'm tired

22:47 answering questions like this one is a great way to learn a new system, tho

23:01 steiger: ynniv: sorry for the delay

23:01 ynniv: i used the time to format my code to be clojurebot friendly:

23:01 ,(let [make-data (fn [d] (proxy [clojure.lang.ISeq] [] (first [] (apply hash-map (first d))) (next [] (recur (next d))) (more [] (recur (rest d))) (cons [o] (cons d o)) (count [] (count d)) (empty [] (empty d)) (equiv [a] (= d a)) (seq [] (map #(apply hash-map %) (seq d)))))] (seq (make-data { 'a 1 'b 2 })))

23:01 clojurebot: ({a 1} {b 2})

23:01 ynniv: and use #'recur for the first time

23:02 steiger: ynniv: thank you, that's what i wanted. i was trying to extend ASeq, but implementing ISeq really seems to be cleaner

23:03 ynniv: only because you can use convenient clojure funcs like "rest" instead of trying to bridge to java :)

23:03 I am continually impressed by the design and implementation of clojure

23:04 steiger: indeed :]

Logging service provided by n01se.net