#clojure log - Jul 15 2011

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

1:46 Demosthenes: so i'm a lisp scripter (history of common lisp and racket) looking to distribute binaries to multiple platforms, any feedback on doing that for clojure (ie: windows w/ msi, linux?)

2:43 ihodes: Demosthenes: maybe I don't understand you, but can't you send off a jar?

3:36 dans_: can you clever folks give me some book recommendations?

3:40 Dranik: Practical Clojure and then The Joy of Clojure

3:43 dans_: reading practical clojure :)

3:43 but i didnt mean just clojure or programming....just in general

3:46 Dranik: have a look at rich hickey clojure bookshelf

3:47 http://www.amazon.com/Clojure-Bookshelf/lm/R3LG3ZBZS4GCTH

3:49 dans_: thanks

3:50 ah nice

5:54 tsdh: Does (:foo {:foo "bla"}) work because maps implement clojure.lang.ILookup?

6:04 bsteuber: yes

6:04 terom: tsdh: I think so, yes, at least based on skimming clojure.lang.Keyword source

6:04 bsteuber: if(obj instanceof ILookup)

6:04 return ((ILookup)obj).valAt(this);

6:04 return RT.get(obj, this);

6:05 tsdh: Hm, would it be possible to make that interface a protocol, so that you could extend other types to support keyword lookup?

6:06 For example, I'd love to write (:name myNode) instead of (value myNode :name).

6:08 bsteuber: tsdh: how about using a record?

6:08 or is it a java type you don't own?

6:19 Pupeno_: Hello.

6:21 Anyone using Clojure+Slime on Aquamacs?

6:25 tsdh: bsteuber: It's a java type I do know.

6:32 bsteuber: tsdh: then you're screwed basially

6:33 you could subclass it oO

6:33 but probably you just want to use your own ILookup replacement without the syntactic sugar

6:34 tsdh: bsteuber: Well, basically, the java types are in my control, so I could implement ILookup. But I don't want to create a dependency to clojure only because of some syntactic sugar.

6:42 tibbe: anyone know why PersistentHashMap uses hash collision leaves instead of extended hashing?

7:06 Dranik: hi all!

7:06 bendlas: hi

7:07 Dranik: I'm still struggling with utf8

7:07 this is what I'm doing

7:07 https://gist.github.com/1084495

7:07 the encoding is still broken.

7:08 how to fix the encoding?

7:13 cemerick: Dranik: Seems like that should be [:headers "Content-Type"]

7:13 Dranik: let me try...

7:15 cemerick: didn't work :-(

7:17 cemerick: Dranik: Clojure will load your source file as UTF8; is it saved in some other encoding?

7:18 Dranik: it shouldn't be bcs I use linux with LANG="ru_RU.UTF-8"

7:18 cemerick: (BTW, you can use the ring.util.response/content-type fn instead of rolling your own assoc-in)

7:19 I'd double check in any case :-)

7:19 Dranik: cemerick: can you show how?

7:19 cemerick: how what? Check the file encoding?

7:20 Dranik: ok, wait, I'll try the content-type fn

7:21 cemerick: That shouldn't do anything different than what you have, it's just better to use a standard fn instead of rolling your own.

7:21 Dranik: agree

7:22 though I still can't understend why it doesn't work

7:22 cemerick: Anyway, `file -I foo.txt` will (usually) report the encoding of files for me. (OS X here) Presumably the linux file command is similar enough.

7:23 Dranik: routes.clj: text/html; charset=utf-8

7:23 cemerick: next, I'd curl -v the URL to see exactly what is being sent

7:23 Dranik: moment...

7:25 Content-Type: text/html; charset=iso-8859-1

7:25 and question marks in conent instead of unicode letters

7:27 cemerick: ah, progress

7:27 bendlas: Dranik: that's because most user agents send smth like "Accept-Charset:ISO-8859-1,utf-8;q=0.7,*;q=0.3"

7:27 notice that ISO-8859-1 is preferred over utf-8

7:28 cemerick: oh, hah

7:28 bendlas: and web servers oblige

7:28 cemerick: You're setting the content type on the *request*, not the response.

7:28 Dranik: ok, how to set it on the response?

7:29 bendlas: the charset is subject to content negotiation

7:29 AFAIR the served variant is chosen by the highest score

7:29 Dranik: btw, how to get the user's input in utf-8 if he posts a form?

7:30 cemerick: bendlas: That's if the server supports the Accept headers; Ring doesn't, at least not out of the box (though I'm sure there's middleware somewhere that does).

7:31 bendlas: cemerick: for the mime type that's true

7:31 cemerick: Dranik: Something like (assoc-in (handler request) [:headers "Content-Type"] "text/html; charset=utf-8") will set it on the response, though you need to ensure that the handler's return value is coerced into a response object if necessary (it could be a String or File, etc).

7:31 bendlas: but I always supposed, that the accept-charset stuff is handled by jetty, ...

7:32 cemerick: Good point, I'm not sure.

7:32 However, if you're setting Content-Type as a ring header, I really doubt that jetty will quash it down to ISO-XXXX.

7:32 bendlas: because that happens between Reader/Writer land and IOStream land

7:32 let me check tough

7:33 Dranik: cemerick! yeah! that works!

7:33 thanks!

7:34 and how about the users input? will it be utf-8 out of the box?

7:34 bendlas: https://github.com/mmcgrana/ring/blob/master/ring-servlet/src/ring/util/servlet.clj#L71

7:34 Dranik: java Strings are always unicode

7:35 UTF-16 though (which doesn't have to bother you)

7:35 Fossi: exept for the boms ;)

7:35 Dranik: great!

7:36 bendlas: thanks

7:36 bendlas: you only need to be careful when reading from an InputStream

7:36 Dranik: is there anywhere an architecture description of Ring?

7:36 bendlas: i.e. slurp

7:36 Fossi: Dranik: yes, should be first or second hit on google

7:39 bendlas: Dranik: hmm actually, you do get user input as an InputStream

7:39 the :body key on the request

7:40 fortunately the request has a :character-encoding key to

7:40 Dranik: bendlas: so how to set it correctly?

7:40 bendlas: so you can do (InputStreamReader. (:body req) (:character-encoding req))

7:41 to get a Reader Object from which you get properly decoded character data

7:41 Dranik: OMG, isn't there a simplier way?

7:42 bendlas: you need to read the inputstream anyway

7:43 because you can't do anything with a plain inputstream

7:43 Dranik: why? if the user has just supplied his text in, for instance, in cyrillic encoding, I can access the form's fields

7:44 the question is: whether it will work the same way for utf8

7:44 bendlas: you're talking about form data?

7:44 Dranik: yep

7:45 bendlas: that is handled by ring.middleware.params

7:45 which does the decoding at https://github.com/mmcgrana/ring/blob/master/ring-core/src/ring/middleware/params.clj#L50

7:46 so yeah, it should work

7:46 Dranik: but who does set the utf8 encoding there?

7:47 bendlas: the utf8 _decoding_ is done by slurp

7:47 Dranik: ok, great!

7:47 bendlas: which is aproximately (read-into-string (InputStreamReader. %))

7:47 Dranik: thanks!

7:47 bendlas: np

8:42 bsteuber: what parsing libraries exist for clojure now?

8:42 last time I checked there was only fnparse

8:43 but I guess there's more now

8:45 bendlas: bsteuber: last I've heard, CCW switched to cgrand's parsley

8:46 https://github.com/cgrand/parsley

8:47 bsteuber: bendlas: thanks, looks interesting

8:48 bendlas: yw

9:03 jcromartie: interesting... https://github.com/SergeyDidenko/Simple-Persistence-for-Clojure this is exactly the sort of thing (replaying simple transactions/events) I was thinking about lately

9:04 one small step out of the tarpit, actually :)

9:07 now if you add invariants you've got something

9:31 Is there any sense in maintaining my own `clj' script or /Library/Clojure or any of the other nonsense I've cobbled together?

9:31 it seems to confuse lein

9:37 wjlroe: I'm trying to do some web dev with clojure and I want the code to reload through slime obviously but running this - `(future (run-jetty example {:port 8080}))` results in a stacktrace (java.lang.IllegalMonitorStateException) (I'm following the examples from http://techbehindtech.com/2010/08/24/compojure-demystified-with-an-example-part-4/ )

9:40 chrissbx: Is it better style to write [a b] instead of (vector a b) to return multiple values?

9:41 Chousuke: yes

9:41 use literals

9:42 vector literals are a popular alternative for (list a b) as well

9:44 chrissbx: Ok. BTW to my understanding "literal" means "constant", I find it a tad strange to say that vector syntax is a literal.

9:45 (The way you say it makes me guess that Clojure people are using the term this way freely, though.)

9:49 Chousuke: chrissbx: if it were a constant I'd say constant :P

9:50 though in a way, it is a constant. as code, it's a vector of two symbols

9:51 the resulf of evaluating such a form is context-dependent though :)

9:51 result*

9:53 chrissbx: Well, with this reasoning many expressions would be constant.

9:53 When I say literal, then I mean that the value of an expression is literally what I typed. Which isn't the case if symbols are replaced with values transparently.

9:54 Chousuke: [a b] is literally a vector of two symbols. it just evaluates to something else.

9:54 chrissbx: If there would be some way to capture the expression before the symbols are replaced, then calling it a literal would have some validity.

9:55 Chousuke: that's (quote [a b]). but that's literally a list of a symbol and a vector :P

9:55 chrissbx: So, you're saying that just a is a literal, too?

9:56 * chrissbx testing that quote form

9:56 Scriptor: ,(class (quote [a b]))

9:56 clojurebot: clojure.lang.PersistentVector

9:56 Chousuke: I'm not so sure about that.

9:56 chrissbx: Nah, quote really makes it a constant.

9:56 Chousuke: the value of [a b] is constant after evaluating it though

9:57 so it's kind of difficult

9:57 chrissbx: Well, any value from an expression is constant after evaluating the expression.

9:57 Chousuke: I'm not sure what you would call a vector form if not a literal

9:57 chrissbx: As long as the language is functional.

9:57 Just vector *syntax*.

9:57 But maybe this is just me.

9:58 Scriptor: what's this discussion about?

9:58 Chousuke: the syntax is irrelevant to it actually being a vector though.

9:58 [a b] is not equivalent to (vector a b)

9:58 Scriptor: huh, depends on the context, doesn't it?

9:58 Chousuke: (though they evaluate to the same thing)

9:59 Scriptor: if you're using a function, both will be evalauted to the same thing before you can do anything

9:59 Chousuke: in the end I guess it doesn't matter too much but it's interesting to think about

9:59 Scriptor: but if you use a macro they will be different lists

9:59 well, not lists per se

9:59 Chousuke: Scriptor: (vector a b) actually calls a function though. [a b] might do something else

10:00 Scriptor: Chousuke: ah, right

10:01 joegallo: i think we mean vector literal in the sense that c has string literals and java has array literals and javascript has array and object and regex literals -- that is, this isn't some made up clojure thing :)

10:01 but yeah, it's just syntax

10:01 Scriptor: looks like when you pass [a b] to a macro it will pass an actual vector data structure

10:02 Chousuke: of course

10:02 Scriptor: but vector needs to evaluate before it passes that, which is why if you try to use it with let it will complain that it got a list instead

10:02 Chousuke: because [a b] *is* a vector :)

10:02 Scriptor: yep

10:02 hmm, this discussion is kind of like determinging whether

10:02 Chousuke: similarly if you give #{:foo :bar} to a macro you will get an actual set

10:03 Scriptor: 5 is equivalent to (+ 2 3)

10:03 chrissbx: More like whether (infix 2 + 3) is equivalent to (+ 2 3)

10:03 (assuming that there's an infix form that translates to the latter)

10:03 Chousuke: Scriptor: the evaluated results of both forms are identical

10:04 Scriptor: Chousuke: right

10:04 but passed to a macro they're different data structures

10:04 the literal equals the result of the latter's evaluation

10:04 Chousuke: in other languages this probably is a non-issue but lisps are funny like that :P it actually matters what your code is

10:05 mdeboard: homoiconicity

10:05 Scriptor: I think it's a difference in how programmers read the code

10:05 chrissbx: Well, Clojure is probably the only lisp that has the vector syntax.

10:05 Chousuke: common lisp has too

10:05 Scriptor: someone might see (vector 2 3) and thinks "the vector of 2 and 3"

10:05 chrissbx: At least as source code (i.e. "literals" ;)

10:06 Chousuke: #(foo bar)... the difference is, they don't have evaluation semantics

10:06 or rather, it's just "return object as is"

10:06 Scriptor: whereas we would see "the vectorization of 2 and 3" if we're passing it to a macro

10:06 Chousuke: whereas in clojure the evaluation strategy for a vector is to return the vector you get from evaluating all elements in the vector.

10:08 Demosthenes: so i'm a lisp scripter (history of common lisp and racket) looking to distribute binaries to multiple platforms, any feedback on doing that for clojure (ie: windows w/ msi, linux?)

10:08 chrissbx: I wasn't aware that you can have vector syntax in source code in CL; but yes it is implicitely quoted (i.e. a real constant..)

10:08 Chousuke: Demosthenes: I think the most common way is to just do it the Java way. ie. jars

10:09 Demosthenes: it's not quite the same as native packages, but it works

10:09 mdeboard: unless you're compiling to javascript

10:09 right?

10:09 or how does that work for clj on other platforms

10:10 Scriptor: with CLI you can probably use one of the installer-builders that visual studio has

10:10 Demosthenes: my issue is i commonly use scripting languages, and i need to distribute a stand alone binary to customers for a project

10:11 and racket might fit the bill because it can make exe's

10:11 but libraries are an issue

10:11 Scriptor: you can use jars to pack all the libraries into it

10:11 Chousuke: leiningen can make uberjars for you

10:11 Scriptor: ^

10:11 mdeboard: (inc Chousuke)

10:11 sexpbot: ⟹ 1

10:12 Demosthenes: didn't someone just say they weren't like native packages?

10:12 Scriptor: quick question, how does the jvm know what code to start with in a jar/uberjar?

10:12 there aren't any main methods as far I see

10:12 Demosthenes: and can a windows user just doubleclick a jar to launch?

10:13 pjstadig: it writes the main method to call to the jar manifest or something

10:16 cemerick: Demosthenes: If they have the Sun/Oracle JRE installed, yes, a double-click should run it.

10:18 Chousuke: Demosthenes: they are, in that they don't integrate with native package management

10:18 Demosthenes: ah

10:19 Chousuke: though I'm pretty sure there are tools to put the jars in an MSI and creating launcher executables

10:19 after all, java is pretty popular in the enterprise :P

10:19 +for

10:21 Demosthenes: hrm, that could be a selling point

10:21 Chousuke: I don't know much about such tools but you will probably find something if you search

10:21 mdeboard: Yeah I'm 100% certain jars in MSIs is pretty standard

10:21 Demosthenes: i've had great luck with scripting languages for my projects, but i can't expect an end user to install all the runtimes

10:22 Chousuke: Clojure's pretty decent in that you can just include clojure.jar with your project. though the executable will tend to be somewhat large. :P

10:22 jcromartie: there are good examples of native-ish Java apps out there... like Minecraft

10:23 Chousuke: also make sure you comply with all the licences when you bundle things. In Clojure's case the EPL should not be a problem (unless you modify Clojure itself)

10:24 most clojure-based libraries tend to use the EPL too

10:28 cemerick: Demosthenes: I've shipped the JRE wholesale to customers plenty in the past.

10:29 Demosthenes: interesting ;]

10:29 that's an ability i've lacked with scripting languages

10:52 i guess i oughtt o install a clojure environment and try out a few jars

11:02 jcromartie: y'all might find this useful: https://gist.github.com/1084860

11:15 cemerick: technomancy: I had to do this to get javac running after AOT: https://gist.github.com/225e07be131eb8635d84

11:15 Does that seem idiomatic to you?

11:17 Demosthenes: Yeah, you can put together an installer with the JRE + your app + a native launcher that works pretty well. I've used NSIS in the past for building launchers and installers, but there are comparable tools. A lot depends on your specific requirements.

11:22 chrissbx: I need to translate this Scheme code to Clojure, how would you do it?: (call-with-input-file foo read-all)

11:23 joegallo: http://launch4j.sourceforge.net/

11:23 chrissbx: i.e. give a list of all s-exprs that are in the file named in foo

11:35 joegallo: (read-string (slurp foo))?

11:35 chrissbx: I can't even find how to open a file. I've looked in the navigation of the reference (and various pages) and the "cheatsheet".

11:35 slurp, aha

11:36 joegallo: read-string only reads the first object though

11:36 chrissbx: That's a problem, yeah.

11:36 I've found with-in-str, but same problem

11:36 joegallo: then you would need to look at with-open, binding *in*, and read.

11:36 chrissbx: I mean, I've only found read, no read-all

11:37 joegallo: keep calling read repeatedly

11:37 chrissbx: well can wrap this

11:37 yep

11:41 How do you take optional arguments in a function?

11:41 other than "mis-using" &

11:42 something like (fn [a b &optional (c 1) (d 2)] ...)

11:42 jcromartie: chrissbx: you can use (fn ([arg list one] body one) ([arg list number two] body two)) to overload arity

11:42 chrissbx: where 1 and 2 are the default values for c and d if no argument is passed for those.

11:43 Yes, I've learned about that already, but then I'd have to define an external function to allow me sharing code between the cases;

11:43 is this how you're doing things in Clojure?

11:45 (Also, that means to duplicate part of the argument lists, which can be a bit tedious in some cases)

11:46 jcromartie: chrissbx: there are some other defn varieities

11:46 I'm not sure if there's anything as extensive as CL's

11:47 but you can user write your own :)

11:47 s/user/sure/

11:47 sexpbot: <jcromartie> but you can sure write your own :)

11:47 chrissbx: I could, but then I'd be alone.

11:47 jcromartie: or you could contribute it back

11:47 chrissbx: Where are those other defn varieties?

11:48 jcromartie: there's defnk in clojure.contrib.def

11:48 that's a keyword argument defn

11:49 what kind of argument bindings do you want?

11:49 chrissbx: Just an optional argument or two.

11:50 jcromartie: ok so as an example

11:51 like what would your fn be

11:51 (paste it somewhere)

11:51 sorry

11:51 chrissbx: something like (fn [a b &optional (c 1) (d 2)] ...)

11:52 chrissbx: ok, will do in a couple moments

12:00 jcromartie: http://paste.lisp.org/display/123288

12:00 Well, current-input-port is Scheme, dunno how to translate this.

12:00 Also, I guess read in Clojure doesn't take a port argument?

12:00 Also, I know I should use the loop macro instead of fn rec.

12:01 jcromartie: port? no... input stream yes

12:01 chrissbx: Well, that's the same thing I guess.

12:01 aka filehandle

12:02 jcromartie: ,(doc read)

12:02 clojurebot: "([] [stream] [stream eof-error? eof-value] [stream eof-error? eof-value recursive?]); Reads the next object from stream, which must be an instance of java.io.PushbackReader or some derivee. stream defaults to the current value of *in* ."

12:02 chrissbx: ok

12:03 So I guess (aside these errors) what I wrote is how you'd do it?

12:03 jcromartie: something like that

12:03 well hold on

12:04 you might as well put the body of read-all-1 in the body of your 1-ary read-all

12:04 chrissbx: hm, that's true. Recurse to read-all.

12:06 jcromartie: here's an idea

12:06 (take-while identity (repeatedly read))

12:08 amalloy: jcromartie: not very good. input forms could be nil or false

12:08 jcromartie: true

12:10 amalloy: you need something more like (let [in (PushbackReader. (reader filename)), sentinel (Object.)] (take-while (complement #{sentinel} (repeatedly #(read in false sentinel)))))

12:10 or, slurp the whole thing into a string, slap [] around it, and then a single read-string will give you a vector of the objects

12:11 technomancy: cemerick: you're leaving :java-source-path out of defproject explicitly in order to avoid pre-aot javac?

12:12 cemerick: it looks reasonable. my understanding is that 90+% of mixed-source projects have java as the lower level (legacy stuff) with clojure on top, which is why your use case is not more streamlined. is this something you see or expect to see commonly?

12:12 this is only the second time I've heard of it.

12:14 cemerick: there is an open issue for this actually: https://github.com/technomancy/leiningen/issues/180 fwiw

12:14 amalloy: looks like my parens in the sample code above don't balance properly. adjust as necessary

12:15 technomancy: amalloy: what, you don't have paredit in irc?

12:15 amalloy: technomancy: well, i got the right number of each kind

12:15 but i nested them wrong

12:15 technomancy: oic

12:15 * technomancy takes his hand away from the ~guards button

12:16 amalloy: i just installed paredit as a brain upgrade. seemed simpler than installing it for every editor i use (go ahead and ~guards me for not using erc)

12:19 mdeboard: Anyone know if there's a clojure wrapper lib for github api?

12:19 I asked before searching github obv

12:20 amalloy: $google clj-github

12:20 sexpbot: [alienscience/form-dot-clj - GitHub] https://github.com/alienscience/form-dot-clj

12:20 amalloy: hm

12:20 well, yes, there is

12:20 but it's for v2, maybe even v1

12:20 cemerick: technomancy: Yes, I'm aiming to suppress the usual pre-AOT javac. I don't need it, but it's a helpful pattern to present to an audience that is more likely to have that sort of interop requirement.

12:20 Scriptor: nothing clojure-y on here: http://develop.github.com/p/libraries.html

12:21 though there's the java api

12:21 technomancy: cemerick: yeah, especially if you're looking to demo hooks then that's spot-on.

12:21 cemerick: I've done it myself a couple of times in the past, but obviously didn't know the best way to do it in lein right off.

12:22 We'll have a bit dedicated to hooke in a different chapter unrelated to lein, FWIW.

12:22 technomancy: cool

12:22 minou: hello, im new guys, when i do a load-file on slime does it takes much long or does it quit the user input on slime?

12:22 cemerick: part of the "translating specialized design patterns into regular ol' clojure code" chapter

12:23 technomancy: "in which the gang of four are overthrown"

12:23 cemerick: heh, yeah, something like that

12:23 The chapter is currently called "Design patterns in Clojure"

12:23 after reading it, one could reasonably play the "It's a trap!" clip. :-D

12:24 technomancy: heh.

12:24 cemerick: Sort of emblematic of the book as a whole, really.

12:25 technomancy: anyway, thanks for the help and pointers to fill in my lein coverage. :-)

12:27 technomancy: no problem; looking forward to seeing it completed

12:28 cemerick: as am I!

12:34 Dranik: I can't wait when "Clojure Programming" is ready!..

12:40 mdeboard: Dranik: Why

12:40 What about it makes you anticipate it

12:41 Dranik: it is focused on practical ways and tools for everyday programming

12:42 in contrast, all the other published clojure books are mostly about the language itself

12:42 mdeboard: I see, that makes sense.

12:42 And web resources for practical programming in clojure are very slim

12:43 Dranik: clojuredocs.org is the best one for me

12:47 chrissbx: Is it bad to use the slash in symbols for anything other than namespaces? (I guess so?)

12:47 amalloy: chrissbx: it's worse than bad: it's undefined behavior

12:47 chrissbx: Like, I often use names like foo/2 for a function foo that takes 2 arguments.

12:48 So, do I have to replace this with foo:2 or something, I guess.

12:48 amalloy: *2 sounds a little clearer to me than :2, personally

12:49 but i'm not sure you need this as much in clojure? i mean, sure, a little hungarian can be nice if it helps you remember. but clojure has :arglists metadata, so slime will prompt you with the right number of args anyway

12:50 chrissbx: I'm mainly using it in argument names to library functions, to indicate how many arguments are expected by a higher-order function.

12:50 amalloy: ah. sensible

12:50 &(class /)

12:50 sexpbot: ⟹ clojure.core$_SLASH_

12:51 chrissbx: i.e. (defn myspecialfold [fn/3 & lists] ...)

12:51 amalloy: right

12:52 chrissbx: so I'm going to use * instead

12:57 How do you append symbol names? i.e. (symbol-append 'a 'b) -> ab

12:58 Cozey: Hello. Is (set (map ... )) lazy ?

12:58 amalloy: &(symbol (str 'a 'b))

12:58 sexpbot: ⟹ ab

12:58 amalloy: Cozey: no. sets can't be lazy

12:59 chrissbx: so, i guess, (def symbol-append (comp symbol str))

12:59 Cozey: it seems so, but i wanted to be sure :)

13:00 bsteuber: but cats can be lazy!

13:00 amalloy: &(doc lazy-cat)

13:00 sexpbot: ⟹ "Macro ([& colls]); Expands to code which yields a lazy sequence of the concatenation of the supplied colls. Each coll expr is not evaluated until it is needed. (lazy-cat xs ys zs) === (concat (lazy-seq xs) (lazy-seq ys) (lazy-seq zs))"

13:01 ssideris_: hello. in clojure 1.3, the (doc) function seems to be missing... anyone know what the new way is?

13:04 joly: I'm curious about this too. When I start a new REPL, (doc map) works fine. If I switch namespaces, it doesn't work

13:05 "Unable to resolve symbol: doc in this context..."

13:05 ssideris_: oh I didn't realize that it works initially

13:05 maybe it's a bug

13:06 https://github.com/technomancy/swank-clojure/issues/45

13:06 amalloy: joly: a number of namespaces are automatically use'd in the <user> namespace, as a special convenience for you

13:07 is what i recall

13:07 but doc is in clojure.repl, so if you want it somewhere else, you should be able to (use 'clojure.repl)

13:07 joly: amalloy: I thought core functions were imported into new namespaces, at least before 1.3

13:07 amalloy: joly: it's not in core

13:07 is it?

13:07 &#'doc

13:07 sexpbot: ⟹ #'clojure.core/doc

13:07 amalloy: oh, i lied

13:08 ssideris_: (use 'clojure.repl) worked for me

13:08 thanks!

13:08 amalloy: maybe it moved to repl in 1.3 then

13:09 joly: oh, maybe that's it. (use 'clojure.repl) works for me too

13:09 thanks

13:13 bendlasMble: Hey folks

13:16 bendlasMble_: I wonder: has the issue been raised, that one can't develop clojure applications under the GPL?

13:21 jweiss: is there a straightforward way of recursively traversing a clojure.zip tree? (i can visit all nodes with zip/next, but I want to have an action performed when all the nodes in a subtree have been visited, which suggests recursion to me)

13:25 hugod: Anyone have opinions on how to control which exceptions break into the debugger in ritz? https://github.com/pallet/ritz/issues/14

13:33 joegallo: bendlasMble_, what makes you think you can't?

13:41 bendlasMble: joegallo, because clojure is epl

13:42 chouser: bendlasMble: yes. The party line is that that's the GPL's fault, not EPL's.

13:42 bendlasMble: You can't rerelease epl code under gpl

13:42 joegallo: can't i write a gpl program and add an exception to my own code saying it's okay to link with clojure, for instance?

13:43 bendlasMble: Maybe. That's the reason i think i can't, anyway

13:44 Hmm, interesting thought

13:44 joegallo: http://en.wikipedia.org/wiki/GPL_linking_exception

13:44 scgilardi: looks relevant: http://stackoverflow.com/questions/168254/can-you-write-gpl-software-using-cpl-libraries

13:45 joegallo: the highest rated comment there seems to be about copying and pasting cpl code into your gpl program, though

13:45 which is missing the point of the question

13:46 scgilardi: cpl faq reference may help.

13:46 if it weren't dead...

13:46 joegallo: heh

13:47 http://www.eclipse.org/legal/eplfaq.php#USEINANOTHER

13:47 seems to be the same stuff at a different place

13:49 fwiw they seem to take the attitude there that using epl licensed code to write some program doesn't make that program a derivative work of the epl code, and that you can license your stuff however you'd like

13:51 bendlas`: IMHO the only real solution would be to dual licence clojure

13:52 hv: Is there an automatic way of generating clojure-api style docs for open source java libraries?

13:53 joegallo: http://tomfaulhaber.github.com/autodoc/

13:55 bendlas`: I'm thinking about this, because I'm doing a project for which I'd really like strong copyleft

13:56 i.e. an end user program in an educational area

13:59 pjstadig: joegallo: ?

13:59 joegallo: hmmm???

13:59 pjstadig: the epl is a weak copyleft license... changes to the original code must be released under EPL

14:00 joegallo: right, so if create a sweet new version of clojure, then that needs to be epl

14:00 pjstadig: you can combine it with whatever code you want, distribute it as a binary, and use whatever license you want

14:00 joegallo: exactly

14:00 pjstadig: you can also combine it at a source code level

14:00 but any modifications to the files from the original project must be released under the EPL

14:01 joegallo: right, the problem is that the gpl side isn't as friendly, and wants everything to be gpl, but if you are the copyright holder, then you can license it as gpl+exception for clojure

14:01 so i don't see the problem

14:01 pjstadig: and of course the original code must stay under the EPL, so you can't re-license it as GPL

14:01 joegallo: yeah that was my thought, use gpl+exception

14:01 joegallo: now, if you are trying to take someone else's gpled program and combine it with someone else's epled program, then you are out of luck

14:02 pjstadig: but i think you can only do gpl+exception in binary form

14:03 joegallo: the other way to do this is to just do what you want and wait for the letters from lawyers :)

14:03 pjstadig: hehe

14:03 bendlas`: :)

14:03 joegallo: it's like linus and the proprietary drivers issue, if he refuses to stop you from releasing them, then does it really matter if the gpl says you are allowed to or not?

14:04 in the end, the epl for clojure means whatever people are willing to sue over

14:04 if the core is too busy to sue you, then i guess you escape

14:04 but that's not really being a good citizen, and we all want to play fair

14:05 hv: joegallo: thanks. Does autodoc generate APIs for java libraries, too?

14:05 joegallo: i dunno

14:05 pjstadig: hv: doubt it

14:06 hv: joegallo: thanks. I couldn't find anything related to java in it, so I asked to be sure.

14:06 amalloy: $javadoc

14:06 hv: pjstadig: thanks.

14:06 amalloy: $javadoc Integer

14:06 sexpbot: http://download.oracle.com/javase/6/docs/api/java/lang/Integer.html

14:06 amalloy: (that is: you can use the built-in javadoc tool for that)

14:08 hv: amalloy: I want the API in a clojure-friendly format, not the ordinary javadoc.

14:08 amalloy: what is "clojure-friendly"? if you're looking up java APIs for use with clojure, you better not be allergic to javadoc

14:11 bendlas`: I think the clojure autodoc format reflects the fact, that a clojure API prett much consists of functions in namespaces

14:12 where as in java you have packages, classes, methods in any combination of static, non-static, public, protected

14:12 hv: I use javadoc everyday. But for the future, clojure community will definitely need to have a place for reformatted java APIs (at least the important ones) for someone that does not know the least about java the language.

14:12 bendlas`: then the occasional member

14:12 not to mention types

14:13 pjstadig: maybe it will change, but for now it is hard to totally avoid Java APIs in clojure, and there's no point in trying to hide that

14:13 hv: currently people are encouraged to learn some java and only then start learning clojure. That cannot go on forever.

14:14 Scriptor: they are?

14:14 this explains some confusion...

14:14 amalloy: i don't think that's true

14:14 Scriptor: honestly though, as long as someone reads up on java pckaging and namespaces they should be more than fine

14:15 amalloy: learn clojure, and then when you run into some bits that need java, learn that

14:16 hv: amalloy: I believe for anything serious you will run into java apis fairly quickly, so you find it difficult to hold back learning java more than one week into learning clojure.

14:17 amalloy: hv: so? that's no reason to impose a strict "first java, then clojure" order

14:17 if you do that, you'll never know which bits of java "matter"

14:19 hv: I would say first some java intro (hopefully written by someone who knows clojure) and then you can go on and learn clojure.

14:19 Scriptor: amalloy: to be honest, enough to know from looking at some java code what's what

14:20 most java code has plenty in common

14:20 bendlas`: i suggest, we have that talk about host platform doc, as soon as we have every java bit in clojure.lang behind protocols

14:20 and an impl of those protocols, that compiles to machine code

14:21 :D

14:24 hv: amalloy: the bottom line is, you need to know some java, and the amount of java that you need to know should be clear for a new student.

14:25 amalloy: *shrug* you may well be right. i came from java, so i'm not the target audience

14:26 joegallo: start with ejbs, that's what i always say

14:27 * amalloy remembers when beans were cool

14:30 Demosthenes: you know, i have avoided java apps for years... the only reason i'm considering clojure is it seems to be the only lisp i can package for my target audience without buying one of the commercial compilers.

14:31 chouser: Demosthenes: that is not a coincidence. That's a core Clojure goal.

14:32 Demosthenes: i'm not opposed to buying one, but as a small dev i can't outlay $1500-2500 bucks just to publish an app

14:32 joegallo: http://www.gnu.org/licenses/gpl-faq.html#InterpreterIncompat

14:32 http://www.gnu.org/licenses/gpl-faq.html#GPLPluginsInNF

14:32 Demosthenes: i'd drop $500 in a heartbeat

14:32 joegallo: i was trying to find those earlier, but my google-fu was weak

14:33 hv: Demosthenes: you are not alone! I think more people have avoided java apps than people who liked them.

14:33 Demosthenes: hv: well, all the "enterprise" apps i see in java (1.4!) are HORRIBLE

14:33 memory leaking, cpu sucking pigs.

14:33 and the native java syntax makes my skin crawl.

14:34 but.... a lisp on jvm? i'm open to that

14:34 pjstadig: joegallo: the FSF has a very precise and nuanced worldview

14:34 joegallo: itym gnu/worldview, but yes :)

14:35 pjstadig: damn!

14:35 hodapp: the biggest problem with RMS is that he's ever right about anything.

14:44 paraseba: is (class (int 42)) supposed to be a Long in clj 1.3.0?

14:45 amalloy: probably

14:46 paraseba: amalloy: it's a little surprising

14:46 I'd be ok with (class 42) being Long, but (int 42) too?

14:47 amalloy: paraseba: there's a related ticket on jira somewhere. something about aset-int breaking with the change to make ints autobox to Long

14:47 $google clojure jira aset-int box long

14:47 sexpbot: [Overview - Clojure v1.2 API documentation] http://clojure.github.com/clojure/

14:47 paraseba: it probably brings a lot of interop problems (I know I'm having them)

14:48 Scriptor: where's the clojure 1.3.0 repo?

14:49 paraseba: amalloy: maybe this? http://dev.clojure.org/jira/browse/CLJ-820

14:50 hum, created yesterday, no comments yet. I'm not sure if it's a bug, or a "feature"

14:50 amalloy: Scriptor: it's the same as the 1.2 repo? github.com/clojure/clojure

14:51 paraseba: i was thinking of something on the clojure-dev mailing list, apparently, not a jira issue

14:52 http://groups.google.com/group/clojure-dev/browse_thread/thread/d64923aaaf18a22b?pli=1 is related

14:53 but, as usual on google groups, i can't find the one i'm thinking of

14:53 paraseba: probably this? https://groups.google.com/d/topic/clojure-dev/W4aFkFezW2g/discussion

14:53 amalloy: yes

14:54 paraseba: hum, still not sure if it's intended or just a bug..

14:58 raek: paraseba: IIRC, 'int' and friends only return primitives if the return value is _immediately_ consumed by a function or method that takes a primitive as an argument

14:59 if the receiver argument type is Object (like for 'class') the number will be boxed

14:59 paraseba: raek: but shouldn't be boxed to Integer?

15:01 amalloy: raek: that seems like a misstatement. it returns an int in all cases

15:01 but most consumers box that

15:02 raek: paraseba: in clojure 1.3, byte, short, int and long are boxed to Long, and float and double are boxed to Double

15:02 amalloy: ah, that makes sense

15:03 ,(= (int 1) (long 1))

15:03 clojurebot: true

15:03 raek: ,(set (int 1) (long 1))

15:03 clojurebot: java.lang.IllegalArgumentException: Wrong number of args (2) passed to: core$set

15:03 paraseba: raek: what I find strange is the behavior of int function. Even if we always box to Longs, shouldn't int box to Integer?

15:03 amalloy: &(.equals (int 1) (long 1))

15:03 sexpbot: ⟹ false

15:03 raek: ,#{ (int 1) (long 1)}

15:03 clojurebot: #{1 1}

15:03 amalloy: paraseba: no!

15:03 int is sepcifically designed to not box things

15:04 raek: here you have a set of an Int and a Long... (this is clojure 1.2)

15:04 paraseba: amalloy: hum, I see

15:04 Pupeno: Hello.

15:05 Is it possible to have slime working with aquamacs?

15:05 amalloy: paraseba: the point is that int doesn't do any boxing (since it's for performance), and once it comes time to box, the compiler has lost track of the information that the thing was returned from (int)

15:06 ~aquamacs

15:06 aw

15:06 paraseba: amalloy: that makes sense... so somewhere else the output of (int 42) is getting boxed into a Long, which is now the default box

15:06 amalloy: right

15:07 paraseba: so now, we need to do (Integer. 42) to create a boxed Integer

15:07 amalloy: Pupeno: fsbot in #emacs says that "[aquamacs is] considered to be so significantly changed, buggy and "unemacs" that people in #emacs are known to be reluctant to help"

15:08 Pupeno: amalloy: I know, but it's pretty and I'm trying to show Clojure in a conference... well, I'll try to make TextMate work.

15:09 raek: Pupeno: did you try the official swank-clojure instructions?

15:09 paraseba: amalloy: do you know where I can read about this changes in 1.3.0

15:10 amalloy: paraseba: i don't know of an official document (still!). on the rare occasions that i care, i find someone else who cares and ask them

15:11 eg dnolen or cemerick

15:11 Pupeno: raek: I tried the ones in Clojure getting started, it didn't work. I didn't investigate as it said it's not supported but might work, I wanted to gather some feedback to see if anyone was actually using it or not.

15:11 raek: paraseba: https://github.com/clojure/clojure/blob/master/changes.txt and http://dev.clojure.org/display/design/Home

15:11 aaelony: hi, what is the most idiomatic way to see if a file is gzipped? is there a gzipped? function somewhere?

15:12 paraseba: raek: will try that, thanks

15:14 raek: and what about (class (short 42)) being Short? shouldn't that be Long too? according to " in clojure 1.3, byte, short, int and long are boxed to Long"

15:14 (int) seems to be the only one having this behavior...

15:15 maybe short and bytes are still being boxed to their corresponding types instead of Long?

15:15 raek: hrm, that is a bit odd :)

15:15 http://dev.clojure.org/display/doc/Enhanced+Primitive+Support

15:15 this page says "all long-or-smaller integers are boxed as Long"

15:15 amalloy: "long or smaller". as if that were a necessary qualifier

15:15 raek: and "You can't use primitive coercions to force specific box types"

15:16 paraseba: yes ... it's very specific about that

15:16 raek: ...but apparently you can

15:16 paraseba: so, then, maybe (int) is the only one with the intended behavior

15:17 aaelony: ok, wrote one myself...

15:22 raek: it doesn't make sense for me that this is only done for 'int'...

15:22 * raek writes a mail to clojure-dev

15:22 paraseba: raek: or you could comment the jira ticket

15:22 clj-820

15:40 amalloy: anyone know if brian marick hangs around in here, or do i have to send him an actual email to get in touch?

15:41 raek: amalloy: dunno, but he is very active on twitter

15:41 amalloy: oh god, so he is. i had to unfollow him eventually

15:43 * fliebel thinks about a tool to match up full names with nicks

15:45 nybbles: fliebel: this guy probably has some ideas for that: http://arstechnica.com/tech-policy/news/2011/02/how-one-security-firm-tracked-anonymousand-paid-a-heavy-price.ars

15:58 Cozey: Does anyone here know if there is already any clojure job market ?

16:02 amalloy: Cozey: there's some. i work at www.geni.com doing clojure with ninjudd, Raynes, and lancepantz

16:03 Cozey: I see also thortech is doing some clojure support

16:03 so geni makes money out of dead people, eh?

16:03 amalloy: i know ztellman works with amit and some other folks at www.runa.com

16:04 and nathanmarz is at backtype, who were recently acquired by twitter

16:06 jcromartie: amalloy: got it... so you're saying use Clojure, get acquired by Twitter

16:06 :P

16:07 Cozey: is clojure used mostly in data mining ?

16:08 fliebel: Cozey: Have you seen the survey by cemerick?

16:08 Cozey: oh i remember

16:08 right

16:08 also Incanter is a big point here

16:08 fliebel: http://cemerick.com/2011/07/11/results-of-the-2011-state-of-clojure-survey/

16:09 * fliebel needs to look at what Incanter can do besides drawing pretty graphs.

16:11 fliebel: But if so many people use Clojure for data mining, why aren;t there loads of similarity and clustering things, or even NLP stuff...

16:12 kumarshantanu: when i (load-file "file-name.clj"), can i let-bind local vars around it?

16:12 fliebel: kumarshantanu: huh?

16:13 kumarshantanu: so that the local binding will be available in the load-file'd code

16:13 dnolen: fliebel: not everyone using Clojure is interested in opensource.

16:13 kumarshantanu: (let [x :foo] (local-file "file.clj")) ; i want file.clj to have access to x

16:13 s/local/load/

16:13 sexpbot: <kumarshantanu> (let [x :foo] (load-file "file.clj")) ; i want file.clj to have access to x

16:14 fliebel: kumarshantanu: I think you'd have to use binding.

16:14 dnolen: but the same could be said of web frameworks, and we have tons of these.

16:17 amalloy: kumarshantanu: no

16:18 kumarshantanu: amalloy: any alternative?

16:19 amalloy: global vars

16:19 or, preferably, "stop trying to do things like that"

16:19 technomancy: fliebel: there's plenty of clustering libs on github

16:19 jobbim, cascalog, conduit, work

16:20 practically every mid-sized company using clojure has rolled their own

16:21 amalloy: technomancy: eerily reminiscent of "the lisp curse"

16:21 technomancy: NLP is another story because it's actually difficult to implement. job distribution systems are decidedly not.

16:21 Pupeno: Anybody remembers that comic about a young programming learning about closures and thinking they are the poor man's objects and then about objects and thinking they are the poor man's closures?

16:21 amalloy: Pupeno: not a comic

16:21 technomancy: amalloy: eval plus amqp. done.

16:21 Pupeno: amalloy: I remember a comic strip.

16:22 amalloy: http://people.csail.mit.edu/gregs/ll1-discuss-archive-html/msg03277.html

16:22 search for "the venerable master qc na"

16:22 technomancy: amqp?

16:22 technomancy: amalloy: advanced message queueing protocol. rabbitmq being the popular implementation

16:23 Pupeno: Someone turned it into a comic.

16:23 amalloy: Pupeno: okay. well, feel free to find that and paste a link here

16:23 Pupeno: amalloy: I will if I find it... but it's proving hard.

16:48 fliebel: technomancy: I was talking about *document* clustering, like k-means and stuff.

16:50 Scriptor: fliebel: what's the difference between document clustering and regular clustering?

16:50 fliebel: Scriptor: The one is about classifying text, the other about distributing work.

16:51 Scriptor: er, I meant regular clustering as in just regular k-means, but I see document clustering means specifically clustering text

16:51 rather than, say, numbers

16:53 fliebel: Scriptor: Uhm, well, I just wanted to make clear I was not talking about task queues and such.

16:53 amalloy: fliebel: i forget, are you the one who wrote sexpbot's ping plugin?

16:54 fliebel: amalloy: Well, you could say so, yes. But Raynes refactored it a lot I think.

16:55 amalloy: fliebel: Raynes never refactors, he just makes code uglier. i think i refactored it a lot

16:55 Raynes: amalloy: I hate you.

16:55 fliebel: oh, right :)

16:55 amalloy: anyway, i finally got around to figuring out what broke it ages ago (not your fault, of course) and fixing it. thought you might want to know it's working again

16:57 fliebel: amalloy: Did Raynes break it? So maybe it was him after all, who did the refactoring. Anyway, glad to know it works again, I used it *tons*

16:57 amalloy: haha

16:58 well, we did a global refactor on how plugins are supposed to send messages, and didn't update the ping plugin

17:00 fliebel: $huglle Raynes

17:00 Hm, I think there was something like that...

17:01 https://github.com/cognitivedissonance/sexpbot/blob/master/src/sexpbot/plugins/utils.clj#L184

17:02 amalloy: fliebel: the word is huggle

17:02 * fliebel is dyslysex or tired

17:02 fliebel: good night

17:03 amalloy: night

17:08 ssideris_: hello... is there a way to create a proxy to an interface that is not known at compile time?

17:09 Demosthenes: drewr: muahahaha

17:09 ssideris_: the fact that (proxy) is macro forces me to define the interface to be proxied at compile time, right?

17:09 *is a

17:12 amalloy: ssideris_: you want to proxy an interface, but you don't know what it is? that sounds hard

17:13 ssideris_: I have a standard way of mapping certain keywords to certain java interfaces

17:13 and I'm trying to write the function/macro that will take a keyword as input (and some code) and produce a proxy for you

17:14 amalloy: ssideris_: fwiw, if you're working with interfaces, 95% of the time you want reify, not proxy

17:14 not that this fixes your current problem

17:15 ssideris_: oh that's a good tip, let me go and look it up

17:15 thanks

17:15 the actual problem though...

17:15 whidden: given a symbol that resolves to a name space. How do I determine if it is a macro or a function?

17:16 ssideris_: it does sound a bit reflection-heavy to be honest

17:17 amalloy: proxy seems to have the advantage of being able to selectively define methods, you don't need all of them...

17:17 amalloy: ssideris_: "advantage"

17:18 if you have an instance of an interface and only want to support some of its methods, you're not really conforming to the interface

17:19 ssideris_: when it comes to swing listeners, not all the methods are relevant all the time

17:19 amalloy: well, yes

17:19 * amalloy rails in vain against swing

17:20 * ssideris_ clojurizing swing

17:20 ssideris_: it's hard :-)

17:21 amalloy: ssideris_: i don't think that what proxy does is what you want for swing

17:21 iirc if you call an implemented method, it throws an exception, not silently continues

17:22 $javadoc java.awt.WindowListener

17:22 $javadoc javax.swing.WindowListener

17:23 $google java windowlistener

17:23 sexpbot: [WindowListener (Java 2 Platform SE v1.4.2)] http://download.oracle.com/javase/1.4.2/docs/api/java/awt/event/WindowListener.html

17:23 amalloy: &(doto (proxy [java.awt.event.WindowListener] [] (windowOpened [e] nil)) (.windowIconified nil))

17:23 sexpbot: java.lang.IllegalStateException: Var null/null is unbound.

17:24 ssideris_: ok, then I'll use reify to silently suppress calls to the unimplemented parts

17:24 thanks

17:24 amalloy: yeah, that's pretty much your only choice

17:24 though see also WindowAdapter

17:24 ssideris_: in fact, I think that is the source of a bug in my current implementation

17:25 so double-thanks

17:25 :-)

17:25 the adapters are useful, but don't exist for everything in swing

17:25 amalloy: i know

17:25 ssideris_: so I'm trying to offer a solution that covers everything

17:25 amalloy: yeah, i guess it's hard to see how to productively use an adapter

17:29 ssideris_: there are at least 2 other swing DSLs out there already, right?

17:29 amalloy: dunno. not my problem

17:29 all i know about is seesaw

17:31 aaelony: has anyone used to-time-zone from joda time? The doc says it takes a date and a time, but i get a string exception

17:31 jtime

17:31 #<DateTime 2011-07-07T13:59:59.979Z>

17:31 (to-time-zone jtime "America/Los_Angeles")

17:31 java.lang.ClassCastException: java.lang.String cannot be cast to org.joda.time.DateTimeZone (NO_SOURCE_FILE:0)

17:31 any ideas?

17:33 nevermind... it seems it needs to be a org.joda.time.tz.FixedDateTimeZone

17:33 for the offset

17:34 ssideris_: amalloy: so why do you dislike swing so much?

17:34 amalloy: ssideris_: that anyone would write WindowAdapter and not realize there's a problem saddens me

17:35 ssideris_: :-)

17:35 ok point taken

17:35 amalloy: it's an application of interfaces to a concept that doesn't really match

17:36 if i were rewriting it today, i'd probable start with something closer to: public enum WindowEvent { ICONIFIED, ...}; public interface WindowListener { public void handle(WindowEvent e); };

17:37 coopernurse: amalloy: just tried out your fork of clj-doc-test - do you know if it has issues with functions in namespaces?

17:37 amalloy: coopernurse: uhhhh, i think i forked clj-doc-test and then didn't ever actually do anything to it. i have no knowledge about it, really

17:38 coopernurse: amalloy: ah, ok. thanks.

17:38 for pure functions it seems like a nice way to do tests

17:38 but it doesn't seem like it has caught on with the clojure community

17:39 amalloy: yeah, i had some grand plans for it, but i don't remember what they were and i think i decided they weren't a good idea

17:39 it looks like my only commit was to make it cake/lein-friendly

17:46 coopernurse: amalloy: gotcha

17:57 dabd: I was looking for a way to write loops where you exit when a condition is met which is not very easy to do in a functional way. However I found trampolines very useful to implement this. Is this a common use case? I used it like this example http://pastebin.com/U5iecrhu

17:58 amalloy: dabd: ew

17:59 drop the trampoline, and replace #(max-4-matches ...) with (recur ...)

17:59 dnolen: dabd: I don't see what stops you from just using recur, at least in this case.

18:00 sritchie: dabd: https://gist.github.com/1085641

18:00 haven't debugged that yet, but that's meant to be a straightforward conversion of what you'd had

18:01 amalloy: though tbh the whole function can easily be written as (count (take 4 (filter #{\x \o} s)))

18:01 dabd: sritchie: any advantages of using your version vs trampolines?

18:01 dnolen: dabd: trampolines are pretty slow, and just unidiomatic for what you're doing.

18:02 sritchie: you don't need mutual recursion between two functions, here, just a single recursion

18:02 dabd: ok

18:03 amalloy: someone tell me if i'm wrong, but i think any trampoline that doesn't involve mutual recursion can be trivially transformed into a loop/recur

18:03 dnolen: amalloy: trampoline is for mutual recursion.

18:04 dabd: amalloy: let me test your version

18:04 sritchie: dabd: https://gist.github.com/1085641

18:04 that's a little cleaner

18:04 (than the first one I posted, imo)

18:05 amalloy: dnolen: i know

18:05 dnolen: amalloy: i know you know :) came out the wrong way.

18:05 dabd: amalloy solution is the best way to do what you want and quite concise.

18:06 sritchie: amalloy: haha, didn't see that

18:06 dekuderp: I'm having a bit of trouble; the compiler is telling me I'm not recurring from a proper tail position

18:06 https://gist.github.com/1085656

18:07 specifically, I get: Can only recur from tail position (map_maker.clj:13)

18:07 amalloy: dekuderp: move the second recur into the if

18:07 dabd: unfortunately none of the versions work as I intend: I want to check how many consecutive \x or \o chars are in the string stopping as soon as I find 4 but anytime I find a different char I reset the counter

18:07 amalloy: actually, look up how if works

18:07 sritchie: I think you're also forgetting parens around your different function versions

18:07 so, wrap [xmax ymax] (recur xmax ymax xmax ymax {}) in parens, as well as the next argvec-body pair

18:08 dekuderp: amalloy: thanks

18:08 sritchie: so every [arg] (function body) should be ([arg] (function body))?

18:08 sritchie: yeah

18:10 dekuderp: okay here is the new error I am getting: Mismatched argument count to recur, expected: 2 args, got: 5 (map_maker.clj:13)

18:10 dabd: ofc it is easy to correct amalloy's version to have this behavior thanks guys

18:10 dekuderp: https://gist.github.com/1085665

18:10 dabd: sorry I meant sritchie's version

18:11 dekuderp: so why can't it tell that there is a 5-arg version? I thought I've written clojure code that works like this, but perhaps I'm misremembering

18:12 sritchie: I usually write (generate-map xmax ymax xmax ymax {})) in this case -- not sure why recur doesn't jump between the different arg versions, though

18:12 amalloy: dekuderp: recur doesn't work that way. you can only recur to the top of the current body

18:12 sritchie: because recur is a GOTO, and each function body is a method

18:12 sritchie: got it

18:13 dekuderp: amalloy: thanks!

18:17 jonabbey: question: did anyone come up with any better pattern for closing streams in clojure than was discussed in http://groups.google.com/group/clojure/browse_thread/thread/b9238d1c26997eea/c85b2e289ae92c88?lnk=gst&q=lazy+stream&fwc=1 ?

18:18 i.e, there remain no deterministic destructors in clojure, so you have to do all management of stream lifespan with functional resource management blocks?

18:19 i'm trying to do a lazy seq on a stream reader, and i've got it working, but it doesn't close the stream unless the lazy seq is evaluated to the end

18:21 dekuderp: in this function: https://gist.github.com/1085679 why doesn't (if (and (zero? ycur) (zero? xcur)) worldmap) cause the generate-map function to return the worldmap data structure?

18:22 after setting up a few printouts I figured out that it is getting hit, but that the function isn't returning, instead getting stuck in an infinite loop

18:24 jonabbey: /list-usrs

18:24 er

18:27 amalloy: dekuderp: again, look up how if works

18:27 &((fn [] (if true 1) (if false 2) 3))

18:27 sexpbot: ⟹ 3

18:30 dekuderp: so how do I prevent the continued evaluation? am I supposed to be using cond instead?

18:31 this http://clojure.org/special_forms#if isn't really helping me understand my mistake, but I'm looking for other stuff too

18:31 amalloy: yes, but you can do it with if

18:31 &((fn [] (if true 1 (if false 2 3)))

18:31 sexpbot: ⟹ 1 ; Adjusted to ((fn [] (if true 1 (if false 2 3))))

18:31 amalloy: sexpbot: smartass

18:32 dekuderp: the general thrust is, every expression returns something, always

18:32 "early" returns are silently ignored by the special form (do expr1 expr2), which defn includes implicitly

18:33 dekuderp: so the only way to make an if statement have the power to return a value for the parent function is to chain the if's together?

18:33 ok, I think I sorta get it now

18:33 amalloy: yes, though you should try to stop thinking about early returns

18:33 those are "statements": "return this value now"

18:34 clojure just has expressions, describing *what* the result of an expression is, not *how* to get it

18:35 Abezethibou: Hello all.. After a same studing aboud Common lisp (aproximately a year)

18:36 I start to study clojure

18:36 dnolen: jonabbey: lazy-seqs and resources don't really play together well, open design problem.

18:36 Abezethibou: I am reading practical clojure

18:36 dekuderp: amalloy: thank you very much for helping me understand htat

18:36 that*

18:36 Abezethibou: and little bit joy of clojure

18:37 Does anyone have any suggestion about a complate book

18:38 kylpo: technomancy: I've been thinking about learning lisp before clojure. Would you recommend I stick with that plan? Or just go right for clojure. Currently my goal is for learning/practice, I don't really have a project in mind.

18:38 technomancy: kylpo: you mean common lisp?

18:39 kylpo: technomancy: yes. The book I'm using is Land of Lisp: http://www.amazon.com/Land-Lisp-Learn-Program-Game/dp/1593272812

18:39 bsteuber: kylpo: just learn clojure ^^

18:40 technomancy: kylpo: I don't think there's any value in learning CL at all

18:40 kylpo: technomancy: K, thanks. Except for understanding elisp, right?

18:41 technomancy: that's true; CL has a lot of overlap with elisp

18:41 and it has a lot more literature

18:41 kylpo: technomancy: do you have an elisp book you like?

18:41 technomancy: kylpo: no, not really

18:41 kylpo: technomancy: k

18:42 technomancy: I guess I learned most of my elisp from Practical CL

18:42 kylpo: technomancy: a clojure book you like?

18:42 technomancy: only got about halfway through the book though

18:42 kylpo: I've read Programming Clojure and the Joy of Clojure. good and great respectively

18:42 PC if you just want the basics quickly and JoC for a more thorough grounding

18:43 kylpo: technomancy: K, thanks. I'm thinking I'll check out your peepcast, too. Making games are good ways for me to practice.

18:43 technomancy: yeah, games are great

19:07 dekuderp: so apparently this function is not correctly generating a data structure I want: https://gist.github.com/1085752

19:07 I think this command shows that my logic is sound:

19:07 ,(if (nil? ((keyword (str 1)) {})) (assoc {} (keyword (str 1)) {}))

19:07 clojurebot: {:1 {}}

19:08 dekuderp: but for some reason the function only returns nil instead of the real structure I want

19:11 amalloy: i'm not sure exactly what your function is trying to do, but it looks like it's in need of update-in and fnil

19:13 (dekuderp: that last directed at you)

19:15 dekuderp: note also that ##(assoc nil :x :y) works just fine with nil

19:15 lazybot: ⟹ {:x :y}

19:21 ssideris_: what's a concise way to go from [[1 10] [2 20]] -> [[1 2] [10 20]] ?

19:21 for the general case

19:24 duh, I suppose [(map first v) (map second v)]

19:24 where v is the structure

19:25 the vector I mean

19:26 amalloy: &(apply map vector [[1 10] [2 20]])

19:26 lazybot: ⟹ ([1 2] [10 20])

19:27 amalloy: ssideris_: more general, working for NxM matrices

19:28 ssideris_: wow nice

19:28 thanks

19:29 dekuderp: um, I have been looking at the documentation for update-in, and it seems really useful, but I don't know how to use it

19:29 the only example I got to work in my repl is ##(update-in {} [(keyword (str 1)) (keyword (str 2))] {})

19:29 lazybot: ⟹ {:1 {:2 nil}}

19:29 amalloy: dekuderp: well, explain to me what your function is actually doing

19:30 the mess of repeated nested assocs is not easy to follow

19:31 dekuderp: I want to create a 2d matrix to store other maps in

19:31 amalloy: so maybe just assoc-in?

19:31 &(assoc-in nil [:1 :2] "data")

19:31 lazybot: ⟹ {:1 {:2 "data"}}

19:32 dekuderp: amalloy: that is definitely the function I was looking for

19:32 and I would use update-in for updating the 2d array, right?

19:33 amalloy: for changing one entry in it

19:33 dekuderp: okay, well those functions certainly make life easier

19:33 thanks!

19:34 amalloy: &(let [world (-> nil (assoc-in [:1 :2] "data") (assoc-in [:3 :5] 9))] (update-in world [:3 :5] dec))

19:34 lazybot: ⟹ {:3 {:5 8}, :1 {:2 "data"}}

19:34 amalloy: i still don't understand at all why you want to use keywords as keys instead of numbers

19:35 dekuderp: ^ all that stuff

19:37 dekuderp: amlloy: what do you mean? I am using numbers

19:37 I am using ##(keyword (str 1)) and such for every num

19:37 lazybot: ⟹ :1

19:38 dekuderp: at least that's how I figured out how to turn numbers into keys

19:41 I'm guessing that I'm doing it wrong?

19:41 amalloy: stop making numbers keys! we had this discussion the other day, didn't we? you can just use the actual integer 1 as a key

19:42 &{1 'test, 10 'sample}

19:42 lazybot: ⟹ {1 test, 10 sample}

19:42 dekuderp: oh, now I get it

19:42 amalloy: or use a vector of vectors, since vectors are indexed by index anyway

19:43 dekuderp: do you think I should be using vectors?

19:43 I'm not very sure of the trade off in my case, so my choice was pretty arbitrary

19:43 amalloy: &(let [world (vec (repeat 4 (vec (repeat 4 nil))))] (assoc-in world [3 1] 'test))

19:43 lazybot: ⟹ [[nil nil nil nil] [nil nil nil nil] [nil nil nil nil] [nil test nil nil]]

19:45 amalloy: if the world is large and mostly empty, a map is surely better. otherwise, it probably depends but doesn't matter much

19:46 dekuderp: okay, I'll try it with vectors since I am planning on storing data at every entry

20:20 mdeboard: ,(min-key 7 8 9(

20:20 clojurebot: EOF while reading

20:20 mdeboard: ,(min-key (7 8))

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

20:20 mdeboard: Can someone clue me in on what min-key is for :|

20:21 amalloy: &(min-key :size {:size 1 :name "test"} {:data 4 :size 10})

20:21 lazybot: ⇒ {:size 1, :name "test"}

20:21 amalloy: &(min-key - 1 2 3)

20:21 lazybot: ⇒ 3

20:22 amalloy: mdeboard: ^

20:29 mdeboard: &(min-key - 3 2 1)

20:29 lazybot: ⇒ 3

20:29 mdeboard: what.

20:30 &(min-key + 1 2 3)

20:30 lazybot: ⇒ 1

20:31 amalloy: mdeboard: it calls - on each element before comparing

20:31 and -3 is smaller than -1

20:31 mdeboard: Oh.

20:31 &(min-key (partial (< 3)) 1 2 3)

20:31 lazybot: java.lang.IllegalArgumentException: Wrong number of args (1) passed to: core$partial

20:32 mdeboard: &(min-key (> 3 %) 1 2 3)

20:32 lazybot: java.lang.Exception: Unable to resolve symbol: % in this context

20:32 * mdeboard drums his fingers

20:32 dnolen: &(min-key (partial < 3) 1 2 3)

20:32 lazybot: java.lang.ClassCastException: java.lang.Boolean cannot be cast to java.lang.Number

20:32 amalloy: mdeboard: unlikely to work anyway. > returns a boolean

20:33 dnolen: &(min-key (partial min 3) 1 2 3)

20:33 lazybot: ⇒ 1

20:34 * mdeboard scratches his beard

20:34 mdeboard: I see

20:38 dekuderp: is there an easy way to generate a random # between 0 and 1 in clojure?

20:39 amalloy: &(rand)

20:39 lazybot: ⇒ 0.5675409978355913

20:39 dnolen: ,(rand-int 2)

20:39 clojurebot: 0

20:40 dnolen: ,(take 10 (repeatedly #(rand-int 2)))

20:40 clojurebot: (0 1 1 1 0 1 1 0 0 0)

20:40 dnolen: ,(take 10 (repeatedly rand))

20:40 clojurebot: (0.8182436567649329 0.9637135524821122 0.9122072063831675 0.2888228218745055 0.3761627320246498 0.2602531326683677 0.34970107144974993 0.8873792800568543 0.4710056658729913 0.7726407255548855)

20:42 mdeboard: Now, can someone give me a very very simple example of apply's usage? :\

20:43 dekuderp: thanks!

20:43 mdeboard: The actual operation indicated by the ->> macro would seem like it woul be described with "apply"

20:43 technomancy: mdeboard: (apply * [1 2 3])

20:43 becomes (* 1 2 3)

20:43 amalloy: dnolen: repeatedly takes an optional how-many arg these days

20:44 mdeboard: technomancy: So .. it's reduce?

20:44 amalloy: &((juxt apply reduce) (partial list '*) [1 2 3])

20:44 lazybot: ⇒ [(* 1 2 3) (* (* 1 2) 3)]

20:44 amalloy: mdeboard: the difference is that

20:44 technomancy: mdeboard: (reduce * [1 2 3]) results in two calls to *

20:44 mdeboard: apply is a single call

20:45 mdeboard: ah

20:45 interestink

20:51 * amalloy loves his little (juxt apply reduce) demonstration, even if nobody else does

20:55 technomancy: amalloy: oh dang; I didn't catch what was going on there

20:55 it's like your own private macroexpand-like facility

20:55 amalloy: technomancy: more like a trace

21:21 mdeboard_: &(apply + [1 2 3])

21:21 lazybot: ⇒ 6

21:23 mdeboard_: &(apply min-key 5 [1 2 3])

21:23 lazybot: java.lang.ClassCastException: java.lang.Integer cannot be cast to clojure.lang.IFn

21:27 mdeboard_: &(min-key min [

21:27 lazybot: ⇒ [] ; Adjusted to (min-key min [])

21:27 brehaut: wait; lazybot? when did that happen

21:28 mdeboard_: &(min-key min [1 2 3] [4 5 6] [7 8 9])

21:28 lazybot: java.lang.ClassCastException: clojure.lang.PersistentVector cannot be cast to java.lang.Number

21:28 mdeboard_: &(min 1,2,3)

21:28 lazybot: ⇒ 1

21:29 mdeboard_: Sorry I'm on my phone at Harry potter. This is the only repl I have :(

21:29 brehaut: mdeboard: damning review of a the movie there

21:30 amalloy: brehaut: earlier this afternoon

21:30 mdeboard_: you can /msg lazybot &(min 1 2 3)

21:31 mdeboard_: Ya doing that now amalloy

21:31 brehaut: We're here early.

21:37 babilen: mdeboard_: https://market.android.com/details?id=com.sattvik.clojure_repl (fwiw) -- but watch the movie, and don't play with the phone ;)

21:37 mdeboard_: I'm on iPhone :(

21:55 ihodes: cemerick: hey chas

22:01 cemerick: hey :-)

22:21 gfrlog`: clojurebot: lazybot?

22:23 amalloy: clojurebot: lazybot is sexpbot's new name. Same bot, same features, less nsfw-looking name!

22:23 clojurebot: ping?

22:24 ,1

22:24 gfrlog`: clojurebot was only ever interested in sexpbot

22:24 amalloy: hiredman: clojurebot seems to be dead

22:24 ihodes: cemerick: haha i didn't mean pick me for any particular reason, just a student who's using Clojure, though not in the classroom

22:25 cemerick: ihodes: Yeah, I had no idea you were a student, actually. :-)

22:38 ihodes: cemerick: for one more year, at least. i wish the CS dpt used Clojure. i'm a math major anyway, though. it feels more like programming anyway.

22:39 cemerick: ihodes: Check your PMs :-)

22:46 gfrlog`: &(nth (sorted-set 1 2 3) 1)

22:46 lazybot: java.lang.UnsupportedOperationException: nth not supported on this type: PersistentTreeSet

22:46 gfrlog`: :(

22:51 amalloy: gfrlog`: the sorted-set impl couldn't do that any faster than ##(nth (seq (sorted-set 1 2 3)) 1) anyway

22:51 lazybot: ⇒ 2

22:52 amalloy: but i bet there's a measure for a finger tree that combines sorting with random access

22:56 gfrlog`: amalloy: a tree set can't nth? :/

22:56 that's....unnecessary

22:57 amalloy: no, why would it bother?

22:57 gfrlog`: because it's so close to being able to?

22:58 amalloy: no it isn't

22:58 gfrlog`: then I don't know what a tree set is

22:59 amalloy: it would have to track, at each node, how many things are in the left and the right branch

22:59 gfrlog`: amalloy: that's what I meant by so close

22:59 all it would have to do is track, at each node, how many things are in the left and the right branch

22:59 amalloy: gfrlog`: i imagine clojure's persistent tree set is pretty close to the mutable tree set. for a mutable set it's a bigger change

23:00 but seriously, this is what finger trees are for. go try them out

23:00 gfrlog`: I know :(

23:00 Scriptor: amalloy: like, teh #{} kind of set?

23:00 *the

23:01 gfrlog`: Scriptor: ##(sorted-set 1 3 2)

23:01 lazybot: ⇒ #{1 2 3}

23:01 amalloy: Scriptor: uh, what is this in reference to?

23:01 Scriptor: amalloy: <amalloy> gfrlog`: i imagine clojure's persistent tree set is pretty close to the mutable tree set. for a mutable set it's a bigger change

23:01 * gfrlog` is still wondering what amalloy meant by that

23:01 amalloy: Scriptor: #{} is a hash set (well, probably array set)

23:02 sorted-set is a tree set

23:02 Scriptor: ah, interesting

23:02 amalloy: gfrlog`: a mutable tree set would have to percolate the changes back up to the root at every insertion

23:02 persistent tree sets have to do that anyway

23:03 gfrlog`: amalloy: so how would clojure's implementation be "pretty close" to the mutable tree set?

23:03 amalloy: gfrlog`: i dunno man

23:03 gfrlog`: it seems like an all or nothing attribute to me

23:06 amalloy: i mean the code to implement it seems like it would be similar, not that they would behave similarly

23:06 and who knows, maybe i'm wrong. feel free to read more thoroughly into the source; i've only skimmed

23:07 * gfrlog` runs off to give finger-trees a less nsfw name, like lazy-trees

23:08 amalloy: cuddle-trees

23:09 gfrlog`: rooted acyclic graphs with ordered children

23:10 (ragwoc?)

23:10 I guess that's a description of trees generally, not finger-trees specifically :/

23:14 amalloy: trees don't neessarily have ordered children

23:14 gfrlog`: finger-trees don't?

23:15 $google tree data structure

23:15 lazybot: [Tree (data structure) - Wikipedia, the free encyclopedia] http://en.wikipedia.org/wiki/Tree_(data_structure)

23:19 amalloy: gfrlog`: they do. but you said it was a description of trees generally, so i interjected

23:19 gfrlog`: :)

23:19 yeah I admit it was ambiguous

23:20 although, if it can be said that a tree has two separate pertitent definitions -- a data structure, and a type of graph -- then one could argue that the first should be understood by the context

23:20 (by "a type of graph" I mean specifically connected acyclic graphs)

23:24 amalloy: gfrlog`: {:a nil :b {:c 2}} is a "tree data structure". what order are the children a and b in?

23:25 gfrlog`: I prefer to call it a map :P

23:26 okay you win this round

23:27 amalloy: (inc pedantry)

23:27 lazybot: ⟹ 1

23:28 gfrlog`: (inc (inc pedantry))

23:28 lazybot: ⟹ 1

23:28 gfrlog`: (inc )

23:28 lazybot: ⟹ 1

Logging service provided by n01se.net