#clojure log - Dec 07 2009

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

0:17 somnium: if you use clojure to generate code in 'blub' that depends on libraries that are not eclipse-compatible, but there is no dependency on clojure in the generated 'blub', are there any issues?

0:25 JAS415: wait hut

0:25 what*

0:26 am i generating source code to blub or bytecode to blub?

0:26 and why am i generating blub code when i could be generating clojure code?

0:26 and what does eclipse have to do with it?

0:26 i dont even use eclipse, i use emacs

0:28 _ato: what does eclipse-compatible even mean?

0:28 or do you mean the EPL?

0:29 clojure in no way sets what license code you write that uses it has to be

0:29 it's a weak-copyleft

0:29 you just can't relicense clojure-itself to say GPL

0:29 JAS415: oh its a license thing

0:30 _ato: yeah I had to read the sentence 5 times before I realised he was talking about licenses

0:30 because Eclipse-the-IDE-compatible makes absolutely no sense

0:30 so there's no issues

0:30 JAS415: yeah

0:32 _ato: what the non-eclipse-compatible licenses say is another thing though. But if it's the GPL you're talking about I'd say that's probably okay. It's like using Visual Studio to compile a GPLed project. You don't have to supply the source code to visual studio

0:33 JAS415: yeah or if you submitted a patch to clojure that used GPL code

0:33 that would be a no-no

0:33 somnium: pure-blub, not byte-code

0:34 JAS415: im generating LFE into a text file

0:34 works great :-)

0:35 somnium: just wondering, playing with js generation that calls libs like mootools/dojo/jquery

0:35 JAS415: oh like scriptjure

0:35 yeah that works

0:35 somnium: clojure-script lite kind-of

0:36 JAS415: you can either include the (jquery for example) script file as a seperate link or you can slurp it and concatenate them (probably)

0:36 somnium: but a clojure generated jquery plugin mould be okay to release under whatever license?

0:36 JAS415: oh

0:36 we are on licenses

0:36 i think the answer is 'yeah'

0:38 somnium: btw, anyone know how clojure finds tail positions?

0:38 _ato: looks for the last argument in every do form?

0:38 somnium: doing a bit of wheel reinvention implementing loop*, though its fun it its way

0:39 _ato: the recur I hacked into scriptjure looks like: (str "return arguments.callee(" (str/join ", " (map emit args)) ");")

0:40 somnium: hmm, need to add explicit return so really need to find last node

0:40 _ato: (that's a non-TCO version though)

0:41 somnium: _ato: not using scriptjure, but trying to implement loop* as a do-while for loop* and fn*

0:41 need to find every actual tail position though... probably need a zipper

0:44 do ... {blah} while (gensym__recur)

0:44 where is clojure's recur TCO implemented?

0:47 JAS415: you could look at core.clj

0:47 hiredman: that's not in core.clj

0:47 _ato: RecurExpr in Compiler.java

0:47 hiredman: that's in the compiler

0:47 JAS415: hmm

0:47 _ato: and various other places

0:47 somnium: yeah, ive read it, recur and loop* are special forms

0:48 JAS415: right

0:48 but its like a goto or whatever, right?

0:49 _ato: gen.goTo(loopLabel);

0:49 does javascript have named loops?

0:50 oh well I guess it doesn't need to if you implement your script's while in terms of loop

0:54 timothypratley: ,(defmacro foo [form] `(println ~form))

0:54 clojurebot: DENIED

0:54 JAS415: you can probably implement loop in terms of while

0:55 timothypratley: (foo (1 2)) <--- doesn't do what I want :)

0:55 JAS415: err

0:55 somnium: Ive got let* working, and destructuring will just-work (using js primitive arrays and objects), but was hoping someone knew a tail finder algorithm I could just use for TCO

0:55 JAS415: you need (foo (list 1 2))

0:55 otherwise it evaluates (1 2)

0:56 and 1 isn't a fn

0:56 timothypratley: Indeed, but being a macro... isn't there some way to avoid evaluating (1 2)?

0:56 _ato: ~'form

0:56 clojurebot: excusez-moi

0:57 _ato: or wait

0:57 it's the other way '~form is what you want

0:57 timothypratley: ah great!

0:57 JAS415: yeah

0:57 somnium: ,`(println ~(str '(form)))

0:57 clojurebot: (clojure.core/println "(form)")

0:57 timothypratley: thanks.... mindboggling

0:58 _ato: might be more obvious why as: (quote ~form)

1:00 JAS415: somnium, you can't do something like:

1:01 while (recur)

1:01 {

1:01 (set recur false)

1:01 (do stuff)

1:01 }

1:01 recur (bindings)

1:01 (set recur true bind-bindings)

1:01 and make recur like a macro-ey thing

1:01 and have that while for stand in for loop

1:02 of course you'd still have to detect if it is actually a tail

1:03 somnium: I want to be able to macroexpand a subset clojure code and compile it to executable js

1:03 _ato: it's sort-of annoying as you have to track the return value

1:03 somnium: _ato: yes

1:04 I tried to read clojurescript.clj to see how chouser did it but its impenetrable to me

1:04 _ato: you also need to deal with javascript's variable scoping, null out all the variables when you break out of the loop and such

1:05 somnium: no, scoping is easy with containing functions

1:05 _ato: ah right, I thought you were trying avoid the overhead of that

1:05 somnium: let* is more or less (function() { ...bindings ... body })()

1:05 _ato: but yeah, should be doable

1:05 ah

1:06 well that makes your return values easier then

1:06 cause you can just return

1:06 somnium: in what im hacking on anyway

1:06 _ato: if you wrap all loops in anonymous functions

1:06 hiredman: that is an odd way to do let

1:06 somnium: hiredman: how else to guarantee local scope?

1:07 hiredman: (function(...names..){body})(..values..)

1:07 somnium: hmm, almost the same no?

1:08 _ato: hmm

1:08 hiredman: sure, which is way your way seems so odd

1:08 let as a λ like that is right out of sicp

1:08 somnium: js is quite lispy

1:09 hiredman: it's scheme minus the good bits

1:09 _ato: (function(x) { while(true) { if (x < 5) { x = x + 1; continue; } else { return x; } } })(0);

1:09 somnium: at least it has more than a cons-cell :p

1:09 _ato: would be something like: (loop [x 0] (if (< x 5) (recur (inc x)) x))

1:10 hiredman: I've been tinkering with a lisp -> php compiler

1:11 I'm stopped right now because I think I need to throw out my whol function call and recur implementation

1:11 somnium: If I can get recur working, it should be enough to start writing clojure in js in clojure, which sounds fun

1:11 hiredman: what I currently have won't support varargs nicely

1:12 (or really at all)

1:12 somnium: I was planning on doing var

1:12 args with the arguments object in js

1:12 at least until its possible to get seq working

1:12 hiredman: yeah, matching the host is good

1:13 I did not, and match php up to lisp can be maddening

1:14 http://www.thelastcitadel.com/lab/pl/a.phps generated code

1:16 somnium: hiredman: it sounds so painful I cant imagine what compelled you :)

1:18 http://github.com/tenderlove/phuby

1:18 ^^ might be worth inspiration, or a laugh

1:18 technomancy: heh... phuby is so ridiculous

1:18 (but it's ridiculous on purpose.)

1:19 hiredman: cute

1:19 technomancy: http://www.rubyconf.org/talks/60-worst-ideas-ever-

1:28 somnium: hiredman: I can hardly distinguish your php-compiler's output from idiomatic php

1:28 other than the gensyms

1:31 James__d: What does k-lined mean?

1:32 hiredman: somnium: well, I did run it through a beautifier for the nice formating

1:33 but I would like the generated php code to be ok to deal with without the lisp source

1:34 somnium: hiredman: isnt 'being okay to deal with' always the achilles heel of php?

1:34 hiredman: :P

1:43 TheBusby: What's the best way to return the counts of various values in a list? Ex. '(1 2 2 3 3 3 44) into {1 1, 2 2, 3 3, 4 2}

1:44 er, the Example should be '(1 2 2 3 3 3 4 4) into {1 1, 2 2, 3 3, 4 2}

1:45 arbscht: ,(doc frequencies)

1:45 clojurebot: "([coll]); Returns a map from distinct items in coll to the number of times they appear."

1:45 arbscht: from c.c.seq-utils

1:45 TheBusby: arbscht, thank you!

1:46 hiredman: (apply merge-with + (map #(array-map % 1) (1 2 2 3 3 3 44)))

1:46 ,(apply merge-with + (map #(array-map % 1) (1 2 2 3 3 3 44)))

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

1:46 hiredman: bleh

1:46 ,(apply merge-with + (map #(array-map % 1) '(1 2 2 3 3 3 44)))

1:46 clojurebot: {44 1, 3 3, 2 2, 1 1}

1:48 timothypratley1: ,(reduce #(assoc %1 %2 (inc (%1 %2 0))) {} [1 2 2 3 3 3 4 4])

1:48 clojurebot: {4 2, 3 3, 2 2, 1 1}

1:50 timothypratley1: (defmacro foo [f] `(def ~(symbol (str "foo" (count (meta (var f))))))) <--- how can I make this work? :)

1:50 arbscht: timothypratley1: that's pretty much how c.c.seq-utils/frequencies is implemented :)

1:51 somnium: timothypratley1: what is that supposed to do?

1:51 timothypratley1: arbscht: yup frequencies is the way to go :)

1:52 somnium: I want a macro foo that I can call like (foo defn)

1:52 and it will def foo7

1:53 so that I can create tests with deftest with a symbol that is dependent on meta-data of another var

1:53 (what a tongue twister)

1:56 The bit I'm stuck on is getting (var f) hmmm maybe I should be doing (resolve f) or something

1:57 omg - that actually works....

1:57 sorry for the noise.

2:03 KirinDave: Man I see a red line in my history but I cannot find it.

2:03 Did someone mention my name or something?

2:27 Man, I love it

2:28 Someone hacker-newses my clojure chat

2:28 and within 2 hours someone says, "I have a better one in scala. Just install lift!"

3:31 LauJensen: Morning gents

4:12 cgrand: KirinDave: I'm interested to know what wasn't working for you with Enlive

4:39 Licenser_: good morning clojure world!

4:41 Is there a 'common and good aproach' for writing a clojure app that comunicates over network to send forth and back information/commands

4:41 implementing a low level protocoll seems a bit of an overkill to me for just sending a bit of information

4:42 somnium: Licenser_: I dont know, but if you write a wrapper for nio do put it on github :P

4:43 cark: Licenser : both the server and client are clojure applications ?

4:44 Licenser_: cark, yap

4:44 somnium: what is nio?

4:44 clojurebot: What is meta

4:44 Licenser_: and nice to hear from you again :) how is your mongo driver doing?

4:44 cark: well you can easily serialize clojure data structures by printing these then use clojrue reader to get data structures back

4:45 is that enswering the question ?

4:45 answering =/

4:46 Licenser_: cark: aside of not having a clue how to serialize or deserialzie (but I guess google will tell me that) yap that is what I was looking for I think

4:46 somnium: Licenser_: java.nio has tools for tcp/ip stuff, with os access to os streams, but a bit low level

4:46 cark: i'm not talking about real serialization, just printing, which is the same, and very easy

4:46 somnium: been using for my attempts to reimplement the mongo driver in clj

4:47 Licenser_: somnium: ah I see, I don't really want to go into that low level, I mostly want something like sawpn a process, connect to a server be happy and not worry about anything as TCP or below

4:48 cark: ,(read-string (with-out-str (pr '(a b :a :b [1 2 3]))))

4:48 clojurebot: (a b :a :b [1 2 3])

4:48 cark: so now you can devise your high lvl protocol based on it

4:49 carefull about *read-eval* though

4:49 Licenser_: cark: you're my hero

4:50 cark: =)

4:50 Licenser_: cark: it's a entirely non critical application so I don't worry much about read-eval also I don't think I'll even need it

4:50 tomoj: munges structmaps though :/

4:51 cark: wan't there a flag for that ?

4:51 can't remember it now =/

4:51 tomoj: *print-dup* ?

4:51 cark: ah could be yes

4:51 tomoj: that will just make structmaps print unreadably

4:51 at least in my version

4:52 cark: ahwell anyways you get a standard map in the end, so i guess that's good enough for communications

4:52 Licenser_: Yap it's good enough for me at least

4:53 tomoj: packing the regular maps you get back into structmaps wouldn't be too hard I guess

4:53 well of course it wouldn't be hard, but I think it shouldn't slow you down much either

4:54 ,^(read-string (binding [*print-dup* true] (with-out-str (pr (with-meta [] {:foo 3})))))

4:54 clojurebot: java.lang.RuntimeException: java.lang.Exception: EvalReader not allowed when *read-eval* is false.

4:54 Licenser_: Bottelneck won't be maps, rather waiting for the othser side to do something

4:54 so I don't worry much about it

4:54 tomoj: oh

4:55 well with *print-dup* and *read-eval* on, you get to keep your metadata

4:55 cark: i think a protocol should be as simple as possible, and decoupled from your internal representation anyways

4:56 Licenser_: *nods*

4:56 tomoj: c.c.json is easy :)

4:56 cark: json isn't good enough in most cases

4:57 i mean, no decimals ?

4:57 somnium: cark: strings!

4:57 cark: bleh that's ugly =)

4:57 i have to do this for web stuff, but i hate it

4:57 tomoj: I really like it

4:57 but the choice was already made for me by couchdb anyway

4:57 somnium: hopefully c.c.json will speed up a lot with types/protocols

4:58 cark: if you want speed i'm pretty sure there must be som good java json libraries

4:58 somnium: recursive multimethod calls really dont show closures strength

4:58 tomoj: hmm that's a good idea

4:59 maybe I will try converting c.c.json to learn the new stuff

4:59 still don't understand it at all

4:59 somnium: the one packed with mongo is crazy fast, and jackson is supposed to be really good

5:00 jackson has 200 or so classes though :/

5:00 cark: oh nice a streaming api =P

5:02 somnium: cark: thats what was recommended to me, but I havent had the determination to wade through the javadoc yet

8:07 fliebel: Hey, What is a good Clojure editor?

8:07 Chousuke: emacs .)

8:08 fliebel: I tried emacs today, but its key combinations seem horrid to me.

8:12 Maybe it's a good tool after having used it for years on the terminal, but for me it's not really friendly.

8:13 cemerick: fliebel: enclojure is pretty nice

8:14 fliebel: Hmm, seems like a good choice since NetBeans also supports Python and PHP if I remember correctly. Somehow Netbeans always make me think 'Java'.

8:15 cemerick: ...and ruby and C++ and scala and javascript... :-P

8:15 esj: i'd say emacs

8:16 but really, nothing to get excited about

8:16 cemerick: I guess it's better to get the editor discussion of the week out of the way early

8:16 esj: yeah, then we can move onto seque :)

8:17 fliebel: esj: I find Clojure hard enough, I don't want to learn another 1000 keyboard commands.

8:18 tomoj: :D

8:18 esj: fliebel: fair play.

8:18 fliebel: esj: what's with seque?

8:18 cemerick: the number of commands isn't the problem, it's the lack of discoverability because of the 70's terminal UI.

8:19 tomoj: I love the lack of discoverability

8:19 it means I am always finding new things :)

8:19 fliebel: At least it has the geek factor....

8:19 esj: fliebel: blocking queues etc

8:19 cemerick: tomoj: yeah, I love a good game of "how the frig am I supposed to do X?" ;-)

8:20 tomoj: luckily that question doesn't come up very often for me

8:20 esj: cemerick: its usually C-x A-w C-%

8:20 tomoj: but "oh shit, I can do Y too??" happens often

8:20 cemerick: esj: see, I don't know if you're agreeing with me or not now. ;-)

8:22 esj: cemerick: emacs is well weird, no doubt, but uniformly weird - but it work the same on all my computers, OS/s, virtualised blah blahs etc. Time saver.

8:23 notallama: i was reading about emacs history the other day. more keyboards should have a cokebottle modifier.

8:25 esj: noallama: looking that up...

8:28 fliebel: is vim any better then emacs when dealing with keyboard shortcuts?

8:29 esj: fliebel: that's the question that has launched 1000 warships.

8:29 * chouser fights and wins the battle against entering an editor discussion.

8:30 fliebel: I should have known that… especially with Lisp guys like you… Sorry…

8:30 esj: space-cadet keyboard: n.

8:30 A now-legendary device used on MIT LISP machines, which inspired several still-current jargon terms and influenced the design of EMACS. It was equipped with no fewer than seven shift keys: four keys for bucky bits (‘control’, ‘meta’, ‘hyper’, and ‘super’) and three regular shift keys, called ‘shift’, ‘top’, and ‘front’

8:30 glorious !

8:30 tomoj: what are my options for providing configuration for my library? take e.g. a database client library. I don't think I want to have to pass my database config to every library function (or do I?). I also don't think I want to put a binding that provides the config around every place I use the library. is there another way?

8:32 or maybe one of these is good and I'm just thinking about it wrong

8:32 ordnungswidrig: hi all

8:33 esj: i'd be interested to hear what ppl think here ? I'd plump for *my-config* and keep the function interface tidy, but then i'm usually wrong :)

8:33 noidi: is it possible to tell whether a module is being run from a command line as a script, or loaded as a library?

8:33 I'd like to have something like python's `if __name__ == "__main__"`

8:39 cemerick: noidi: (when *command-line-args* ...), if memory serves

8:40 hrm, no, that's probably not right

8:40 fliebel: Can't you check the namespace? (just a guess)

8:40 chouser: tomoj: having a rebindable var as the only way to pass in the db config is likely to get annoying in several contexts.

8:41 tomoj: yeah, it sounds annoying

8:41 chouser: tomoj: if possible, I'd recommend allow both -- a db arg that, if not given, defaults to *db*

8:41 tomoj: that doesn't sound too bad

8:42 chouser: noidi: hm, that's come up before. I have a vague memory of everyone reaching a consensus and then doing nothing about it.

8:43 noidi: :)

8:43 tomoj: -main is one way but requires compilation to classes :/

8:43 noidi: there seems to be a bug in parsing the command line arguments... clojure seems to treat `'foo bar' baz` as `foo bar baz`

8:44 i.e. it doesn't understand command line arguments with spaces in them

8:44 chouser: on stackoverflow, someone's recommending *command-line-args*, but that doesn't seem quite right.

8:45 that'll be true for all libs if any command line args were given.

8:47 huh. it's quite a common question.

8:55 jonathanturner: I've googled around a bit, but I was wondering if clojure has a zip command. Something like (zip [1 2 3] [4 5 6]) over lazy sequences?

8:55 I didn't know if the clojure one has a different name

8:56 chouser: ,(map vector [1 2 3] [4 5 6])

8:56 clojurebot: ([1 4] [2 5] [3 6])

8:56 chouser: so depending on what you want to do with it, you may be able to put the next operation right in the 'map' call.

8:59 fliebel: Can you define macros that do not use sexps? like define _some string_ to turn into (strong "some string") (whatever that might do)?

9:00 Chousuke: those are called reader macros, and no

9:01 jonathanturner: chouser: thanks, and that's lazy as well?

9:01 I was thinking of the equivalent of a lazy seq that's pulling off zipped values

9:02 Chousuke: jonathanturner: map is lazy, so yes. :)

9:02 jonathanturner: Chousuke: cool, thanks

9:02 fliebel: Chousuke: would that be possible to implement… theoretically? It would be so cool to make your own data types and stuff...

9:02 noidi: fliebel, you could read the code in and modify the result before passing it to eval

9:03 Chousuke: fliebel: well, it wouldn't be too difficult to implement but Rich doesn't want to, at least for now

9:04 noidi: ,(eval (map #(if (= 1 %) 3 %) (read-string "(+ 1 2)")))

9:04 clojurebot: DENIED

9:04 Chousuke: noidi: that's not quite as neat as a reader macro :P

9:05 fliebel: So, how many kinds of macros are there(that would be cool to have in Clojure)?

9:05 noidi: yeah, maybe not, I've never used common lisp so I don't know

9:06 Chousuke: fliebel: I think the primary reason for not having a user-extensible read-table is the namespacing issue

9:06 noidi: I don't like reader macros as an idea, but maybe that's just because I haven't used them

9:06 fliebel: I like anything that lets you fiddle with the language :D

9:06 Chousuke: noidi: clojure has many reader macros already. :)

9:06 noidi: they're just not user-definable.

9:07 noidi: yeah, I know

9:07 fliebel: Chousuke: where are they defined?

9:07 Chousuke: in the java source

9:07 LispReader.java

9:07 But hm, Common Lisp also has compiler macros

9:07 noidi: maybe I should learn a bit of CL and give them a try

9:07 Chousuke: I'm not sure what those do, though.

9:08 fliebel: What are compiler macros? I guess I asked about them a while back, without knowing they where compiler macros.

9:08 Chousuke: noidi: they're pretty useful sometimes but having them might lead to fragmentation (everyone has their own reader macros for things they think are important) and collision :/

9:08 noidi: yeah, the collisions are the part that I'm worried about

9:09 Chousuke: If you can solve those issues though, maybe you could convince Rich to allow user access to the read table. I don't know :)

9:10 noidi: my ignorant gut-feeling is that you might as well go all the way and implement a proper parser instead of messing with Clojure's reader

9:10 if you want to use a language radically different from Clojure

9:11 cemerick: I'm guessing that a most if not all of use cases for userland reader macros will be addressed when things wind around to supporting java-in-parens, and similar

9:11 Chousuke: I've been thinking about having some reader pragma for enabling a user read-table, which would be specific to each loaded file or character stream

9:11 duper: Say for example I want to use Clojure on the .NET runtime instead of the JVM, what are the advantages it has over pre-existing LISPy .NET dialects, i.e. why would I want to use Clojure instead of something like IronScheme for example?

9:12 (I'm coming from a Dr/Mz-Scheme and GNU guile background if that makes any difference)

9:12 Chousuke: so at the top of your source file you could say something like #reader:(use-read-table foo.bar/my-readtable)

9:13 fliebel: or like the ns definition at the top of some code, just allow users to specify their own read table.

9:13 Chousuke: the reader doesn't care about the ns declaration though.

9:14 but if readtable mods were made explicit in every source file, it might not be so bad to have them.

9:15 at least you'd always have a "warning"

9:17 stuartsierra: Once you start messing with the read table, though, you're basically implementing a parser.

9:18 fliebel: stuartsierra: A lot easier then writing your own language, don't you think? :D

9:18 stuartsierra: fliebel: maybe, but writing parsers really isn't that hard

9:19 chouser: duper: Clojure is unique from other lisps in it's first-class support of non-list collections (maps, sets), its seq abstraction, immutability, concurrency support, to name a few.

9:19 stuartsierra: And I've yet to see an example of user-defined reader macros that offers significant advantages over (function "string")

9:21 fliebel: stuartsierra: I think support for writing regexes or xml in your source is quite cool… sometimes… when used with caution… or not at all…

9:21 stuartsierra: :)

9:23 chouser: ok, guys. The first chunk of the (as yet untitled) book _fogus_ and I have been working on is about to go out for technical review.

9:23 cemerick: stuartsierra: we'd *love* to have a reader macro for our regex impl *shrug*

9:23 liebke: congrats chouser!

9:24 chouser: If any of you have the time to read the whole thing and respond over the course of a week or two (not sure what the deadline is exactly), I can forward your contact info to the Manning editor that's running the review process.

9:24 I guess send me a private message with your real name and email address if you're interested.

9:25 otherwise you can wait a couple more weeks, get the early-release PDF of the same content, and comment on the book forum which will be up by then.

9:25 liebke: thanks!

9:26 _fogus_: liebke: Thanks!

9:27 liebke: hey _fogus_! So you still haven't settled the title issue yet?

9:27 aking: chouser: is it aimed at the beginner, intermediate or advanced user?

9:27 fliebel: Are you guys writing a Clojure book?

9:27 _fogus_: liebke: not yet :( Reviewers would probably have a say in the matter

9:28 chouser: aking: intermediate or advanced. If you're an ambitious beginner it should be sufficient for you, but we're concentrating on really getting inside Clojure's head, thinking the way Clojure thinks about things.

9:28 fliebel: yes

9:29 shr3kst3r: sounds fun

9:30 aking: in that case, I'll submit my name :)

9:31 fliebel: chouser: I would appreciate an intermediate book, I'm tired of reading the same beginner stuff at every tutorial, but I'm still not capable of doing anything in Clojure.

9:33 noidi: chouser, sounds great!

9:34 imho there's a real need for a book that teaches OO programmers to think in a functional, lazy, immutable way

9:35 fliebel: noidi: +1

9:36 chouser: Manning also has "Clojure in Action" coming, which I think is more of an intro book, though it also digs into several very practical real-world examples. I think. I haven't read it yet, but the TOC and first chapters are up.

9:37 rys: Agreed, something to stop the "hang on, what?" moments if you've never programmed functionally before would be cool

9:39 fliebel: chouser & _fogus_: Are you programmers writing a book or writers doing Clojure? I read the author of "Clojure in Action" say somewhere on the MEAP forum "This is the first time I'm writing a book", which makes me fear for the quality.

9:41 chouser: fliebel: we're programmers, but we each have blogs you can peruse to get a sense of how we write. Also, Manning has a great set of (mostly non-technical) editors who have been working to keep up the over-all quality of the content.

9:42 fliebel: chouser: ok, fine :)

9:42 esj: three cheers for more Clojure books ! Thanks chouser.

9:42 fliebel: Chouser: what is the address of your blog?

9:43 chouser: ok, thanks to everyone to volunteered, we'll pass your names along.

9:44 _fogus_: Yes, thank you all.

9:45 chouser: fliebel: http://blog.n01se.net/?cat=14

9:45 fliebel: thanks

9:45 chouser: fliebel: see also http://blog.fogus.me/

9:46 ordnungswidrig: chouser: off topic but nice, your md-lvm-migration. Finally I see I'm not the only one trying such things :-)

9:46 chouser: ordnungswidrig: ah, yes ... I'm not the only author on that blog. But I endorse anything agriffis says about lvm :-)

9:46 _fogus_: fliebel: You will ultimately be the judge if we can write or not, but I can say that we likely have the only Clojure book that quotes Dr. Seuss.

9:48 ordnungswidrig: chouser: oh, I see. anyway lvm is great fun. Some years ago I remote-repartitioned a root server from a 2-partition installation of red hat into a lvm based debian. The reboots were exciting moment. No remote hands to my rescue...

9:49 chouser: ordnungswidrig: I can relate to that kind of excitement. :-)

9:50 ordnungswidrig: chouser: btw twitter fails in hrefing your blog's urls. It stops at "?". How annoying

9:51 chouser: ordnungswidrig: Clicking the links should work, I think, even though the url doesn't look right.

9:55 ordnungswidrig: can lein do multi-project builds=

9:56 s/=/?/

11:10 patrkris: were there a discussion going on about the CACM-article "Software transactional memory: why is it only a research toy?" once? Can't seem to find it on Google Groups.

11:12 reify: '""""""""""""""

11:16 saml: give me a tutorial for clojure. how to set up a project (or be leech aside java project) and the tutorial should teach frequently used emacs key bindings

11:18 ordnungswidrig: saml: emacs can tell you itself

11:19 saml: but it tries to tell me too much

11:19 well i'll figure out and write a tutotirl

11:20 fliebel: chouser: On your blog you're writing about Clojure-in-Clojure. Is this really going to happen soon? And will there be an implementation on Parrot?

11:22 ordnungswidrig: saml: there are a lot of emacs tutorials around.

11:24 saml: it shouldn't take more than 10 minutes for the first timer to figure out buffer navigation. emacs fails

11:24 _fogus_: patrkris: http://groups.google.com/group/clojure/browse_thread/thread/82497ffad880de2b/ (maybe)

11:25 saml: never mind. i fail. i found a toturial

11:25 patrkris: _fogus_: exactly that, thanks

11:29 slyrus: so, unless I'm missing something obvious, tools like lancet and leiningen are designed for building jars. what do folks use for loading .clj files into an already-running clojure instance?

11:31 ordnungswidrig: slyrus: swank/slime

11:32 slyrus: that's what I'd use

11:32 slyrus: ordnungswidrig: well, yeah, of course, i'm using swank/slime :)

11:35 ordnungswidrig: yes, a slime-asdf-like contrib that provided slime-load-system that worked with clojure projects would be nice, but it's the underlying asdf-like infrastructure that i'm having trouble finding, not the slime wrapper for such

11:36 the-kenny: Everyone is waiting for M-x swank-lein :)

11:36 slyrus: I guess i'm looking for the clojurey equivalent to (asdf:oos 'asdf:load-op ...)

11:36 the-kenny: slyrus: (require 'namespace)

11:36 (with the classpth set to the right files)

11:40 slyrus: thanks the-kenny

11:43 MikeDev: the-kenny

11:43 the-kenny: pm please?

11:43 the-kenny: MikeDev: Sure

11:43 Do it ;)

11:45 KirinDave1: the-kenny: I wanted to thank you and technomancy for your help yesterday. People seemed to like the chat server.

11:46 I need to redditwhore it today, tho

11:47 the-kenny: KirinDave1: You're welcome :) I'm pleased when I can help

11:48 KirinDave1: Although the people on news.ycomb were… kinda ridiculous.

11:48 Things like, "That's cool, but this scala version written with lift is wayyyy cooler I mean totally."

11:48 cemerick: KirinDave: live by the YC, die by the YC :-)

11:48 KirinDave1: Or, "Sure, but the Node.js will scale to thousands of users. Can Java do THAT?!"

11:49 I think I am going to make a series out of it.

11:49 next up is netty integration

11:50 cemerick: KirinDave: using what framework, do you think (or, none at all)?

11:50 KirinDave1: cemerick: ?

11:50 cemerick: I dunno. I have never been a java man.

11:50 cemerick: Any suggestions would be greatly appreciated.

11:51 cemerick: KirinDave1: there's a bunch of clojure frameworks that simplify jetty deployment (even beyond the already-simple java-native paths)

11:52 KirinDave1: cemerick: Jetty is a web framework, right?

11:52 cemerick: jetty is a webapp server

11:52 KirinDave1: cemerick: I think I am going to keep this as a raw socket application.

11:52 cemerick: As in the spirit of the original node.js submission.

11:53 cemerick: But adding major speed+scalability and maybe even SSL without too much code would be a pretty powerful demo.

11:53 Don't you agree?

11:53 cemerick: indeed

11:54 KirinDave1: So netty provides non-blocking event-driven IO support.

11:54 So I don't need to have a thread per user.

11:54 cemerick: hah, I was assuming 'netty' was a mistyping of jetty

11:54 KirinDave1: No, I think jetty is a punned name? :)

11:54 Or netty.

11:55 No idea which came first.

11:55 Last time I did java for seriously was in college in 2003.

11:55 cemerick: jetty has been around for a *long* time, but that doesn't mean anything, I suppose

11:55 KirinDave1: Back in the Java 2 days

11:55 I was happy to discover java.nio.

11:55 I consider java.io to be kind of java.io.whoops-sorry-about-that

11:56 and it looks like (and sounds like) java.nio is more like java.nio.relax-i-got-dis

11:56 Which is good, because in college I was so effing screwed by java efficiency issues on a few of my projects.

11:58 ordnungswidrig: is there a json pretty-printer for clojure?

11:59 oh there it is: (org.danlarkin.json/encode-to-str {:a :b :c :d} :indent 4)

12:00 MikeDev: Is there an HTML parser in clojure that doesn't require external libs?

12:01 ordnungswidrig: MikeDev: HTML or XHTML?

12:01 hiredman: use tagsoup

12:01 MikeDev: HTML

12:01 hiredman: I should say "no, use tagsoup"

12:01 replaca: ordnungswidrig: or there's a "more sophisticated" but slower version in clojure.contrib.pprint.examples.json

12:02 ordnungswidrig: the pp version works more like a lisp pretty printer in that it keeps things together on a line when it makes sense

12:02 so it's "prettier" :-)

12:05 KirinDave1: that chat server example is sweet. Thanks for posting about it.

12:06 MikeDev: clojure.contrib.tagsoup?

12:07 does tagsoup require external jar file?

12:09 replaca: MikeDev: yeah. just google and you'll find it

12:10 MikeDev: it's a super-common java library

12:10 MikeDev: not a contrib piece

12:10 MikeDev: http://home.ccil.org/~cowan/XML/tagsoup/tagsoup-1.2.jar ?

12:10 replaca: MikeDev: sounds right

12:11 MikeDev: o great, it has no closure docs

12:13 the-kenny: MikeDev: I think there isn't a clojure-interface to tagsoup.. just call the java-methods

12:14 patrkris: MikeDev: there is a pretty neat interface to tagsoup, it's called enlive

12:14 the-kenny: Oh.. forget what I've said

12:14 patrkris: MikeDev: http://clj-me.blogspot.com/2009/01/enlive-yet-another-html-templating.html gives a pretty good idea of what you can do with it

12:15 MikeDev: good because i didnt see any docs on it at it's webpage even in java

12:15 patrkris: it's pretty cool, since you can select HTML elements using CSS-style selector syntax

12:16 replaca: patrkris: although enlive is mostly aimed at templating (i.e. transforming html) as opposed to reading

12:16 replaca: a cool project would be a tagsoup -> clojure.zip interface

12:17 patrkris: replaca: you are probably correct, but the link I gave above shows how well it can be used for reading HTML (scraping in this case of websites)

12:17 replaca: patrkris: yeah, I think it woulld just be a simplification of stuff Christophe haas already done in enlive

12:18 patrkris: replaca: as far as I can see it's right there :)

12:18 cgrand: I started enlive as a templating system but I think there are more people using it for screenscraping than for templating

12:18 dnolen: patrkris: enlive is very good at scraping, probably the simplest use of enlive really. enlive also uses clojure.zip. and at 600 LOC can't get much simpler I think ;)

12:19 MikeDev: What I'm trying to accomplish is fetching the text out of header tags

12:19 cgrand: (-> your-url duck-streams/reader html-source (select [:h1]) text)

12:20 MikeDev: my regexp isnt good enough though I was fairly warned by people in #perl

12:20 so it's my fault

12:20 it was quicker at the time though

12:20 cgrand thx

12:20 patrkris: MikeDev: forget about regex in this case :)

12:21 ordnungswidrig: parsing HTML with regex is your way to hell

12:21 MikeDev: lesson learned

12:21 but this isnt production code

12:22 patrkris: i think tagsoup is really good at handling almost any html you can throw at it (as far as I've read)

12:22 cgrand: MikeDev: oops, (map text (-> your-url duck-streams/reader html-source (select [:h1])))

12:23 MikeDev: just letting me know that duck-streams reader html-source is what I want is fine

12:24 but thnx very much

12:26 Licenser: aloa

12:30 replaca: cgrand: it doesn't get much simpler than that. very cool - I seem to use only the complex use case and forgot about the simple one :-)

12:35 MikeDev: is text text that I'm supposed to be matching?

12:35 it would have to be a function though?

12:36 patrkris: MikeDev: not sure if I understand, but text is a function to get the textual contents of a tag

12:36 MikeDev: doesnt seem to be defined for me

12:36 i've use'd duckstreams and reader is defined

12:37 patrkris: yes, but these are from clojure-contrib

12:38 have you referred to enlive correctly (it's on you classpath, you have imported it by means of use/refer/require)?

12:38 MikeDev: o i need enlive

12:38 okay

12:38 i thought i only needed duckstreams

12:38 patrkris: that must have been a big surprise for you :D

12:39 you need enlive to be able to traverse the HTML from the duck-stream reader

12:41 MikeDev: I like how github does "hardcore archiving action"

12:42 patrkris: yeah :) alternatively you could just get git and clone the repository... probably less hardcore

12:42 in the archiving-sense of the word

12:46 MikeDev: does enlive depend on tagsoup?

12:47 patrkris: yes

12:48 MikeDev: my system doesnt have git

12:51 hiredman: just get tagsoup

12:51 * hiredman feels kind of like a broken record

12:51 saml: tofu soup is good

12:52 hiredman: clojurebot: zipsoup?

12:52 clojurebot: Huh?

12:53 hiredman: http://github.com/hiredman/odds-and-ends/blob/master/newegg.clj <-- use the zipsoup function from here, Chouser wrote but I can't find the original anymore

12:55 MikeDev: what do you "use" for tagsoup?

12:56 cgrand: MikeDev: have you leiningen?

12:57 MikeDev: huh?

12:58 cgrand: Leiningen is a build tool that manages dependencies for you.

12:59 MikeDev: I just dl'ed the jar and included it in my classpath

12:59 cgrand: Anyway if you click download on github for enlive you should get a zip which include tagsoup

12:59 the-kenny: leiningen is really cool :)

12:59 MikeDev: but having a hard time finding API docs

12:59 let alone cloure docs

13:00 it is SAX compliant though

13:00 so that's sweet

13:00 whatever that is

13:01 http://home.ccil.org/~cowan/XML/tagsoup/tagsoup.pdf maybe

13:01 boy was that well hidden

13:02 cgrand: MikeDev: so you have contrib, tagsoup and enlive on your classpath?

13:02 KirinDave1: Ah, am I not the only person having problems with enlive? :)

13:02 MikeDev: just contrib and tagsoup

13:03 and contrib is use'd

13:03 tagsoup is a jar

13:03 use'd within clojure

13:05 cgrand: ok, then copy the function startparse-tagsoup that hiredman pointed you to http://github.com/hiredman/odds-and-ends/blob/master/newegg.clj

13:05 then (clojure.xml/parse url startparse-tagsoup) should return a tree of your HTML resource

13:07 KirinDave1: I'd like you know what problems you encountered with enlive

13:08 MikeDev: http://clojars.org/repo/enlive/enlive/1.0.0-SNAPSHOT/enlive-1.0.0-20091121.091400-3.jar if you still want to use enlive

13:09 MikeDev: and what does zip-soup return?

13:10 That tree zipped?

13:10 cgrand: yup

13:10 MikeDev: what does that mean

13:10 here let me see

13:12 Returns a zipper for xml elements (as from xml/parse),

13:12 given a root element

13:12 I wish I knew what a zipper was

13:12 let me see

13:13 navigation, editing,

13:13 and enumeration.

13:14 I hate trees in functional langs

13:15 cgrand: which tags do you want to retrieve?

13:16 MikeDev: header tags

13:17 BTW, if this wasnt due this second and for a job, I wouldnt be this stupid

13:17 cgrand: h1..h4, nothing else, no special classes or any other rules (only header in this div or...)

13:17 ?

13:17 MikeDev: correct

13:18 I just need the header tag's text

13:19 cgrand: (map enlive/text (-> your-url duck-streams/reader enlive/html-source (enlive/select [#{:h1 :h2 :h3 :h4}])))

13:19 using zippers directly won't be easier

13:20 MikeDev: do I have to 'use' anything for enlive?

13:20 cgrand: (use 'net.cgrand.enlive-html) ; once enlive is on you classpath

13:22 or (require '[net.cgrand.enlive-html :as enlive]) to match my code snippet

13:23 MikeDev: net.cgrand.enlive-htm

13:23 java.lang.NoSuchMethodError: clojure.lang.Namespace.importClass(Ljava/lang/Class;)Ljava/lang/Class; (exercises.clj:0)

13:23 cgrand: net.cgrand.enlive-html with a L after htm

13:23 MikeDev: (ns Exercises

13:23 (:use compojure clojure.contrib.duck-streams net.cgrand.enlive-html)

13:23 )

13:24 see Exercises

13:24 -l was copying error

13:24 cgrand: ah ok

13:24 MikeDev: CLASSPATH=Compojure/compojure.jar:/usr/local/jline/jline.jar:tagsoup-1.2.jar:enlive-1.0.0.jar

13:26 :(

13:26 cgrand: classpath hell...

13:28 KirinDave1: cgrand: Actually I'm just being glib

13:28 cgrand: After you put in that zipper patch, it worked.

13:28 cgrand: Are you open to patches? Some simple failure cases don't report very informative errors.

13:30 MikeDev: java -cp clojure.jar clojure.lang.Repl

13:30 Should that work?

13:30 cgrand: KirinDave1: ah, ok it was that bug and yes I'm open to patches

13:30 MikeDev: Hello?

13:31 KirinDave1: cgrand: Cool.

13:31 MikeDev: Why does that work in a shell script but not in cmd line

13:31 cgrand: MikeDev: try to put your whole classpath after -cp

13:31 MikeDev: maybe because I mispelled clojure.jar

13:32 cgrand: MikeDev: ok, let's try simply java -cp clojure.jar:enlive.jar clojure.lang.Repl

13:33 MikeDev: yeah that's what I was gonna don

13:33 cgrand: and then (use 'net.cgrand.enlive-html)

13:33 MikeDev: nope

13:33 same error

13:35 cgrand: and both jars are in your working directory?

13:35 MikeDev: O I C. this is your code

13:35 yes they are

13:36 cgrand: oops I forgot to include tagousp in the classpath -- did you include it?

13:36 MikeDev: nope, will try

13:36 that works

13:37 cgrand: phew :-)

13:37 MikeDev: wait

13:37 cgrand: :-(

13:37 MikeDev: 1 sec

13:37 nope

13:37 do you have another build?

13:38 cgrand: you used the one from clojar?

13:38 MikeDev: i used the one you had me dl

13:38 i dont have git on my machine

13:39 and dont know how to build

13:39 * MikeDev is retarded

13:39 cgrand: the one I directly linked to?

13:39 MikeDev: at least in this stuff

13:40 i dl'ed:

13:40 cgrand: this one: http://clojars.org/repo/enlive/enlive/1.0.0-SNAPSHOT/enlive-1.0.0-20091121.091400-3.jar ?

13:40 MikeDev: yes

13:40 let me do it again

13:40 can I rename it?

13:41 cgrand: sure

13:41 MikeDev: Which version of tagsoup u using?

13:41 i've got 1.l2

13:41 1.2 excuse me

13:42 cgrand: 1.2 too

13:49 MikeDev: DO I need to use anything for tagsoup???

13:54 So if you do first <zipper> what does that mean?

13:54 how are the nodes in a zipper flattened?

13:54 stuartsierra: 48 cores on a chip http://arstechnica.com/business/news/2009/12/intel-demos-48-core-cloud-datacenter-on-a-chip.ars

13:55 MikeDev: but I wanted 49 :(

13:56 do you have to 'use' anything for tagsoup?

13:57 it would appear not

14:04 Is there any way to flatten a zipper? Children?

14:06 hiredman: tree-seq

14:06 if you look at newegg.clj it is basically doing what you want to do

14:07 MikeDev: I am indeed

14:07 hiredman: it is grabbing all the td elements from a page, filter out things that don't have their class attribute set to "totalPrice" and picking the last one

14:15 MikeDev: comp:

14:15 comp f g is f(g)?

14:18 hiredman: (comp f g)

14:18 _fogus_: ,((comp #(+ 3 %) #(+ 1 1)))

14:18 clojurebot: 5

14:18 MikeDev: yes is that f(g)

14:18 hiredman: f(g) in what?

14:18 stuartsierra: more like f o g

14:18 MikeDev: normal language

14:19 hiredman: in algol like syntax f(g) is the function f applied to the argument g

14:19 which comp is not

14:19 MikeDev: f(g(x))

14:19 hiredman: ,(doc comp)

14:19 clojurebot: "([f] [f g] [f g h] [f1 f2 f3 & fs]); Takes a set of functions and returns a fn that is the composition of those fns. The returned fn takes a variable number of args, applies the rightmost of fns to the args, the next fn (right-to-left) to the result, etc."

14:19 MikeDev: yes it's either g(f) or f(g)

14:21 _fogus_: ,(let [f #(println "f o" %) g #(str 'g)] ((comp f g)))

14:21 clojurebot: f o g

14:21 hiredman: f(g) is not function composition in any syntax that I know of

14:22 MikeDev: and why use first?

14:22 I have junk at the end

14:22 is it to get rid of that

14:22 an extra nil?

14:23 hiredman: "junk at the end"

14:25 _fogus_: ,(let [f #(println "f o" %) g #(str 'g %) u #(str 'u %) s #(str 's)] ((comp f g u s)))

14:25 clojurebot: f o gus

14:25 _fogus_: Couldn't resist

14:25 chouser: heh

14:27 MikeDev: Yeah, when I do zipsoup I get a vector of what is my html ad then a nil

14:28 Yeah, when I do zipsoup I get a vector of what is my html and then a nil

14:28 devlinsf: Why is there space after the o?

14:28 MikeDev: 2 element vector

14:28 first gets rid of the nil

14:28 (partial tree-seq map? (comp seq :content)) appears to strip out the style

14:29 _fogus_: devlinsf: println does that

14:29 devlinsf: _fogus_: Hmm... gonna have to experiment with that

14:29 hiredman: MikeDev: it doesn't

14:30 devlinsf: _fogus_: Oh, i get it! I was assuming that (println "a" "b") is the same as (println (str "a" "b"))

14:30 ,(println "a" "b")

14:30 clojurebot: a b

14:31 devlinsf: ,(println (str "a" "b"))

14:31 clojurebot: ab

14:31 devlinsf: _fogus_: Hmmm... Interesting behavior

14:31 Chousuke: I think println is supposed to print a newline

14:31 but clojurebot filters them out

14:32 devlinsf: I don't have access to a normal REPL now.

14:32 clojurebot: a is t

14:32 chouser: MikeDev: the fact that a zip loc is a two-element vector is an implementation detail. use 'node' to get the node at a loc

14:32 devlinsf: Can sombody quick run it at a normal REPL?

14:33 MikeDev: or use first

14:34 rhickey: fine-grained locals clearing - core and contrib - all tests pass!

14:34 anyone got any test cases for head-retention? (no big files required please)

14:35 devlinsf: Chousuke: println doesn't interpose a newline

14:35 Chousuke: hm

14:36 eno: user=> (println "f o" "gus")

14:36 f o gus

14:36 nil

14:36 devlinsf: Try this at you REPL (println "a" "\n" "b")

14:36 Only one newline

14:38 MikeDev: (partial tree-seq map? (comp seq :content)) appears to add :content in front of every subvector

14:38 scellus: btw, what is pmap supposed to do (in the master branch) if i have a lazy seq of lazy seqs. i don't have an example, but i had problems until i wrote doall to realize elements for pmap. otherwise nothing parallelized.

14:38 hiredman: MikeDev: it doesn't

14:39 stuartsierra: rhickey: I was working on this

14:39 lisppaste8: stuartsierra pasted "Laziness examples" at http://paste.lisp.org/display/91726

14:40 MikeDev: well it appears to add something

14:41 hiredman: MikeDev: it doesn't

14:42 devlinsf: Chousuke: I just checked the source of println. It eventually calls pr. (pr "a" "b") appears to be the same as (pr (str-join " " ["a" "b"]))

14:42 Chousuke: That is to say, it injects a space

14:43 MikeDev: (first (zip-soup url))

14:44 ((partial tree-seq map? (comp seq :content)) (first (zip-soup url)))

14:44 It appears to create a list of every subtag?

14:44 hiredman: MikeDev: does it?

14:45 MikeDev: yes

14:45 chouser: MikeDev: the fact that a zip loc is a two-element vector is an implementation detail. use 'node' to get the node at a loc

14:45 MikeDev: I'm talking about (partial tree-seq map? (comp seq :content))

14:45 chouser: or don't use zip-xml at all if all you want is the tree and not a zipper

14:46 MikeDev: I dont think it makes a big diff and I'd prefer to follow hiredman as closely as possible

14:47 (partial tree-seq map? (comp seq :content)) appears to take the html tree and make a list with every subtag

14:47 the first tag is repeated, then the body tag, etc.

14:48 rhickey: where'd stuartsierra go? all of his tests work now. Any others?

14:48 preferably non-tail usage of seqs, in lets etc

14:49 stuartsierra: all of your examples now work, any others?

14:49 MikeDev: which makes it easier to search for tags

14:50 becaue they're all in a sequence now

14:50 stuartsierra: rhickey: awesome; I will try to come up with some more

14:50 MikeDev: next, you search for td tags with

14:50 (partial filter #(= :td (:tag %)))

14:50 stuartsierra: cgrand or Chouser had an example with large arrays

14:51 MikeDev: Please tell me if I'm wrong

14:51 I'm trying to learn

14:51 rhickey: stuartsierra: that one runs indefinitely - how long is it supposed to take when it doesn't fail?

14:52 Licenser: Hmm wow network programming (at lest server side) is incredible easy with clojure o.O I'm impressed!

14:52 chouser: I had one that would run forever if it didn't break.

14:53 hiredman: MikeDev: yes

14:53 chouser: rhickey: ,(let [s (iterate #(java.util.Arrays/copyOf % (count %)) (int-array (range 1e7)))] [(first s) (last s)])

14:54 rhickey: rather, (let [s (iterate #(java.util.Arrays/copyOf % (count %)) (int-array (range 1e5)))] [(first s) (last s)])

14:54 MikeDev: could I replace (= :td (:tag %)) with some kind of regexp for maching any h1-h6

14:54 tags

14:54 yes I'm wrong?

14:54 chouser: it's meant to fail fast, not necessarily demonstrate somethng that's supposed to work.

14:54 rhickey: chouser: yeah, ran that, runs indefinitely

14:55 chouser: ok

14:55 cgrand: MikeDev: (#{:h1 :h2 :h3 :h4 :h5 :h6} (:tag %))

14:55 rhickey: so, this is full liveness tracking for all locals

14:55 chouser: wait, really? I assumed that would be impossible

14:55 stuartsierra: me too

14:55 hiredman: MikeDev: you can replace it with any function that will return a logical true value for things you want to keep

14:56 rhickey: with liveness tracking, s is cleared before last is called

14:56 chouser: wow!

14:56 rhickey: yeah, Clojure's biggest incidental complexity now gone

14:57 pending lots of testing, this was a very complex change

14:57 stuartsierra: awesome, amazing, unbelievable!

14:57 chouser: I can only imagine.

14:57 rhickey: I'd just like to run a few more tests if anyone's got any failure cases, before I push

14:57 chouser: at this rate we're never going to need clojure-in-clojure

14:58 cgrand: liveness tracking? awesome!

14:58 rhickey: chouser: I really wanted to wait, but too many people are tripping over it, and worse, designing clunky non-workarounds

14:58 stuartsierra: yes

14:58 ericthorsen: rhickey: is this change in the 'new' branch as well?

14:58 rhickey: so now, if you aren't using it any more, you aren't holding it

14:58 ericthorsen: will be in a few minutes

14:58 you can use large seqs in let etc

14:59 no more limit to tail call clearing

14:59 just one extremely painful lost weekend :)

15:00 stuartsierra: This is really going to make sequences much more powerful, instead of a clever trick.

15:00 rhickey: there must be some more examples in the group...

15:00 MikeDev: {}'s are sets?

15:00 stuartsierra: The most common case is reading a large file line-by-line.

15:01 rhickey: I assume this will also work with iterator-seq?

15:01 rhickey: stuartsierra: it is independent of the type of seq

15:01 LauJensen: liveness tracking O_o? :) Does that incur some kind of overhead or how is that implemented?

15:01 MikeDev: So the last thing I need is to filter based on the text'edness of the content

15:02 rhickey: LauJensen: basically the last use of a local clears it (before the use)

15:02 wherever that use occurs, not limited to tail call arg

15:03 data structure inits, callis in the middle of do, lets, etc

15:03 LauJensen: Wow, cant wait to give that a test-drive

15:03 chouser: MikeDev: {} make a map, #{} makes a set

15:03 stuartsierra: rhickey: Is this pushed yet? I want to test with my hadoop wrapper lib.

15:03 rhickey: so, now based upon use, not merely local bound in scope

15:03 chouser: MikeDev: rather, {} is a map, #{} is a set

15:04 rhickey: I guess pushing it is the best way to get it tested...

15:04 stuartsierra: :)

15:04 Chousuke: yay

15:04 stuartsierra: Will this make it into 1.1 then?

15:05 * stuartsierra makes puppy-dog eyes

15:05 chouser: heh

15:05 Chousuke: This is a big usability improvement for Clojure. It was sometimes pretty difficult to tell whether you were holding onto something or not :/

15:05 stuartsierra: And all because of a bug in the JVM. :)

15:06 MikeDev: Would it be worng once I had a handful of headers to use regexps on the contents?

15:06 LauJensen: ~regex

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

15:06 chouser: this is true.

15:07 rhickey: stuartsierra: not in 1.1, no

15:07 cp2: sounds neat

15:07 stuartsierra: chouser: Of every technology ever invented.

15:07 chouser: also true is that if you have some text you need to process, regex is frequently the best solution available.

15:07 stuartsierra: yessir

15:08 LauJensen: Whats the name of that functional text parser in Clojure, which gives an alternative to regex?

15:08 stuartsierra: rhickey: I guess that's reasonable, given the newness.

15:08 MikeDev: Okay so how should I approach finding only textful headers given that I have all of them in a map?

15:08 hiredman: LauJensen: fnparse?

15:08 MikeDev: A list of maps

15:08 LauJensen: hiredman: Thats the one

15:09 rhickey: stuartsierra: it's also a huge compiler change, and there are already a lot of huge compiler changes in new - I dread merging them

15:09 stuartsierra: rhickey: fair enough

15:09 rhickey: ok, it's up

15:10 LauJensen: MikeDev: Are you looking for items that are solely alpha-numerical ?

15:10 MikeDev: Pretty much

15:10 certainly no subtags

15:12 this is only an exercise

15:13 stuartsierra: rhickey: great, is it on a particular branch?

15:13 rhickey: new

15:13 stuartsierra: ok

15:13 rhickey: http://github.com/richhickey/clojure/commit/76c8f45293987b80e3599535dd86482e1180661d

15:14 MikeDev: I might do "[A-Za-z0-9 .-]"

15:14 I might do "[A-Za-z0-9 .-]+"

15:14 _fogus_: That's a lot of green

15:16 rhickey: _fogus_: heh, I was just going to say - it doesn't look like much now, the hard part being figuring out how to enable the feature with minimal change

15:19 we need to get 1.1 out so we can get 1.2 out

15:19 _fogus_: rhickey: I take that back, relative to the total file size it's actually *not* a lot of green. Github just highlights the greeness in the commit view.

15:21 stuartsierra: rhickey: yes yes

15:21 MikeDev: What is #(= :td (:tag %))

15:21 rhickey: feedback welcome on the locals clearing in new - be on the lookout for 2 things - 1)bad - premature clearing (set to null before last use), most likely will show up as NPE, 2)insufficient clearing - local stays around

15:21 hiredman: MikeDev: it is a function

15:22 MikeDev: what arg does it expect?

15:23 It's comparing its arg to what tag maps to to see if it's equal to td

15:23 but I dont understand how it doesn that

15:24 LauJensen: MikeDev: Do you know how to do the basic selecting with Enlive?

15:24 MikeDev: cgrand and I couldnt get enlive working for me

15:24 devlinsf: rhickey: if I'm reading assembla right, ticket 218 is the only thing holding up RC1 (or Beta 1, whatever you want to call it)

15:25 LauJensen: MikeDev: 'Cgrand .... couldnt get it working' is not a possible scenario

15:25 MikeDev: (map text (-> your-url duck-streams/reader html-source (select [:h1])))

15:25 dnolen: I missed the early part of the locals clearing discussion, is not have to care about holding onto the head of a lazy data structure the main benefit or are there others?

15:25 rhickey: devlinsf: 1.1 is not waiting for patches, but all the peripheral stuff surrounding a release

15:25 MikeDev: What are you talking about

15:25 devlinsf: rhickey: docs, tests & stuff?

15:26 LauJensen: MikeDev: Enlive requires 2 things, enlive.jar and tagsoup.jar, put those on your class path, see in (System/getProperty "java.class.path") that they are there, and Enlive will work

15:26 MikeDev: i did that and got

15:26 drewr: looks like locals clearing breaks something in the socket code with swank-clojure

15:27 trying to isolate

15:27 hiredman: MikeDev: so the zip-soup function returns the html structure as a set of nested maps and vectors

15:27 MikeDev: java.lang.NoSuchMethodError: clojure.lang.Namespace.importClass(Ljava/lang/Class;)Ljava/lang/Class;

15:27 drewr: getting an NPE in a macro that I need to expand

15:27 hiredman: tree-seq flattens it out

15:27 rhickey: devlinsf: http://groups.google.com/group/clojure-dev/browse_frm/thread/be3f0a7c26ee2fd6

15:28 hiredman: MikeDev: import is for java classes only

15:28 rhickey: dnolen: it is primarily a benefit for use of lazy seqs, yes

15:28 dnolen: i note that the locals clearing change breaks swank-clojure: java.lang.Exception: No such var: swank.swank/ignore-protocol-version (NO_SOURCE_FILE:3)

15:28 MikeDev: so

15:28 I dont use import

15:28 enlive must

15:28 devlinsf: rhickey: yeah, I'm in that thread.

15:28 dnolen: rhickey: fantastic

15:28 devlinsf: rhickey: So can I assume master is stable, and I can start testing that?

15:28 hiredman: MikeDev: I hear enlive depends on tagsoup

15:28 LauJensen: MikeDev: Try putting all 3 jars in the same directory and run java -cp clojure.jar:enlive.jar:tagsoup.jar clojure.main and then type import enlive

15:29 hiredman: LauJensen: import?

15:29 MikeDev: use

15:29 LauJensen: use, require, something :)

15:29 MikeDev: he told me to use

15:30 LauJensen: then use

15:30 hiredman: anyway, when I did newegg.clj I was thinking of using enlive or zip-filter, but by the time chouser answered the question I asked here, I had the tree-seq version working :P

15:30 LauJensen: If you do that, it will work, or you're on Windows

15:30 MikeDev: <cgrand> (use 'net.cgrand.enlive-html) ; once enlive is on you classpath

15:30 LauJensen: yes, thats correct

15:30 MikeDev: that's what causes the error above

15:31 hiredman: odd

15:31 MikeDev: he left

15:31 hiredman: where did you get the enlive jar from?

15:31 MikeDev: cgrand ent me a link

15:31 1 sec

15:31 hiredman: what version of clojure are you using?

15:32 MikeDev: http://clojars.org/repo/enlive/enlive/1.0.0-SNAPSHOT/enlive-1.0.0-20091121.091400-3.jar

15:32 1.0.0

15:33 closure v1.0.0

15:33 hiredman: j

15:33 MikeDev: is there something to print on the repl to doublecheck

15:34 hiredman: that enlive jar might not work with clojure 1.0

15:34 anyway

15:34 rhickey: devlinsf: yes, please use master

15:34 MikeDev: which should I try?

15:34 hiredman: you were 70 to 80 percent done with tree-seq

15:34 MikeDev: yeah

15:35 hiredman: before random people popped in and started suggesting you do other things

15:35 MikeDev: and u said I should do things that way

15:35 and u r smart

15:35 hiredman: #() is an anonymous function

15:35 MikeDev: plus it helps me learn

15:36 hiredman: #(a b %) ~= (fn [x] (a b x))

15:36 MikeDev: well basically if I'm not using regexps, what do I use on the content of my headers?

15:37 jonase_: I pulled the 'new' branch and now I get "java.lang.IllegalStateException: Var null/null is unbound. (matrix.clj:37)" when trying to load the code in http://gist.github.com/234535

15:37 hiredman: MikeDev: you can use regexs or whatever you want

15:37 MikeDev: they told me not to

15:37 hiredman: MikeDev: you understand how filter works?

15:37 twbray: What's the idiomatic way to turn {:a 10 :b 20 } into {:a 11 :b 21}, i.e. do a map on a map and get a map?

15:37 hiredman: MikeDev: I imagine they were not paying attention and assumed you were parsing the entire html document with regexs

15:37 MikeDev: ok

15:38 i did clearly say I had the headers

15:38 but no complaints

15:38 lpetit: twbray: it depends, what do you want to do ?

15:38 ,(doc merge-with)

15:38 clojurebot: "([f & maps]); Returns a map that consists of the rest of the maps conj-ed onto the first. If a key occurs in more than one map, the mapping(s) from the latter (left-to-right) will be combined with the mapping in the result by calling (f val-in-result val-in-latter)."

15:38 lpetit: whoops

15:38 MikeDev: filter takes a function, applies it to each element and returns those elements for which the functions returned true

15:38 Licenser: uch

15:38 hiredman: ,(let [m {:a 10 :b 20 }] (reduce #(update-in %1 [%2] inc) m (keys m))

15:38 clojurebot: EOF while reading

15:38 hiredman: ,(let [m {:a 10 :b 20 }] (reduce #(update-in %1 [%2] inc) m (keys m)))

15:38 clojurebot: {:a 11, :b 21}

15:39 Chousuke: twbray: (into {} (map (fn [[k v]] [k (inc v)]) themap) will work

15:39 twbray: lpetit: I have a map. I want to produce a new map with the same keys and values produced by running a func over the input values

15:39 lpetit: twbray: you have the answer above :)

15:39 clojurebot: You will not become skynet

15:39 twbray: Chousuke: Thanks

15:39 hiredman: MikeDev: so you can write any function you want

15:39 lpetit: ,(doc map-vals)

15:39 clojurebot: Pardon?

15:39 MikeDev: yes

15:40 hiredman: I would first recommend filtering for headings, which I think chouser or Chousuke pasted a function for

15:40 MikeDev: that's what I'm doing I think

15:40 rhickey: lpetit: one question about a map-vals, should ht efn take the val or key + val, or [key val]?

15:40 MikeDev: here:

15:40 ((partial filter #(#{:h1 :h2 :h3 :h4 :h5 :h6} (:tag %))) ((partial tree-seq map? (comp seq :content)) (first (zip-soup URLArg))))

15:41 that gets me the headers I want

15:41 hiredman: :(

15:41 I guess

15:41 Chousuke: urgh, too much point-freedom

15:42 hiredman: so then you need to filter again based on whatever regex or what have you

15:42 rhickey: was anyone able to isolate the swank problem with fine-grained locals clearing?

15:42 MikeDev: ok

15:42 i was trying that

15:43 (partial filter #(re-find #"^[A-Za-z0-9 .-]+$" (:tag %)))

15:43 nope

15:43 oh, hell i mean content

15:45 lpetit: rhickey: is it a serious question, or was it asked to demonstrate that it's not possible to provide such a function ?

15:45 MikeDev: netsplits!!!

15:46 welcome back

15:46 java.lang.ClassCastException: clojure.lang.PersistentVector cannot be cast to java.lang.CharSequence

15:46 rhickey: lpetit: yes, serious, not a difficult function, just tricky to spec a useful version. Mapping inc across vals isn't too hard without it, but there aren't many k+v - taking functions around yet.

15:46 Chousuke: there's nothing wrong with using parametrised functions, you know.

15:46 why are you even using partials there?

15:46 hiredman: Chousuke: he doesn't know clojure so he is just copy and pasting me code around

15:46 rhickey: lpetit: that's what's held up something like map-vals

15:46 MikeDev: Chousuke, because hiredman and jesus wanted it that way

15:47 Chousuke: isn't that just (filter (comp :tag #{:h1 ...}) (tree-seq map? (comp seq :content) (first (zip-soup URLArg))))

15:47 hiredman: you have a bad influence on people :(

15:47 hiredman: MikeDev: I didn't, I showed you an example of code that does something similar to what you want

15:47 and you are cargo culting it

15:47 MikeDev: cargo culting: I like it

15:48 hiredman: http://en.wikipedia.org/wiki/Cargo_cult_programming

15:48 MikeDev: is that a real phrase?

15:48 Chousuke: hm, wait. args in comp are the wrong way around

15:48 MikeDev: I'd have said black boxing

15:48 Chousuke: try to write code that you understand yourself :)

15:48 hiredman: or at least try to understand the code you write

15:49 lpetit: rhickey: here are my own (freshly translated from french for your pleasure :-) versions I used at work : http://paste.lisp.org/display/91728

15:49 MikeDev: i will when it's not due 5 hours ago

15:49 chouser: rhickey: have you thought at all about compiler-macros, or something like them?

15:50 hiredman: MikeDev: well, maybe it is for the best

15:50 rhickey: chouser: not too much

15:50 lpetit: rhickey: needs were value (not key+val).

15:50 rhickey: chouser: I'd much rather have symbol-macrolet

15:52 devlinsf: lpetit: I've been talking about this on the dev list for a while

15:52 stuartsierra: rhickey: someone did symbol-macrolet in contrib http://richhickey.github.com/clojure-contrib/macro-utils-api.html

15:52 devlinsf: http://groups.google.com/group/clojure-dev/browse_thread/thread/9a518c853bfbba8b

15:52 chouser: a macro that expands to something that includes a symbol-macrolet would be pretty powerful.

15:52 devlinsf: lpetit: I'm partial to a visitor solution now

15:53 lpetit: devlinsf: ?

15:53 devlinsf: lpetit: You'll see it at the end of the thread

15:53 thehcdreamer: Anyone know how I can uninstall gitosis from my server? Google isn't helping me

15:53 sorry wrong channel

15:53 chouser: devlinsf: I've read your latest proposal at least once -- sorry I haven't responded. My gut reaction is much more positive now.

15:54 devlinsf: chouser: Life happens

15:54 dnolen: rhickey: not sure if this helps, http://gist.github.com/251096, this is the source of the error and the related fns

15:54 devlinsf: chouser: Good to hear it

15:57 dnolen: rhickey: also this is the macroexpansion for the offending function, http://gist.github.com/251100

15:58 MikeDev: hiredman, but you dont understand the business implications. Clojure is the sort of thing where I bet it's really hard to find someone who knows it so they're actually hiring newbies. To get a PHP job you need 5 years experience plus high volume experience the latter of which I'll never get

15:58 Plus when you do get a PHP job, you have a PHP job and why would you want that

15:59 Chousuke: :)

15:59 hiredman: MikeDev: sure, but you plainly don't know any clojure

15:59 MikeDev: I've been at it for 3 days. I can learn

15:59 Chousuke: Do you have the book?

15:59 MikeDev: not yet

16:00 arohner: lpetit: those functions look pretty similar to mine

16:00 lpetit: devlinsf: sorry, but I don't know exactly why, but when I read "visitor pattern", some warning flashes in the back of my head. Must read your (rather comprehensive!) post carefully, not sure I'll be able to do so right now.

16:00 * hiredman hasn't finished the book

16:00 MikeDev: If I get the job I will buy the soft and hard copy

16:01 rhickey: dnolen: thanks, I'll see what I can make of that

16:01 devlinsf: lpetit: No problem. Feel free to post or email any questions

16:01 lpetit: devlinsf: sure

16:02 Chousuke: MikeDev: anyway, try to avoid point-free style (the partials and comps) in the beginning

16:02 MikeDev: I just need to get this job. They'll help me learn it if I can just get my foot in the door

16:02 Chousuke: It's so easy to make code look magical when you omit the explicit parameters :/

16:03 what's your current problem?

16:03 MikeDev: a couple of exercises. i've given up on the second

16:03 right now the problem is a regexp for the contents

16:03 of the headers

16:05 lpetit: arhoner: I guess lots of uses of maps are for easily accessing their values. And then, either the keys are not relevant for functions having to process the values (e.g. keys are at a different level of abstraction than the values, e.g. keys are technical identifiers, values are business meaningful), either the keys have some meaning at the same level of abstraction than the values, and then...

16:06 ...chances are that the value already embeds the key value somewhere inside it. But that's just a quick generalization from the kind of problems I'm faced with, so maybe it's not true at all for most of the cases (I don't say "the general case", I don't think there exists a general case for such generic functions ?)

16:06 Chousuke: MikeDev: doesn't sound too difficult

16:06 MikeDev: and eventually I'd like to turn the list of maps into a list of 2ple vectors

16:06 ([headername headercontent] ...)

16:06 Chousuke: MikeDev: just keep in mind the structure of the data you're working with, and then filter and process it one step at a time.

16:07 MikeDev: when I think back to learning ML, this was not how I did it

16:07 arohner: lpetit: I don't need to go that far for an explaination. Often, I just need to transform a map, like

16:07 (map-keys keyword coll)

16:08 lpetit: arohner: I was testing my arguments on you, before explicitly directing them to Rich :-)

16:08 MikeDev: at least I can read what most stuff is now

16:08 types

16:09 Chousuke: MikeDev: well, say you have a list of strings and you want a list of all strings starting with "s", uppercased. The easiest way to do that is of course is to filter first, yielding another seq of strings, and then uppercase those

16:09 rhickey: dnolen: did swank-clojure work with the prior checkin of new branch?

16:09 dnolen: rhickey: yes, I did a git reset --hard HEAD^ just to make sure

16:09 MikeDev: U have all been very patient, ty

16:10 Chousuke: MikeDev: it really doesn't get much more complicated, if the problem really is just data filtering

16:10 MikeDev: and thanks to lazy seqs, you won't actually be going through all the data multiple times.

16:12 MikeDev: and remember, even maps can be treated as seqs of [key value] pairs

16:12 MikeDev: then maybe I wont have to convert that then

16:13 wait, yes I will

16:13 cuz I want [headername headertext] not [:tag h1, :content "blah"]

16:14 excuse me, {:tag h1, :content "blah"}

16:14 Chousuke: you have a seq of maps {:tag "h1", :content "blah"} or something?

16:14 and you want to select all "hN" tags, right?

16:14 MikeDev: ({:tag :h1, :attrs {:style "width: 200px; margin: 20px auto; text-align: center"}, :content ["Results Table"]} ...)

16:14 arohner: do deftypes respect *print-length* yet? I seem to be getting stackoverflows when printing a circular datastructure of deftypes

16:15 MikeDev: list of maps

16:15 I want to get all the tags whose content is text

16:15 hiredman: Chousuke: the selecting all the hN tags should already be taken care of

16:15 MikeDev: doesnt have subtags

16:15 Chousuke: hmm, right.

16:16 that's why you need the tree-seq

16:16 MikeDev: yes, it flattens

16:16 but some of the header tags could have ,a. tags

16:16 <a> tags

16:16 Or more likely with bad html, god knows what

16:17 Chousuke: well, filter those out after you've selected the header tags?

16:17 MikeDev: I dont wanna have to parse that crap further

16:17 so now that I have the header tags, I just wanna dump everything without nice text in it

16:18 Chousuke: that's another filter then, right?

16:18 MikeDev: yep

16:18 but this one I cant copy from hiredman

16:18 Chousuke: hmm. can't tagsoup sanitise html?

16:19 maybe it could remove any malformed crap for you.

16:19 MikeDev: according to it's site, htmltidy is what you'd want for that

16:19 Chousuke: ah. okay.

16:19 MikeDev: but this isnt production

16:19 Chousuke: well, maybe you can just use a regexp then :/

16:19 MikeDev: this is just for an exercise

16:20 but I dont want it to bomb on certain sites like it was before

16:20 when I did this:

16:20 "<(h[1-6])>(?:<.*?>)*(.*?)(?:</.*?>)*</h[1-6]>

16:20 thought that was an attempt to drill down into tags

16:21 the worst thing about that was, it allowed <h1></h2>

16:21 Chousuke: maybe select h-tags without flattening first and then filter out any tag content from them?

16:21 MikeDev: i dont like that

16:21 Chousuke: update-in is pretty good for transforming maps

16:22 MikeDev: well it doesn't flatten recursively

16:22 it does a search and makes copies into a list

16:22 Chousuke: hmm :/

16:22 MikeDev: think of it as any header subtree is added to a list

16:24 actually I suppose if someone did <h1><h2>srgwrg</h2></h1> i'd get the h2

16:24 the list would be 2 elements, the h1 tag and the h2 tag

16:25 arohner: rhickey: I seem to have a bug, where I get a stack overflow if I try to print a deftype that contains a cycle with other deftypes. should I file a bug?

16:26 MikeDev: can you use - ' " in clojure regexps

16:26 arohner: actually, it's worse than just printing, because using slime to reload the file can also cause the stack overflow, if the last expression returns the type with a cycle

16:27 MikeDev: with escapes \?

16:27 dont think it's letting me

16:28 rhickey: potential fix for swank-clojure + fine-grained locals clearing up in new branch: http://github.com/richhickey/clojure/commit/6c0c37e048f49ee5cd3afa79ce461abbc6a0c367

16:28 arohner: yes, thanks

16:29 chouser: MikeDev: you can use \" in a literal regex to match " ... no need to escape '

16:29 technomancy: rhickey: I haven't gotten a chance to give the new branch much attention; does it necessitate changes to swank-clojure?

16:29 chouser: ,#"'"

16:29 clojurebot: #"'"

16:29 arohner: rhickey: should I work on a patch? I'm effectively blocked. the fix looks simple, just add checks for *print-level* to print-deftype

16:30 rhickey: technomancy: hopefully not, I pushed a change today that broke swank, just pushed a fix - need someone to try it

16:30 arohner: sure

16:32 MikeDev: how about POSIX character classes like [:alpha:]

16:32 chouser: MikeDev: everything Java regex supports.

16:33 MikeDev: http://java.sun.com/j2se/1.5.0/docs/api/java/util/regex/Pattern.html

16:34 arohner: rhickey: can you please promote me to member on assembla?

16:36 technomancy: rhickey: trying new+swank now. anything specific I need to do to trigger the potential problem or is it pretty obvious?

16:37 chouser: (deftype Foo [x]) fails with java.lang.IllegalStateException: Var null/null is unbound. for me, latest 'new'

16:37 anybody else seeing that?

16:38 rhickey: technomancy: got me, seems like it fell right down before

16:39 chouser: yes, looking at it now

16:40 * technomancy grins to see deprecation warnings for ^

16:40 MikeDev: This seems to be serviceable: (re-seq #"<(h[1-6])>([^<>]+?)</h[1-6]>" HTMLArg)

16:42 * rhickey wishes for tests for deftype/reify/protocols

16:42 ataggart: was the change from ^ to #^ just for consistency?

16:43 MikeDev: who me?

16:44 AFAIK #"blah" is a regexp pattern

16:44 chouser: ataggart: #^ hasn't changed. ^ is going away because (meta ...) is already there, ^ is not the inverse of #^, and ^ is wanted for other things

16:44 ataggart: ah, no I meant the change to the reader. https://www.assembla.com/spaces/clojure/tickets/215-Deprecate-^-reader-macro

16:45 k

16:46 rhickey: chouser: fixed

16:46 technomancy: rhickey: hrm; looks like the example dnolen gave doesn't compile regardless of the new branch or swank version. =\

16:48 I'll try again if I see him come back online

16:50 rhickey: technomancy: this was is first report: i note that the locals clearing change breaks swank-clojure: java.lang.Exception: No such var: swank.swank/ignore-protocol-version (NO_SOURCE_FILE:3)

16:50 chouser: rhickey: great, thanks.

16:51 deftype objects seem to respect *print-level* for me

16:53 (deftype Foo [x]) (nth (iterate Foo 1) 20)

16:53 innermost prints as #:Foo{:x #:Foo#} if capped by *print-level*

16:55 rhickey: chouser: maybe the problem was mutually recursive structures?

16:56 arohner: my structure is mutually recursive. trying to reproduce with a smaller example now

16:58 chouser: not sure what you mean. this also works (nth (iterate (fn [x] #{(Foo x)}) 1) 20)

16:59 arohner: lisppaste8: url

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

17:00 arohner pasted "deftype circular explosion" at http://paste.lisp.org/display/91733

17:01 chouser: are you sure you have *print-level* set?

17:02 arohner: chouser: arg, no, only *print-length*

17:03 chouser: ah, that'll do it. :-/ sorry.

17:03 arohner: well, thanks for "fixing my bug"

17:03 :-)

17:03 chouser: I generally set *print-length* to 103 and *print-level* to 15

17:03 seems to work well most of the time for me.

17:04 MikeDev: So to what extent do people here think clojure has a bright business future?

17:04 arohner: I'm surprised the default for print-level is nil. once I had a circular structure, everything broke quickly

17:05 102 is too small, but 103 is just right?

17:05 ;-)

17:05 chouser: exactly

17:06 hiredman: MikeDev: there are four or five startups with JRuby on Rails frontends and Clojure backends

17:06 chouser: arohner: don't want an even number in case it makes me think something is working (stopping at the right length) when it's not.

17:06 LauJensen: ~source ->

17:06 MikeDev: how long has the lang existed?

17:07 durka42: two years

17:08 MikeDev: well basically the way you make money is by picking up a lang early, having it grow like crazy while getting 5 years experience with it

17:08 chouser: really?

17:08 MikeDev: then you're set

17:08 yep

17:08 chouser: huh

17:08 MikeDev: then you can consult wherever

17:08 hiredman: chouser: and here you thought it was in publishing books

17:09 chouser: if only I'd known!

17:09 MikeDev: chouser, you publish the book?

17:09 chouser: MikeDev: working on writing one. It's not out yet.

17:13 MikeDev: The company I want to work for is somehow gonna use it to make websites work on mobile phones more automagically

17:13 at least that's the plan

17:14 sound like a good idea?

17:14 good pairing of lang with problem?

17:20 the-kenny: hm.. I think clojure is well-suited for that problem

17:21 MikeDev: hi, well I gave up on the macro thing

17:22 the-kenny: MikeDev: I don't understand why you don't understand macros, so I can't help you... sorry.

17:22 MikeDev: well I think I kinda understand macros, just not how they could do what is in that problem

17:23 I understand how they can be used to replace text however

17:26 Chousuke: MikeDev: I think that's the problem. they are not text replacement :/

17:28 macros are code-generating functions; and unlike most languages, Clojure code is made of lists and symbols and other data elements and structures.

17:28 the-kenny: MikeDev: they are there for modifying clojure syntax at compile time

17:29 hiredman: ,pl

17:29 clojurebot: java.lang.Exception: Can't take value of a macro: #'sandbox/pl

17:29 hiredman: excellent

17:31 ,(pl reverse $ (↕reduce range $ 10 () λxy (↕conj inc $ y x)))

17:31 clojurebot: (1 2 3 4 5 6 7 8 9 10)

17:32 the-kenny: clojurebot: with-out-str

17:32 clojurebot: Excuse me?

17:32 Chousuke: MikeDev: anyway, to build the macro, start with manually coding one instance of the code your macro is supposed to generate

17:33 the-kenny: MikeDev: For an example take a look at with-out-str

17:34 hiredman: ,(macroexpand-1 '(with-out-str (println "foo")))

17:34 clojurebot: (clojure.core/let [s__6049__auto__ (new java.io.StringWriter)] (clojure.core/binding [clojure.core/*out* s__6049__auto__] (println "foo") (clojure.core/str s__6049__auto__)))

17:34 the-kenny: MikeDev: For an example take a look at with-out-str at: http://github.com/richhickey/clojure/blob/master/src/clj/clojure/core.clj#L3129

17:34 hiredman: (with-out-str (println "foo"))

17:34 ,(with-out-str (println "foo"))

17:34 clojurebot: "foo\n"

17:35 the-kenny: It binds *out* to a string-writer and evaluates it's "arguments" in the let

17:35 s/let/context/

17:35 Chousuke: ,(letfn [(foo [x] `(+ y ~x)] (foo 'somesymbol)) ; foo is basically a macro... it's just not marked as one, so its arguments need to be quoted and the result is not evaluated :)

17:35 clojurebot: Unmatched delimiter: ]

17:35 Chousuke: gah

17:35 the-kenny: whops, I pasted the code to wth-in-str, but it's basically the same

17:35 Chousuke: ,(letfn [(foo [x] `(+ y ~x))] (foo 'somesymbol))

17:35 clojurebot: (clojure.core/+ sandbox/y somesymbol)

17:41 Chousuke: hmm

17:42 I suppose it might help to just think of the syntax-quoted form as a template rather than worry about constructing lists too much :/

17:44 I guess it'd enable writing simple macros even without completely understanding them

17:47 piccolino: I'm trying to write a library that has some macros that generate Clojure code. And I'd like to be able to insert calls to private functions from the library's namespace into the code that gets output. But it seems I need to make those functions public for this to work at runtime.

17:47 Is that corret?

17:48 correct?

17:48 ataggart: yes.

17:49 jwhitlark: Am I doing something wrong, or does -Xbootclasspath not play nice with files like clojure.test?

17:49 chouser: piccolino: I don't know if it's passed to the level of idiomatic yet or not, but you can use the var instead

17:49 ataggart: since the funciton is actually being called from the ns intowhich the macro was expanded

17:49 MikeDev: thanks everybody

17:49 piccolino: The var?

17:49 chouser: piccolino: ((var myns/foo) ...) instead of (myns/foo ...) -- then foo can be private

17:50 jwhitlark: When I (use 'clojure.test) with the -Xbootclasspath, I get java.lang.ExceptionInInitializerError (NO_SOURCE_FILE:0)

17:50 polypus: is there some convention for namespace naming of clojure projects hosted on github and clojars? like should i use my username in the namespace, etc?

17:52 piccolino: Oh, cool, thanks chouser. Wasn't aware of that.

17:53 chouser: piccolino: for short, (#'foo ...)

17:53 piccolino: Yeah, I just saw that in the docs.

18:19 technomancy: jwhitlark: I saw that too.

18:19 jwhitlark: transitive requires inside -Xbootclasspath files are problematic

18:20 you can solve it by requiring what clojure.test requires before you load clojure.test

18:20 see leiningen/test.clj inside leiningen for an example

18:20 (that was a crazy error to track down)

18:21 hiredman: http://www.tedneward.com/files/Papers/BootClasspath/index.html

18:28 dnolen: rhickey: seems like you figured out the issue? swank-clojure working for me again.

18:32 rhickey: dnolen: I think so - you weren't here when I put it up - thanks for the report!

18:36 jwhitlark: That's great. Thanks for all the help

18:44 devlinsf: rhickey: I'm going through a diff of core.clj between 1.0 and master. I'm finding a few things you might want to look at yourself before releasing 1.1

18:44 rhickey: should I post them on the dev group?

18:45 drewr: fwiw, swank-clojure works for me again on new as well

19:21 technomancy: anybody used Joda time? does it support parsing dates of an unknown format?

19:21 like just "give it your best shot to figure out what format it is"?

19:24 devlinsf: technomancy: I don't think so

19:26 technomancy: I've only used it a little. To me, it seemed that Joda's strength was time zones, dst, and date calculations

19:27 technomancy: It'll support all sorts of explicit parsing. Adding a Clojure front end to that would probably be straightforward

19:29 defn: Is there a good tutorial out there on how to build simple clojure applications?

19:31 I've never used things like ant or maven in the past, leiningen looks cool, but I guess I don't really understand the big picture well enough to get how to use it

19:32 rhickey: devlinsf: yes, post to the group would be best - thanks

19:33 devlinsf: rhickey: n/p

19:35 dnolen: defn: lein makes it possible to build clojure apps simply. There's a lot of pain around managing dependencies and classpaths, particular because Clojure inherits a most if not all of these issues from Java.

19:35 defn: good tutorial here, http://incanter-blog.org/2009/11/20/leiningen-clojars/

19:39 defn: awesome, thanks dnlen

19:59 hiredman: I wonder if you could use the bootclasspath option to replace the system classloader with something more dynamic

20:02 rhickey: hiredman: -Djava.system.class.loader could be used for interactive use

20:03 hiredman: oh!

20:08 jwhitlark: dnolen: I'm trying the lein tutorial, and while it downloads the lein jar, It's not downloading the clojure jar it's expecting.

20:09 Now, I've already got clojure, so I guess I could just hack up the lein script, but I wanted to see if there was a simple answer first...

20:09 dnolen: jwhitlark: what do you mean not downloading the clojure.jar it's expecting?

20:10 jwhitlark: lein self-install. The docs says it'll put a clojure jar in .m2, but it's just getting lein.

20:10 dnolen: jwhitlark: did you install lein from github?

20:11 jwhitlark: well, I pulled down the lein bin script from http://github.com/technomancy/leiningen/raw/master/bin/lein, and tried lein self-install

20:12 I didn't clone the repo, but I got the script from there.

20:12 dnolen: jwhitlark: so nothing in .m2?

20:13 technomancy: jwhitlark: self-install only works with the stable branch; see the readme.

20:13 jwhitlark: jw@jw-cisco-dt:~/.m2$ find .

20:13 .

20:13 ./repository

20:13 ./repository/leiningen

20:13 ./repository/leiningen/leiningen

20:13 ./repository/leiningen/leiningen/1.0.1-SNAPSHOT

20:13 ./repository/leiningen/leiningen/1.0.1-SNAPSHOT/leiningen-1.0.1-SNAPSHOT-standalone.jar

20:14 ah.

20:14 dnolen: jwhitlark: there you go, spoken by the man himself :)

20:15 jwhitlark: The tutorial on the Incanter site has a link to master.

20:15 technomancy: liebke: ^^ any chance you could fix that?

20:16 liebke: sure, where do you want me to point to?

20:16 technomancy: just the stable branch

20:17 liebke: http://github.com/technomancy/leiningen/raw/stable/bin/lein?

20:18 done

20:18 polypus: there's also this one

20:18 jwhitlark: There we go. That's working nicely. Thanks for the help.

20:18 polypus: http://zef.me/2470/building-clojure-projects-with-leiningen

20:19 jwhitlark: yea, that one seems to point to master instead of stable, also.

21:07 tolstoy: Anyone know what 'Can't refer to qualified var that doesn't exist' means in the context of a macro?

21:07 Hm.

21:07 JAS415: is it inside a syntax quote?

21:08 because sq qualifies everything

21:08 so you might have forgotten to escape something

21:08 or gensym it

21:08 either/or

21:09 or it could be a typo

21:09 tolstoy: Yes, I was thinking I have a stray backquote or ~ or something in there.

21:10 JAS415: yeah

21:10 qualified var refers to like namespace/varname

21:11 it might be more obvious if you macroexpand it

21:12 tolstoy: So, defmacro foo [name] `(do (println ~name))

21:12 I'm running this as a script, so it'll be a bit of a task to macroexpand. I was hoping to avoid that....

21:13 JAS415: hm

21:14 you can't fire up a repl and past it in there?

21:14 tolstoy: Yes. I'll just need to get my classpath loading stuff working.

21:14 JAS415: ah

21:15 is name a var?

21:16 tolstoy: It's a string.

21:16 JAS415: hm

21:17 tolstoy: Ok, think I've got things set up to do macroexpand.

21:19 JAS415: ok

21:23 tolstoy: If you're defining a macro you'd like to use everywhere, is there a namespace you can put it in so you don't have to always use the namespace?

21:23 I guess the right kind of require/use or something solves that.

21:27 JAS415: yeah if you do a use then you don't have to namespace it

21:27 for repl you can also switch to the namespace itself

21:28 arohner: can anyone recommend a library for cron-like tasks?

21:28 i.e. go run this fn in an hour, or twice a day, etc

21:30 lisppaste8: tolstoy pasted "can't refer to qualified var?" at http://paste.lisp.org/display/91745

21:30 JAS415: oh

21:30 hiredman: arohner: http://github.com/hiredman/clojurebot/blob/56f8e9d824c3447036a88fbfea027f518f4ce627/hiredman/schedule.clj

21:30 JAS415: yeah can fix that

21:30 you need to do like ~'log-info

21:31 then i think it doesn't get qualified

21:31 tolstoy: I guess I'm wondering which "var" the error is talking about. ;)

21:31 Ok, I'll try that.

21:31 JAS415: is talking about all the function names

21:31 hiredman: it doesn't expose all of the functionality of a scheduledthreadpoolexecutor

21:32 tolstoy: JAS415: Ah, right! Okay. I think I get it now.

21:32 JAS415: the log-info functions will be in whatever ns it expands in

21:33 good :-)

21:33 arohner: hiredman: thanks

21:33 tolstoy: Right. It's so easy to forget that macros produce sexps.

21:33 hiredman: arohner: it's a start

21:34 tolstoy: Even when you remember it to yourself as you're writing them.

21:35 JAS415: after a few months you get used to it

21:35 months/years

21:36 tolstoy: Yeah.

21:47 ataggart: tolstoy: just fyi, there's already logging stuff in contrib

21:48 tolstoy: Yes, I've seen that. Thought I'd just try this to demo to folks how "easy" it is to craft up stuff in closure.

21:48 ataggart: gotcha

21:48 tolstoy: However, using a macro to generate another macro is maybe not such a good idea. ;)

21:49 dnolen: tolstoy: actually that's a pretty common use case ;)

21:49 ataggart: it's macros all the way down

21:50 tolstoy: So, (defmacro foo [a] '(blah blah (defmacro other [].....))

21:51 dnolen: tolstoy: more like (defmacro foo [a] `(bar (amacro baz ...)))

21:52 tolstoy: Well, but I want to create a macro which is defined at the time of the outer macro is, uh, compiled.

21:52 (let [foo val] (defn func ..) (defn func2 ..) (defmacro mac [] (use foo)))

21:53 But, like I say, it might not be such a hot idea.

21:54 Actually, it works, but the code that the embedded macro generates has a problem, and that's hard to debug.

21:54 I think a helper function is what's needed.

22:09 JAS415: macros generating macros is hard

22:10 tolstoy: Yeah.

22:10 I want a defmacro to produce another defmacro, but only because I need it to have a reference to the "log" variable.

22:11 Probably I could just use something other than let. That might do it, actually.

22:11 defn: why does (def agent1 (agent 0)) (send agent1 increment 5) => 5, while @(send agent1 increment 5) => 0

22:11 JAS415: is helpful to use helper functions for that type of stuff

22:11 split complicated things out

22:12 defn: user.oO (send agent1 increment 5) #<Agent@4532be10: 40>

22:12 user.oO @(send agent1 increment 5) 40

22:14 it's like it's always 1 call behind the current version

22:18 _mst: defn: agents are asynchronous so there's no guarantee your action will have been handled by the agent at the point you dereference it

22:19 so you might observe it in a state either pre or post update

22:19 defn: how do we know if we're at post update time?

22:20 _mst: you can call (await) on the agent to have the current thread blocked until your action has been dispatched

22:20 defn: ah-ha

22:22 so if agent1 is 0, (await (send agent1 increment 10)) (await (send agent1 increment 10)) agent1 => 20

22:22 otherwise i'd get 10

22:22 err nevermind, deref'ing is different

Logging service provided by n01se.net