#clojure log - Mar 31 2011

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

0:07 amalloy: mec_: (defn mapmap [f & colls] (for [c colls] (map f c)))?

0:08 i guess that's different

0:21 mec_: here we go https://gist.github.com/895803

0:27 tho not sure how you would adapt that to pre or post

0:29 brehaut: (defn lift-map [f n col] (((apply comp (repeat n (partial partial map))) f) col))

0:29 &(let [lift-map (fn [f n col] (((apply comp (repeat n (partial partial map))) f) col)] (lift-map inc 3 [[[1 2] [3] [4 5 6]]]))

0:29 sexpbot: java.lang.IllegalArgumentException: let requires an even number of forms in binding vector

0:30 brehaut: &(let [lift-map (fn [f n col] (((apply comp (repeat n (partial partial map))) f) col))] (lift-map inc 3 [[[1 2] [3] [4 5 6]]]))

0:30 sexpbot: ⟹ (((2 3) (4) (5 6 7)))

0:30 brehaut: im pretty sure theres a special circle of hell for that

0:31 mec_: lol

0:32 my gist lets you apply a different f at each depth

0:35 brehaut: mec_: yeah mine is specifically a narrow application of a lifted functor over sequences

0:36 it could probably be made into a more general functor by using clojure.contrib.generic.functor/fmap

0:38 amalloy: brehaut: nice, (((

0:38 a 100% reliably indicator of good code

0:39 brehaut: amalloy: haha yes. i thought (partial partial … was also a pretty strong indicator

0:39 amalloy: (partial partial apply) is better

0:39 brehaut: thats true

0:40 (use 'clojure.contrib.generic.functor)

0:40 &(use 'clojure.contrib.generic.functor)

0:40 sexpbot: java.io.FileNotFoundException: Could not locate clojure/contrib/generic/functor__init.class or clojure/contrib/generic/functor.clj on classpath:

0:40 brehaut: ,(use 'clojure.contrib.generic.functor)

0:40 clojurebot: java.io.FileNotFoundException: Could not locate clojure/contrib/generic/functor__init.class or clojure/contrib/generic/functor.clj on classpath:

0:40 brehaut: oh well

0:52 jacortinas: ,(= 2 2.0)

0:52 clojurebot: true

0:54 amalloy: &(.equals 2 2.0)

0:54 sexpbot: ⟹ false

0:55 jacortinas: hmm

0:55 clojure-koans have a problem written as (= __ (= 2 2.0))

0:56 with the answer for __ being false

0:56 feels wrong though, can someone explain this to me?

0:56 &(= 2 2.0)

0:56 sexpbot: ⟹ true

0:56 trptcolin_: yeah, that's the case in 1.3

0:57 jacortinas: I though as much

0:57 trptcolin_: clojure-koans is currently on 1.3-alpha4

0:57 raek: ,*clojure-version*

0:57 clojurebot: {:major 1, :minor 2, :incremental 0, :qualifier ""}

0:57 jacortinas: so I cloned the clojure-koans repo, then ran lein deps

0:57 and then was only doing "script/run"

0:57 raek: I think clojure has always had numeric equality defined that way

0:58 jacortinas: and it's apparently running it using 1.2

0:58 trptcolin_: jacortinas: wacky - 2 clojure jars in the lib dir or something?

0:59 raek: in 1.2, (= 2 2.0), but not in 1.3

1:00 jacortinas: trptcolin_: no, this is the contents of the lib (clojure-1.3.0-alpha4.jar deps.clj jline-0.9.94.jar junit-3.8.1.jar)

1:00 trptcolin_: it was one of the very few changes i needed to make to the koans after updating to 1.3-alpha1

1:00 and yet you do ./script/run and *clojure-version* is 1.2?

1:00 raek: ah, hrm.

1:02 trptcolin_: err, i mean ./script/repl :)

1:03 jacortinas: hmm

1:03 seems to be just fine now

1:04 maybe just me being stupid... let's just pretend this never happened

1:04 trptcolin_: what never happened? ;)

1:04 jacortinas: lol

1:04 what?

1:04 clojurebot: what is seq

1:05 jacortinas: test?

1:05 clojurebot: forget latest is 1382

1:05 jacortinas: eh?

1:18 sritchie: hey all -- does anyone have any insight into why I'm getting this sequence after fn*, in this macro? https://gist.github.com/895855

1:19 if I take away the fn (even though that renders this useless), that surrounding set of parens after fn* goes away

1:22 mec_: is there a switch statement? i swear i remember seeing one

1:23 scottj: there's cond and condp and case

1:23 mec_: ah case, thanks

1:27 raek: ,((fn ([x] (* x x))) 5)

1:27 clojurebot: 25

1:28 raek: sritchie: if you have lists in that position, you can have multiple arities of the function

1:28 sritchie: got it

1:29 I see that (fn [x] (* x x)) macroexpands to the same thing, so turns out my problem lies elsewhere

1:29 raek: sritchie: I often use macroexpand-1 when checking my macros, since it only expands the thing I'm working on

1:29 (well, one step of it)

1:30 sritchie: raek: that's proven really helpful

1:30 raek: the (-> ...) will expand to (phase-fn session_... [x] (+ 1 2))

1:31 i.e. the session will appear before the argument vector

1:32 you can work around it by either letting the anonymous fn to a local, or by adding an extra pair of parens around it

1:32 ,(-> 5 ((fn [x] (* x x))) inc)

1:32 clojurebot: 26

1:32 sritchie: oh

1:33 oh! I see

1:34 raek: you're the man, the second pair of parens was just what I needed

1:40 * raek just discovered https://github.com/technomancy/clojure-mode/pull/16/files

1:42 amalloy: hey raek, glad you like

1:42 (assuming you like, anyway, or you wouldn't mention it)

1:44 scottj: nice I don't have to edit my clojure-mode.el anymore

1:45 amalloy: scottj: i just edited .emacs, before putting together that code. seems weird to add to clojure-mode.el

1:46 scottj: oh I didn't read the commit closely, yeah I have those changes in .emacs, what I have in clojure-mode.el is things I want to be highlighted like defuns

1:48 amalloy: scottj: if you want to send me your clojure-mode.el i can see about adding a customization for that

1:48 sritchie: raek: one more quick macro question -- is there a way, here, to have that last statement write something if (seq (rest forms)) is true, and simply not exist if not? https://gist.github.com/895876

1:48 I don't want nil, if the conditional evaluates to false

1:48 scottj: amalloy: https://github.com/scottjad/clojure-mode/commit/a7cbdfabb23a17feddc983c5c98e48d9fdd84396

1:49 amalloy: sritchie: return either a vector or nil, and splice it in

1:49 eg `(whatever whatever ~@(when foo [`(actual code)]))

1:50 &(let [foo true] `(whatever whatever ~@(when foo [`(actual code)])))

1:50 sexpbot: ⟹ (clojure.core/whatever clojure.core/whatever (clojure.core/actual clojure.core/code))

1:50 amalloy: &(let [foo false] `(whatever whatever ~@(when foo [`(actual code)])))

1:50 sexpbot: ⟹ (clojure.core/whatever clojure.core/whatever)

1:50 raek: amalloy: yes, certainly! I've been doing this: (eval-after-load 'clojure-mode '(define-clojure-indent (foo 'defun) (bar 'defun)))

1:50 sritchie: amalloy: fantastic, thanks a lot

1:50 amalloy: raek: so had i till last night

1:50 did it one too many times :P

1:51 scottj: https://github.com/technomancy/clojure-mode/pull/15 this feature is nice

1:51 raek: sritchie: you mean something like (do (when (some-pred? x) ...) x)?

1:52 I think it's hard to squeeze something like that into ->

1:52 sritchie: what amalloy referenced was right on -- here's what I did, see the last one -- https://gist.github.com/895876

1:53 whoops, without that println

1:55 amalloy: scottj: i don't know enough about elisp compile-vs-load semantics to know whether i could implement that

1:56 the indentations i was pleased to discover i could cause to take effect instantly

1:58 sritchie: it seems kinda weird to be unquoting almost every form in your syntax-quote. have you considered building it with just (list)?

2:00 sritchie: I'm still very, very young where macros are concerned, so I'm up for any advice --

2:00 amalloy: well, this particular advice is questionable, so... :P

2:01 sritchie: so, you're saying, use list, then backquote anything that needs to be -- or, flip back-quotes and unquotes?

2:01 amalloy: yeah, something like that

2:02 i'm not sure it comes out looking better in this case

2:02 sritchie: it does look crowded now, for sure

2:03 amalloy: i mostly just advocate people realizing macros don't have to be one gargantuan backtick-form

2:13 whoa sritchie: you're using symbols like foo# outside of a backtick. they don't have any special meaning there

2:13 sritchie: amalloy: okay, so for those let-bound variables, just use subphase and left?

2:13 amalloy: yeah

2:16 sritchie: amalloy: thanks for the macro help

2:17 point taken, about the backtick, too

2:18 amalloy: sritchie: some proposed edits at https://gist.github.com/895897

2:19 i guess [argvec & [subphase & left]] is silly. should be equivalent to [argvec subphase & left]

2:20 but i guess if you don't always have a subphase, the double-& is needed

2:21 hiredman: multifn!

2:21 (fn [argvec

2:21 sritchie: when left is fine, here?

2:21 I guess "left" is going to be nil

2:21 hiredman: (fn ([argvec] ...) ([argvec subphase] ...) ([argvec subphase left] ...))

2:21 sritchie: okay, got that

2:22 hiredman: & for optional arguments is used a lot, but multifns almost always end up better

2:22 sexpbot: java.lang.Exception: Can't take value of a macro: #'clojure.core/for

2:22 sritchie: amalloy: yeah, there's actually one more line -- (check-session (str "The session passed out of" '~subphase))

2:23 so, I was thinking that the version that only gets an arg vector, like (phase-fn []), should return an identity phase that checks the incoming session

2:23 rather than just identity

2:23 amalloy: hiredman: he already has a 1-arity version and a 2+ arity version. i proposed, callously, converting it to a 1-arity and 3+ arity

2:24 hiredman: amalloy: and?

2:25 amalloy: hiredman: in theory that introduces a distinction because he gets an exception for calling with just two args. arguably this is better than generating a bogus expansion, but i didn't make the change intentionally

2:27 ugh. and my previous statement is totally false. never mind. they are identical

2:28 gist updated to reflect that added prettiness

3:24 thorwil: good morning!

3:26 mec_: wow it is morning, time for bed

3:26 thorwil: so, using appengine-magic, i submit a form with a "body" of text and want to store that in the datastore

3:27 with a long text, it complains that a String property only takes up to 500 characters

3:28 I have to make it use a Text property instead

3:28 in the source of ackbar, i found (:import (com.google.appengine.api.datastore EntityNotFoundException Text)))

3:29 (ds/save! (Post. url title (Text. body) ts in-feed? category))

3:29 but if i do the same, i get: "java.lang.RuntimeException: java.lang.IllegalArgumentException: Don't know how to create ISeq from: com.google.appengine.api.datastore.Text"

8:16 Licenser: aloa

8:18 mec: Can paredit swap a form with the one above it? (a b |(c d) -> (c (a b d))

10:20 simard: is there a way to have "lein swank" start faster ? or "lein" anything, for that matter ?

10:21 TimMc: You could use cake instead. :-P

10:23 cemerick: simard: try `lein interactive`

10:23 described in the FAQ here: https://github.com/technomancy/leiningen ;-)

10:26 simard: hum so it's java's fault

10:27 well, that's hardly surprising anyway, where else would have lein lost its time :)

10:27 dnolen: hmm 2K lines of pure Clojure is powerful stuff.

10:28 simard: dnolen: I wrote a little app for making grocery lists out of scalable recipes... in a few hours and 125 lines of clojure, and I'm quite sure an experienced clojure programmer could reduce it much.. then I realized how hard to debug that would have been if written in C

10:28 I'm in love with the language now :D

10:29 I just need to find a new project

10:29 dnolen: what's these 2K lines do btw ?

10:30 dnolen: simard: my logic programming library i been hacking on for 6 months or so.

10:31 simard: logic programming eh.. is it out somewhere ?

10:31 clgv: simard: now I am curious. why would have been harder to debug in C than in Clojure?

10:31 dnolen: simard: https://github.com/swannodette/logos

10:31 about to add a fast constraint feature a la XSB, getting close.

10:31 kephale00: clgv: if only because he probably wouldn't have been using a c interpreter

10:32 simard: clgv: clgv well, somehow bugs seem easier to find or avoid

10:32 clgv: I don't have hard science to back this up.. it's just how it feels

10:32 clgv: simard: hm ok that's a blurry fuzzy answer ;)

10:32 simard: yeah :)

10:33 maybe it's because you can do so much more with less code... assuming the number of bugs is proportionnal to the length of code

10:33 clgv: I for myself found that there is a lack of debugging tools for clojure. the jvm ones dont help much in a lot of cases since you see only the compile java bytecode there

10:34 dnolen: clgv: have you looked at cdt ?

10:34 powr-toc: dnolen, woah... you're faster than SWI?

10:34 clgv: dnolen: what is cdt?

10:35 dnolen: powr-toc: :D only for Zebra really, SWI does some wacky optimizations for certain kinds of logic programs.

10:35 simard: clgv: oh yeah I would suppose that's a problem in itself.. but I found you can "debug" by examining subexpressions on the fly with the interpreter. I expect someday I will need a more sophisticated debugger though

10:35 or I might not

10:36 dnolen: powr-toc: but in general the goal is to have a reasonable fast Prolog from Clojure. Constraints on variables, Tabling.

10:36 clgv: http://georgejahad.com/clojure/cdt.html

10:36 powr-toc: dnolen: cooool! how does mini kanren differ from prolog?

10:37 dnolen: powr-toc: some programs can be run in reverse that can't run in reverse in Prolog. fairer search strategy. easier to make parallel.

10:38 I'm brainstorming having optional support for fork/join, you can mark your logic program in such a way as to say run this bit in parallel if possible.

10:39 powr-toc: sounds like it might be quite neat

10:40 dnolen: powr-toc: being faster than SWI on some things is kind of interesting, SWI is 200K of C last I checked, I'm at 1.6K of Clojure. Perhaps persistent data structures are a win here.

10:40 powr-toc: dnolen, how so?

10:41 simard: 200K vs 1.6K ? and it does "the same thing" ?

10:41 dnolen: powr-toc: miniKanren is a purely functional design, a map of bindings is passed through the logic program, so easy to map to Clojure's persistent data structures.

10:42 simard: no, doesn't do the same thing. Prolog's are usually based on Warren's Abstract Machine or some variant of it.

10:42 simard: but it's why I'm interested in miniKanren, 200 lines of Scheme get you a lot of Prolog's characteristic.

10:44 powr-toc: haha yeah, every lisp contains a half implemented poorly specified version, slow version of prolog ... so the saying goes anyway :-) It'd be nice to have something serious :-)

10:45 simard: I should take a more involved look into these logic languages some day.. if I could find an application for them in my research. apart from solving the Zebra puzzle, what kind of "real-world" problem can it solve (and be useful in doing so) ?

10:46 dnolen: powr-toc: yeah I've trying hard to make it fast, been slow going.

10:46 powr-toc: sounds like you're getting somewhere

10:46 dnolen: powr-toc: one could say it's a crazy performance experiment for me.

10:46 simard: you'll need to look at the *large* body of existing literature.

10:47 clgv: simard: what research are you doing?

10:47 dnolen: simard: constraint solvers are getting big. declarative networking, static analysis, semantic web, theorem proving...

10:48 simard: clgv: basically, wireless microelectronics, for biomedical implants. I'm not going in vivo, but I design the chip considering constraints of low-power, small form factor, wide bandwidth.

10:48 a bit far from CS anyway.

10:48 clgv: indeed ;)

10:49 simard: but I want to converge to neuroscience eventually.. I'm hopeful I will find a way to mix all that together (microelectronics, neuroscience, CS). :)

10:51 powr-toc: ewww semantic web :-)

10:52 pyr: hi guys

10:52 clgv: I wonder if I will ever see the day when semantic web is put to some real use ;)

10:53 powr-toc: clgv: for humanities sake, I hope not!

10:53 clgv: lol :D

10:53 gtrak: skynet?

10:53 pyr: seeing conversation diverge from the normal course, i'll just put out there that $job is hiring clojure people (not 100% clojure) in Paris, if anyone's interested, pyr@milestonelab.com

10:53 powr-toc: its only use right now seems to be in keeping academics on the funding gravy train

10:55 clgv: hmm maybe I should claim that I do semantic web as well to get some funding next year ;)

10:55 powr-toc: gtrak: haha not a chance ... I'm more concerned about the environmental costs of rdf processing... and if it ever finds a real use, the dread that one day I might have to use semantic web technologies again :-\

10:56 clgv: lol

10:58 gtrak: powr-toc, but the environmental cost comes with a gain of being able to do more stuff, I think. That's an argument to use against any new technology. Plus, how many cpus are sitting idle as we speak?

11:00 clgv: gtrak: that an argument for SETI@home or *@home ... lol ;)

11:00 gtrak: sure, or cloud-computing

11:01 I guess that was two arguments in one, the one I'd want to argue about is if the processing is worth the gain

11:01 clgv: uuuh, then you have to know whether there is anything to gain

11:02 gtrak: indeed

11:06 powr-toc: gtrak: Personally I always though the semantic web came more from the "do less with more" school of design, rather than the "more with less" one

11:10 * dnolen has amassed an incredible amount of intuitional knowledge on the performance cost of various Clojure features

11:10 no_mind: dnolen, so why not document you knowledge ?

11:10 clgv: dnolen: write down for others to learn ;)

11:11 dnolen: heh not enough time in the day dammit.

11:11 kephale00: dnolen: voice record then later run voice-to-text

11:43 Is there a way (other than a custom macro) of defining key/val pairs in order such that keys which are defined later can reference previously defined key/vals?

11:43 similar to the way let works

12:07 scottj: kephale00: maybe not a good idea, (reduce (fn [m [k v]] (assoc m k (if (keyword? v) (m v) v))) {} {:a 1 :b :a :c :b})

12:12 kephale00: scottj: well using that technique would need a little more substitution than the keyword? check, as I'd like to be able to use previously defined values within full expressions such as {:a 3 :b 8 :c (+ (m :a) (m :b))}

12:36 mec: How might I generalize post- and pre- walk, and what might be better names? https://gist.github.com/895803

13:07 amalloy: mec: try paredit-convolute-sexp

13:07 with point right before c, as i recall

13:10 ah, point right before d, i guess

13:11 (a b (c |d)) M-x paredit-convolute-sexp => |(c (a b d))

13:12 i have it bound to M-LEFT, and i use it for turning (if something (f a b) (f a c)) into (f a (if something b c))

13:15 duncanm: la la la

13:17 mec: le sigh, 2 days until JoC arrives

13:25 technomancy: who's in charge of planet clojure?

13:26 dakrone: I believe that would be Alex Ott

13:26 oh perhaps not, I believe he was just a contributor

13:31 mec: amalloy: lol i was just reading your blog and didnt even realize it until I saw your def for unfold

13:32 amalloy: heh

13:32 that must be...my most recent entry, i guess

13:48 mec: amalloy: how come you make unfold* instead of just recurring on unfold: (cons value (unfold next done? new-seed))

13:48 amalloy: mec: didn't want to pass next and done over and over

13:49 it's worth optimizing HOFs like that that i expect to use in lots of places

13:49 (imo. opinions may vary. consult your lawyer before use, etc etc)

13:50 mec: makes sense

13:58 dnolen: any Clojurians who are also Schemers?

13:59 technomancy: I implemented it once. never used it though.

14:00 cemerick: ha. :-)

14:00 dnolen: technomancy: giving a preso in NYC for people getting familiar w/ Scheme but not Clojure. Curious to know what a Schemer would like to hear covered.

14:01 technomancy: dnolen: talk to KirinDave next time he's around.

14:02 dnolen: technomancy: ah good idea.

14:08 duncanm: dnolen: hey, mr. swannodette!

14:08 dnolen: i was a Schemer before learning Clojure

14:10 dnolen: for me, having generic operations for seqs was a big deal, no more length/string-length/vector-length

14:11 dnolen: duncanm: hey! yeah, I'm definitely going to talk about the benefit of having the core data structures built on interfaces. other things?

14:12 duncanm: dnolen: the STM stuff (refs, atoms, agents) is another obvious thing

14:12 dnolen: i haven't looked into clojure macros much, maybe that's something also?

14:12 technomancy: dnolen: the cultural differences of not having to worry about whether libraries you bring in carry mutability concerns is worth mentioning

14:12 dnolen: it seems like schemers appreciate immutability but can't enforce it.

14:12 duncanm: dnolen: also, depending on which scheme, they might be interested in module/namespace stuff

14:12 dnolen: duncanm: yeah, probably won't have enough time to get into all the concurrency stuff.

14:13 technomancy: dnolen: http://clojure.org/state is important for anyone to hear regardless of concurrency though.

14:13 dnolen: duncanm: oh yeah good point. technomancy: true, for that reason it seems like the study group focuses on Racket.

14:13 technomancy: dnolen: does racket let you disable setcar/setcdr?

14:13 duncanm: technomancy: yes

14:13 technomancy: excellent

14:14 duncanm: oh

14:14 dnolen: little things, but the literal syntaxes in Clojure are fun

14:15 dnolen: the Racketeers decided to make []s synonymous with ()s, which other Schemers didn't like

14:15 dnolen: and Clojure has shown that by keep them distinct, it can result in a pretty nice syntax

14:15 amalloy: duncanm: i remember that from before i even knew the difference between common lisp and scheme

14:15 technomancy: dnolen: here's what was interesting to me right off the bat coming from elisp: http://technomancy.us/121

14:16 clojurebot: clojure |can| make the Kessel Run in under twelve parsecs.

14:16 clojurebot: Roger.

14:16 dnolen: duncanm: yeah I noticed that, [] in Racket.

14:16 amalloy: clojurebot: clojure?

14:17 hm

14:17 duncanm: dnolen: the #() lambda syntax is a particularly nice touch, for me

14:17 dnolen: technomancy: old sckool! pre lein right?

14:17 amalloy: technomancy: what did that do?

14:17 technomancy: dnolen: absolutely

14:17 clojurebot: botsmack

14:17 I killed it. =(

14:17 amalloy: ~o/

14:17 :(

14:17 duncanm: dnolen: oh, btw, nice call pointing out that prolog quote from a few weeks ago

14:17 technomancy: amalloy: |foo| is for arbitrary verbs in definitions

14:17 amalloy: technomancy: i thought so too, though i'd only seen |reply| or something similar. but then he didn't answer

14:18 dnolen: duncanm: thanks, I kinda stumbled on that by accident. I just recalled that Alan Kay had a soft spot for Prolog.

14:18 duncanm: dnolen: oh, he still does

14:18 dnolen: i'm friends with someone who's at his research outfit

14:19 dnolen: are you on their 'fonc' mailing list? it's kinda low-volume, but occasionally, interesting tidbits bubble up

14:19 hiredman: clojurebot: ping?

14:19 clojurebot: PONG!

14:19 dnolen: duncanm: cool. I have a couple of their papers I need to sort through.

14:19 hiredman: clojure?

14:19 clojurebot: clojure is cheating

14:19 duncanm: dnolen: i started reading Ch 4.4 of SICP after that exchange about prolog with you on twitter

14:19 dnolen: duncanm: no but I've run into it in my google searches time to time.

14:19 duncanm: dnolen: it's low volume, so it's not a hassle to subscribe

14:20 dnolen: and Alan himself replies from time to time

14:20 dnolen: duncanm: nice! Ch 4.4 is good stuff. I remember dismissing it 7 years ago and 'not worth it'

14:20 duncanm: heh

14:21 dnolen: i have a copy of Norvig's PAIP too, i think he too has a chapter on implementing Prolog in Lisp

14:21 and of course, norvig's book covers a lot of grounds on different types of search

14:22 dnolen: duncanm: Yeah I look at PAIP from time to time. The main issue with PAIP is that it does lean on imperative programming a bit, so it's not always natural/obvious to convert to Clojure.

14:22 duncanm: ahh, yeah

14:23 dnolen: i started with Scheme first, and like you, thought CL and Scheme were similar

14:23 dnolen: i ported some CL to Scheme a few summers ago, and was initially shocked to see all the SET!s

14:24 dnolen: duncanm: I often find myself spending a crazy amount just trying to sort out how to do things efficiently in Clojure. It's challenging and rewarding.

14:24 duncanm: dnolen: i know that feeling, sometimes i wonder if it's worthwhile (to do everything functionally)

14:25 when the data size is small, there's no real need to parallelize, the priority is to make it work ASAP,

14:25 dnolen: duncanm: heh agreed. Can't wait for Pods.

14:25 duncanm: spending time trying to rewrite something functionally seems like a real distraction

14:26 dnolen: duncanm: yeah Clojure has a hammock development feel. But I do notice if you solve it the hard way up front, a lot of things are easy later.

14:26 nickik: dnolen, are pods more of a speed inprovment or something else?

14:27 too

14:27 I never used transiants for example because I just don't have code that requires it.

14:27 dnolen: nickik: another reference type, not really related to speed, but it would be safe place to but mutable stuff.

14:29 duncanm: dnolen: oh, you might want to talk about destructuring

14:30 dnolen: CLers know about them, but it's not common in Scheme

14:30 dnolen: duncanm: yeah I have a bunch of slides like "Where is car?!"

14:30 duncanm: ahh, but Racket has fancy syntax nowadays

14:30 keywords and stuff like that

14:31 nickik: My other car is a cdr.

14:31 dnolen: Racket is just plain fancy. in a good way.

14:31 duncanm: heh

14:31 dnolen: i went to Northeastern as an undergrad, so my profs were the PLT folks

14:32 dnolen: duncanm: crazy folk.

14:32 duncanm: dnolen: Typed Scheme is the fanciest iteration of it all!

14:32 amalloy: dnolen: not really a schemer here, but i imagine it's important to cover the fact that seqs *really aren't* car/cdr pairs under the hood (i also imagine you already knew this)

14:32 dnolen: duncanm: totally. want for Clojure.

14:32 joly: dnolen: You're probably already covering it, but I'd expect no TCO and the lesser reliance on explicit recursion to be of interest

14:33 dnolen: amalloy: yeah will talk about that. joly: that's the later half of the talk - life w/o TCO.

14:33 duncanm: the name changes are somewhat "annoying"

14:34 dnolen: duncanm: any particular that you confuse a lot?

14:34 duncanm: even now, i think i'll feel happy if s/def/define/, s/defn/define-function/, s/do/begin/

14:34 nickik: I think your the expert on the life w/o TCO

14:34 duncanm: dnolen: do and begin still bothers me a bit ;-P

14:34 dnolen: duncanm: noted.

14:34 duncanm: dnolen: but i like clojure's assoc a lot

14:35 scheme's assoc is now get in clojure, i think

14:35 dnolen: duncanm: I noticed when I go back and forth between Racket/Clojure I mixup my define/defn a lot.

14:35 duncanm: dnolen: oh! = vs. all the variants of equal? eq? eqv? is another point

14:36 technomancy: yeah, point them at Baker's Equal Rights for Functional Objects

14:36 duncanm: i don't think i ever got them quite right in my head

14:36 assoc assv and something else

14:36 technomancy: very compelling to non-FP-users

14:37 joly: I loved switching to built-in maps from Scheme's hash tables, not having to find the right SRFI to load, etc

14:38 duncanm: actually, i haven't thought of this before: instead of doing fancy destructuring in the arg list, is it faster to just use the java overload feature?

14:38 dnolen: duncanm: yeah = awesome is on my slides.

14:38 duncanm: (for handling simple optional arguments)

14:38 amalloy: duncanm: yes

14:38 duncanm: (defn foo ([a] ...) ([a b] ...)) is kinda unexpected, coming from Scheme

14:39 dnolen: duncanm: yup will address that too.

14:39 duncanm: and occasionally results in rather nice code

14:40 dnolen: duncanm: do the PLTers have any opinions of the Indiana Scheme crew?

14:40 duncanm: oh

14:41 haha

14:41 Chez Scheme?

14:41 people get very attached to their preferred scheme systems....

14:42 dnolen: duncanm: heh yeah.

14:42 duncanm: dnolen: i think PLTers are particularly proud of their syntax and module system, and consider other systems 'inferior' simply because they don't have them

14:42 amalloy: duncanm: reminds me of lispers in general

14:42 duncanm: dnolen: so Chez Scheme i think is a straight up impl of syntax-case, where as PLT's syntax is a superset of syntax-case

14:43 dnolen: another thing that frustrated me was the difference between the various Schemes. In fact it's probably my only complaint about Racket, that sometimes figuring out how to write R5RS is a pain the butt.

14:43 duncanm: and i dunno what module system the Chez people use, maybe nothing at all before, and now moving towards the R6RS one?

14:43 i know of a couple of famous Schemers who are happy with the Javascript-style of modules (ha!)

14:44 dnolen: ugh

14:44 duncanm: define a bunch of null top levels

14:44 write everything inside a let

14:44 dnolen: double ugh

14:44 duncanm: set! the internal defines to the top levels

14:44 presto!

14:45 actually, i dunno about "a couple"

14:45 anyhow, i've seen that done before

14:45 * dnolen lives and breaths fake JS modules everyday.

14:45 duncanm: dnolen: there's a PLT alum at mozilla now, working on getting proper modules

14:45 dnolen: David Herman right?

14:46 duncanm: right

14:49 i understand the philosophy at all that, but i wish there were a defclass in Clojure, just for writing JComponents ;P

14:57 hiredman: b/win 14

15:04 duncanm: technomancy: i'm reading a blog lamenting the lack of namespaces in tcl now, but whenever i see arguments like that, i think emacs lisp

15:05 technomancy: i'm not saying it's a bad thing to have namespaces, but emacs lisp has shown that it's definitely possible to build a robust and long-lasting software system without it

15:05 all of this has been said in the beautiful code chapter before...

15:05 technomancy: duncanm: I don't know; everyone I talk to who writes much elisp code wishes it had a module system.

15:06 duncanm: technomancy: oh of course

15:06 technomancy: just results in lots of extra typing =\

15:06 duncanm: all i'm saying, emacs is ane existance proof that namespaces are a necessity

15:06 are not a necessity

15:06 technomancy: yeah, that's true

15:07 duncanm: i wonder if a similar argument can be made for hygienic macros

15:07 ;-P

15:17 Havvy: What is the idiomatic way to dynamically create functions?

15:19 TimMc: Havvy: Composition, closures, etc.

15:19 That's probably not what you're asking, though.

15:19 duncanm: wave your hands!

15:20 Havvy: Closures, no. Not sure what you mean by composition. Trying to create a function that defines two other functions that may be used later in the program.

15:22 TimMc: Havvy: Defines functions that have names that can be used from elsewhere in the program, or just functions that will be passed around as values and later called?

15:22 Havvy: Former

15:23 joly: I don't think it's encouraged, but you can (defn a[] (defn b[] 6)), and b isn't defined until you call a

15:24 TimMc: Unless you hear otherwise from the more experienced people in the channel, I'd say what you're doing is not idiomatic in the first place.

15:24 raek: Havvy: have you considered macros?

15:24 brehaut: rule of thumb: defs should only changed by a developer

15:25 Havvy: raek: I have, but was hoping not to have to use them.

15:25 brehaut: changing them programattically is not idiomatic

15:25 TimMc: Havvy: Note that in joly's suggestion, the inner defn creates a global var that is immediately available, but not set until a is run.

15:26 brehaut: Havvy: perhaps if you explained the problem you are trying to solve (ie, take a step back) we might be able to provide more specific ideas

15:26 Havvy: TimMc: I understand that. But it runs into the issue of if you don't know what the name of the function is...

15:26 TimMc: Oh, the name would be b.

15:27 But brehaut is right.

15:27 raek: Havvy: there is probably some other way of solving the problem. currently, we know nothing about the problem you are trying to solve. you question was regarding a proposed solution, and not about the problem itself

15:27 Havvy: brehaut: Given the name of two measurements a and b, and a ratio, create two functions for converting between a and b "a=>b" and "b=>a".

15:29 I already have a function that can create the names.

15:29 brehaut: Havvy: ok, next thing: what is the context for this behaviour

15:29 joly: I'd be inclined to go the macro route

15:30 Havvy: An end unto itself, or otherwise trying to learn more about the language.

15:30 nickik: mybe put the functions into a hashmap and look them up by name

15:30 TimMc: Havvy: Wouldn't you have to call these by name from elsewhere in your code anyway?

15:31 Havvy: TimMc: Yes.

15:31 TimMc: Then I suspect I don't understand what the pain point is.

15:32 brehaut: Havvy: from what you have said it sounds like a simple macro should do the job for you

15:32 duncanm: a macro could work, but is it what you really want?

15:33 hmm

15:33 i've been writing snippets of clojure at work for 2 yrs, and i have yet to write a single macro

15:33 maybe i'm just not that smart ;P

15:33 Havvy: duncanm: The entire task is a task upon itself. brehaut: So this can only be done using macros?

15:34 brehaut: duncanm: it sounds like he wants to create named pairs of functions from a template; that sounds like a suitable application to me :)

15:35 joly: Might be possible in other ways, but a macro seems more straightforward

15:35 brehaut: Havvy: im not super up on the details of vars and namespaces, but anything else requires def shenanigans

15:36 TimMc: Contrived problems (and I mean that in a neutral sense) often have different solutions than very similar real-world problems. A macro might be suitable for this experiment, but not for a real app.

15:36 raek: Havvy: the thing is, if you call def in a function, you will unconditionnally mutate a global variable. (this might be safe in some specific cases, but not in general) unconditional mutation is what clojure was designed to get away from.

15:36 duncanm: hah!

15:37 15:24 Given the name of two measurements a and b, and a ratio, create two functions for converting between a and b "a=>b" and "b=>a".

15:37 raek: it is possible, just unideomatic

15:37 duncanm: i mean

15:37 TimMc: raek: Nothing wrong with a macro (called from the top level) to def stuff though, yeah?

15:38 duncanm: (defn make-convertors [a b ratio] (letfn a->b ... b->a ...)) and then return a seq of the two funcs

15:38 raek: well, if any time is the time for defs, it would be compile-time

15:38 Havvy: raek: I understand that. They are technically impure, but the side effect is what I care for. Though duncanm's line avoids that a bit.

15:40 duncanm: do you really need (compare-foo->bar a-foo a-bar) instead of ((make-comparator foo bar) a-foo a-bar)

15:40 nickik: if you ned them to be only computet once you could make a atom that holds the functions

15:40 duncanm: you can memoize make-comparator!

15:40 Havvy: Though I think there would still be the issue that letfn is a macro and won't execute the code necessary to make it read a->b at run-time.

15:41 TimMc: Havvy: It sounds like you want a top-level form of (defconv a b 4.5) that turns into (def a->b [a] (* a 4.5)) (def b->a [b] (/ b 4.5))

15:41 Havvy: duncanm: It's a contrived example, so I don't need anything. The latter does seem more idiomatic though.

15:41 TimMc: Is that correct?

15:42 Havvy: TimMc: Yes.

15:42 duncanm: i saw some Ruby code where the guy went all out generating functions like that

15:42 it seems silly to me

15:42 Havvy: It is silly.

15:42 duncanm: i think it was some translation API

15:43 so he generated all variations of from_english_to_russian (text) and from_russian_to_english (text)

15:43 so on

15:43 oh

15:43 it's ruby too, so it's test.from_english_to_russian

15:43 woohoo!

15:44 brehaut: i'm curious if F#'s units of measure stuff could be ported to idiomatic clojure

15:44 duncanm: brehaut: the surface syntax part is probably not the difficulty

15:45 brehaut: indeed; it relys on a lot of type system stuff to track units which is already heading down a different path to idiomatic clojure

15:46 TimMc: Havvy: Should be an easy macro to write.

15:46 Havvy: TimMc: Yes, it should. :)

15:48 Can a macro contain multiple definitions like functions can? I.e. is (defmacro ... [a b n] exprs [a b] exprs) allowed?

15:48 amalloy: yes, but you have to write it properly (just as you would a function)

15:48 (defmacro ([a b n] exprs) ([a b] exprs))

15:49 duncanm: it'd be nice if syntax-rules were available

15:49 i dunno what the difficulties are for implementing that

15:49 TimMc: syntax-rules won't help here

15:49 Havvy: Ah, I knew I was missing parens somewhere. It looked too ambiguous.

15:49 amalloy: duncanm: someone implemented (most of?) that already. i don't know scheme so i can't speak to how good an impl it is

15:50 dnolen: https://github.com/qbg/syntax-rules

15:50 Havvy: IMO, those parenthesis are easier to read than a bunch of lines of other languages.

15:50 duncanm: dnolen: i saw that too, browsing thru the tests didn't reveal anything interesting to me

15:53 dnolen: duncanm: yeah I'm not sure what state it's in.

15:54 duncanm: yeah, i don't even know what the interface to defmacro is

15:55 i used a Scheme with explicit-renaming macros, so define-syntax took in a lambda with environment/renamer/comparer

15:55 TimMc: $findfn 'user/a 'a

15:55 sexpbot: []

15:55 TimMc: $findfn 'user/a "a"

15:55 sexpbot: [clojure.core/name clojure.contrib.string/as-str]

15:57 TimMc: Havvy: I think I have a macro for this now.

15:58 It's kind of hacked together, but if you want to see it: https://gist.github.com/897116

15:59 And if you want to work through it yourself first, that

15:59 works too.

16:01 Havvy: What's the point of letting num-sym to a gynsym'd name?

16:01 technomancy: http://github.com/technomancy/lein-retest <= would love to see feedback on that

16:01 TimMc: Havvy: Making sure it is only eval'd once.

16:01 mec: Havvy: If you mean num-expr it's so that doesnt potentially evaluate twice

16:01 TimMc: It might be an intensive computation.

16:02 technomancy: gotta love it when the readme has more lines than the implementation

16:02 Havvy: TimMc: Ah, useful.

16:03 TimMc: Havvy: Or worse, it might have side-effects. :-)

16:03 amalloy: yeah. usually unless your macro is used explictly to evaluate things more than once, you should usually use let to make sure args aren't evaluated more than once

16:04 TimMc: Havvy: Ideally, the macro would also have some error-checking code to make sure that you don't do (defconv (a) :b 5) or something.

16:04 You should add that as an exercise. :-)

16:05 amalloy: TimMc: throwing an exception at expansion time sounds like fine error-checking

16:05 which i think is what you end up doing?

16:05 TimMc: I honestly don't know.

16:05 It might just do weird shit.

16:05 amalloy: &(symbol '())

16:05 sexpbot: java.lang.ClassCastException: clojure.lang.PersistentList$EmptyList cannot be cast to java.lang.String

16:05 amalloy: tada

16:06 TimMc: &(symbol (str '()))

16:06 sexpbot: ⟹ clojure.lang.PersistentList$EmptyList@1

16:06 amalloy: &(name ())

16:06 sexpbot: java.lang.ClassCastException: clojure.lang.PersistentList$EmptyList cannot be cast to clojure.lang.Named

16:06 * amalloy wins?

16:06 TimMc: Yup.

16:06 But that's an implementation detail and there really should be an explicit check.

16:07 amalloy: not unreasonable

16:07 TimMc: If the user makes a mistake like (defconv 'a 'b 5) they get java.lang.ClassCastException: clojure.lang.Cons cannot be cast to clojure.lang.Named (NO_SOURCE_FILE:0)

16:07 and who the hell know what that means without a decent error message. :-)

16:07 Havvy: I've a function that does this. Catches keywords and empty lists already. (str-join "=>" [a b]

16:08 amalloy: Havvy: eh? does what? join already exists

16:08 Havvy: And handles the case when you send it 'a and 'b by actually working.

16:08 str-join is in clojure.contrib.str-utils

16:08 amalloy: Havvy: gross. just use clojure.string/join

16:08 contrib is for things that aren't already in core, ideally

16:09 Havvy: (doc clojure.string/join)

16:09 clojurebot: Huh?

16:09 amalloy: &(require '[clojure.string :as str])

16:09 sexpbot: ⟹ nil

16:09 amalloy: &(doc str/join)

16:09 sexpbot: ⟹ "([coll] [separator [x & more]]); Returns a string of all elements in coll, separated by an optional separator. Like Perl's join."

16:11 Havvy: (str/join ['a 'b] "=>")

16:11 amalloy: Havvy: wrong order

16:11 &(str/join "," '[a b])

16:11 sexpbot: ⟹ "a,b"

16:13 hiredman: anyone know if redefing causes the watchers on a var to be notified?

16:14 Havvy: Now I want to write in a book I don't own. X.X

16:15 TimMc: hiredman: It does.

16:16 (based on a test I just did)

16:17 hiredman: "Var watchers

16:17 are triggered only by root binding changes, not thread-local

16:17 set!s.

16:17 bah

16:19 sritchie: hey all -- is there some way to return an anonymous macro in clojure?

16:19 amalloy: sritchie: to *return* an anonymous macro? no; what is it you want to do?

16:19 sritchie: let me post a gist

16:20 TimMc: sritchie: Whatever you're doing, stop it!

16:20 sritchie: haha, okay

16:20 TimMc: I want to see, though. :-)

16:20 sritchie: https://gist.github.com/897167

16:21 so! originally, this was a single macro called phase-fn, that stuck a line that "checked" the threaded argument between ever y form

16:21 s/ever y/every

16:21 sexpbot: <sritchie> so! originally, this was a single macro called phase-fn, that stuck a line that "checked" the threaded argument between every form

16:21 sritchie: I wanted to generalize it, by allowing it to accept different checkers, and give me back a macro with that checker implemented

16:22 -> can be substituted for ->, it doesn't matter for this example

16:23 so, (checked-thread-fn identity) would give me back a macro that was equivalent to ->

16:24 the only requirement is that the checker function take two arguments -- the threaded argument, and a string explaining the form that caused the break

16:25 AND, of course, I made up macro-fn right now.

16:25 amalloy: sritchie: (a) can you kill sritchie_, he's ruining my tab-completion; (b) you could either make it def a top-level macro and use that, or make it take all the args at once and expand immediately, instead of returning a macro that will expand

16:26 eg instead of ((checked-fn identity) [args] whatever more stuff), call (checked-fn identity [args] whatever more stuff)

16:26 TimMc: technomancy: Exception in thread "main" java.lang.Exception: retest requires robert/hooke dep.

16:27 Ah, I suppose I need that for hooks.

16:30 Can't lein-retest pull that in?

16:31 sritchie: amalloy: for the first option, like this? https://gist.github.com/897167

16:31 amalloy: sritchie: no; you want the second defmacro to be part of the expansion, so it needs to be in backticks

16:32 $google amalloy macro writing macros

16:32 sexpbot: First out of 30 results is: Clojure: macro-writing macros

16:32 http://hubpages.com/hub/Clojure-macro-writing-macros

16:36 sritchie: amalloy: okay, I'll play with this. the issue with a macro-writing macro is that, to get the identity expander, I need to have the line (checked-thread-fn identity-threader (fn [arg & rest] arg))

16:37 technomancy: TimMc: it can't pull it in because it's a dev-dep, and hooke needs to be a regular dep. needs to be clarified in the readme.

16:37 Havvy: Heh: #'user/:b=>:a

16:37 technomancy: good catch though

16:37 sritchie: Ideally, I could include (def identity-threader (checked-thread-fn (fn [arg & rest] arg)))

16:37 amalloy: sritchie: that's kinda-sorta possible but not the easiest way

16:38 sritchie: I guess the outer macro could be called with (def-checked-threader identity-threader (fn [arg & rest] arg))

16:38 with better names

16:38 amalloy: right

16:39 see also https://github.com/amalloy/amalloy-utils/blob/master/src/amalloy/utils/macro.clj#L26, which would let you define all your threaders in one go

16:39 sritchie: hey, great

16:39 there's anon-macro

16:40 amalloy: sritchie: that's mine too

16:40 but it uses macrolet

16:40 sritchie: yup

16:40 amalloy: you can't actually return that macro - it only exists inside the macrolet scope

16:42 sritchie: thanks, I'm on the right track, now! I'm a bit confused about how to add a backtick around my other backticked stuff -- this will be good practice

16:42 TimMc: They just nest, right?

16:42 amalloy: sritchie: as my article above says, doing that is usually a recipe for unnecessary pain

16:42 sritchie: actually, I can have a backtick inside a backtick, whtat am I talking about

16:42 amalloy: TimMc: yes, but try getting the unquoting right

16:43 TimMc: eep

16:43 amalloy: &`(let [foo# 10] `(inc ~foo#))

16:43 sexpbot: ⟹ (clojure.core/let [foo__11114__auto__ 10] (clojure.core/seq (clojure.core/concat (clojure.core/list (quote clojure.core/inc)) (clojure.core/list foo__11114__auto__))))

16:43 sritchie: haha, sorry, I can tell I'm skidding around in the dark, thanks for bearing with me

16:52 mec: I seem to do (condp #(%1 %2) ..) alot, it feels like there should be a better way

16:53 dnolen: mec: (condp #(%1 %2) x ...) whre x is %1?

16:54 mec: oh sorry #(%2 %1)

16:55 amalloy: mec: two of my utils let you write #(%2 %1) as (reorder invoke). more wordy for sure and maybe not something to brag about, but you might prefer it

16:59 sritchie: https://gist.github.com/897167 -- the 1-argument version expands properly, but the 2+ is having some issues

16:59 am I allowed to nest a syntax-quote like that?

17:00 amalloy: same issue you pointed out in your sexpbot call

17:01 amalloy: sritchie: i didn't point out an issue; i gave an example of how gross the correct way looks

17:01 sritchie: oh, yeah, the call to seq does make things look quite gross

17:01 amalloy: sritchie: looks like you're missing a ~ on (when ~left)

17:02 oh

17:02 nm

17:02 sritchie: yeah, I think that one's okay --

17:02 this is the error -- Can't use qualified name as parameter: pallet.crate.hadoop/session__9445__auto__

17:03 amalloy: ah

17:03 `(fn [~'session#]), i think

17:04 or to avoid figuring out how to combine all those unquotes, you can let a gensym at the toplevel for session, and use it everywhere

17:04 &`(let [x# 1] `(let [y# 2])) is your problem

17:04 sexpbot: ⟹ (clojure.core/let [x__11123__auto__ 1] (clojure.core/seq (clojure.core/concat (clojure.core/list (quote clojure.core/let)) (clojure.core/list (clojure.core/apply clojure.core/vector (clojure.core/seq (clojure.core/concat (clojure.core/list (quote clojure.core/y__1112... http://gist.github.com/897242

17:05 amalloy: observe that y is being turned into clojure.core/y__1112. instead ##``(let [~'y# 2]) should fix it

17:05 sexpbot: ⟹ (clojure.core/seq (clojure.core/concat (clojure.core/list (quote clojure.core/let)) (clojure.core/list (clojure.core/apply clojure.core/vector (clojure.core/seq (clojure.core/concat (clojure.core/list (quote y__11131__auto__)) (clojure.core/list 2)))))))

17:06 sritchie: okay, that makes sense

17:06 amalloy: haha then you're one step ahead of me :)

17:06 sritchie: I'm checking out the expansion of the identity threader now, I think I'm almost there

17:06 hell of a way to go to get something equivalent to -> :)

17:06 amalloy: indeed

17:10 sritchie: working -- https://gist.github.com/897167

17:12 amalloy: sritchie: oh man, that ~'macro-name just screams error - is it actually right?

17:12 i guess it is. jeez i hate these things

17:12 sritchie: amalloy: yeah, this might end up staying a thought experiment

17:13 amalloy: good plan

17:13 (no offense)

17:14 if you want to see something really monstrous you should check out clojail's safe-eval construct (used by sexpbot): https://github.com/cognitivedissonance/clojail/blob/master/src/clojail/core.clj#L109

17:14 sritchie: none taken

17:14 I actually like the idea of the monster that's getting created, here --

17:15 but it's very convoluted, getting there

17:15 amalloy: *chuckle*

17:20 sritchie: amalloy: last question, before I let this die --

17:20 https://gist.github.com/897167 -- is this the proper way to do a top-level session gensym?

17:20 amalloy: yep

17:20 sritchie: I'm getting Unable to resolve symbol: G__10075 in this context

17:21 amalloy: hm

17:22 sritchie: not that important, just curious

17:22 amalloy: &(let [x (gensym)] `[(inc ~x) `(inc ~~x)])

17:22 sexpbot: ⟹ [(clojure.core/inc G__11146) (clojure.core/seq (clojure.core/concat (clojure.core/list (quote clojure.core/inc)) (clojure.core/list G__11146)))]

17:23 Havvy: When I return multiple values, what is the best type to return them as? A list?

17:23 amalloy: Havvy: vector

17:23 Havvy: Kk.

17:23 amalloy: the literal syntax is much more convenient for those

17:24 mec: All of these ways to search a map for keys look hackish, there has to be a better way https://gist.github.com/897285

17:24 Havvy: [] instead of (list ...) yeah... :P

17:25 TimMc: mec: Use the map as the predicate?

17:25 dnolen: hmm what would you call a map like thing in which keys point to multiple values and the values point back to multiple keys? multi-multi-map ?

17:27 mec: TimMc: I like it, would I just use nil for the expr?

17:27 TimMc: Not familiar with condp yet, so I can't judge hackishness.

17:27 mec: your solution is perfect, cant believe it never occured to me

17:28 TimMc: What does my solution look like? :-P

17:28 mec: i updated the gist

17:28 amalloy: sritchie: i think it needs another quote

17:29 ~'~session

17:29 clojurebot: Cool story bro.

17:29 dnolen: mec: what about select-keys ?

17:30 amalloy: (condp contains? m :key1 key1 :key2 key2)

17:30 mec: oo i like it even more

17:31 amalloy: &(condp contains? {:x 1} :y 1 :x 0)

17:31 sexpbot: java.lang.IllegalArgumentException: No matching clause: {:x 1}

17:31 TimMc: mec: Are the values expressions that do things or just simple literals?

17:31 mec: ya thats no good, the order is wrong

17:31 TimMc: both

17:31 amalloy: errrr i guess that's true

17:31 TimMc: OK, so you need delayed eval, got it.

17:32 amalloy: i always have to look up argument order for condp

17:32 TimMc: $findfn {:x 1} :x true

17:32 sexpbot: [clojure.core/not= clojure.core/distinct? clojure.core/contains?]

17:33 TimMc: $findfn :x {:x 1} true

17:33 sexpbot: [clojure.core/not= clojure.core/distinct? clojure.core/not-any? clojure.core/not-every?]

17:33 hiredman: ~botsnack

17:33 clojurebot: thanks; that was delicious. (nom nom nom)

17:33 mec: how is not-any? there true

17:34 amalloy: mec: ##(:x (first {:x 1}))

17:34 sexpbot: ⟹ nil

17:34 mec: ah hah

17:35 Havvy: Is there a built-in function that tells me if a string is a substring of another string, and if so, at what location it starts at?

17:35 TimMc: $findfn :b '#{a b c} true

17:35 sexpbot: [clojure.core/not= clojure.core/distinct? clojure.core/not-any? clojure.core/not-every?]

17:35 TimMc: $findfn 'b '#{a b c} true

17:35 sexpbot: [clojure.core/not= clojure.core/distinct? clojure.core/not-any? clojure.core/not-every?]

17:35 TimMc: Havvy: .indexOf ? :-)

17:36 Havvy: Thanks.

17:36 (New to both Clojure and Java I am.)

17:37 TimMc: ,(.indexOf "slaughter" "laugh")

17:37 clojurebot: 1

17:37 TimMc: (Sorry, the only word-in-word I could come up with on the spot was kind of creepy.)

17:37 Havvy: Heh, what an interesting substring for that word. :P

17:38 amalloy: TimMc: you won't find anything useful for those findfns because ##('#{a b c} 'b)

17:38 sexpbot: ⟹ b

17:38 amalloy: doesn't return true

17:38 TimMc: Ah, right... logical true.

17:38 amalloy: insane clowns: putting the laugh back in slaughter

17:40 Havvy: btw .indexOf returns -1 if it doesn't match. that's logical true, so you have to check for it

17:40 Havvy: amalloy: REPL testing has told me as such.

17:40 amalloy: hurrah for the repl

17:40 TimMc: indeed

17:41 Havvy: Also my memory of Javascript told me something similar. ;)

17:45 sritchie: amalloy: better identity phase-fn -- (defmacro unchecked-phase-fn [argvec & forms] `(fn [session# ~@argvec] (-> session# ~@forms)))

17:46 Havvy: Creating a function that returns the left-hand and right-hand side of a string "a=>b". Throws an error if there is no arrow in it. What would be the line for that? (throw "StringMissingArrow")?

17:47 TimMc: You need to throw a Throwable of some sort, just like in Java.

17:47 Havvy: I have no knowledge of Java.

17:47 TimMc: So, you could do (throw (IllegalInputException. "Missing arrow yada yada"))

17:47 amalloy: TimMc: that class doesn't exist :P

17:47 try IllegalArgumentException

17:47 TimMc: yeah, that one!

17:48 Havvy: (throw (IllegalArgumentException. "Test error!"))

17:48 amalloy: &(throw (IllegalArgumentException. "Test error!"))

17:48 sexpbot: java.lang.IllegalArgumentException: Test error!

17:49 Havvy: For s-exp-bot, what do the & and , reader functions do?

17:50 TimMc: They're not reader functions, just triggers.

17:51 , is clojurebot's trigger

17:51 clojurebot: java.lang.Exception: Unable to resolve symbol: is in this context

17:51 TimMc: See? :-)

17:51 Havvy: & is for sexpbot then?

17:51 sexpbot: java.lang.Exception: Unable to resolve symbol: is in this context

17:51 TimMc: clojurebot: Do you not know what the meaning of "is" is?

17:51 clojurebot: meaning of life is to become one with Lisp

17:51 Havvy: clojurebot++

17:52 amalloy: (inc clojurebot)

17:52 sexpbot: ⟹ 1

17:52 amalloy: Havvy: ^

17:52 TimMc: ~botsnack works too :-P

17:52 clojurebot: thanks; that was delicious. (nom nom nom)

17:52 amalloy: heh

17:52 Havvy: &(clojurebot)

17:52 sexpbot: java.lang.Exception: Unable to resolve symbol: clojurebot in this context

17:52 amalloy: they are greedy buggers

17:53 Havvy: he doesn't know about clojurebot when he's actually eval-ing code with &. only when you activate the karma plugin by saying (inc someone)

17:53 Havvy: (inc amalloy)

17:53 sexpbot: ⟹ 6

17:53 Havvy: (inc TimMc)

17:53 sexpbot: ⟹ 1

17:54 TimMc: &(inc TimMc) <-- the *real* inc

17:54 sexpbot: java.lang.Exception: Unable to resolve symbol: TimMc in this context

17:54 amalloy: he also recognizes inline eval requests like ##'clojurebot and ##(dec 10)

17:54 sexpbot: (quote clojurebot) ⟹ clojurebot

17:54 (dec 10) ⟹ 9

17:55 Havvy: So that explains why the double hash is used.

17:55 TimMc: Yeah, you need something unlikely to trigger the bot by accident.

17:56 You can also private-message the bots.

17:56 clojurebot:

17:56 clojurebot: #<ClassCastException java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.String;>

17:56 TimMc: bah

17:56 amalloy: lol nice work TimMc

17:56 Havvy: Lawl.

17:56 TimMc: Wait, what was that?

17:56 Havvy: sexpbot:

17:57 sexpbot: (+ 2 2)

17:57 clojurebot: (+ 2 2)

17:57 clojurebot: 5 (for large values of 2)

17:57 TimMc: ahaha

17:57 Havvy: clojurebot: (* 2 2)

17:57 clojurebot: * is just for when you are lazy and sloppy

17:57 amalloy: TimMc: looks to me like he does (into-array args) on the assumption that args will be strings. if you give it no args it winds up being an object array, which causes problems later

17:57 TimMc: Now it's just grabbing quotes.

17:57 Havvy: (+ 1 2)

17:57 clojurebot: 3

17:57 amalloy: ~#24

17:57 clojurebot: 24. Perhaps if we wrote programs from childhood on, as adults we'd be able to read them.

17:57 Havvy: clojurebot: (+ 1 2)

17:57 clojurebot: ,(let [testar (fn [x y] (if (= (reduce + (filter odd? (range 0 x))) y) (str y " is an")) )] (testar 10 25))

17:58 Havvy: clojurebot: (+ 2 1)

17:58 clojurebot: ,(let [testar (fn [x y] (cond (= (reduce + (filter odd? (range 0 x))) y) (str y " is a")) )] (testar 11 25))

17:58 Havvy: ...

17:58 TimMc: Havvy: You're not using the eval trigger, so it is free-associating.

17:58 amalloy: Havvy: if you address him with a message he doesn't understand, he just does his best, i think

17:58 clojurebot: ,(+ 2 1)

17:58 clojurebot: 5 (for large values of 2)

17:59 TimMc: heh

17:59 amalloy: hmph

17:59 well, you can pm him ,(+ 2 1)

17:59 TimMc: clojurebot: (+ 2 14)

17:59 clojurebot: ,(let [testar (fn [x y] (cond (= (reduce + (filter odd? (range 0 x))) y) (str y " is a")) )] (testar 11 25))

18:00 Havvy: clojurebot: ,(+ 5 10)

18:00 clojurebot: Excuse me?

18:00 TimMc: Havvy: /msg clojurebot ,(+ 5 10)

18:00 Oh, and it will also occasionally respond to things that weren't addressed to it, just for fun.

18:00 Havvy: TimMc: I know how to use IRC. I'm an IRC OP on the server of an IRC client that Freenode blocks.

18:01 TimMc: Hah, OK. :-)

18:01 Havvy: clojurebot: .Math.PI

18:01 clojurebot: excusez-moi

18:01 TimMc: ,Math/PI

18:01 clojurebot: 3.141592653589793

18:01 TimMc: for statics

18:01 * Havvy was hoping for the value "3" in the state of (whatever)

18:01 TimMc: / for statics

18:02 Havvy: Oklahoma I think...

18:02 Nope, Indiana.

18:02 TimMc: Arkansas, as the urban legend I know tells it.

18:02 amalloy: indiana, i thin

18:02 Havvy: http://en.wikipedia.org/wiki/Indiana_Pi_Bill

18:05 TimMc: Oh hah, I didn't know about that one.

18:06 All the ones I had heard of involved a Southern state. :-P

18:06 Good to know the real story.

18:07 no_mind: is there a list of clojure based applications somewhere ?

18:07 amalloy: clojurebot: pi is about three, in Indiana

18:07 clojurebot: Alles klar

18:07 amalloy: pi?

18:07 clojurebot: pi is about three, in Indiana

18:08 TimMc: amalloy: Pi *is* about three, though.

18:08 amalloy: TimMc: it's not *defined* as "about three"

18:08 Havvy: clojurebot: no, pi is about three point two in Indiana.

18:08 clojurebot: In Ordnung

18:08 Havvy: pi?

18:08 clojurebot: pi is about three, in Indiana

18:08 amalloy: Havvy: i doubt he'll soak that up

18:08 Havvy: no, pi?

18:09 no?

18:09 amalloy: Not as smart as firebot then. :(

18:35 https://gist.github.com/897401 << Will this do the error handling?

18:37 TimMc: Havvy: What happens when you (macroexpand-1 `(defratios (a) :b 3)) ?

18:38 Havvy: false

18:39 TimMc: and is returning false, so that's what the form will expand to

18:39 What you actually need to do is throw an error.

18:40 when or when-not would be appropriate here.

18:41 Havvy: If I use a when, how can it throw an error?

18:42 TimMc: (when condition stuff ...) rest of macro ...

18:42 And stuff should involve a throw

18:42 I updated my gist with my solution.

18:42 https://gist.github.com/897116

18:44 Havvy: Ah. Useful to know.

18:47 All this time, and only 42 lines of code. I sure hope my productivity will increase.

18:48 9 of which are practically done by you Tim.

18:54 amalloy: Havvy: you could have written 300 lines of java with less functionality than 42 lines of clojure. don't judge productivity by LOC

18:55 kephale00: Havvy: or if LOC really make you feel better write a clojure script to generate code for you and run it overnight

18:55 amalloy: btw TimMc it seems silly to use a# and b# for symbols that will (a) be exposed in the :arglist meta, and (b) can't be accessed by user's code

18:55 goodside: Or, if you do judge productivity by LOC, consider them a negative.

18:56 amalloy: i like (defn ~ab-sym [~'a] (* ~'a num#))

18:57 TimMc: amalloy: Ah, that's what I was looking for.

18:59 Havvy: amalloy: I'm pretty sure that I'd be writing the same in Java, if I was writing in it...

18:59 amalloy: arguably better still, you can remove the repetitive structure of the defns: `(let [num# ~expr] ~@(for [[op arg name] [['* 'a ab-sym] ['/ 'b ba-sym]]] `(defn ~name [~arg] (~op ~arg ~num#))))

18:59 TimMc: I've heard of a programmer boasting that at his last job he was responsible for -100,000 LoC or something.

18:59 Deleting is good.

19:00 Havvy: Only when you start refactoring...

19:00 brehaut: http://www.folklore.org/StoryView.py?story=Negative_2000_Lines_Of_Code.txt

19:00 amalloy: Havvy: huh?

19:00 kephale00: Havvy: with Clojure you are almost always refactoring as soon as you start writing your code

19:01 it is a different development process than procedural languages

19:01 TimMc: brehaut: Similar story, yeah. Maybe the original.

19:01 kephale00: unless you were using a java interpreter

19:01 amalloy: i guess my proposed change probably doesn't work because num# is being used in two contexts and gets a different symbol. something similar though

19:09 https://gist.github.com/897441 makes a couple changes to yours, Havvy

19:09 TimMc: No syntax highlighting?

19:10 amalloy: TimMc: i forked his and his didn't have any. sec

19:10 there

19:10 TimMc: thanks

19:11 amalloy: could probably do better by using a-symb instead of 'a

19:11 TimMc: amalloy: I'm not sure what you were trying to say about the gensym.

19:12 ,`(a# a#)

19:12 clojurebot: (a__4781__auto__ a__4781__auto__)

19:12 amalloy: &`(let [a# 1] ~@[`(let [a# 1])])

19:12 sexpbot: ⟹ (clojure.core/let [a__11632__auto__ 1] (clojure.core/let [a__11631__auto__ 1]))

19:12 amalloy: is what i had written

19:13 TimMc: Ah, so they weren't in the same syntax-quote.

19:13 amalloy: right

19:13 so in my gist i get a gensym explicitly

19:25 i've noticed CL code often uses a gensym when it needs a sentinel: (let ((end (gensym))) (return a bunch of items, stopping when one of them is eq to end)). in clojure i usually do (let [end (Object.)] (take-while (complement #{end}) (iterate #(or more-stuff end))))

19:25 should i be using gensyms as well, or is (Object.) more idiomatic?

19:26 TimMc: You should probably request a UUID from a web service at macro expand time.

19:26 Clearly.

19:26 brehaut: TimMc: i didnt realise you work for an Enterprise

19:26 TimMc: :-)

19:26 new Object() is idiomatic for Java, that I know.

19:27 amalloy: TimMc: which is weird, because i don't remember ever seeing new Object() in my years writing java

19:28 TimMc: I saw it used as a sentinel and also as a thing to synchronize on.

19:28 brehaut: amalloy: it probablly looked like Private Class MySentinel Implements ISentinel {} … new MySentinel();

19:28 amalloy: TimMc: synchronization i've seen

19:28 even as *shudder* a recommended best practice

19:29 so here's something weird: ##(let [a1 (gensym "a") a2 (symbol (str "a" "11687"))] [a1 a2 (= a1 a2)])

19:29 sexpbot: ⟹ [a11687 a11687 true]

19:30 amalloy: are gensyms not guaranteed perpetually-unique like in CL?

19:31 TimMc: Try again with eq.

19:31 amalloy: TimMc: you mean identical?

19:32 TimMc: yeah

19:33 amalloy: sure, they're not the same object (verified this). but i thought CL did something that prevented them even evaluating the same

19:33 TimMc: Oh, huh... ##(identical? 'a 'a) has different behavior in Clojure than in PLT Scheme.

19:33 sexpbot: ⟹ false

19:34 TimMc: I think.

19:38 ssideris: hello, I tried to do (apply proxy-super a [b c d])

19:38 And I got: Can't take value of a macro: #'clojure.core/proxy-super

19:38 amalloy: i notice that in sbcl (eq 'a 'a) is true

19:38 * TimMc mumbles something about interned vs. uninterned symbols at amalloy

19:39 amalloy: TimMc: yeah

19:39 ssideris: I understand why

19:39 but I'm not sure how I would go about writing differently

19:39 amalloy: ssideris: you want a macro that expands into a call to proxy-super, probably

19:39 TimMc: ssideris: Macros are infectious.

19:40 ssideris: amalloy: oh you mean something like apply-proxy-super ?

19:41 (which does not exist yet)

19:41 amalloy: uhhh, probably. keep in mind the args will have to all be known at compile time anyway or you're just moving the problem

19:42 ssideris: hm, they're not

19:42 amalloy: then you ain't calling a macro that needs to know something about them

19:43 ssideris: I'll look into the macroexpand-1 of proxy-super and mimic that

20:03 gertalot: anyone else having trouble accessing clojure.org? I'm getting an SSL domain name mismatch for wikispaces.com

20:35 htierno: Hi there, i'm new to clojure. I was checking out the ants simulation code

20:35 gertalot: sigh :( I guess I'm the only one who can't access the clojure website eh.

20:36 htierno: I was having a hard time understanding the def world ... expression

20:36 TimMc: gertalot: works for me

20:36 gertalot: hm.

20:36 brehaut: htierno: can you provide al ink to the ants code you are looking at?

20:36 htierno: yeah

20:36 http://clojure.googlegroups.com/web/ants.clj?gda=g2CpRjoAAACo4x-COryhtXrsT4ddJVE-X_nZkB4F4_E0DdHzerfpau9OU0NQiFWgQuhmPR7veGf97daDQaep90o7AOpSKHW0

20:36 brehaut: (htierno its very old (for clojure) and there are few versions in the wild)

20:37 gertalot: it's accessing session.wikispaces.com and they're using a content distribution network through edgecast, but the ssl certificate isn't valid :(

20:37 htierno: this is the function

20:37 ;world is a 2d vector of refs to cells

20:37 (def world

20:37 (apply vector

20:37 (map (fn [_]

20:37 (apply vector (map (fn [_] (ref (struct cell 0 0)))

20:37 (range dim))))

20:37 (range dim))))

20:37 brehaut: htierno: have you dont any functional programming before?

20:38 htierno: brehaut: yes, but only in school 10 years ago

20:38 I've read a lot about clojure

20:38 a couple of books

20:38 brehaut: htierno: ok cool. so a good way to start unpacking this is from the inside of the expression out

20:39 and to jump ahead, the result of the expression is a vector of vectors

20:39 ie a 2d struction

20:39 htierno: how did you figure that out

20:39 ?

20:39 gary_poster: wallyworld, would you still like that pypi permission?

20:39 brehaut: how did i figure what out? that its a 2d structure?

20:39 htierno: brehaut: yes

20:40 gary_poster: meh sorry, wrong channel :-P

20:40 brehaut: a) i read the program a few years ago, but importantly b) there is two "(apply vector (map …" nested

20:41 htierno: brehaut: ok, that's and interesting hint

20:41 brehaut: htierno: so the first bit of could you should look at is

20:41 hiredman: apply vector is very old, vec is preferable

20:41 brehaut: htierno: (map (fn [_] (…)) (range dim)

20:42 htierno: brehaut"

20:42 brehaut: hiredman: there are lots of old things in this example; it also has (dorun (for…) for example

20:42 htierno: brehaut: his applying fn with the world function arguments to the ref ?

20:42 brehaut: htierno: sorry, the first bit of code. ive abbrevated it down to the core for you.

20:43 htierno: what's dim ?

20:43 brehaut: dim is defined to be 80

20:43 htierno: oh, sorry

20:43 yes, it's defined up there

20:44 brehaut: htierno: so range generates a sequence from 0 to dim-1

20:44 htierno: so, the "inner" vector it's 80 in lenght

20:44 brehaut: yup

20:44 the body of the fn in map (ref (struct cell 0 0)) tells you what each item i nthe vector contains

20:45 htierno: I can't see that

20:45 the indentation mess me up a bit

20:46 brehaut: you'll also notice that the argument to fn is _ (an underscore) this is idiomatic for that the argument is ignored

20:46 htierno: its the body of the (fn … ) passed to the inner map

20:47 htierno: so, the first (range dim) makes a sequence of 80 in length

20:47 brehaut: someone can probably confirm this, but i think defstruct and struct are deprecated as of 1.2

20:47 ,(map (fn [_] :c) (range 10))

20:47 clojurebot: (:c :c :c :c :c :c :c :c :c :c)

20:47 gertalot: could someone please point me to the clojure api docs? Normally I access that through clojure.org but that's inaccessible for me atm.

20:47 brehaut: gertalot: you could try clojuredocs.org/

20:48 gertalot: excellent brehaut! ty

20:48 htierno: clojurebot: ok, i got that

20:48 clojurebot: bartj: it's not broken. Unless you know the performance hit there is actually a problem, I'd recommend leaving it alone.

20:49 Havvy: ##*out*

20:49 brehaut: htierno: so the 'ref' function returns a new STM reference that wraps its argument

20:49 htierno: in this case a 'struct' which you canthink of as a map (the data structure, not the function)

20:50 htierno: ok, so then we have 80 ref cells

20:50 brehaut: yup

20:50 htierno: actually a vector of ref cells

20:50 brehaut: correct

20:50 so we had previously (apply vector (map (fn [_] …) (range dim)))

20:51 where the … made ref cells

20:51 htierno: yes, that make the vector of vectors of ref cells

20:51 brehaut: you can see that code repeated except that … is now the expresion that generates a vector of refs

20:52 htierno: so that all makes sense now?

20:52 htierno: not yet

20:52 I don't get the indentation

20:52 brehaut: may i suggest experimenting in your repl?

20:53 htierno: if you have a list form such as (fun arg arg arg)

20:53 htierno: everything else is clear now, thanks for the patience brehaut

20:53 brehaut: and you add line breaks, the first character of the second argument should line up with the first character of the first argument

20:54 htierno: ok then

20:54 so map takes a fn and a sequence

20:54 brehaut: yup

20:54 htierno: thanks

20:54 brehaut: htierno: do you have a repl running?

20:54 htierno: thanks again for your patience

20:54 yes

20:54 but I was trying to read some code

20:54 brehaut: htierno: try (doc map) for instance

20:54 (doc map)

20:54 clojurebot: "([f coll] [f c1 c2] [f c1 c2 c3] [f c1 c2 c3 & colls]); Returns a lazy sequence consisting of the result of applying f to the set of first items of each coll, followed by applying f to the set of second items in each coll, until any one of the colls is exhausted. Any remaining items in other colls are ignored. Function f should accept number-of-colls arguments."

20:55 brehaut: htierno: it will tell you what the possible arguments it can take are

20:55 and no problem

20:55 htierno: thanks brehaut

20:56 brehaut: htierno: while the ants demo is cool and you can learn a lot from it, its 3 stable versions of clojure out of date in terms of idioms, so it might differ from more recent code you find

20:56 so just keep that in mind

20:57 htierno: about the things deprecated in that example

20:57 apply vector is replaced by vec ?

20:57 brehaut: yup

20:58 htierno: rule of thumb for #clojure, if hiredman tells you something, its right

20:59 htierno: what about struct ?

20:59 that seems ok

20:59 cell is a struct defined earlier

20:59 brehaut: htierno: its been deprecated i believe. defrecord replaces it

20:59 but learning about defrecords is probably overkill for you ATM

21:00 htierno: ok, I will look up that

21:00 brehaut: htierno: a struct is just a fancy map with keyword keys anyway

21:00 so you can just treat it as a map

21:00 htierno: ok

21:00 I'm looking at the API

21:01 and it doesn't say that this macro is deprecated

21:01 so, how do you now for sure ?

21:01 or is it that defrecord is actually "more" correct ?

21:02 by "more" correct I mean better

21:02 brehaut: so the idea of structs is that they are maps with faster access; defrecord is the same idea with a radically different implementation that compiles down to host classes

21:02 so its capable of being _much_ faster

21:02 htierno: great, so it's actually not deprecated

21:03 but there is a better way of doing the same thing

21:03 brehaut: if it is not officially deprecated, it is nolonger idiomatic

21:03 htierno: ok

21:04 brehaut: htierno: http://clojure.org/data_structures#Data%20Structures-StructMaps theres a note immediate below 'StructMaps' that doesnt use the word deprecated but states the same thing

21:04 htierno: is there another group about clojure for us newbies ?

21:05 I don't like to ask stupid questions that may offend some users on this channel

21:05 brehaut: htierno: you wont offend anyone

21:05 not by asking a question anyway

21:06 htierno: ok, thanks again

21:32 amalloy: structs are officially deprecated. someone was insisting that "deprecated" means "it will be removed at some point", and that it must not be deprecated because that's not a guaranteed outcome by any of the docs. but "deprecated" means "you shouldn't do this [anymore]", and structs are that

21:34 i'm not sure that vec is a replacement for apply vector, though of course in most cases it is. it doesn't seem unreasonable, to me, to prefer (apply vector 1 2 some-var) to (vec (list* 1 2 some-var))

21:50 htierno: amalloy: thanks for the explanation

21:50 amalloy: why don't you put the "deprecated" tag on struct ?

21:51 amalloy: umm. (a) i don't have anything like commit access to clojure.core, (b) clojure functions don't have javadoc?

21:51 Havvy: amalloy: They do have metadata though. ;)

21:52 #^{:deprecated-to 'defrecord}

21:52 Hmm, can metadata have metadata? :P

21:52 cemerick: yup, they're all maps :-)

21:53 Havvy: Has anybody made use of that feature?

21:53 cemerick: There's always someone crazy enough.

21:54 Metadata is "real" data somewhere, so it might need metadata in that context.

21:54 Who's to say that you don't need metadata on your metadata?

21:55 * cemerick barely suppresses a yo dawg

21:55 tomoj: hardly barely

21:55 amalloy: heh

21:56 cemerick: I can't get enough of somewhat-out-of-date memes.

21:57 tomoj: seems like in the limit the best memes would be those that only you have

21:58 Havvy: tomoj: You mean inside jokes?

21:58 tomoj: with oneself? I guess

21:58 the "best" memes in some sense are those that spread best, but then they're not cool anymore

21:59 Havvy: A meme is just an idea that spreads...which really just sounds like a fancy word for 'idea'.

22:00 Oh wait, it is a unit of cultural idea, value, or pattern...

22:01 tomoj: I guess "meme" is a good meme

22:01 Havvy: I wonder if a meme could be spread: "Every time you say something is a meme, you prove evolution." :P

22:02 brehaut: tomoj: careful, cemerick only barely suppressed the yo dawg the first time round

22:02 tomoj: don't you have to suppress something to barely suppress it?

22:02 use/mention I guess?

22:02 amalloy: tomoj: he suppressed one of them. the other snuck out

22:02 tomoj: :)

22:03 cemerick: brehaut: don't worry, I've composed myself again.

22:03 brehaut: (comp cemerick cemerick) ?

22:04 cemerick: MPD is right around the corner.

22:06 tomoj: I feel like if I'm a function I should be one if its parameters too

22:06 s/parameters/arguments/

22:06 Havvy: tomoj: So you can update yourself?

22:07 Hmm, if a ref contains a function that contains code to modify that function, would it work?

22:07 tomoj: I guess you can get a reference to a ref inside a function in the ref, but callers will only see the new function if they go through the ref

22:08 Havvy: :confused

22:10 java.lang.Exception: Unable to resolve symbol: do-sync in this context

22:10 :(

22:10 brehaut: Havvy: what about dosync ?

22:11 Havvy: Oh. Yes, that works.

22:11 Yes, a ref that is a function can modify itself. >_>

22:12 brehaut: of course

22:15 tomoj: a ref that is a function?

22:15 brehaut: tomoj: i presume he means a ref that contains a function

22:15 tomoj: a function in a ref can modify the ref

22:16 functions are surely immutable?

22:30 Havvy: le sigh: (def test-ref (ref (fn [] (dosync (ref-set test-ref 10)))))

22:31 ,(def test-ref (ref (fn [] (dosync (ref-set test-ref 10)))))

22:31 clojurebot: DENIED

22:31 Havvy: &(def test-ref (ref (fn [] (dosync (ref-set test-ref 10)))))

22:31 sexpbot: java.lang.SecurityException: You tripped the alarm! def is bad!

22:32 amalloy: Havvy: what's the point? a ref/atom can be set to anything by anyone; not sure what you're trying to demonstrate

22:33 Havvy: I would think it would run into a race condition with itself...but it seems not.

22:36 amalloy: there is nobody to race with. it's *not* modifying the function's code in any way

22:36 tomoj: functions that get removed from refs run just as fine as those that don't

22:37 amalloy: it just has three objects of interest: a ref-to-anything, a function, and the integer 10. the ref begins pointing at the function. the ref is deref'd, the resultant function is called (nobody is even looking at the ref anymore at this point), and the function sets the ref to point to 10

22:39 &(let [a (atom nil)] (reset! a (fn [] (reset! a 10))), (@a), @a)

22:39 sexpbot: ⟹ 10

22:40 Havvy: If you can call the number 10 interesting. It's merely a 'what can this be replaced with?' value. But yeah, nifty that it can do that.

22:42 pdk: 10 is badass man

22:42 no hati

22:42 hatin

23:32 gertalot: ugh. It's Friday afternoon... what is the practical difference between atoms and refs?

23:32 wondering what the use cases are for both.

23:34 amalloy: atoms: changing something that can be grouped under a single object. refs: coordinating changes across multiple things

23:34 gertalot: thanks amalloy!

23:34 that helps.

23:35 amalloy: i rarely use refs: i find it interesting and challenging to work out how to fit the stuff i need to work with under a single atom

23:36 gertalot: so, suppose I have Jobs that represent long-running computations, I could use (def jobs (atom {})) to store jobs

23:36 amalloy: indeed

23:36 gertalot: and each job could be a ref, because the long running computations need to update Job state every now and then

23:36 or is that wrong? :)

23:37 amalloy: it's on the crazy side

23:37 gertalot: haha :)

23:37 ok

23:37 the thing is, I don't want to couple job storage to the computations.

23:38 amalloy: i'd do like (swap! jobs update-in [job-id] assoc :done true)

23:38 or whatever

23:38 gertalot: ah that gives me hope. That's close to what I currently have, but I thought there could be a better way

23:38 thanks again amalloy!

23:39 amalloy: rata had an interesting case convincing me that (atom {id (agent nil), id2 (agent nil)}) was a good idea, but in general nesting reference types seems dangerous

23:41 gertalot: I think I'll stay away from it unless I really really need it, in which case I'd probably have a good argument for it too.

23:41 tomoj: I heard you like reference types

23:42 amalloy: groan

23:44 tomoj: &(let [a (ref nil) b (ref a)] (dosync (ref-set a b)))

23:44 sexpbot: java.lang.StackOverflowError

23:44 tomoj: why?

23:44 clojurebot: why not?

23:44 tomoj: why?

23:44 clojurebot: why not?

23:44 tomoj: every time?

23:46 amalloy: weird

23:47 tomoj: oh

23:47 &(let [a (ref nil) b (ref a)] (dosync (ref-set a b) nil))

23:47 sexpbot: ⟹ nil

23:47 tomoj: it's just the printing, which is exactly the stack overflow I was expecting

23:47 amalloy: hah

23:57 scottj: clojure scripting just got better, jark supports super simple #! and is really fast, launching the persistent JVM if not already running

23:58 it's official, leiningen is being deprecated in favor of cake

Logging service provided by n01se.net