#clojure log - Aug 10 2009

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

0:17 rlb: Does clojure have an rfc-822 date parser?

0:19 arbscht: doesn't java have a class for that?

0:19 LauJensen: yep

0:20 arbscht: java.text.SimpleDateFormat, I suppose

0:25 rlb: Sure, though it looked like that might require multiple patterns. I had just wondered if clojure already had something simpler. Anyway, thanks.

0:26 LauJensen: It might - Just not something that I know of. Check clojure.org under libraries maybe

0:27 rlb: I saw the email lib -- perhaps it provides access to the date parser.

0:28 nevermind, that's just for sending

0:34 Anniepoo: clojurebot: paste

0:34 clojurebot: lisppaste8, url

0:34 lisppaste8: To use the lisppaste bot, visit http://paste.lisp.org/new/clojure and enter your paste.

0:49 Anniepoo pasted "with-foo" at http://paste.lisp.org/display/85108

0:51 hiredman: binding

0:51 Anniepoo: probably a very simple question, but I nee dto know what the buzzword is for this

0:51 Thanks!

0:51 hiredman: ,(doc binding)_

0:51 clojurebot: "([bindings & body]); binding => var-symbol init-expr Creates new bindings for the (already-existing) vars, with the supplied initial values, executes the exprs in an implicit do, then re-establishes the bindings that existed before."

0:51 Anniepoo: ah, sweet

0:51 ok, thanks

0:51 that's what I wanted

0:51 hiredman: anyway, binding is for dynamic binding

0:51 Anniepoo: yah, what about concurrancy?

0:52 hiredman: threadlocal

0:52 Anniepoo: ok, cool

0:52 8cD Clojure continues to amaze and delight

0:53 LauJensen: (and it'll keep doing it for a while)

1:23 d2dchat: How can I make a function repeat 2 or any number of times I specify?

1:23 twice*

1:23 like the equivalent of times.do in ruby

1:23 I tried (repeat 2 (my-recursive-function))

1:23 LauJensen: ~(take 10 (repeat 2))

1:23 clojurebot: Gabh mo leithscéal?

1:23 d2dchat: but that didn't work

1:24 hmm what does take do?

1:24 LauJensen: When you say repeat, do you mean execute in sequence?

1:24 d2dchat: it doesn't matter the order, as long as it repeats the function twice

1:25 executes twice

1:25 LauJensen: (dotimes [i 2] (my-func))

1:26 d2dchat: LauJensen: ah! That worked beautifully

1:26 how come repeat doesn't work?

1:26 LauJensen: I have no idea, it works locally

1:26 ~(repeat 2)

1:26 clojurebot: It's greek to me.

1:26 LauJensen: ~(doc repeat)

1:26 clojurebot: Excuse me?

1:26 Fossi: d2dchat: repeatedly

1:26 repeat repeats a value

1:27 ,(doc repeat)

1:27 clojurebot: "([x] [n x]); Returns a lazy (infinite!, or length n if supplied) sequence of xs."

1:27 d2dchat: well for whatever reason repeat didn't execute the function twice

1:27 and dotimes did

1:27 not sure why

1:27 LauJensen: But repeat is not what you want

1:27 I thought you wanted a data sequence

1:27 But may I ask why you're executing something twice?

1:27 Fossi: repeat repeats a value

1:27 d2dchat: well it could be variable.. depends on arity

1:28 Fossi: it does not call a function

1:28 d2dchat: Fossi: gotcha

1:28 LauJensen: my function generates functions randomly based on arity :)

1:28 hiredman: ,(doc repeatedly)

1:28 clojurebot: "([f]); Takes a function of no args, presumably with side effects, and returns an infinite lazy sequence of calls to it"

1:29 d2dchat: hmm, my function has args

1:29 hiredman: d2dchat: wrap it in a thunk

1:30 Fossi: thunkamajunk

1:30 hiredman: ,(take 2 (repeatedly #(+ 1 2)))

1:30 d2dchat: thunk? :)

1:30 clojurebot: (3 3)

1:30 hiredman: ~google thunk

1:30 clojurebot: First, out of 1370000 results is:

1:30 Thunk - Wikipedia, the free encyclopedia

1:30 http://en.wikipedia.org/wiki/Thunk

1:30 LauJensen: d2dchat: Sounds awesome

1:31 d2dchat: hopefully it will be.. Genetic Programming is fun :)

1:31 LauJensen: If you can program a hamster which brews coffee, please let me know

1:31 d2dchat: LauJensen: I'm on it!

1:31 ;)

1:32 Will call is Javaster

1:32 LauJensen: Clamster

1:32 d2dchat: Beanster

1:33 now I have to learn how to preserve state across functions.. do I just pass a parameter around?

1:34 well

1:34 it's the same function

1:34 I will experiment :)

1:34 LauJensen: To be truely functional you have to pass everything around

1:34 Anniepoo: look at 'let'

1:34 d2dchat: Is it better to pass it around?

1:35 LauJensen: http://en.wikipedia.org/wiki/Functional_programming

1:35 Skim that

1:35 d2dchat: Right, I know some erlang

1:35 just wanted to know clojure conventions because it's a hybrid

1:35 but I guess opt for immutability !

1:56 How come this isn't allowed?

1:56 user=> (defn blah [something] (something))

1:56 #'user/blah

1:56 user=> (blah ())

1:57 I'm assuming there is a better way to push an empty list to a function :)

1:57 user=> (defn blah [something] (something))

1:57 #'user/blah

1:57 user=> (blah ())

1:57 java.lang.ClassCastException: clojure.lang.PersistentList$EmptyList cannot be cast to clojure.lang.IFn (NO_SOURCE_FILE:0)

1:57 Fossi: you call something

1:58 hiredman: you are trying to call the empty list as a function

1:58 it isn't

1:58 so surprisingly you get an exception

1:58 d2dchat: Sure, makes sense, is there a way to test that?

1:58 hiredman: lists == function application

1:59 LauJensen: The empty list is '() not ()

1:59 hiredman: ,(list? ())

1:59 clojurebot: true

1:59 hiredman: LauJensen: the empty lists doesn't need quoting

1:59 ,()

1:59 clojurebot: ()

1:59 LauJensen: oh

1:59 Old habit then

2:00 hiredman: ,((fn [something] (something)) 1)

2:00 clojurebot: java.lang.ClassCastException: java.lang.Integer cannot be cast to clojure.lang.IFn

2:00 d2dchat: hmm I think what I want is to create an expression on the fly

2:01 without it evaluating quite yet

2:01 hiredman: that function will give you an exception if you call it with anything that does not implement IFn

2:01 d2dchat: right, make ssense

2:01 LauJensen: ,(def f (fn [x] 5))

2:01 clojurebot: DENIED

2:01 d2dchat: :)

2:02 is it possible to execute [+ 5 6] ?

2:02 hiredman: d2dchat: you seem not to have read any docs, I think it would help if you read some, tried out a few euler problems

2:02 etc

2:02 what the blip.tv videos

2:02 watch

2:13 osaunders: I'm confused. Is Clojure object-oriented? How do I create an object?

2:14 hiredman: no

2:14 clojurebot: rationale

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

2:16 osaunders: Still confused. There are multimethods but it's not object-oriented?

2:16 hiredman: osaunders: multimethods can dispatch on any function

2:17 ~bliptv

2:17 clojurebot: Huh?

2:17 hiredman: ~blipt.v

2:17 clojurebot: It's greek to me.

2:17 hiredman: bah

2:17 ~blip tv

2:17 clojurebot: I don't understand.

2:17 hiredman: ~blip.tv

2:17 clojurebot: blip.tv is http://clojure.blip.tv/

2:17 hiredman: horrible

2:17 anyway watch the videos, read the rationale

2:18 osaunders: I watched the ones for Java Programmers.

2:18 Guess I should move on to the ones for LISP ones.

2:20 "Systems that utilize runtime polymorphism are easier to change and extend. Clojure supports polymorphism at 3 levels. First, almost all of the core infrastructure data structures in the Clojure runtime are defined by Java interfaces."

2:20 hiredman: osaunders: did you see anything with objects and calling methods on objects in the video?

2:21 osaunders: No

2:21 Should I?

2:21 hiredman: would you expect to see such in a video about an oop language?

2:22 have you looked at the rationale page?

2:23 there is a whole website beyond the page on multimethods

2:23 osaunders: Wow, you're almost berating me here.

2:23 hiredman: *shrug*

2:25 osaunders: Does Rich thing Smalltalk is a spaghetti code language?

2:25 *think

2:26 Fossi: osaunders: dunno, maybe ask him? ;D

2:26 osaunders: Fossi: hiredman is having me look at the rationale as if that's going to explain the characteristics of the language.

2:27 Fossi: well, it kinda does

2:27 at least it has some major points on there

2:28 osaunders: Hang on, let me read this fully http://clojure.org/runtime_polymorphism

2:28 Fossi: that being said i'd argue that clojure is mainly functional, but as a lisp, it can't keep you from coding in a OO style if you must

2:28 clojurebot: that is not what I wanted

2:29 hiredman: http://clojure.org/state is also good

2:29 Fossi: only that it would be awkward and prolly slow as well :)

2:30 bbl

2:49 d2dchat: Is there a way to concatinate lists without evaluating them?

2:49 I have a loop that gives me (+) (5) and (6)

2:49 but I want to make it (+ 5 6)

2:50 hiredman: http://clojure.org/sequences

2:52 mikehinchey: concat

2:53 d2dchat: mikehinchey: isn't that just for vectors?

2:54 mikehinchey: no, most functions like that work on any seq

2:54 d2dchat: user=> (concat (5) (5) (5))

2:54 java.lang.ClassCastException: java.lang.Integer cannot be cast to clojure.lang.IFn (NO_SOURCE_FILE:0)

2:55 hiredman: d2dchat: lists are function application

2:55 mikehinchey: if you quote each (5), it will work '(5)

2:55 d2dchat: ahh OK

2:55 makes sense

2:55 hiredman: (5) tries to call 5 as a function

2:56 d2dchat: yup

2:56 user=> (concat '(5) '(5) '(5))

2:56 (5 5 5)

2:56 grr

2:56 stupid mistake :(

2:56 hiredman: please read the url I pasted

2:56 sequences and sequence functions are very import in clojure

2:57 d2dchat: reading through it

4:16 mikehinchey: What does #= do? I thought it was a reader macro for evaluation, but #=(if true 1 2) fails.

4:17 hiredman: read the exception

4:17 mikehinchey: "can't resolve if"

4:17 hiredman: the evaluation at readtime is very limited

4:18 #=() is typically just used to call contructors

4:18 ,#=(java.util.ArrayList. (1 2 3))

4:18 clojurebot: #<ArrayList [1, 2, 3]>

4:19 hiredman: so you can have the reader read an ArrayList

4:19 constructors

4:19 mikehinchey: ok, that's fine, it's not what I wanted then

4:20 hiredman: ,#=(System/exit 1)

4:20 clojurebot: System

4:20 hiredman: bah

4:22 mikehinchey: thanks

5:42 alrex021: Is there any online paste that has clojure syntax highlight?

5:43 Chousuke: gist.github.com

5:45 alrex021: thx Chousuke

5:46 I am trying to get my head around conditional flow in clojure. I have a following code snippet: http://gist.github.com/165113

5:47 chat-view is meant to check if session has :login key, if not it must add it. After that it must continue on to return the html fragments

5:47 Chousuke: hm

5:47 then your problem there is that (layout... is the else branch

5:48 alrex021: yup, exactly...

5:48 how do I setup a control flow so that (layout ... is always ran

5:49 Chousuke: you need (if-not pred then-branch nil)

5:49 or alternatively, (when-not pred then-branch=

5:49 )*

5:49 which is just a shortcut for the above :)

5:50 alrex021: hmm, I am not following 100% :) .. what is wrong wih my if-not?

5:50 well...hmm layout falls in else part?

5:50 Chousuke: if-not requires both the then-form and else-form

5:50 and your layout is in the place where it expects the else-form

5:52 alrex021: but my (layout ... part should be ran regardless of the if-not outcome...

5:52 Chousuke: btw, it looks like your session-assoc is a function containing a dosync... I think it's better style to not have dosyncs hidden in the actual "alter" functions

5:53 alrex021: hmmm, its compojure's session-assoc which they advise to use

5:53 Chousuke: ah, hmm. in that case, I guess there's no helpong it :/

5:53 alrex021: and yes, it internally does an alter on the session ref

5:54 Chousuke: I just think one should keep most of the logic in pure functions. .)

5:55 eg. instead of a side-effecting function, I think it'd be better to have a pure function like (alter-session assoc :login whatever) designed to be wrapped in a dosync

5:55 arbscht: you could probably refactor that with the mutation in some kind of chat-login-controller function around chat-view

5:55 Chousuke: but I guess if it's the framework that's providing it to you, you should use it.

5:55 arbscht: a -view altering the session should ring bells, even in compojure

5:56 alrex021: interesting

5:57 Chousuke: Anyway, you want to do (when-not guest (session-assoc ...)) (layout ...)

6:01 alrex021: hhmm still doesn't seem right http://gist.github.com/165113

6:02 prob is when (session-assoc ..) runs it doesn't bind it to guest in local block

6:02 that my guess

6:03 arbscht: oh, you want to use the updated session in chat-view

6:04 that would need a new request

6:05 alrex021: hmm, interesting... so I would need to exit the function and come back in?

6:05 would'n if-let help with this to maybe rebind guest to new value for new session :login

6:06 am I just making this look so difficult or is it really this difficult?

6:06 arbscht: you're conflating clojure flow with compojure+http flow :)

6:08 hm, compojure docs are offline? :/

6:08 alrex021: what docs? :)

6:08 arbscht: oh, there was a secret site at preview.compojure.org

6:08 Chousuke: arbscht: ah, right.

6:09 arbscht: try (let [guest (or (session :login) (session-assoc :login (guest-account)))]

6:10 alrex021: ok this worked....http://gist.github.com/165113

6:11 for some reason I still think thats not really the cleanest way

6:11 So if-not guest, then add :login to session and then redirect back into the view via http call

6:12 arbscht: yes, that login check and redirect should go in a non-view function

6:12 Chousuke: yeah

6:12 alrex021: I see, that makes sense....the mutable bit so then view would have no side-effects....does that sound right?

6:13 arbscht: right

6:13 Chousuke: and in general, doing non-view stuff in the view, mutable or not.

6:14 alrex021: but would the view call this func that has side-effects...?

6:14 Chousuke: the other way around I think

6:14 arbscht: the router would dispatch to the -controller (or whatever), which would call the appropriate view after determining login etc

6:14 Chousuke: you write the function that checks the login, alters the session if needed, and then calls the view function.

6:15 alrex021: oh I see...that makes very much sense...thx I'll give that a try quick

6:43 Ok I have a new working version that separates the pure function from one that alters the mutable data... http://gist.github.com/165113

6:44 only question I have is....is it ok for the chat-view to still have a check on guest and then if required to redirect to login-controller to perform login then redirect to chat

6:45 arbscht: that's hard to make sense of without seeing the routes

6:46 alrex021: sorry about that, I just added the routes.... http://gist.github.com/165113

6:47 doesn't seem clean that my chat-view actually deals with login check

6:48 arbscht: right

6:48 I'd suggest associating "/chat" with a controller, rather than a view, since it may affect the session state

6:49 alrex021: so just anotherer level of indirection?

6:49 arbscht: essentially, yes

6:50 alrex021: chat-controller ....checks login and takes you to chat-view

6:50 this way chat-view has no side-effects

7:00 arbscht: I have made the changes now and it looks much better. The chat-controller now holds the control logic and then delegates to chat-view pure function .. http://gist.github.com/165113

7:04 arbscht: very good :)

7:05 having the login-controller only redirect to "/chat" seems too specific. you could probably generalize it further somehow

7:06 alrex021: yup, pass in :next param maybe

7:06 arbscht: that certainly cleaned up the view nicely, though

7:07 alrex021: thx

7:07 arbscht: if session-assoc fails for some reason (say, disabled cookies), could you get caught in a redirect cycle?

7:16 alrex021_: I added next-url param to login-controller so now its more generic...

7:16 other controllers could redirect to it with next-url param that indicates where to go after login

7:17 "f session-assoc fails for some reason (say, disabled cookies), could you get caught in a redirect cycle?" -> very good question....that is a big prob

7:19 I'd hope that then an exception is raised or something to break the flow and then I could redirect to error page

7:20 Again, this is just Simple Chat prog I;m building to learn more about clojure, conurracy api, ..etc

7:22 Chousuke: hm

7:23 well, it should be rather easy to check if session-assoc failed or not.

7:23 just try and see if the value you put there is present.

7:24 if not, redirect to an error page from the controller.

7:24 alrex021_: yup, that makes sense..

7:25 so check (session :login) after assoc call

7:25 if not there, well then cookies prob not enabled...so show error page

7:39 arbscht: sorry, what I mean is if the client rejects the session data in the response, it would be like a new visitor after the redirect

7:40 * arbscht wonders if it's time for a #compojure channel :-)

8:43 weissj: is there a way to define functions, etc in something other than the current namespace? seems strange to keep switching ns, doing a defn, switching again, etc

8:46 cark: i usually recompile the whole file, which has the ns form on top

8:47 weissj: cark: not sure i understand

8:47 cark: are you using emacs ?

8:47 weissj: no

8:47 cark: how are you developing ?

8:47 weissj: clojure-dev (eclipse)

8:47 cark: oh i see

8:47 i can't help then =(

8:48 weissj: this question isn't an environment question, it's a clojure lang question

8:48 cark: well it's a about your developement process

8:48 weissj: my file has the ns form at the top, but i want to defn something in that file that goes in a different ns

8:48 cark: oh

8:48 that seems strange

8:49 weissj: cark: yeah, it's using clj-record, which is like ruby on rails' ActiveRecord

8:49 it creates namespaces for each table and creates functions for them

8:49 using macros

8:49 smoonen: weissj -- does (intern) do what you want?

8:50 weissj: ,(doc intern)

8:50 clojurebot: DENIED

8:50 weissj: smoonen: yeah i think that's it, thanks!

8:51 smoonen: wait, maybe not. it creates vars, what about functions?

8:53 smoonen: weissj -- seems to work if I pass it a lambda

8:53 (intern 'user 'f (fn [x] (inc x)))

8:54 weissj: smoonen: huh, ok, not quite how i imagined it would work, but i think that'll do it

8:54 i was expecting something more like "let"

8:55 sorta like (let-ns ns (block))

8:56 in-ns switches ns, but does it permanently, it doesn't wrap anything

8:56 cark: you may use the binding form

8:57 (binding [*ns* ..]

9:00 weissj: cark: ok let me give that a shot

9:06 cark: doesn't work =/

9:06 because it's a read-time thing instead of compile-time

9:35 slaney: is clojurebot a opensouce project that I can use myself?

9:36 arbscht: slaney: http://github.com/hiredman/clojurebot/tree/master

9:36 slaney: ah, great thanks

9:48 ericthorsen: What is the equivalent to memfn for static methods in a java class?

9:50 Chousuke: (doc memfn)

9:50 clojurebot: "([name & args]); Expands into code that creates a fn that expects to be passed an object and any args and calls the named instance method on the object passing the args. Use when you want to treat a Java method as a first-class fn."

9:50 Chousuke: hm.

9:50 ericthorsen: ...if I want to treat a static method as a first-class fn

9:50 Chousuke: I'd just use #(Foo/static %1 %2 %3...)

9:52 ericthorsen: Chouser: yes...that would work...too simple. I guess I was hoping Foo/static would just return something I could use.

10:32 weissj: is there something like "let" for namespaces (ie, execute this block in this namespace)

10:33 seems like the only option is to use in-ns which changes ns permanently (until you change it back)

10:33 Chouser: I've wondered the same thing.

10:33 smoonen: couldn't find anything. you could definitely write your own via macro.

10:34 weissj: so the macro would just save the value of *ns* and switch it back after the block runs?

10:34 Chouser: The most obvious interface to me would be just (defn other.ns/foo ...) but that appears to be explicitly unsupported

10:34 weissj: Chouser: yeah i tried that :)

10:35 i would have thought in-ns would have a different form for that

10:43 Anniepoo: wondering what constitutes real metadata

10:44 I've got a bunch of code that shoves around vectors that represent 3D boxes

10:46 the boxes have to actually come from a list with other info

10:47 in a structmap. Eventually I'll want to get back to the structmap. Is it kosher to shove it into metadata?

10:49 Chouser: does it seem to anyone else that the questions in here keep getting harder?

10:49 Anniepoo: LOL

10:50 we're learning!

10:50 Chouser: Anniepoo: I would imagine that's ok.

10:50 Anniepoo: ok, cool

10:50 Chouser: Using metadata like that is probably ok, I mean. Learning is unacceptible.

10:50 Anniepoo: I know from bitter experience with XML attributes that mixing metadata and data willy nilly is a bad thing

10:51 I'm actually solving the knapsack problem at the moment.

10:52 Chouser, can you solve the knapsack problem for me? ;c)

10:58 Chouser: 0-1 ? one constraint?

10:59 Anniepoo: I've got what actually isn't the knapsack problem (or I wouldn't be solving it), I need to exactly pack an AABB with

10:59 AABB's drawn from a list. I also have available, fortunately, any sized AABB up to a certain maximum dimension on each side

11:00 (AABB = axis aligned bounding box, a non rotated rectangular prism)

11:01 Chouser: 3D?

11:01 Anniepoo: yes

11:02 the key is the variable sized one. I pack the thing with the biggest piece that will still fit, over and over, until the remaining chunks are under the limit of the rubber cube

11:16 lisppaste8: cgrand pasted "microbenchmark: PersistenthashMap2$TransientMap" at http://paste.lisp.org/display/85126

11:21 Chouser: cgrand: wow. care to summerize the difference, or should I just keep trying to read the code?

11:26 cgrand: Chouser: ideas from rhickey: no leave nodes and inner nodes aren't packed as soon as they are half full

11:28 Chouser: cgrand: version 3 will use new new? :-)

11:30 cgrand: maybe

11:35 cemerick: Chouser: welcome back :-)

11:35 (if you had actually gone somewhere, that is)

11:36 Chouser: cemerick: thanks! family "vacation".

11:37 cgrand: so ArrayNode instead of LeafNode?

11:41 cgrand: Chouser: ArrayNode instead of FullNode and BitmapIndexedNode now contains an interleaved array of keys and values (if the key is null then the value is an INode))

11:51 duplo: Is there a webpage that explains "if-let" more than the clojure page?

11:52 drewr: duplo: not sure; what are you confused about?

11:58 duplo: drewr: The explanation just seems a little terse to me.

11:59 drewr: But maybe I need to read up a bit on macros for it to make more sence.

12:04 arohner: duplo: ,(source if-let)

12:04 drewr: duplo: it's a substitution for a common idiom (let [x true-or-false] (if x :foo :bar))

12:07 duck1123: I use it more often to test if the let contains something, or is nil

12:09 I just wish if-let would allow me to have multiple let statements. (perhaps with AND semantics for each statement)

12:09 Chousuke: that shouldn't be too difficult to implement.

12:10 would be a backwards-compatible change too

12:11 Chouser: are you sure 'and' is what you'd want?

12:11 duck1123: not sure. that, or just like a normal let, with the if only applying to the last one

12:14 the latter is closer to how I've tried to use it, before I got the error

12:15 but in those cases, each statement in the original let was true anyway

12:17 Chousuke: I suppose it would be possible to have (if-let :any [x foo y bar] ...)

12:18 (and :all too)

12:23 duck1123: Chousuke: would :last be the default then?

12:23 Chousuke: duck1123: maybe.

12:25 I'm still wondering whether it really makes sense, though.

12:25 to extend if-let like that I mean.

12:25 cemerick: I think not, if only because I'd expect :all to be the default. :-/

12:25 ...and others would expect :first

12:26 and then someone would suggest a way to specify alternate schemes, like :alternating

12:26 yeah, that was snark ;-)

12:27 duck1123: I think :last is the best one truthfully. That's the one that fit's my use case when I ran into this yesterday

12:28 Chouser: this is all to avoid one more nesting of 'let'?

12:28 duck1123: (let [a foo] (if-let [b bar] ... )) becomes (if-let [a foo b bar] ... ) but I can see how people might want :all as well

12:50 unlink: Where can I find a list of all the new transient methods?

12:50 Chousuke: hmm

12:51 find-doc transient will probably find you them all

12:52 unlink: Thanks.

12:53 So assoc! is how I mutate arrays?

12:54 Chousuke: vectors, and yes

12:54 unlink: right...transient vectors

12:55 tomoj: is this sane? (map #(vec [:foo %]) coll)

12:55 Chousuke: making a vector out of a vector is a bit weird :P

12:55 tomoj: that's what I thought

12:55 but not sure how to do it without "vec" there

12:56 since otherwise the map will try to call the vector as a function

12:56 Chousuke: you probably want to use a real lambda (map (fn [x] [:foo x]) coll)

12:56 tomoj: aha

12:56 thanks

12:57 unlink: Do transients scream 'leaky abstraction' to anyone else? Persistent data structures enforce immutability, but transients come with a caveat -- don't bash in place -- which is not technically enforced and easy to get wrong

12:57 Chousuke: #(foo) is short for (fn [] (foo)), which trips people up sometimes.

12:57 tomoj: ah, I see

12:57 there is no shortcut for (fn [] foo) I guess?

12:57 Chousuke: no

12:57 though you can do #(do foo)

12:58 tomoj: rather use a real lambda I think

12:58 Chousuke: unlink: I think it's possible it might become enforced at some point

12:59 though I suppose enforcing it would have to cost something

13:00 but I don't think it's a problem. Transients are supposed to be used carefully to begin with.

13:00 unlink: The second you start designing your programming language with warnings that a construct needs to be "used carefully", you have already failed.

13:01 Chousuke: well, I mostly meant that you should first design the algorithm with persistents, and then swap in transients if performance is a problem.

13:02 unlink: I agree that they should not be the go-to idiom for designing clojure programs, but the "incidental" mutability of transient values is a very real part of the API of clojure.

13:02 And no amount of warning will take that away.

13:02 (Unless technically enforced)

13:03 Chousuke: it'd help if the old values were invalidated, but I think that would cost too much in terms of performance.

13:04 you'd need a flag for every interim value to indicate whether it's been used or not.

13:04 tomoj: hmm.. I thought clojure was big on always enforcing immutability except through a few very specific APIs

13:05 well, and all of Java

13:05 unlink: Which could kill cache locality. You're right -- it would negate part of the benefit of transients. As they stand, transients expose an enormous correctness abstraction leak.

13:05 however.

13:06 What makes this dangerous is that transients support the same read API as persistents.

13:06 Chousuke: hmm

13:06 I don't think that

13:06 ... will be a problem

13:08 unlink: Perhaps this correctness issue could be culturally enforced. I know however I would be more comfortable if there was a safety net that ensured that I could never be handed a transient value that could change under my feet and still read like a persistent without warning.

13:09 Chousuke: well, transients can't be used outside the thread they were created in.

13:10 so even if you happen to get a transient as input to a read-only function, it's not going to change between two reads unless you also write to it through the transient api.

13:13 unlink: Right, that is an essential safety measure.

13:13 Chousuke: hmm, I wonder if transients could cache the most recent value of "this" and check it upon edits.

13:14 wait, that makes no sense.

13:14 * Chousuke is thinking of persistent collections :(

13:20 cemerick: would it really be bad if a flag were set on every transient instance that had been used as the basis of a mutation operation (assoc!, conj!, etc)?

13:20 yeah, I guess it would.

13:21 Chousuke: some indirection could work :P

13:22 cemerick: but defeat the point, at least somewhat

13:22 Chousuke: yeah

13:23 cemerick: I'm happy enough to let the pitfalls be documented, and be done with it.

13:23 you can't blame the rope when you hang yourself

13:24 e.g. (let [a ..some transient..] (assoc! a :foo 5) (assoc! a :bar 6)) reflects some incredibly misguided thinking in general, so protecting against that is a tough order

13:28 (I was called a 'lisp weenie' over the weekend. Maybe this is the kind of attitude that prompted that. :-P )

13:29 Chousuke: I'm always wary of function bodies that contain more than one expression :P

13:30 d2dchat: How do you do the equivalent of && in a boolean expression?

13:31 Chousuke: use (and ...)

13:32 d2dchat: Chousuke: thx! I wonder why I couldn't find that in the API

13:33 Chousuke: well, and is not the easiest word to search for :P

13:33 rather, it's a bit too easy to find :)

14:06 kotarak: How can I parse xml files containing UTF-8 characters with clojure.xml/parse? The characters always turn to '?'.

14:09 gcv: what's the right way to determine the type of a Clojure value? I'm looking for an equivalent to (class x) which would return, e.g., :vector instead of clojure.lang.LazilyPersistentVector.

14:11 hiredman: gcv: why would anything return :vector

14:12 kotarak: gcv: quick hack http://paste.pocoo.org/show/133501

14:12 tomoj: (count (filter ...)) is not good with laziness, is it?

14:12 kotarak: but why do you need it?

14:12 tomoj: no

14:12 hiredman: tomoj: how could count be lazy?

14:13 tomoj: well, I mean, does it need to load the whole seq into memory at once, or not?

14:13 kotarak: obviously

14:14 tomoj: guess I need to write filter-count then

14:14 clojurebot: filter doesn't stop

14:14 gcv: kotarak: yeah, I was hoping to get a quick lookup... I'm working on writing Clojure values to Berkeley DB, and I need type tags, so I don't want to worry about the various vector types

14:15 kotarak: gcv: use multimethods with IPersistentMap etc, as dispatch values

14:15 hiredman: ,(ancestors [])

14:15 clojurebot: nil

14:15 hiredman: er

14:15 ,(ancestors (class []))

14:15 clojurebot: #{java.lang.Iterable java.lang.Runnable clojure.lang.Obj clojure.lang.IPersistentVector java.util.Collection clojure.lang.IFn clojure.lang.Seqable clojure.lang.Indexed java.util.List clojure.lang.AFn clojure.lang.Streamable java.lang.Object java.util.concurrent.Callable clojure.lang.IMeta java.util.RandomAccess clojure.lang.IObj clojure.lang.Sequential clojure.lang.IPersistentStack java.io.Serializable clojure.lang.Revers

14:16 gcv: ancestors!

14:16 hiredman: thank you, that's the function I needed

14:16 hiredman: clojure.lang.IPersistentVector msot likely what you want

14:16 gcv: hiredman: judging by the implementation of vector?, yes it is

14:17 d2dchat: can someone help me figure out why expression is not evaluating properly?

14:17 http://pastie.org/private/kax4t0yrhw2caujppupa

14:18 hiredman: d2dchat: what do you mean "not evaluating properly"

14:18 d2dchat: I'm getting an exception at the very end

14:18 Exception in thread "main" java.lang.ClassCastException: clojure.lang.LazySeq cannot be cast to clojure.lang.IFn (darwin.clj:0)

14:19 hiredman: so somewhere you are trying to call a lazy-seq as a function

14:19 d2dchat: do (/ 5 6) expressions turn into lazy sequences if you are concat'ing them?

14:20 hiredman: sure

14:20 but (/ 5 6) is also not a function

14:20 so you cannot call it

14:20 d2dchat: but you can eval it ?

14:20 hiredman: sure

14:21 d2dchat: I would really suggest you spend more time getting to know the language instead of just jumping and trying to write genetic algorithms

14:21 d2dchat: hehe

14:21 I learned a lot from this exercise, but I agree ;)

14:21 I think I got far though!

14:24 hiredman: can you explain to me why when I (println expression) on line 39, I get my desired output

14:24 but when I try to println outside of that context on line 48 it throws an exception?

14:25 isn't it just passing that around?

14:25 Chousuke: btw, rather than quoting each of the inner lists, you can just quote the vector :P

14:26 hiredman: d2dchat: in the paste there are only 25 lines

14:26 d2dchat: I didn't think I was using any vectors... don't vectors use [] notation?

14:26 hiredman: whoops haha I have comments in my code

14:27 hiredman: are you for real?

14:27 do you see all the [] in your code?

14:27 d2dchat: hiredman: Yes, but I'm using them for parameters?

14:27 hiredman: line 16 = line 39

14:27 line 25 = line 48

14:28 sry for the confusion

14:28 OOOHH

14:28 I see what you're saying

14:28 lol

14:28 Chousuke: thx :)

14:29 hiredman: d2dchat: somewhere you are trying to call a sequence like it is a function

14:29 d2dchat: Chousuke: made my API much nicer :)

14:30 Chousuke: hmm I get an exception now running with this: '[+ - / *]

14:30 hiredman: since you are building lists (I guess, I really don't want to step through this line by line) I imagine expression is a list/sequence

14:30 d2dchat: Exception in thread "main" java.lang.ClassCastException: clojure.lang.PersistentList cannot be cast to clojure.lang.IFn (darwin.clj:0)

14:30 Chousuke: I think it's in the rand-item

14:30 hiredman: on line 16 you try and call expression as a function

14:31 is it?

14:31 d2dchat: hiredman: right, then I try to quote line 16 and it just returns (expression)

14:31 and when I try evaling that

14:31 it is like what??

14:31 hiredman:

14:31 please learn clojure first

14:31 please

14:32 d2dchat: lol, I didn't realize this room was reserved for complex questions.. sry.. I will do more research on my own :(

14:33 I understand that it can be annoying to answer the same questions all the time, but just thought I could get some quick reference

14:37 cemerick: d2dchat: simple questions are very welcome here, but trying to debug blobs of application code through irc isn't particularly easy

14:38 d2dchat: cemerick: agreed. I'm very appreciative of the help I received :)

15:26 weissj: does anyone know a way to add command history to the repl?

15:27 Chouser: I like rlwrap

15:27 smoonen: weissj -- I use http://utopia.knoware.nl/~hlub/uck/rlwrap/

15:27 kotarak: there is jline (for completeness sake)

15:27 gcv: weissj: SLIME :)

15:28 weissj: hm ideally i could use it in eclipse, but i doubt that clojure-dev supports any of these

15:28 kotarak: And VimClojure Repl also does history

16:43 replaca: tomoj, kotarak: (count (filter #(...) ...)) isn't lazy, but it doesn't hold head either. So you can run it without blowing memory.

16:44 for example, (time (count (filter #(zero? (rem % 2)) (range 1000000000)))) runs without any problem, with java staying at about 210MB on the billion item list.

16:44 kotarak: replaca: depends on the second ...

16:45 tomoj: replaca: huh, and it's actually faster than the custom filter-count I wrote

16:45 :)

16:46 kotarak: tomoj, replaca: (let [r (range 1000000000000)] (count (filter #(zero? (rem % 2)) r)))

16:47 tomoj: isn't that holding the head?

16:48 kotarak: tomoj: bingo. If you aren't charge of the seq you get, you cannot guarantee that (count (filter...)) does not blow up.

16:48 replaca: kotarak: that's cause you're holding head with the let

16:49 tomoj: luckily I'm in charge :)

16:49 replaca: that's just always a problem with lazy seqs!

16:50 kotarak: tomoj: and you buy that with computing time. If you want to use the actual seq again without count, you have to recompute it again.

16:51 tomoj: I don't :)

17:28 Anniepoo: clojurebot: paste

17:28 clojurebot: lisppaste8, url

17:28 lisppaste8: To use the lisppaste bot, visit http://paste.lisp.org/new/clojure and enter your paste.

17:35 Anniepoo pasted "optional element in list" at http://paste.lisp.org/display/85162

17:35 Anniepoo: silly style question

17:36 Chousuke: hm

17:37 maybe syntax-quote could help you?

17:38 ,`(1 2 ~@(do nil) 4)

17:38 clojurebot: (1 2 4)

17:38 Chousuke: ,`(1 2 ~@(do '(3)) 4)

17:38 clojurebot: (1 2 3 4)

17:38 hiredman: depends what you mean by "build a list"

17:39 you mean just have a list literal that conditionaly includes some element?

17:39 Anniepoo: well, I'm calling a bunch of functions in order and surrounding them with list

17:39 hiredman: :(

17:39 sounds horrid

17:40 Anniepoo: well, I'm interacting with an imperative system I can only talk to over http in 2K chunks\

17:40 and can't use more than 64K memory

17:40 hiredman: ,(for [x [#(inc 1) #(inc 3) #(inc 4)]] (x))

17:40 clojurebot: (2 4 5)

17:42 hiredman: so you know which element you want to conditionally include?

17:42 Anniepoo: ,(list "foo" (if (< 3 7) "maybe") "bar")

17:42 clojurebot: ("foo" "maybe" "bar")

17:42 Chousuke: ,(for [x [inc dec not identity] :let [z (x 1)] :when z] z)

17:42 clojurebot: (2 0 1)

17:43 Anniepoo: but that's broken for

17:43 ,(list "foo" (if (< 8 7) "maybe") "bar")

17:43 ,(list "foo" (if (< 8 7) "maybe") "bar")

17:43 clojurebot: ("foo" nil "bar")

17:44 Anniepoo: expecting ("foo" "bar")

17:44 kotarak_: ,(concat (list 1 2) (when false (list 3)) (list 4))

17:44 clojurebot: (1 2 4)

17:44 hiredman: :(

17:44 concat

17:44 Anniepoo: yah, that looks more right

17:45 make a sublist for each piece and concat them

17:45 hiredman: what is the issue with filter?

17:45 Anniepoo: not one

17:45 hiredman: ,(remove nil? (list "foo" (if (< 8 7) "maybe") "bar"))

17:45 clojurebot: ("foo" "bar")

17:46 Anniepoo: this just felt 'horrid' and un-clojure-like

17:46 ah, cool

17:46 hiredman: well, it isn't

17:47 Anniepoo: this one seems closest to expressing the idea of the code

17:47 ,`(1 2 ~@(do nil) 4)

17:47 ,`(1 2 ~@(do nil) 4)

17:47 clojurebot: (1 2 4)

17:48 hiredman: sure, but are you using a literal or not, and willyou always be using a literal?

17:49 if the list of strings is built, it is possible to put the logic in the function that builds the list

17:49 Anniepoo: no, I'm not using literals, I'm calling a different function for each element

17:49 hiredman: the other thing to keep in mind is:

17:49 ,(str nil)

17:49 clojurebot: ""

17:49 kotarak_: For strings when should be sufficient

17:49 ,(str "a" (when false "b") "c")

17:49 clojurebot: "ac"

17:50 hiredman: ,(apply str (list "foo" (if (< 8 7) "maybe") "bar"))

17:50 clojurebot: "foobar"

17:50 Anniepoo: wanted ("foo" "bar")

17:50 hiredman: Anniepoo: but the list, not the elements of the list, is the list a literal or constructed

17:50 Anniepoo: hmm... maybe I'm not understanding that question

17:51 I'm calling list

17:51 hiredman: (list (foo 1) (bar 2)) or (somefunction-that-produces-a-list some-input-data)

17:52 do you think you will always produce the list that way? is it possibly you might switch to some other list producing function in the future (pull the list from a database, or over the network, or whatever)

17:52 Anniepoo: the first

17:53 no

17:53 hiredman: filter/remove will work for both cases (list …) and a list produced via some other method

17:53 Anniepoo: the list represents a series of commands to the external system

17:53 I'm writing a compiler for that system

17:55 this is the convert-sane-representation-to-sequence-of-cmds-that-instantiates-it-on-what-amounts-to-hardware

17:57 hiredman: I think anything you do will reimplement filter

17:57 Anniepoo: ok, cool

17:57 hiredman: you want to conditionally remove items from a list

17:58 Anniepoo: just wondered if there was an idiomatic way

17:58 rich hickey said at one point to try to stay close to expressing the idea of the code

17:59 hiredman: something like (remove nil? (list "foo" (if (< 8 7) "maybe") "bar"))

17:59 Anniepoo: and the idea here in English is 'if 3 < 7 then add the third item'

17:59 hiredman: using when instead of if

17:59 Anniepoo: yah, looks like it

17:59 thanks

17:59 hi Mike!

17:59 mikehinchey: hi Annie

18:00 hiredman: if you make whatever recieves the list tolerant of nils in someway (silently ignore them?) then you don't need the remove

18:00 Anniepoo: true

18:01 if I do that, what I should do is some 'flatten' operation

18:01 hiredman: ,(doc flatten)

18:01 clojurebot: "([x]); Takes any nested combination of sequential things (lists, vectors, etc.) and returns their contents as a single, flat sequence. (flatten nil) returns nil."

18:01 tomoj: anyone heard anything about continuation-based web dev in clojure? reading an old thread from december, but it died

18:02 Anniepoo: yah, oddly, that's the solution here

18:04 ,(flatten ("foo" '() "bar"))

18:04 clojurebot: java.lang.ClassCastException: java.lang.String cannot be cast to clojure.lang.IFn

18:04 tomoj: ,(flatten '("foo" () "bar"))

18:04 clojurebot: ("foo" "bar")

18:04 Anniepoo: ,(flatten '("foo" () "bar"))

18:04 clojurebot: ("foo" "bar")

18:04 Anniepoo: thanks tom

18:04 whoo hoo, that's right

18:04 glad I asked

18:05 thanks all

18:46 prospero_: what allows *print-length* to be changed via set!

18:46 if I try to change a def of my own, I get a "can't change root binding with set" error

18:47 hiredman: prospero_: the repl is executed inside a binding

18:48 prospero_: yes, but if I call "set! *print-length* 10" outside the repl, it doesn't throw an exception

18:49 it doesn't do anything either, I know, but I'm just wondering why it doesn't throw an exception

18:50 hiredman: it's possible that the binding is created by the compiler

18:50 *shrug*

18:50 I never use set!

18:51 prospero_: well, maybe you can suggest a decent way to handle this:

18:51 I'm trying to handle memory management on the gpu

18:51 hiredman: Oh

18:51 prospero_: and I want to be able to define a threshold, above which it collects unused textures

18:52 this should be a global setting, not necessarily within a binding

18:52 so set! seems like a decent candidate

18:52 hiredman: uh

18:52 prospero_: but maybe not?

18:52 hiredman: have you read the docs on set! ?

18:53 prospero_: maybe not as carefully as I should have

18:53 hiredman: set! only works on threadlocaly bound vars, which are generally setup via binding

18:53 prospero_: I was more going on how it's used with *print-length*

18:53 Anniepoo: prospero, it might make sense to make it an atom. You're trying to make something mutable

18:53 hiredman: prospero_: http://clojure.org/vars#toc1

18:53 prospero_: anniepoo: that makes sense, it just seemed cleaner if it weren't wrapped in an atom or ref

18:54 Anniepoo: (def texture-mem-threshold (atom 7500000))

18:54 osaunders: How do I split a string into characters?

18:54 _mst: would alter-var-root be an option maybe?

18:54 Chousuke: osaunders: calling seq on it will return a seq of characters

18:54 _mst: I've never seen it used much in the wild so I'm unsure...

18:54 prospero_: hiredman: making it thread-local would be fine, actually

18:54 Chousuke: ,(seq "foo")

18:54 clojurebot: (\f \o \o)

18:54 prospero_: I'll take a second look at the docs

18:54 hiredman: prospero_: so then use binding

18:54 osaunders: Chousuke: Thanks :)

18:55 Anniepoo: somebody explained to me, when I asked similar question, that the @mem-threshold had a salutary effect of warning that it's mutable

18:55 because of the @

18:55 Chousuke: if you use binding, it's not really mutable.

18:55 prospero_: hiredman: fair enough

18:55 Chousuke: it can just vary depending on the dynamic environment.

18:55 hiredman: Chousuke: tell that to set!

18:56 Chousuke: hiredman: set! is evil and shall be ignored.

18:56 hiredman: :D

18:56 that's what I like to hear

18:57 Anniepoo: Chousuke has a set of tights and a cape with a no-@ symbol and calls himself immutable man 8cD

18:57 prospero_: ok, so I guess I'll leave set! to *print-length*

18:57 clojurebot: count

18:57 Chousuke: but really, set! is for setting stuff at the repl, and for java fields :)

18:58 hiredman: ,(macroexpand '@x)

18:58 clojurebot: (clojure.core/deref x)

18:58 hiredman: no @ needed

18:58 deref should yeild immutable values anyway

18:59 Chousuke: though my syntax-quote macro uses a thread-locally bound var as a "mutable".

18:59 but it's not shared between syntax-quote calls so it's fine.

18:59 hiredman: :(

19:00 Chousuke: in fact, an atom wouldn't work since I'd have to take care of resetting it, and then you couldn't use the syntax-quote macro in two threads at the same time :/

19:02 I'm not using set! though.

19:02 it kept throwing exceptions and after a while I got alter-var-root to do what I needed.

19:05 actually, I wonder

19:05 now that I tested it, it's not doing what I want :(

19:12 and now it seems to work just right, when I changed it back to using set! ...

19:13 * Chousuke is thoroughly confused

19:14 hiredman: wonder if it would make sense to have an ur-clojure reader and compiler that work with ArrayList and HashMap for bootstrapping cinc

19:15 Chousuke: ...

19:15 I think I will just stop trying to be clever with vars and pass down the autogensym map as a parameter...

19:15 hiredman: if all the Persistent collections are written in clojure

19:16 Chousuke: well, the old clojure reader will probably work?

19:19 hiredman: I guess

19:20 I guess LispReader.java isn't that bad

19:24 Chousuke: gahh

19:24 it was laziness that was causing the trouble.

19:25 hiredman: clojurebot: laziness?

19:25 clojurebot: Pardon?

19:25 hiredman: clojurebot: laziness is what will save us all

19:25 clojurebot: Alles klar

19:26 Chousuke: now it all works beautifully

19:26 clojure.core> (syntax-quote (foo# ~@(list 1 2 3) foo#))

19:26 (foo__auto__7666 1 2 3 foo__auto__7666)

19:26 hiredman: nice

19:26 Chousuke: I just have to get my reader into somewhat usable state too.

19:27 currently, it can read itself!

19:27 hiredman: that is syntax-quote as a macro?

19:27 Chousuke: yes

19:27 (producing, unfortunately, not quite correct output ;()

19:27 (the reader, that is)

19:28 syntax-quote seems to be working

19:28 hiredman: what does the macroexpand to?

19:28 Chousuke: (clojure.core/first (clojure.core/list (clojure.core/concat (clojure.core/list (quote foo__auto__7676)) (do (list 1 2 3)) (clojure.core/list (quote foo__auto__7676)))))

19:29 hiredman: :(

19:29 Chousuke: that's what syntax-quote does anyway :)

19:29 just read-time, so you never see it.

19:29 hiredman: yeah

19:30 Chousuke: the (first (list ..)) at the start could probably be done away with, but it simplifies the implementation.

19:30 hiredman: I think it is a good idea to keep computation in the same place it was before

19:30 read → compile → run

19:31 I guess it doesn't make a huge difference

19:34 Chousuke: http://github.com/Chousuke/clojure/tree/clojure-reader here's what I have now (probably easiest to look at the commits page)

19:34 it's not usable yet at all, and I may destroy the branch at any time, but it's there if you're curious :P

19:36 jwhitlark: Is there anyway to create an interface other than gen-interface? I need to dynamically create and pass an interface (not a class) to a function.

19:39 Chousuke: I'm not aware of any dynamic way of creating interfaces :/

19:39 would the function use reflection or something to figure it out, then?

19:40 jwhitlark: kinda. It's for the java lib for dbus. You need to pass in an interface that tells what the remote object implements.

19:40 Of course, dbus provides that information, but I've not found a way for the java lib to use that to create the object.

19:40 yet.

19:41 perhaps a better approach would be to cast the resulting object against a proxy which implements the interface, but I'm not sure it that would work.

19:42 (can't test it at the moment, I'm on the wrong machine)

19:42 Chousuke: hm :/

19:43 I have no idea. And I'm off to get some sleep. Good night :)

19:43 jwhitlark: Thanks for trying, anyway. Good night.

21:00 ataggart: is there a way to make the following work properly? (defmacro foo [] `(defn bar [s] (println s)))

21:01 right now when I call (foo), I get "java.lang.Exception: Can't use qualified name as parameter: user/s"

21:02 arbscht: (defmacro foo [] `(defn bar [s#] (println s#)))

21:03 ataggart: hmm, though I tried that

21:03 *thought

21:04 thanks

21:59 rabidsnail: Why does clojure.zip/children not return a seq of nodes, but instead a seq of the data at the nodes?

22:00 hiredman: a seq of nodes would be pretty useless

22:00 well

22:00 rabidsnail: (clojure.zip/branch? (first (clojure.zip/children (clojure.zip/vector-zip [1 [2 [3 [4 5]]]])))) --> java.lang.ClassCastException: java.lang.Integer cannot be cast to clojure.lang.IFn (NO_SOURCE_FILE:0)

22:01 hiredman: ,(-> [1 [2 [3 [4 5]]]] zip/vector-zip)

22:01 clojurebot: [[1 [2 [3 [4 5]]]] nil]

22:01 hiredman: ,(-> [1 [2 [3 [4 5]]]] zip/vector-zip zip/children)

22:01 clojurebot: (1 [2 [3 [4 5]]])

22:01 hiredman: ,(-> [1 [2 [3 [4 5]]]] zip/vector-zip zip/children first)

22:01 clojurebot: 1

22:01 hiredman: ,(-> [1 [2 [3 [4 5]]]] zip/vector-zip zip/children first zip/branch?)

22:01 clojurebot: java.lang.ClassCastException: java.lang.Integer cannot be cast to clojure.lang.IFn

22:01 hiredman: ~def clojure.zip/vector-zip

22:02 gjahad: /join #sa-website

22:02 hiredman: weird

22:03 rabidsnail: Could it be a bug?

22:03 hiredman: oh

22:03 it is not a bug

22:03 tomoj: what exactly does the fact that watches are "Experimental" mean?

22:04 they might not work right? or they might change/disappear in the future?

22:04 hiredman: no, I think just the exact interface has not solidified yet

22:04 tomoj: ah, ok

22:05 hiredman: rabidsnail: you are call branch? on something that is not a zipper structure

22:05 just the exception is not very helpful because of the coding style used in branch?

22:06 rabidsnail: Why doesn't children return zipper structures? next, up, down, etc. do, right?

22:07 hiredman: rabidsnail: because the zipper is immutable, children would have to return new zipper structures for each child

22:08 rabidsnail: Isn't that what up down left and right do?

22:08 Why shouldn't children do that?

22:09 hiredman: rabidsnail: yes, but neither returns more then one zipper structure

22:10 rabidsnail: why do you want children to return zipper structures?

22:10 rabidsnail: So that I can recurse by mapping through them

22:10 hiredman: haha

22:11 you can use something like (iterate zip/left zipper)

22:14 or, for that matter, you can just call vector-zip on each child

22:14 (via map)

22:15 rabidsnail: that's true

22:15 alphaeus: How would you do (for [a1 (range 2) a2 (range 2) ... a40 (range 2)] [a1 a2 ... a40]) without writing all the a variables?

22:15 hiredman: I can only imagine you must be doing this for side effects

22:16 alphaeus: I wouldn't

22:16 ,(doc nth)

22:16 clojurebot: "([coll index] [coll index not-found]); Returns the value at the index. get returns nil if index out of bounds, nth throws an exception unless not-found is supplied. nth also works for strings, Java arrays, regex Matchers and Lists, and, in O(n) time, for sequences."

22:16 hiredman: actually

22:16 map vector

22:16 ,(map vector (range 10) (range 10 20) (range 20 30))

22:16 clojurebot: ([0 10 20] [1 11 21] [2 12 22] [3 13 23] [4 14 24] [5 15 25] [6 16 26] [7 17 27] [8 18 28] [9 19 29])

22:18 Anniepoo: clojurebot: paste

22:18 clojurebot: lisppaste8, url

22:18 lisppaste8: To use the lisppaste bot, visit http://paste.lisp.org/new/clojure and enter your paste.

22:24 alphaeus: hiredman: I don't understand how that code is a substitute for using for

22:25 ,(count (for [i (range 10) j (range 10 20) k (range 20 30)] [i j k]))

22:25 clojurebot: 1000

22:25 hiredman: oh, right

22:25 *that*

22:27 *shrug* write a macro to generate the for expression for you

22:30 lisppaste8: Anniepoo pasted "multimethods oopsie" at http://paste.lisp.org/display/85172

22:30 Anniepoo: this is my first multimethod - I'm clearly having some noobie problem, but I can't see it

22:31 (scroll to bottom before doing painful code reading)

22:34 arbscht: alphaeus: see clojure.contrib.combinatorics/cartesian-product

22:35 hiredman: Anniepoo: something is trying to call a method on nil

22:35 tomoj: aw man

22:35 hiredman: so look for nils

22:35 arbscht: (count (apply cartesian-product [(range 10) (range 10 20) (range 20 30)])) => 1000

22:36 Anniepoo: nils are my life

22:36 * Anniepoo shaves her head, wears saffron robe, tries to become nil

22:36 tomoj: alphaeus: https://gist.github.com/1df4bbae8b2685b02826

22:36 my first macro in clojure :)

22:37 but use contrib

22:39 are you really going to use 40??

22:39 ..really big seq

22:44 alphaeus: arbscht: thanks

22:44 tomoj: I wish I could but I don't think I have enough cpu or patience for it to evaluate

22:44 tomoj: I did (count (n-bits 40)) and then I thought about what I just typed a bit...

22:52 arbscht: Anniepoo: I don't follow what's going on in lsl-type. is "^x" a typo? is meta-type a function?

22:53 Anniepoo: it's the metadata for x

22:54 I need to ensure that things get uploaded as the proper type in the external system

22:54 so I tag my data with it's type in the external system

22:55 hiredman: Anniepoo: start add println's and look for the source of the nil

22:55 Anniepoo: it's that line

22:55 that is, it's the multimethod call

22:56 it's not getting to any of the multimethod cases that I can see

22:56 though I can trip a breakpoint in lsl-type

22:56 hiredman: Anniepoo: that means it is the dispatch function

22:56 arbscht: can you explain what meta-type is?

22:56 hiredman: so something in the dispatch function is calling a method on nil

22:57 possibly x is nil

22:57 ,^nil

22:57 clojurebot: nil

22:57 hiredman: bah

22:57 ,(let [x nil] ^x)

22:57 clojurebot: nil

22:57 Anniepoo: this system is a GUI that lets the user draw stuff onscreen, then sends it by an arcane system to the Second Life virtual world

22:57 meta-type is the type the data will have in Second Life

22:58 hiredman: oh

22:58 arbscht: in cond, you're invoking it as a function

22:58 Anniepoo: lsl-type extracts the type

22:58 hiredman: yeah

22:58 Anniepoo: the metadata is authoritative

22:58 hiredman: ,(nil)

22:58 clojurebot: java.lang.IllegalArgumentException: Can't call nil

22:58 Anniepoo: but it's often obvious from the clojure type

22:58 aaargh!

22:58 hiredman: Anniepoo: you are call meta-type as a function

22:58 Anniepoo: you're right

22:58 thanks

22:59 I meant to just check if it was nil

22:59 hiredman: well it was

22:59 Anniepoo: LOL

22:59 odd, wonder why it's nil

23:01 rabidsnail: Is there a reverse operation for seq-zip?

23:02 hiredman: uh

23:03 what?

23:03 rabidsnail: (reverse-operation (seq-zip thing)) == thing

23:03 hiredman: ,(doc zip/root)

23:03 clojurebot: "([loc]); zips all the way up and returns the root node, reflecting any changes."

23:04 rabidsnail: when I do that I get a bunch of stuff added.

23:04 hiredman: http://clojure.org/other_libraries#toc5

23:04 rabidsnail: vectors and maps and such

23:05 hiredman: that means you are changing the zipper

23:05 if you want to keep the original, you should hang on to it before you start editing

23:06 rabidsnail: I don't want the original, I wan a clean chaned version that doesn't have maps with :pnodes and :ppath and such

23:06 changed

23:06 rather

23:07 hiredman: uh

23:07 you are doing something wrong

23:08 the :pnodes stuff is part of the editing, once you call root it should be there, if it is, that means you messed up a call somewhere and broke the zipper

23:08 ,(-> [1 2 3 4] zip/vector-zip zip/next)

23:08 clojurebot: [1 {:l [], :pnodes [[1 2 3 4]], :ppath nil, :r (2 3 4)}]

23:08 hiredman: ,(-> [1 2 3 4] zip/vector-zip zip/next zip/root)

23:08 clojurebot: [1 2 3 4]

23:08 rabidsnail: oh

23:22 Anniepoo: in this example are the commas significant?

23:22 (let [{a :a, b :b, c :c, :as m :or {a 2 b 3}} {:a 5 :c 6}]

23:22 durka42: no

23:23 commas are always whitespace

23:23 Anniepoo: thanks

Logging service provided by n01se.net