#clojure log - Sep 12 2010

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

4:20 LauJensen: Morning all

4:55 kjeldahl: Anybody using slime-connect in emacs who can comment on how or why delimiter matching isn't working in the repl environment?

5:19 tomoj: kjeldahl: what do you mean by "delimeter matching"?

5:19 paredit?

5:19 clojurebot: paredit screencast is http://p.hagelb.org/paredit-screencast.html

5:46 kjeldahl: tomoj: When I write things like (let [[a b][1 2]][a b]) I need help matching the ] and )s. Differently from most other places in emacs (including clojure-mode), the slime REPL buffer in emacs doesn't seem to help.

5:46 LauJensen: kjeldahl: SLIME doesn't run Clojure-mode

5:47 kjeldahl: LauJensen: Yes, I get that. I still need help though. Which is why I asked.

5:47 LauJensen: try M-x clojure-mode

5:47 tomoj: that screws it up, doesn't it?

5:48 kjeldahl: what kind of help are you looking for, though?

5:48 paren highlighting?

5:48 kjeldahl: Yes, seems like that screws it up.

5:48 LauJensen: I tried it here a while back because I needed that highlighting for something, and it worked, and there yes I think there was some kind of bug but I forgot which

5:48 kjeldahl: tomoj: Yes, inside the repl in emacs.

5:48 tomoj: kjeldahl: M-x show-paren-mode

5:48 I don't know how to get paredit to play nice with the repl

5:49 if I M-x clojure-mode my repl, it's totally borked

5:49 it's now just an R

5:49 hell it doesn't even R, it's just totally gone

5:49 kjeldahl: Thanks, I know the basics outside of slime-connect repl mode. repl inside emacs matches (, but not [ and probably not {.

5:58 LauJensen: Guess it wouldn't be too hard to rip the font-locking stuff out of cloure-mode and make clojure-repl-mode

6:05 mrBliss: I use clojure-mode in my repl without problems. Here's how: http://github.com/mrBliss/dotfiles/blob/master/.emacs.d/clojure.el#L50

6:06 LauJensen: cool

6:07 tomoj: mrBliss: thanks!

6:07 also paredit, wow

6:07 you are a savior

6:07 mrBliss: I'm not using paredit at the moment, but it is there for when I intend to learn it

6:10 tomoj: aw, it makes you lose the colored repl prompt

6:10 mrBliss: look at slime-repl-prompt-face on line 24

6:11 it's not perfect

6:11 tomoj: ah, I skipped the syntax tweak

6:11 paredit seems busted somehow too

6:11 LauJensen: true

6:11 tomoj: e.g. if you type (()), then point at ((|)), DEL DEL leaves you with ))

6:12 mrBliss: sorry I'm not using it the moment, so I can't help

6:12 tomoj: the binding to paredit-backward-delete is gone for some reason.. hmm

6:12 no problem

6:12 it looks like the binding for DEL is coming from slime-repl-map-mode

6:13 mrBliss: add the bindings again in (eval-after-load "slime-repl" ...

6:17 tomoj: I think that's the only binding that gets clobberd

6:18 kjeldahl: mrBliss: Excellent, thank you.

6:20 tomoj: damn, I can't get that binding for some reason

6:20 oh well, I'll look at it again later

6:20 mrBliss: which binding exactly?

6:22 tomoj: paredit-backward-delete

6:22 to DEL

6:22 mrBliss: I'll see what I can do

6:22 tomoj: tried putting it where the bindings for paredit-open-curly and the other are, no luck. maybe the hook isn't being reloaded or something. don't worry about it though, I'm sure I'll figure it out eventually

6:24 mrBliss: alright

6:59 nlogax: (:lol {:foo "bar", :lol "bbq"}) i was surprised that worked, can someone explain why/how to a noob? :)

7:00 nevermind, i just found it in the docs

7:00 LauJensen: nlogax: maps are functions of their keys

7:01 nlogax: LauJensen: i had seen that one before, but not "callable" keywords

7:01 jjido: I tried converting my program to trampoline but I quickly get a stack overflow. How do I prevent stack from growing? http://pastebin.ca/1938762

7:03 Note: my solution with (loop [next start] (recur (next))) works fine

7:03 tomoj: I think you have far too many trampolines

7:04 I don't understand your code, but my guess would be to try only having the one trampoline in start, and get rid of all the rest

7:08 jjido: tomoj: I think I don't understand trampoline, hence my code

7:09 I want to throw away the current function stack then call a function

7:09 can trampoline do that?

7:10 tomoj: yes, just return the function

7:10 Chousuke: jjido: you return a thunk from the function and the trampoline calls it

7:12 LauJensen: ,(letfn [(dec-even [x] (if (zero? x) x (dec-odd (dec x))))

7:12 (dec-odd [x] (if (zero? x) x (dec-even (dec x))))]

7:12 (trampoline dec-even 6))

7:12 clojurebot: EOF while reading

7:12 LauJensen: well, that would return zero, think its the simplest example of a trampoline I can think of anyway

7:12 Chousuke: LauJensen: that's not right.

7:12 LauJensen: you need to return a function from dec even, not call dec-odd directly

7:13 something like. (letfn [(x [] (print "x") #(y)) (y [] (print "y") #(x))] (trampoline x))

7:14 LauJensen: ,(letfn [(dec-even [x] (if (zero? x) "even" #(dec-odd (dec x)))) (dec-odd [x] (if (zero? x) "odd" #(dec-even (dec x))))] (trampoline dec-even 5))

7:14 clojurebot: "odd"

7:14 LauJensen: ,(letfn [(dec-even [x] (if (zero? x) "even" #(dec-odd (dec x)))) (dec-odd [x] (if (zero? x) "odd" #(dec-even (dec x))))] (trampoline dec-even 6))

7:14 clojurebot: "even"

7:20 jjido: tomoj: Chousuke: ok I just replace my loop with trampoline, that works

7:25 Updated program here (WARNING prints 700000 lines) http://pastebin.ca/1938773

7:30 Chousuke: jjido: you should use two spaces as the standard indent, it makes the code look less nested.

7:30 jjido: ok

7:30 Chousuke: the underscore names are curious too but other than that the code looks fine to me.

7:32 jjido: just to avoid clobbering throw (don't know if there is a return in Clojure)

7:33 Chousuke: there isn't.

7:34 and it's acceptable to shadow names in functions, as long as the function is short enough :)

7:34 jjido: I will use "return" and "error" instead

7:35 Chousuke: my first thought when I saw _return was that it's just a named unused parameter

7:35 as _ is the idiomatic "unused parameter" name

7:38 jjido: how about "loop"? I don't want to clobber that at the top level

7:38 Chousuke: yeah, you shouldn't.

7:38 jjido: would f-loop look more lispy?

7:38 Chousuke: what does the f mean?

7:38 jjido: function

7:39 Chousuke: hmm.

7:40 both names are pretty uninformative in my opinion

7:41 jjido: could be, I did have a "loop" function in my original program (in a different language)

7:41 Chousuke: even if you called it "loop" it raises the question "what loop?"

7:41 jjido: it is a loop that prints "Hello World!" seven times

7:42 Chousuke: so maybe you can call it print-loop or something?

7:42 jjido: is that better style: http://pastebin.ca/1938786

7:44 Chousuke: yeah, looks better. You can use more spaces to align parameters though if that makes the code look better.

7:45 fn_loop should be fn-loop though. (or print-loop as I suggested :P)

7:46 tomoj: Chousuke: yes, I also had to go test whether those would be named but unused

7:46 and I was thinking, wow, someone wrote all this code without ever testing it?

7:46 now I'm trying to remember where I've seen named unused parameters before

7:47 Chousuke: jjido: Maybe you should come up with a naming convention for the continuations to differentiate them from the other parameters

7:49 like yes-c or returnc. I think it would make the code easier to understand. (though more typing for you)

7:49 jjido: Chousuke: the code will be generated

7:49 Chousuke: ah, okay

7:50 tomoj: naming stuff is hard

7:51 Chousuke: yeah, it is.

7:52 LauJensen: was easier in CL

8:03 cwb: I'm reading Programming Clojure and don't understand the difference between next and rest: if rest always returns a sequence then why do we need next equivalent to (seq (rest aseq))?

8:04 LauJensen: ,(next [])

8:04 clojurebot: nil

8:04 LauJensen: ,(rest [])

8:04 clojurebot: ()

8:04 cwb: Aha -- thanks!

8:04 LauJensen: np

8:42 Bahman: Hi all!

10:04 alpheus: What's good style for formal function parameter names that clash with well-known functions? Something scheme-like, spelling list as lst?

10:14 AWizzArd: alpheus: often people want to name parameters like the datatype they are holding. Another way is to type-hint them: (defn foo [^clojure.lang.PersistentList l] ...)

10:19 scottj: How do you disable congomongo's auto converting of strings to keywords? When I insert {"foo bar" 1} it will then always return it printing as {:foo bar 1} even though looking "foo bar" up in it still works

10:20 Raynes: There is an argument you can pass somewhere.

10:20 * Raynes looks for it.

10:21 Raynes: Hrm, maybe not.

11:28 boredomist: Is there a better way of doing (str (char 65)) to change 65 to "A"?

11:28 (for example)

11:38 AWizzArd: boredomist: that's fine.

11:57 LauJensen: If its not paypal, do you guys have some really good experiences with other cart/payment providers?

11:59 kotarak: Can someone explain me, how equiv works?

11:59 Obviously I'm too stupid to implement it.

12:02 LauJensen: kotarak: http://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/APersistentMap.java#L72

12:02 That what we're talking about?

12:02 kotarak: Yeah. Roughly. More for list.

12:03 A translated things into Clojure, but it doesn't like me.

12:03 Argh.

12:03 LauJensen: Looks simple, if its not the same type return false, if its not the same size return false, otherwise, check all element

12:03 s

12:03 kotarak: LauJensen: Never mind. I'm stupid.

12:03 LauJensen: Ok - Now back to my Payment provider question, any recommendations?

12:16 chouser: LauJensen: I've used google checkout a bit. No particular recommendation one way or the other.

12:17 LauJensen: k

12:36 maravillas: from a buyer's or seller's perspective, LauJensen?

12:36 I've bought through google checkout as well, and it's been straightforward enough

12:38 chouser: I guess google checkout provides a bit more management of the sales "workflow", with the payment authorization showing up in a list before the buyer has actually been charged.

12:38 ...so that you can prepare and ship your item, then click the "ship" button to actually charge the buyer.

12:39 but neither google nor paypal strike me as being very good about customer service. I would be nervous if 100% of my income depended on either of them paying out promptly.

12:39 LauJensen: maravillas: seller

14:04 Bahman: My project.clj is (http://pastebin.ca/1938963)

14:05 ivey: Idiomatic clojure question: I'm building a library that wraps a remote API. Is it more appropriat to set *username* and *password* vars and use those everywhere, or create a client data structure and pass that around?

14:06 Bahman: When I run 'lein deps' Leiningen looks for clojure-1.1.0-alpha-SNAPSHOT and fails. Any ideas?

14:10 pomyk: Bahman: maybe incanter or org.clojars.ato/compojure tries to bring it in?

14:10 LauJensen: ivey: Passing arguments around is definitely more function and thus idiomatic. However some libraries take the approach that you save your credentials in a struct, then make all calls (with-credentials struct ....)

14:10 Raynes: ivey: You'll find fans of both styles. Personally, I prefer the latter style in this specific case. I do something similar in my clj-github library. I believe I have an *authentication* var that contains a map with credentials.

14:11 I've seen some similar libraries do similar things. When you have doubts about whether doing stuff like that is a good idea, it's better go err towards passing arguments around.

14:12 * Raynes asked a question on stackoverflow about this ages ago.

14:13 ivey: Taking a look at clj-github now.

14:13 Bahman: pomyk: Checking...

14:14 Raynes: Calls are like (with-auth {:user "Username" :pass "password"} ...calls to various API stuff)

14:15 ivey: Raynes: but if you were doing a lot of calls, you'd do a (def *authentication* {...})

14:15 ?

14:15 Raynes: I've never done that.

14:15 But, I imagine yes, you could.

14:16 ivey: Interesting.

14:16 * Raynes notes that he wasn't saying clj-github is a good library to take notes from. Just using it as an example. :>

14:16 * ivey nods

14:21 pomyk: ivey: why not make a "class" to hold the username/pass and provide api methods?

14:22 ivey: so you get an object that knows how to auth, and has all the calls on it?

14:23 Raynes: ivey: If you're thinking about what I think you're thinking about, that wouldn't work. You'd have to use binding.

14:24 Doing (def *authentication* ..) from a client library shouldn't override the var in the library itself.

14:24 ivey: right

14:24 I have a conceptual map of this territory that's a mashup of Ruby and elisp.

14:25 I think I'll try it with a (with-creds) macro and see how that feels

14:32 Bahman: Is there a simple way to use REPL when working Compojure and Lein?

14:33 KirinDave: ?

14:33 Bahman: What problem are you running into?

14:35 Bahman: KirinDave: Nothing. I just don't have any idea how/where to start. New to clojure.

14:35 KirinDave: Bahman: The answer is "yes, you just do."

14:35 Lein repl works.

14:35 Raynes: You can start a repl with 'lein repl'

14:36 Bahman: Nice. Any chance to use Emacs instead of command line repl?

14:36 KirinDave: yes

14:36 Works fine.

14:36 But!

14:37 Bahman: Just please give me a pointer and I figure it out.

14:37 Raynes: If you have SLIME set up, you can run a swank server with 'lein swank' and connect to it with M-x slime-connect

14:37 KirinDave: Please note that the launch directory for your java instance will be set to the file location of the curent buffer wehn you call slime.

14:37 LauJensen: KirinDave: Congrats on the book :)

14:37 Raynes: What he said.

14:38 KirinDave: LauJensen: Thanks!

14:38 Bahman: "lein swank

14:38 That's not a task. Use "lein help" to list all tasks." I guess I'm missing something.

14:38 KirinDave: Bahman: Newer version required.

14:39 Bahman: I start swank-clojure-project from a dired buffer on the top of the file

14:39 Bahman: So that $ROOT/resources/templates will resolve

14:39 Bahman: KirinDave: Using 1.3.1 ... should I upgrade to 1.4?

14:40 KirinDave: Enlive's template generator, when I last tried it, was less than helpful on errors, especially FileNotFound.

14:40 Bahman: That's too advanced for me now :-) .but will keep it in mind.

14:40 Raynes: Bahman: Add swank-clojure "1.2.1" to your dev-dependencies in project.clj

14:40 I forgot to mention that.

14:40 KirinDave: I don't actually know how to use lein with slime-connect

14:41 Raynes: swank-clojure has the lein plugin in it now.

14:41 So, that'll do the trick.

14:42 KirinDave: Which version has that, is it in the packages, Raynes?

14:42 danlarkin: yes, put swank-clojure as a dev-dependency in your project descriptor and then lein deps, and then you can lein swank

14:42 Raynes: KirinDave: The jar, I mean.

14:42 swank-clojure is on clojars. You just have to add it as a dev dependency.

14:42 KirinDave: Ah

14:43 Raynes: You don't need any Emacs-side swank stuff anymore. Just slime.

14:44 KirinDave: Ah

14:44 Death to swank-clojure-project then

14:44 bane of my existence.

14:44 anonymouse89: I'm confused by: "No matching ctor found for foo"

14:44 KirinDave: anonymouse89: So are we, without context. :)

14:44 danlarkin: there's a lein-swank elsip function floating around out there, maybe technomancy can point you to its canonical location

14:45 anonymouse89: where foo is a fn passed as an arg to another function

14:46 I guess my question would be, is there any documentation that I'm missing that would help with this error? Or for those who have seen this is it more on the specific or general side of things?

14:46 KirinDave: anonymouse89: Could you make a gist of the context, please?

14:46 anonymouse89: gist.github.com has a clojure highlighting mode that is good. :)

14:47 anonymouse89: it's a little obscure, but sure

14:48 KirinDave: LauJensen: I'm looking forward to getting to writing, I just hope I've got the chops to write a whole book.

14:48 LauJensen: KirinDave: Im sure you do, but if not you're in good company I see :)

14:49 KirinDave: LauJensen: The other tough sell is that we want to talk to rubyists and pythonistas.

14:49 LauJensen: And maybe even JS people, in addition to the straightlaced java developer.

14:49 LauJensen: Yea I cant really help you with that, they've never liked my blogposts :)

14:52 Bahman: KirinDave and Raynes: Thanks for the assisst.

14:52 KirinDave: LauJensen: One thing we're not doing

14:52 LauJensen: Whats that?

14:52 KirinDave: LauJensen: is doing a chapter on macros. No macro chapter.

14:52 LauJensen: hehe - Why not?

14:52 Raynes: Anytime.

14:52 KirinDave: We're only going to mention them in context.

14:53 LauJensen: Good call

14:53 Raynes: Clever.

14:53 KirinDave: LauJensen: Well, because it's one of those things that most people won't understand. Syntax-oriented programming is a very alien concept.

14:53 anonymouse89: KirinDave: here's a pared down version: http://gist.github.com/576320 ... I completely understand if this is too involved of a problem (AKA my ignorance is too great :))

14:53 LauJensen: One guy at Conj Labs Brussels was horribly disappointed with macros and especially their frailty and uglyness, so I told him, that Macros were mostly important in discussions with other languages. Like if you're talking to some Scala guy you can always say "Have you got macros? because if not.." :)

14:54 (it was a joke, and funny at the time)

14:54 KirinDave: anonymouse89: Um, so

14:54 anonymouse89: Where is the error occuring?

14:55 anonymouse89: from what I can tell, it occurs when map-qubit-combinations is nested with itself

14:55 KirinDave: LauJensen: I'm researching to try and write an MBE lib. I think most complaints about macros are addressed by plt scheme's macro system

14:55 Which isn't always enough, but for most syntax it's WAY faster and less error prone to use MBE and a syntax transformer that has real eror handling, etc.

14:56 anonymouse89: basically, map-qu-combos applies a function a bunch of times, but if that function also calls map-qu-op then there is the ctor problem

14:56 LauJensen: KirinDave: Sounds incredibly interesting, got a mock of it somewhere?

14:56 KirinDave: anonymouse89: Can you reproduce your problem with fewer than 138 lines of code?

14:56 LauJensen: You can look at the racket documentation if you wanna see how it looks

14:57 I haven't started coding yet. It's a pretty involved project.

14:57 LauJensen: Racket's guide is an excellent intro: http://docs.racket-lang.org/guide/pattern-macros.html

14:58 LauJensen: Great, thanks

14:58 KirinDave: LauJensen: The classic example of a "rotate" macro: http://gist.github.com/raw/576326/b85a4eaa1b47e4f7459eb05dc2fc13df8444f83d/ex.plt

14:58 LauJensen: But the ... expansions can get pretty tricky.

14:59 LauJensen: hehe

15:00 KirinDave: I am trying to go to the conj

15:00 but fuck flying to NC is a pain in the ass.

15:00 Expensive and painful.

15:01 LauJensen: yea, fly to Frankfurt instead

15:01 Raynes: Chas is making my airline reservations. :>

15:01 KirinDave: At least that'd be _easy_.

15:01 Lol

15:01 Raynes: No complication for me. :D

15:01 KirinDave: I should ask him to do that for me.

15:01 Because Delta is refusing my credit card. :\

15:01 And I am not the kind of guy with multiple cards to try.

15:09 anonymouse89: Here is a hint, btw

15:09 anonymouse89: You do not need eval. You *never* need eval. If you think you need eval, it's a sure sign that you don't.

15:10 LauJensen: Yea, thats the give-away sign :)

15:11 anonymouse89: KirinDave: do you see what I'm trying to do in those lines?

15:11 KirinDave: I'd like something like (-> foo (fn-a 0) (fn-b) (fn-a 1) (fn-b) ...)

15:11 KirinDave: Yes, you're trying to make -> statements.

15:13 I'd recommend NOT doing it that way

15:13 What I'd do is use reduce.

15:14 anonymouse89: -> is just a fancy syntax for reduce. You don't need to use that error-prone eval method if you use reduce. Build a list of the functions you need, in order, then use reduce to perform your transform.

15:14 anonymouse89: -> is for syntactic convenience, only.

15:15 It will make debugging easier, too

15:16 anonymouse89: KirinDave: ok, that makes sense.

15:23 KirinDave: Twinql?

15:25 LauJensen: (find-twins :named "Jack")

15:25 returns all twins on facebook as a sql statement

15:25 KirinDave: dang

15:26 LauJensen: yea, powerful technology

15:26 Naah Im just kidding, dont know what that is :)

15:34 _ulises: evening

16:05 anonymouse89: ((a) (b) (c)) into (a) (b) (c) ?

16:06 LauJensen: anonymouse89: one form which expands into 3 forms?

16:07 anonymouse89: LauJensen: yes, I guess more precisely, using (for [i (range 3)] i) gives (1 2 3) where I would like 1 2 3

16:08 *0 1 2

16:08 LauJensen: All Clojure forms return the result of evaluating the final element. I don't know of anyway of returning multiple values that are all atoms

16:09 wwmorgan: anonymouse89: are you doing this in a macro? If so, you can use macro unsplice ~@

16:10 anonymouse89: wwmorgan: no. but thanks for the hint

16:10 LauJensen: wwmorgan: still, it cant be a return, only the argument to something else

16:10 (within the macro)

16:10 anonymouse89: LauJensen: right, that's my situation

16:10 I think I might just use a macro

16:11 LauJensen: either a macro, or apply. Prefer apply

16:11 wwmorgan: anonymouse89: What is your use case? I can't think of one

16:12 anonymouse89: I want to assoc specific indices of a vector with 1 or 0 depending on a condition

16:13 LauJensen: ,(map #(if (even? %) 1 0) [1 2 3 4 5 6])

16:13 clojurebot: (0 1 0 1 0 1)

16:13 anonymouse89: like (assoc index myvector (if (cond index) 1 0)) for indices in (1 3 7 9)

16:13 LauJensen: You could probably work that seq in a more functional style, like the map above

16:14 anonymouse89: LauJensen: that seems like exactly what I should be doing

16:15 LauJensen: anonymouse89: great. If you're coming from an imperative language. I suggest trying to ask your questions more broadly, because odds are you can pick up a few hints about functional design

16:16 anonymouse89: LauJensen: how did you guess? :p I'll try. Also, I think I need to do a lot more general reading on writing functionally

16:17 LauJensen: Either that, or attend conj-labs.eu :)

16:19 anonymouse89: LauJensen: sounds great but ... I'm a student :(

16:19 LauJensen: Well students are welcome as well. I wonder if we should make a special student discount.

16:20 morphling: hi guys, is there a common interface that all integer classes share?

16:20 like Number, but ratios also implement/extend that

16:22 by "all integer classes" I mean Integer, Long and BigInteger

16:24 wwmorgan: ,(->> (ancestors (class 1)) (clojure.set/union (ancestors (class (bigint 1)))) (clojure.set/difference (ancestors (class (/ 5 2)))))

16:24 clojurebot: #{}

16:24 Bahman: morphling: java.lang.Number

16:25 LauJensen: wwmorgan: that was cool :)

16:25 wwmorgan: morphling: it looks like there are not. You could compute the information by doing (zero? (mod n 1)), I think

16:26 morphling: wwmorgan: thanks :)

16:27 I want to dispatch on type with multi methods, and I essentially have the same code for Integer, Long and BigInt

16:28 LauJensen: morphling: use meta data?

16:28 morphling: I'll probably just put the actual code in an external function and call that three times, or do everything in the bigint case

16:28 tomoj: ,(map integer? [(int 1) (long 1) (bigint 1)])

16:28 clojurebot: (true true true)

16:29 KirinDave: anonymouse89: Sorry man, but sadly clojure doesn't support multiple return values like common lisp's.

16:29 anonymouse89: The best way to do it is to assume 0->inf number of elements on all return values OR an error.

16:29 anonymouse89: error-kit should help you handle the error case more rigorously.

16:29 morphling: LauJensen: how can i use meta data for that?

16:29 LauJensen: morphling: multi-methods can dispatch on anything

16:30 So as long as your data supports its. If you want the pure numbers being passed, then you cant

16:30 KirinDave: LauJensen: The burden of history. :)

16:30 LauJensen: ?

16:31 KirinDave: LauJensen: No meta on numbers.

16:31 An implementation detail :(

16:31 LauJensen: yea well... :)

16:31 wwmorgan: morphling: do you need to dispatch on type? If not, then you would just change your dispatch method from type to integer?, or something like that

16:31 morphling: LauJensen: I thought about using a more complicated dispatch function and dispatch on keywords, like :integer for those three, but I don't think it's worth it

16:32 wwmorgan: see above :)

16:32 thanks guys!

16:34 anonymouse89: LauJensen, KirinDave: ah, i think the big thing I was missing was map can take multiple collections, thanks again for your help and patience

16:34 KirinDave: anonymouse89: Don't worry, it's complex for everyone

16:34 LauJensen: thats what we're here for :)

16:55 Bahman: wwmorgan: What does ->> do in the statement above?

16:58 wwmorgan: bahman: ->> is thread-last. (->> a (b c) (d e)) becomes (d e (b c a)). Along with -> (thread-second), it's useful for showing the flow of data and avoiding deep nesting of s expressions

16:59 LauJensen: ,(-> 5 (/ 10))

16:59 clojurebot: 1/2

16:59 LauJensen: ,(->> 5 (/ 10))

16:59 clojurebot: 2

17:00 Bahman: Thanks wwmorgan and LauJensen.

17:01 LauJensen: np

17:01 wwmorgan: LauJensen: that's a great comparison

17:01 Bahman: By "deep nesting" you mean using "let" forms?

17:01 LauJensen: wwmorgan: yea I think its a lot easier to follow than a b c d examples

17:01 (no offense whatsoever)

17:02 wwmorgan: none taken :-p

17:03 Bahman: Right...now the above mystical statement is clear to me :-)

17:03 I was wondering if it was sort of Assembley language :-)

17:04 One last question: What is an "s" expression?

17:04 LauJensen: technically, everything in (println "hi" "there") is an s-exps which contains 3 s-exps, unless I misunderstood completely :)

17:06 Bahman: LauJensen: So every form in Clojure is an S expression?

17:06 LauJensen: yea

17:06 S expressions could be labeled, intelligent XML I guess

17:07 Bahman: Got that. Thanks.

17:11 LauJensen: Im off now - Those looking to secure a seat at Conj Labs Frankfurt with the EB discount, book tomorrow morning :) http://conj-labs.eu

17:14 ivey: If I have an XML doc in a string, how can I turn it into a structmap? xml/parse wants a file.

17:17 nevermind, I got it.

17:45 anonymouse89: is there any way to have a binding without already having that var root-bound?

17:46 wwmorgan: ,(doc with-local-vars) ; <- anonymouse89

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

17:47 anonymouse89: wwmorgan: thanks

17:47 wwmorgan: anonymouse89: actually, it doesn't appear to do what you want

17:47 ,(with-local-vars [a 1] (binding [a 3] @a))

17:47 clojurebot: java.lang.Exception: Unable to resolve var: a in this context

17:48 anonymouse89: I've never seen this before:

17:48 ,(with-local-vars [a 1] (println a))

17:48 clojurebot: #<Var: --unnamed-->

17:49 dakrone: ,(with-local-vars [a 1] (println (var-get a)))

17:49 clojurebot: 1

17:49 anonymouse89: dakrone: is that any different than deref-ing?

17:50 wwmorgan: ,(with-local-vars [a 1] (println @a)) ; This works too. @ is a reader macro for getting the content of a reference type

17:50 clojurebot: 1

17:50 dakrone: anonymouse89: using @ is better

17:50 anonymouse89: dakrone: right, I meant var-get vs. @

17:52 wwmorgan: anonymouse89: looking at the macroexpansion of binding suggests that, if you want to use binding, the vars need to root-bound

17:53 anonymouse89: hmm, it seems like I can't set! vars bound with with-local-vars

17:54 wwmorgan: anonymouse89: set! is for java interop. You want var-set

17:56 anonymouse89: i'm really failing today :( .. but now I know, thanks

18:23 amalloy: i used destructuring to peel apart a complex nested-map structure that one of my functions is receiving, and now it looks way harder for me to read than the naive (fn [obj] (let [thing1 (:child obj)...])) form

18:24 is this usual, or something i'll get used to like all the parens, or a way i should be formatting it more legibly?

18:25 rhudson: What does your destructuring look like?

18:25 amalloy: (defn minimax

18:25 [{{{{p :to-play} :state} :posn

18:25 :as posn} :posn

18:25 :as consq}]

18:26 rhudson: Seems like it would be better to unnest it

18:26 amalloy: by which you mean...?

18:28 rhudson: Something like your suggestion above. Like have one level of destructuring in your arg list, then 'let bindings to destructure successive levels.

18:28 Destructuring is in the lang (I think) partly to make the code more readable, not less

18:29 Generally if you have trouble reading your own code, that's a bad smell

18:29 amalloy: *chuckle*

19:18 Bahman: Couldn't sleep. NetBeans+Enclojure is really nice...maven-based build and nice repl.

19:18 Only if I could make its auto-completion work for project libs. Currently only works for Clojure and Clojure contrib.

19:22 rps_: If I have a vector of articles, how would I print the :title of each article?

19:27 cinim0d: rps_: Hint: map, :title, articles

19:28 rps_: cinim0d: thanks

20:28 sproust: Leiningen question: when I start my VM with "lein swank", I can then connect with slime-connect, but the "lein swank" target does not eval the code of my project. Is there a way to tell leiningen to evaluate some module and then start a swank server, so I don't have to do that every time I reconnect?

20:40 amalloy: i notice that (memoize fib) is no faster than (fib) the first time you call it, because fib does all its recursion internally where memoize can't intercept it. is there a macro somewhere like defmemo that rewrites the function definition to recur through the cache?

20:43 wtetzner: the problem is that (defn fib [n] ...) expands to something like (def fib (fn fib [n] ...))

20:44 so the recursive call doesn't reference the var

20:44 amalloy: wtetzner: sure, i understand why it doesn't work

20:44 wtetzner: there is defn-memo in contrib, but it doesn't solve the problem

20:45 you have to do (def fib (memoize (fn [n] ...)))

20:46 amalloy: you sure defn-memo doesn't solve the problem? it looks like it might, from the source

20:46 Bahman: Does (defn -main [&args] ...) mean that I have to pass some args to -main?

20:47 I thought & means args is optional.

20:47 dakrone: Bahman: args is optional

20:47 Bahman: dakrone: #<CompilerException java.lang.IllegalArgumentException: Wrong number of args (0) passed to: core$-main (NO_SOURCE_FILE:3)>

20:48 That's what I get when I call it like (guestbook.core/-main)

20:48 _ato: Bahman: you need a space between & and args

20:48 wtetzner: amalloy: defn-memo just calls defn and then alters the root var

20:48 dakrone: yea, should be [& args]

20:48 Bahman: Doh!

20:48 wtetzner: amalloy: so you still have the (fn fib [] ...) problem

20:48 Bahman: Thanks.

20:49 amalloy: hm. okay, i think i see

20:49 wtetzner: defn-memo really should have been implemented to expand to (def fib (fn [] ...)) without the name in the call to fn

20:50 _mst: if you want to force the recursive call back through the memoized version, you might want to do the recursive call with: (#'fib ...)

20:51 _ato: or just forget the macro and write your function using (def fib (memoize (fn [n] ...))) :-)

20:51 Raynes: _ato!

20:51 I haven't seen you in forever.

20:52 amalloy: it can't be that hard to write a macro that walks the tree and converts (recur) and (fib) calls and converts them back into calls to the memoized version

20:52 _ato: yep, or do that :)

20:53 wtetzner: tree-walking macros like that are always a bit tricky

20:53 it's easy to forget some case where the replacements you're doing won't work

20:54 for example, what if recur is referencing loop instead of the enclosing function?

20:54 you can account for it, but things like that are easy to forget

20:54 amalloy: bah! who uses loops? :)

20:55 wtetzner: also, if someone is using recur, chances are it's because they want tail recursion

21:04 Bahman: Is it possible to deploy Compojure apps in an ordinary application server (not embedded)?

21:08 chouser: Bahman: pretty sure, yeah.

21:10 Bahman: chouser: So I should use jetty adapter only for development right?

21:13 scottj: What's the easiest logging solution to use w/ c.c.logging, and how to run in debug mode? The default sucks bc all messages look like "Sep 12, 2010 8:59:01 PM clojure.contrib.logging$eval7120$impl_write_BANG___7123 invoke INFO: message"

21:13 chouser: well, that's up to you I guess

21:13 Bahman: if it'll do, I'd use it until it won't do anymore. :-)

21:13 Bahman: chouser: Got your point...thanks.

21:16 amalloy: scottj: passing it through perl or awk or something sounds easier than reconfiguring c.c.logging. perl -p -e 's/^.*invoke/;' < my_log_file

21:16 scottj: amalloy: well c.c.logging supports several logging backends, I'm just wondering which is easiest

21:17 there are like a million tutorials on monads for clojure but none on setting up another backend for logging :)

21:23 dakrone: how do I type something like "^M" in Emacs?

21:23 Raynes: dakrone: C-q-C-character

21:23 dakrone: Raynes: thanks

21:24 Raynes: dakrone: I discovered that by accident about three hours ago.

21:25 scottj: C-q is very common in emacs, you'll use it in paredit too if you ever get unmatched parens

21:25 Raynes: scottj: That's how I discovered it.

21:26 scottj: Raynes: you were right, there's somnium.congomongo.coerce/*keywordize* but it kinda stinks

21:26 Raynes: I knew there was *something*. I couldn't find it though.

21:26 I was looking in the wrong namespace.

21:27 scottj: it stops string keys from becoming keywords, but it also means you can't use keywords for keys

21:49 sproust: Wouldn't it make sense to throw an error when a struct-map is accessed with an invalid key?

21:49 Quite often the default behaviour of returning nil for a key not found hides errors in accessing the s/m's "members".

21:50 Makes typo errors harder to find.

21:50 I suppose I could just create my own failing-getter, but isn't that a really common use case?

21:52 Raynes: It'd be inconsistent, at the very least. Maps return nil if a key isn't found in them. The general idea is that, if you need something other than nil to mean "key not found" you can use get.

21:54 scottj: you don't even need get on either, (:foo {} (Exception. "key not found")) or ({} :foo ...)

21:57 sproust: scottj: that's nice, but it doesn't raise the exception.

21:57 Adding (raise) won't help either, it evals the not-found form before it checks, it seems.

21:57 chouser: people have written safe-get and I think even a safe-map

21:58 sproust: ,(:foo {:foo 42} (throw (Exception. "Not found.")))

21:58 clojurebot: java.lang.Exception: Not found.

21:58 sproust: chouser: Funny I was going to call it just that. Should be core IMHO, so common.

21:59 Oh wait, it's in map-utils

21:59 Never mind, thx.

21:59 Raynes: Orly

21:59 -> (:foo {} "not found"}

21:59 sexpbot: java.lang.Exception: Unmatched delimiter: }

21:59 Raynes: -> (:foo {} "not found")

21:59 sexpbot: => "not found"

21:59 Raynes: When did that happen!!!

22:00 sproust: Raynes: not good enough for my use case; it just returns the value, that'll sweep th eproblem under the rug too many times.

22:00 Hmmm, also surprising we don't have PG's aif in core.

22:00 chouser: sproust: rhicky doesn't like anaphora

22:01 has called them "evil", I believe

22:01 sproust: Oh. He'd really hate Hoyte's entire book then.

22:01 Raynes: You could always write a safe-get like chouser alluded to.

22:01 sproust: Raynes: there's one in map-utils.

22:02 * Raynes has never ventured into map-utils.

22:02 sproust: chouser: clojure.contrib.anaphoric?

22:02 Raynes: clojure.contrib.evil >:)

22:03 sproust: Hahaha

22:03 chouser: I don't like that they introduce new bindings without calling out their names

22:03 sproust: With great power comes great responsibility :-)

22:04 Raynes: I've been guilty of such acts before reading Joy.

22:04 chouser: introduce or change the value of.

22:05 sproust: we do have if-let and when-let

22:07 sproust: Haa, nice. That's cute. I didn't know if-let.

22:07 Lovely.

22:07 Clojure is full of surprises, really a wonderful language.

22:10 How do you switch between "edit expression" and "eval"? I have a bookmark and move my cursor to my "main" expression, then C-M-x, and then back to edit-modify-eval, and then repeat, but it's getting a bit annoying. I'm starting to think I should automate this a bit.

22:24 scottj: if anyone else was wondering how to use log4j w/ c.c.logging and set log level http://groups.google.com/group/clojure/msg/30738d8efc179ea3

22:31 laurus: Does anyone else find the Incanter graphics library horribly ugly?

22:31 chouser: the library or the graphics it produces?

22:31 laurus: chouser, sorry, the graphics it produces :)

22:32 scottj: I think the graphs look decent, definitely better than old excel or old incanter :)

22:32 laurus: I have a lot more experience in Python than Lisp, and I was considering using Clojure to try to do some data analysis, but those plots are a real turn-off for me, unfortunately...

22:32 Is there a way to swap graphics libraries or something?

22:32 scottj: you're definitely not the first to complain

22:33 you can use the dark theme

22:33 chouser: are there not config settings to improve the look? I'm afraid I haven't used Incater at all.

22:34 laurus: chouser, there are themes, but they still look kind of unprofessional, to me at least

22:34 I can't understand why they picked that library, other than sheer convenience

22:38 rhudson: There's quite a bit you can do with the underlying JFreeChart to change appearance

22:40 laurus: rhudson, really, okay!

22:41 That's good to know...

22:41 Perhaps I just need to poke around?

22:44 scottj: wonder why there's no ChartTheme repo for jfreechart

22:45 laurus: I'm new to Clojure, the only Lisp I've really used much is XLisp, where I could run (^ 2 3) and get 8. How do I do exponents in Clojure?

22:46 scottj: ,(Math/pow 2 3)

22:46 clojurebot: 8.0

22:46 scottj: lame, I know

22:46 laurus: scottj, haha, honestly that is kind of lame, but whatever :)

22:46 Zhivago: So, define a function name that you prefer ...

22:47 laurus: Zhivago, will do :P

22:47 Or I'll just get used to it, probably the better way.

22:53 Is _Practical Clojure_ a good introduction to the language?

22:53 scottj: Zhivago: then you have differnt names for a basic function in different people's code or stupid import statements for a basic function that should have been in core.

22:55 chouser: hm. what import statement?

22:56 scottj: say you didn't want to define pow all the time, (:use 'basic-math)

22:56 (sorry if import instead of use was the confusing part)

22:57 s/basic-math/clojure.contrib.math

22:59 chouser: oh, I see. yep.

22:59 laurus: scottj, I wonder why it's not in the core

22:59 chouser: laurus: I don't know, but here's a guess... clojure is pretty minimal and doesn't include much that doesn't add real value.

23:00 laurus: Heh

23:00 chouser: the other math functions are included because they work seamlessly across number types in a way that java interop methods don't.

23:00 laurus: chouser, that's interesting.

23:02 rhudson: As it is, core defines over 500 symbols -- not everything that everyone wants can go into core

23:03 laurus: rhudson, it's cool

23:03 chouser: I suppose one could make an exponent function that returned whole nubmers for whole inputs. But would people actually use it? I dunno...

23:03 rhudson: I use string join or split a hundred times for every time I need an exponent

23:03 laurus: I think I better read some more about Clojure before messing around any more

23:03 rhudson: Apparently that's what clojure.contrib.math/expt does

23:03 laurus: I just wanted to try entering a couple XLisp functions to see what happened :P

23:04 scottj: rhudson: but how many times have you defined a function named expt that wasn't an exponent function? :)

23:04 rhudson: I've never named a function 'expt :)

23:04 chouser: heh, yeah, clojuse is not scheme. there are a lot of differences considering they're both lists.

23:06 laurus: I find it somewhat hilarious that I've seen mentioned on at least three blogs how Clojure is supposedly difficult to get working. It took me about 3 minutes to find the download, download it, unzip the jar, and run it.

23:06 One blogger bragged about how it only took him 20 minutes to get the thing started as I recall, and others claimed to have given up in frustration.

23:07 rhudson: laurus, I think "Programming Clojure" is a great introduction to Clojure, despite it describing 1.0. Some folks here have said that "Practical Clojure" is a good intro, and describes 1.2. "Joy of Clojure" is an outstanding second book on Clojure

23:08 laurus: rhudson, thanks for your opinion. I'll go for one of those two then.

23:08 :)

23:08 rhudson: Laurus, it seems a lot of folks coming from the Lisp side of things find the Java world arcane

23:08 (and vice versa)

23:08 laurus: Ahh... I've actually programmed more Java than Lisp

23:09 scottj: I really like programming clojure. and I think joy is good in theory, but I'd highly reccommend waiting till it's been edited

23:10 rhudson: That's soon now, right chouser?

23:10 The most recent MEAP is really quite good -- a few typos here and there

23:11 phobbs: when is it scheduled to be printed?

23:11 I find it so much harder to read ebooks

23:11 rhudson: That's why I want to get an iPad!

23:12 laurus: phobbs, I prefer paper books too...

23:12 scottj: rhudson: w/ "retina display"!

23:13 rhudson: Scottj: amen! I just got a 4G iPod touch, and the display just blows me away

23:13 My MacBook looks grainy after that

23:13 sproust: laurus: if you're just running the main clojure jar and typing commands at the repl it's pretty straightforward. Slightly more complicated (but not much) issues come about when you need external jars if you're not familiar with Java, and it used to be a bit broken for a little while when clojure's swank support was in flux. That's probably why some people bitched about setup.

23:14 chouser: the MEAP update for "joy" that came out a couple weeks ago has tons of typo/spelling/grammar corrections from the original chapter MEAPs

23:14 laurus: sproust, right, that makes sense... jars are a pain.

23:14 Without ant, or something

23:14 rhudson: laurus, phobbs -- I go for paper too when there's a choice -- but there's too much early access stuff I can't wait to get my hands on

23:15 chouser: I don't think there will be another update until it's ready to be printed, but I haven't heard anything about the schedule of that. All I know is Amazon says December for shipping paper copies.

23:15 rhudson: The Manning site says November (est.)

23:15 sproust: My limited experience with Java Jars is fairly positive; once you provide your list of jars to the vm it pretty much always works. Problem is, startup time is just... very... slow.

23:15 chouser: that's good. Amazon used to and changed it. I hope it's Nov not Dec.

23:16 scottj: the last meap update sounded like there wouldn't be any more till release

23:16 rhudson: me too. You guys did an amazing job with that book

23:16 laurus: sproust, right, I guess it depends how one loads the app. My experience in Java was with web applications on Tomcat, and ant helped a lot there.

23:17 chouser: rhudson: thank you very much. fogus deserves the bulk of the credit, really. it was his project from the beginning and I was pleased to be included.

23:18 I glad it's done

23:18 turns out I prefer writing code to prose. shocker.

23:18 rhudson: :)

23:19 laurus: So what's with this whole Clojure on Clojure thing?

23:20 Er, sorry, Clojure *in* Clojure.

23:20 scottj: laurus: a goal, unless rhickey has been coding on it in private, there's nothing there but features have been added to clojure to make it easier to accomplish

23:20 laurus: scottj, but what is the purpose of that goal? To make it more independent of the JVM or the Java language?

23:21 rhudson: laurus, a lot of the Clojure runtime, including the persistent collections, are currently in Java.

23:21 laurus, I think partly Rich Hickey wants to be writing in Clojure not Java :)

23:22 scottj: I always thought it was funny how fogus and chouser would tweet back and forth about each other and their book. fogus: @chouser's book is brilliant!. chouser: mark twain's got nothing on @fogus!

23:22 laurus: But it would still run on the JVM?

23:22 scottj: oh, I forgot the discount coupon links

23:22 chouser: there are places that the JVM (as it is and will be in the foreseeable future) doesn't fit well. I want to be able to use Clojure in those places anyway.

23:23 scottj: laurus: yeah, it makes porting clojure to .net and javascript etc much easier because clojure datastructures etc are written in clojure

23:23 chouser: such as: iOS, javascript, unix command-line, etc.

23:23 laurus: scottj, oh, got it. So it doesn't affect the end users that much, it's more for the developers of the core language.

23:23 And for portability.

23:23 chouser: laurus: right.

23:23 laurus: Sounds great! :)

23:23 I think it would be great to not have to run it on the JVM, actually

23:23 chouser: Users of Clojure on JVM should see either no difference, or boosts in features and performance.

23:23 laurus: Don't ask me why I think that, it's just a feeling

23:36 Is there a way to log a Clojure REPL session to a file?

23:48 sproust: laurus: do you mean to dump the image, or just the text?

23:49 e.g. like (sb-ext:save-lisp-and-die)

23:49 Actually I've wondered about this too: is there a way to dump the runtime and somehow restart it later, like you would with some CL's?

23:50 KirinDave: sproust: The JVM isn't image based

23:52 sproust: ,(boolean (list))

23:53 clojurebot: true

23:53 sproust: I get bitten by this all the time.

23:53 KirinDave: I was wondering if the runtime LISP structures couldn't be dumped and then have a new process pick them up later.

23:54 wwmorgan: ,(boolean (seq (list)))

23:54 clojurebot: false

23:54 sproust: I find the dual role of that seq function inelegant. On the one hand it returns a seq on the collection, on the other hand it's needed to check if the collection is empty.

23:54 wwmorgan: thx

23:55 I don't know how many times I've tripped up over this; a lot. I'm just too used to cons cells.

23:56 I should just get used to using empty?

23:56 ,empty?

23:56 clojurebot: #<core$empty_QMARK_ clojure.core$empty_QMARK_@15c7277>

23:56 sproust: ,(doc empty?)

23:56 clojurebot: "([coll]); Returns true if coll has no items - same as (not (seq coll)). Please use the idiom (seq x) rather than (not (empty? x))"

23:56 sproust: Hmmm, it says I shouldnt...

23:57 wwmorgan: sproust: the only reason that it works is that nil is logical false

23:57 ,(if nil 1 2)

23:57 clojurebot: 2

23:57 sproust: So (seq x) is the recommended idiom. But it doesn't look like a predicate.

23:57 wwmorgan: _that's_ the only bit that makes sense to me.

23:58 wwmorgan: ,(if (filter even? [1 3]) 0 1) ; sproust: don't let this trip you up either

23:58 clojurebot: 0

23:58 sproust: ,(filter even? [1, 3])

23:58 clojurebot: ()

23:59 sproust: Right, empty list is true.

23:59 wwmorgan: sproust: not the behavior I was trying to highlight, actually. Not my best example

Logging service provided by n01se.net