#clojure log - May 10 2011

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

1:44 seancorfield__: great to meet amalloy tonight at bay area clojure user group

1:45 amalloy: you too, seancorfield__

1:45 jlf from #emacs keeps rsvping for these things and telling me we'll get to meet, but then he doesn't show :P

1:47 seancorfield__: :)

1:47 amalloy: moral: trust clojure hackers, not emacs users

1:47 seancorfield__: lots of interesting folks at tonight's meeting... the autodoc guy, the appengine-magic guy... the clojure in action guy :)

1:47 amalloy: whose is autodoc?

1:49 seancorfield__: tom faulhaber

1:49 was sat to my right

1:49 amalloy: yeah, i recognized the name and noticed the intro. just didn't really know what he did

1:50 tomoj: where?

1:50 clojurebot: where is your source code

1:50 amalloy: tomoj: sf

1:50 tomoj: oh, bay area

1:50 that was my guess :)

1:50 here's hoping someone out there gives us money so I have an excuse to go there

1:50 seancorfield__: he is updating autodoc to work with the new contrib libs... http://clojure.github.com/java.jdbc/ is the guinea pig...

1:51 amalloy: tomoj: there's $20 with your name on it, direct from me, if that encourages you to make the trip :)

1:51 tomoj: heh

1:52 are you out there too?

1:52 amalloy: tomoj: that's why sean was saying he met me

1:53 seancorfield__: the bay area is *horrendously* expensive

1:53 tomoj: aha

1:54 I'm quite willing to live in a tiny bare box for a few years if I get the opportunity

1:54 amalloy: eh, the software companies pay well enough to make it entirely livable

1:56 markoman: I have a strange problem. (if ... (do (myfunc ... (otherfuncs ... for some reason in myfunc for each loop doesnt work. but if i put (if ... (do (println (myfunc ... (otherfuncs then all is fine. what may cause this behaviour?

1:57 amalloy: clojurebot: laziness?

1:57 clojurebot: laziness is what will save us all

1:57 tomoj: "for each loop"?

1:57 amalloy: wow that is wrong

1:57 clojurebot: laziness is hard

1:57 clojurebot: In Ordnung

1:57 amalloy: &(do (map println (range)) 1)

1:57 sexpbot: ⟹ 1

1:57 markoman: sorry, just for loop

1:57 tomoj: as in the macro for?

1:58 clojurebot: for?

1:58 clojurebot: for is not used enough

1:58 markoman: lol

1:58 tomoj: I vaguely remember "for is not a loop"

1:58 amalloy: markoman: (do a b c) evaluates a and b *for side effects*, then throws them away and returns c

1:58 tomoj: but my memory sucks

1:58 markoman: lazyness may save but I dont get it

1:59 amalloy: for *returns* a lazy seq, and if you throw it away you never realize any of its elements

1:59 tomoj: clojurebot: for?

1:59 clojurebot: for is not used often enough.

1:59 tomoj: bah

1:59 amalloy: tomoj: he only has one entry for each thing, iirc

1:59 &(doc doseq)

1:59 sexpbot: ⟹ "Macro ([seq-exprs & body]); Repeatedly executes body (presumably for side-effects) with bindings and filtering as provided by \"for\". Does not retain the head of the sequence. Returns nil."

1:59 tomoj: got two there that really are one

2:00 amalloy: markoman: compare that to ##(doc for)

2:00 sexpbot: ⟹ "Macro ([seq-exprs body-expr]); List comprehension. Takes a vector of one or more binding-form/collection-expr pairs, each followed by zero or more modifiers, and yields a lazy sequence of evaluations of expr. Collections are iterated in a nested fashion, rightmost f... http://gist.github.com/963983

2:00 markoman: so yeah, I have some side effect going on in (do, saving data to session and datastore

2:00 amalloy: clojurebot: doseq?

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

2:01 amalloy: clojurebot: doseq is like for, but for side effects instead of values

2:01 clojurebot: Ok.

2:01 amalloy: there

2:01 all fixed

2:01 markoman: now ask clojurebot about doseq and he'll solve your problem

2:02 tomoj: clojurebot: for?

2:02 clojurebot: for is not a loop

2:02 tomoj: :D

2:02 clojurebot: botsnack

2:02 clojurebot: thanks; that was delicious. (nom nom nom)

2:02 amalloy: tomoj: did you overwrite his existing entry in PM? i think "for is not used often enoguh" is pretty useful too

2:03 tomoj: I asked him in PM but didn't edit anything

2:03 amalloy: ah

2:03 markoman: :) to me it looks like looping over all items in list

2:03 tomoj: wonder if it's random with or without replacement

2:03 ..or that

2:04 seancorfield__: just signed up for amit's day of macros training course - should be fun!

2:04 tomoj: &(first (for [x (range)] (* x x)))

2:04 sexpbot: ⟹ 0

2:04 markoman: hmh, so I should use doseq instead of for or doseq instead of do?

2:04 amalloy: instead of for. it is literally a drop-in replacement

2:05 markoman: and it supports :let :when behavior too?

2:05 amalloy: i know a great way to find out. try it in the repl

2:07 opqdonut_: it's not drop-in. doseq doesn't return the values

2:07 markoman: ok, thanks. i used several hours yesterday trying to find out, why (for didnt work. makes some sense now

2:07 opqdonut_: but yeah, it's the same syntax

2:08 amalloy: opqdonut_: if it were "drop-in" in the way you mean, it would have to be exactly the same function

2:08 since he's using it in the context of (do (for ...) (whatever else)), it's as drop-in as you can imagine

2:08 markoman: in this case i dont need values anyway, because its a side effect sequence

2:09 amalloy: speaking of it being the same sequence, did you know the code for parsing arguments to for is repeated almost verbatim in doseq? nobody refactored that into a helper function

2:09 syntax, not sequence

2:10 markoman: i should really get a book. soon its summer holidays and time to read

2:15 i doubt there is any Clojure user groups in Finland, but how about in New York City?

2:19 tomoj: you must construct additional pylons

2:19 * amalloy gets the reference but doesn't see how it applies

2:20 tomoj: you must

2:21 amalloy: i guess i need to spawn more overlords, cause my poor lil brain can't do all this thinking itself

2:21 tomoj: actually this is just my battery notify-send message but I didn't anticipate the protoss voice burrowing into my brain once a minute when I already know I need to plug in

2:22 amalloy: haha

2:22 i've barely played sc2, but i was always least effective with protoss anyway

2:22 codedigestion: hmmmmmmmmmmmm................ Anyone about that would be able to help me get sessions working in Ring????

2:23 tomoj: that's a lot of dots

2:23 amalloy: i use sandbarrrrrrrrrrrrrrrrrrrrrrrrrrrrr for my sessions

2:26 markoman: i have made my own session.clj but I think it overlaps with Rings own functionality plus doesnt use Rings custom session store handles

2:29 and I have to say this channel has been a great help on learning Clojure

2:30 better than any of the web sites

2:32 thorwil: markoman: do you know that there are libs specifically for handling sessions, using ring?

2:34 markoman: i never found other than sandbar. but at that point i didnt understand the code and how to use it... maybe im now educated more. but what libs you mean thorwil?

2:37 thorwil: markoman: actually it looks like i shouldn't have used plural. sandbar, yes

2:45 markoman: well, less libs, easier decisions

2:50 tomoj: seems sandbar is 2577k raw lines

2:50 amalloy: jeez

2:50 er

2:50 tomoj: 1067 of which in forms.clj

2:50 amalloy: surely you don't mean 2.5M lines

2:50 tomoj: that's small, though, right?

2:50 oh, heh

2:50 2577 lines

2:51 amalloy: tomoj: it's pretty large if you consider how big ring itself is

2:52 tomoj: stateful_session.clj which sounds particularly relevant is only 135 lines

2:52 codedigestion: I can't figure out sandbar??? :P

2:52 I'm trying to use ring session....

2:53 tomoj: ring-core seems to be only 955 total

2:53 codedigestion: can't figure out how to store to a session variable :name, for example....

2:54 :session :name = :param :name type of deal...

2:54 amalloy: tomoj: right. and most of that is optional middlewares

2:54 tomoj: hmm

2:54 codedigestion: (let [name (session :name (params "name"))]) doesn't seem to cut it???

2:54 tomoj: isn't wrap-session enough to get the barebones?

2:54 codedigestion: I've got wrap-session up...

2:55 wrap-params works, but I can't figure out wrap-sessions. :p

2:55 amalloy: incidentally, i was delighted to find how simple it is to write a new ring middleware. that is a very nice model he built

2:56 tomoj: seems you just read out the :session from the request map and update the :session in the response map ?

2:56 codedigestion: no, I'm taking the params from the response map and and trying to store it into the sessoin...

2:57 I'm not sure how to get sessionn going in the first place - so, what I'm doing may be completely wrong in the first place. :((((((((((

2:57 I'm a COMPLETE newb to clojure....

2:57 markoman: i got a feeling wrap carries vars over requests, but doesnt really store them?

2:57 tomoj: I am blind and so probably shouldn't lead you :D

2:58 codedigestion: hmmmm......

2:58 markoman: I made this study a month ago: https://github.com/mmstud/websesstudy/tree/master/src/websesstudy

2:59 codedigestion: thanks markoman.... You've included several comments! hopefully, I'll be able to figure it out!

2:59 thanks! :)

3:02 markoman: np, I'm sure you can do it. there is probably even easier way to handle sessions than on my study, but it may give some hints how you want to implement whole thing

3:03 codedigestion: I certainly hope so! :)

3:07 @markoman, what's "flash" messages, btw?

3:08 markoman: they are meant to show any message on web page from previous page request and then clear message

3:08 codedigestion: really has nothing to do with sessions, eh? What's a use case of a flash message?

3:09 markoman: it uses session to store message between two requests, then cleans session variable

3:11 its like a flash, shows up once. say you make some actions, like storing form and want to inform user after submitting form all was fine. you dont want to keep message popping on screen continously, just once. its very common practice on web frameworks

3:14 post page -> store message -> load new page -> show message -> delete it from session. thats how it works

3:14 codedigestion: got ya'! :)

3:15 does flash store to a specific variable, or just to "flash" and you request "flash" and it gives if somethings there, else nothing?

3:17 markoman: it stores to session store to :flash variable internally and like you figured, I use only flash function for both functionality, setting and getting depending if I pass message or not

3:21 codedigestion: question, you've got -> (:require [websesstudy.session :as ses]))

3:21 isn't that the ring.session?

3:22 where does your session actually come from?

3:22 when did you load it?

3:22 markoman: no, its my session.clj but inside there you can see, I wrap both ring session and my session by middleware

3:23 tomoj: I can't help feeling an existential crisis about sessions after that question

3:23 dude, where DO they come from?

3:24 markoman: session.clj you can see (:use [ring.middleware.session]) so there it is

3:24 codedigestion: ICKES!!!!

3:24 yeah, just looked at yoru session.clj

3:24 I don't understand ANYTHING in it???????????? looks very complicated, man! Just to store a key/value pair to a session???

3:26 markoman: yeah. I had a same feeling when I looked to sandbox. and I thought I made it easier. for me apparently, lol

3:27 codedigestion: :'(

3:27 markoman: but yes, you need to store session information somewhere, I use atom memory based store. it could be database too. I think ring session handler doesnt really take opinion where you want to store data if anywhere

3:28 codedigestion: gosh, tooo many layers of crap just to get things working!

3:28 thorwil: eek, how do i get out of an "Debugger entered--Lisp error: (end-of-file"?

3:28 amalloy: thorwil: C-g?

3:28 or just q?

3:29 thorwil: q, thanks

3:29 codedigestion: @markoman, any idea on how to use ring.middleware.session, or is this as complicated? :P

3:29 tomoj: it's only got one function

3:29 codedigestion: nevermiind...

3:29 i see that's what you used...

3:30 amalloy: codedigestion: if only there were a programming language where writing new libraries to expose new ideas took no effort at all. just wave some fairy dust and you have a webserver with stateful sessions

3:30 markoman: well at the end you just include file and use two functions. codedigestion, I know the feeling really. I was used to easier session variable handling by PHP

3:30 codedigestion: Do I need the UUID?

3:31 markoman: yes, either one generated by ring or your own

3:31 tomoj: seems PHP built their castle on web conveniences, luckily rich was not so foolish

3:31 codedigestion: hmmm.............

3:31 fliebel: 00211111

3:31 amalloy: only if you want to IDentify your clients in a Universally Unique way. if you don't mind client A getting sent client B's session data, you can drop the uuid

3:31 fliebel: that was my cat, sorry

3:31 codedigestion: I didn't think it was rick that made ring?

3:31 markoman: ring session wrapper creates cookie and session id, but I found it better to use my own

3:31 tomoj: exactly!

3:32 thorwil: fliebel: your cat communicates in ternary?

3:34 amalloy: well-educated cats would communicate in balanced ternary: +-=====

3:34 fliebel: thorwil: Nope, it knows more key commands than I do :) It choose the numpad as an appropriate location for some tail wagging today.

3:35 markoman: but Im still happy, now I know better how sessions work under the hood. never needed to thin kabout it with PHP, but its same principle

3:35 codedigestion: @markoman, if I just use your websesstudy.session, should I be able to get my stuff to work provided I follow the principles you've laid out in your core.clj, you think?

3:35 fliebel: I didn't even know there as an enter key there.

3:36 markoman: codedigestion: yes. core.clj is the frontend, you have a session set and get functions and thats all you need

3:37 tomoj: is session set/get much more more than assoc/get?

3:38 I've only ever dabbled in ring but the session middleware seems perhaps deceptively simple

3:38 markoman: I recently made a small fix there with session del function, but havent commited it yes

3:38 yet*

3:38 codedigestion: @markoman, do I just copy your file into my src folder? I'd like to keep it as (:require [websesstudy.session :as ses]), but wouldn't know what folder to put your session file in so that I'd be able to accomplish this in leiningen - any thoughts?

3:40 markoman: you probably just use: (:require [yourpackage.session :as ses]) im not sure of your src layout

3:41 have to go to the meeting, be back later

3:41 amalloy: wow it's been too long since i did balanced ternary. my +-===== is nonsense; 00211111 in "traditional" ternary is +-+++++ in balanced ternary

3:42 codedigestion: fair enough! thanks Mark! I appreciate the patience! :)

3:48 thorwil: i really wonder what's going on there: http://www.foopics.com/showfull/d57a41526055b6001110a2788f45a935

3:49 amalloy: looks vaguely like a bug in swank-clojure

4:03 raek: thorwil: probably a non-ascii character in the file

4:04 you could try customizing slime-net-coding-system to 'utf-8-unix

4:04 and then start the swank server with "UTF-8" as an encoding parameter

4:07 by adding :jvm-opts ["-Dswank.encoding=utf-8"] to the project.clj

4:08 too bad slime has to default to latin-1 when everything in clojure-land defaults to utf-8

4:09 tomoj: seems I didn't need any :jvm-opts

4:10 at least, I haven't seen that damn error since I customized slime-net-coding-system

4:12 raek: hrm. maybe swank-clojure defaults to UTF-8 nowadays...

4:14 tomoj: so you can type (seq "ĉĝŭ") in the repl and get (\ĉ \ĝ \ŭ) back?

4:19 tomoj: yeah

4:20 thorwil: ah, (seq "ĉĝŭ") is a killer here

4:21 tomoj: even with the 1.4.0-SNAPSHOT swank-clojure bin

4:22 raek: encoding issues are tricky, since the effects a bad configuration can cancel each other out in some cases (the seq test reveals this, though)

4:23 tomoj: maybe get-system-encoding in swank.swank is relevant

4:24 (.name (java.nio.charset.Charset/defaultCharset)) here returns UTF-8

4:24 .. but this is the only key in the encodings-map anyway

4:24 swank.core.connection confusingly has (def default-encoding "iso-8859-1")

4:27 thorwil: can't find any slime-net-coding-system

4:27 tomoj: `C-h v slime-net-coding-system` says "No match"^

4:27 ?

4:28 thorwil: (.name (java.nio.charset.Charset/defaultCharset)) says "UTF-8" here, too

4:40 raek: thorwil: tomoj: are you using emacs-starter-kit?

4:41 I don't have it on the computer I'm currently sitting at, and for some reason, the slime.el file is not automatically loaded. if I load it manually, slime-net-coding-system appears

4:41 tomoj: raek: no

4:41 I have slime from tromey's package.el

4:43 I also (setq slime-net-coding-system 'utf-8-unix) in init.el, so that test is pointless..

4:51 thorwil: no, no starter-kit

5:08 no init.el, but i found a place for (setq slime-net-coding-system 'utf-8-unix), so now (seq "ĉĝŭ") works

5:08 thanks, raek, tomoj

5:15 tomoj: I spent months dodging unicode bombs in the repl before, I think, raek gave me that tidbit

5:16 _exterm: Hi everybody. I have implemented some modifications to the clojure 1.1 compiler to allow bytecode generation on Android (building on the work of george jahad). Now I have problems porting it to clojure 1.2.

5:17 see my changes here:https://github.com/exterm/clojure/commit/9bf7109960e2468d00daecd8756c65cb8d1c2f32

5:17 fliebel: Is there something like cond-let? (cond-let [x false] x [y true] y) > true

5:18 _exterm: with clojure 1.2 I can evaluate (defn test [] "") to get a new function test into the namespace (I do this via a modified swank instance that is deployed on the phone)

5:19 But any definitions that are compiled AOT I can't overwrite at runtime

5:19 Trying to find the change in the clojure compiler between 1.1 and 1.2 that is responsible

5:21 any clojure compiler hackers here today? :-)

5:21 tomoj: a bisect to the phone would probably be quite tedious :(

5:21 _exterm: yes, i thought about that

5:21 i'd have to reapply my changes in each step too

5:22 tomoj: ouch

5:22 fliebel: _exterm: Not me. But I do wonder why you are targeting 1.2 with 1.3 just around the corner?

5:22 tomoj: ..ouch

5:22 _exterm: I wanted to base it on a stable version to make it useable now.

5:22 I could of course try 1.3

5:23 fliebel: I use 1.3… Not sure if that qualifies it as usable though.

5:23 _exterm: but I think the relevant change will most likely be in there too

5:23 so that wouldn't really solve my problem

5:24 fliebel: No… except that 1.3 has this ^:dynamic thing that would make life hard for you.

5:24 clgv: humm one of incanter's example doesnt work for me - anybody know why? here it comes:

5:24 (use '(incanter core datasets stats bayes charts))

5:24 (def ols-data (to-matrix (get-dataset :survey)))

5:24 (def x (sel ols-data (range 0 2313) (range 1 10)))

5:25 linear-model fails with NullPointerException in cern.colt.matrix.tdouble.DoubleMatrix2D.zMult

5:26 _exterm: BTW anyone who wants to try developing for android with a swank server on the phone, I have a little script that downloads and builds my project so it's quite easy to get it up and running (using clojure 1.1 though, obviously): https://github.com/exterm/swank-android-builder

5:26 clgv: x and y are proper values

5:28 fliebel: clgv: Maybe it's because you are not using y?

5:28 clgv: fliebel: what exactly do you mean?

5:29 fliebel: clgv: I don't see y being used in your code.

5:29 clgv: -> (linear-model y x :intercept false)

5:30 it's not my code, it's example code from doc ;)

5:31 _exterm: fiebel: ^:dynamic? Do you have a link?

5:34 Fossi: _exterm: i'll try ;)

5:35 fliebel: _exterm: Uhm, no. Maybe Google has. But the short version is that vars cannot be changed in 1.3, unless you mark them dynamic.

5:35 &*clojure-version*

5:35 sexpbot: ⟹ {:major 1, :minor 2, :incremental 0, :qualifier ""}

5:38 raek: changed, as in rebound with (binding [*foo* ...] ...)

5:38 _exterm: good to know ^^

5:38 raek: def still works to correct vars, but causes functions to be recompiled

5:39 _exterm: that could make interactive development on android a bit slower. Anyway, I think I will concentrate on 1.2 for now, could make it easier to port to 1.3 once I have solved the current problems.

5:48 raek: _exterm: btw, have you presented your work to the clojure-dev mail list? I think the core team would be interested since Android support seems to be in the pipeline

5:50 also, I know that Remco van 't Veer and Daniel Solano Gómez has worked on android support too. is your work related to theirs?

5:52 _exterm: raek: oh, I didn't know that. No, I haven't presented it there. My work builds on Remcos modifications to the clojure compiler and his clj-android library, yes

5:54 raek: _exterm: http://dev.clojure.org/display/design/Android+Support

5:55 Fossi: nifty

5:55 ups the prio/visibility

5:57 _exterm: nice

5:57 btw: Some forms fail to compile due to excessive stack use, e.g.

5:57 (for [x (range 5) y (range 5)] [x y])

5:57 quote from your link, raek

5:57 I have implemented a workaround for that, but I believe Remco also did that

6:06 thorwil: trying to improve my understanding of enlive, what's the minimal case for using Enlive's content fn? ((en/content {:tag :p, :attrs nil, :content '("TOM")}) "JERRY") doesn't work

6:44 fliebel: thorwil: What is the error?

6:44 thorwil: fliebel: java.lang.String cannot be cast to clojure.lang.Associative

6:45 SLLCLL: finally made a fast primes sieve

6:45 http://pastebin.com/9F6vfEA2

6:45 fliebel: thorwil: That'd be the jerry. I think that should be a map as well. Or… I don't know actually.

6:46 SLLCLL: Didn;t dnolen do a fast on already?

6:46 thorwil: fliebel: also surprising to me is that the value for :content can't be just ("stuff"), despite that being the way those maps are represented

6:47 SLLCLL: no idea

6:47 fliebel: http://dosync.posterous.com/lispers-know-the-value-of-everything-and-the

6:47 SLLCLL: I'm still happy because this one works around 600000 times faster than my last one

6:47 for x = 1e6

6:48 thorwil: fliebel: ah, this works: ((en/content {:tag :p, :attrs nil, :content '("TOM")}) {"JERRY"})

6:48 but now i feel like understanding even less about it

6:49 * fliebel would laugh if there had been a confusion between 1e6 primes and all primes below 1e6

6:49 fliebel: &{"JERRY"}

6:49 sexpbot: java.lang.ArrayIndexOutOfBoundsException: 1

6:50 * fliebel hates macros

6:50 fliebel: How could that possibly work, without magic?

6:50 thorwil: actually, it works only in so far as it does not throw an error

6:50 content isn't replaced

6:51 fliebel: https://github.com/cgrand/enlive/blob/master/src/net/cgrand/enlive_html.clj#L598

6:51 clgv: fliebel: the force might be strong with him. ;)

6:52 fliebel: clgv: We will not train him then, he is to young.

6:52 clgv: :D

6:52 fliebel: clgv: Where you referring to cgrand or thorwil?

6:52 thorwil: yes, i know how that source looks. i successfully modeled another transformation on it, but i'm failing at constructing yet another

6:53 clgv: fliebel: thorwil ;)

6:53 fliebel: flatten-nodes-coll is dense...

6:55 thorwil: yeah, i don't get through that one at all

6:56 fliebel: I see many macros in there. macros lead to doubt, doubt leads to anger, anger leads to hatred, hatred leads to the dark side of the force. s/everything/correct wording/

6:57 thorwil: At least I think it takes a node, not text. html-content is what you want, I think.

6:58 thorwil: fliebel: if used in a defsnippet as intended, en/content does take plain text

6:59 fliebel: thorwil: Have you tried putting it off and on again? Uh, I meant, macroexpand, to see what happens.

6:59 thorwil: with my new transformation, i get errors regarding number of args, so i figured there's something about the mechanism that i should better get to know

7:00 fliebel: thorwil: readme says it's (content “xyz” a-node “abc”)

7:00 raek: thorwil: what does ((en/content "JERRY") {:tag :p, :attrs nil, :content ["TOM"]}) return?

7:02 I think the call to content returns a transformation function, which is the one that takes a node and returns some nodes

7:02 thorwil: {:tag :p, :attrs nil, :content ("JERRY")}

7:04 raek: i thought these transformations are functions that take nodes via & values in their signature, to deliver an anon fn that takes whatever args needed

7:05 raek: to compose transformers, I think you should be able to use ordinary function composition: ((comp (content "Jerry") (add-class "character-name")) {:tag :p, :attrs nil, :content ["Tom"]})

7:05 Fossi: raek, anybody: what's the main way of communication for something like android support? the ml?

7:06 raek: I think (content “xyz” a-node “abc”) means "construct a transformer that takes a node and returns the node, but with ("zyz" a-node "abc") as its content"

7:07 "Transformations (the right-hand parts of rules) are now plain old closures.

7:07 These functions take one arg (the selected node) and return nil, another node

7:07 or a collection of nodes."

7:11 oh, scratch the comp thing. looks like do-> is the proper way

7:15 thorwil: i've been using do->

7:16 raek: (comp would only work if each transformation returns exactly one node)

7:16 thorwil: my entire problem is how arguments are taken via function signature and then by the inner anon fn

7:17 i got it backwards

7:26 ah, finally, a transformation that applies a fn the the content: (defn tryout [to] #(update-in % [:content] (fn [c] (apply (partial replace-str "token" to) c))))

7:26 you guys are awesome :)

7:54 mat1: Is there a way to call a function given the first part of the function is variable and the second part is constant. for example (${MYTYPE}Reader [somevar])

7:56 clgv: mat1: you can create a symbol from a string and resolve it

7:57 mat1: sounds exactly like what I want.. using the gensym function?

8:00 Chousuke: mat1: like (resolve (symbol "+"))

8:00 gensym creates unique symbols

8:02 mat1: awesome that works

8:03 thanks

8:06 fliebel: Does anyone know where I can get the latest apache commons from maven? Latest is 2.0.1, but central only seems to have 1.3.whatever.

8:06 http://mvnrepository.com/artifact/org.apache.commons/commons-io

8:06 http://commons.apache.org/io/

8:08 cemerick: fliebel: org.apache.commons is a deprecated groupId, IIRC

8:08 fliebel: http://search.maven.org/#search|gav|1|g%3A%22commons-io%22%20AND%20a%3A%22commons-io%22

8:09 fliebel: cemerick: Thanks! So even java land is leaving the reverse domain thing?

8:10 cemerick: fliebel: I don't know the details. The "reverse domain thing" isn't demanded; junit has had a groupId of 'junit' forever.

8:11 That said, I'd prefer the reverse domain idiom here; just how many "commons-io" libraries might various orgs produce?

8:11 fliebel: That is what the paranoid part of me was about to say.

8:24 cemerick: how is it that Clojure source apparently looks great in IntelliJ, but absolute shite everywhere else?

8:30 dnolen: cemerick: that's what rhickey used, right?

8:31 cemerick: dnolen: yeah, and according to fogus, it does look decent there.

8:31 fliebel: cemerick: What is wrong with the source?

8:31 dnolen: I personally don't really understand the complaints about Clojure's Java source. It's quite readable to me.

8:32 cemerick: Indentation is jacked up all over the place.

8:33 Not in an unusual way -- in an irregular, totally inconsistent-from-method-to-method way.

8:33 anyway

8:33 dnolen: cemerick: hardly important considering how clean the code is written. the most beautifully formatted crap is still crap.

8:34 parts of Django's source case in point (sorry to rag)

8:34 fliebel: dnolen: Sure? Explain this then ##(source when-let)

8:34 sexpbot: java.lang.Exception: Unable to resolve symbol: source in this context

8:34 cemerick: dnolen: some of the more deeply-nested blocks that suddenly swing to the left require very careful reading, at least for me.

8:35 fliebel: I'm talking about the Java source, not the .clj Clojure source.

8:35 fliebel: sexpbot, where is your source?

8:35 ah...

8:39 &(use 'clojure.repl)

8:39 sexpbot: ⟹ nil

8:40 fliebel: There we go! ##(source when-let)

8:40 sexpbot: ⟹ Source not found nil

8:40 * fliebel gives up

8:41 cemerick: fliebel: source reads from the classpath, which the sandboxes probably don't allow.

8:41 fliebel: probably… :(

8:42 $source when-let

8:42 sexpbot: when-let is http://is.gd/bqDRKj

8:42 fliebel: (inc amalloy-or-raynes-or-whoever-did-that)

8:42 sexpbot: ⟹ 1

8:52 gfrlog: do watchers of atoms have to be side-effect-free?

8:53 cemerick: certainly not

8:53 gfrlog: well that is quite convenient

8:53 I am going to use a watcher!

8:53 cemerick: write-behind logs are handy :-)

8:53 gfrlog: I'm always writing side-effecty-swap functions and then kicking myself later

8:57 shanmu: hello, all! is there a replacement for duck-streams module in clojure-contrib 1.3?

9:07 technomancy: shanmu: clojure.java.io

9:14 shanmu: technomancy: thanks!

9:17 gfrlog: I'm having a surprising amount of trouble managing a mutually exclusive resource

9:18 actually the mutual exclusivity is not the issue

9:18 let's pretend it's a database connection

9:18 and multiple threads can access it at the same time

9:19 but I only want one of them to be open ever

9:19 so I use an atom to keep track of how many threads are using the thing

9:19 when the first registers, I create one, and when the last unregisters, I close it

9:20 and I believe my error is caused by trying to open one before the previous one was closed

9:20 fliebel: gfrlog: Maybe a CyclicBarrier, ReadWriteLock, or something else in the java.util.concurrent package.

9:20 gfrlog: hmm

9:20 since "closing" is a side effect, I moved that out of the swap function and into a watcher

9:21 but now that it's in the watcher, there's no guarantee somebody else isn't opening a new one at the same time

9:21 I don't think the cyclicbarrier is appropriate

9:22 fliebel: No, I'm looking for another one… hmmm

9:22 gfrlog: I was going to cook up something complex involving promises, but there's gotta be a better way...

9:24 I could use an agent that handles all the swapping + side effects, and any function that wants to do something sends it to agent and waits on a promise :-|

9:24 which just sounds inappropriate

9:26 jedi: i'm trying to get slime working with acquamacs and swank-clojure as per the instructions on https://github.com/technomancy/swank-clojure, but M-x slime-connect results in this error: "Symbol's function definition is void: define-slime-contrib"

9:27 is it fruitless doing this in aquamacs?

9:27 ejackson: jedi: not at all - it should work fine

9:29 jedi: ok i'll keep at it ejackson, thanks

9:29 fliebel: gfrlog: I'm not sure I really understand the problem.

9:29 ejackson: jedi: i followed the instructions for getting the emacs side working here: http://technomancy.us/126

9:29 using ELPA, and it works 100%

9:29 gfrlog: fliebel: there's a thread-safe resource that obeys the open+close interface, but it breaks if you open two at the same time

9:29 technomancy: aquamacs is untested

9:30 gfrlog: so I just want to make sure that when two threads use the resource simultaneously that they're using the same one and not trying to open different ones

9:30 technomancy: GNU Emacs is strongly recommended; I don't test on xemacs or any of the other forks.

9:30 fliebel: ah!

9:30 gfrlog: and I don't want to leave one open, I want it closed when everybody is done with it

9:30 ejackson: technomancy: OK, FWIW I use it all the time with no problems.

9:31 i'm happy to help you to test aquamacs if you like

9:34 technomancy: there's too many arbitrary changes in aquamacs for me to officially support it, but of course bug reports are welcome.

9:35 fliebel: gfrlog: I'm thinking…

9:35 gfrlog: :) strange that it's so hard what with clojure's emphasis on this sort of thing

9:36 fliebel: gfrlog: well, clojure makes it easy to work with persistent stuff. as I discovered with seque, and now again with your problem, clojure does not cover the mutable stuff any better than java.

9:37 gfrlog: does the agent + promise hack sound like it would work correctly?

9:37 actually I don't think you need promises, I think there's a method for waiting on the agent

9:37 ,(doc wait-for)

9:37 clojurebot: Pardon?

9:37 gfrlog: ,(doc wait)

9:37 clojurebot: Huh?

9:37 gfrlog: ,(doc what-function-am-I-thinking-of?)

9:37 clojurebot: Titim gan éirí ort.

9:38 technomancy: ,(doc await)

9:38 clojurebot: "([& agents]); Blocks the current thread (indefinitely!) until all actions dispatched thus far, from this thread or agent, to the agent(s) have occurred. Will block on failed agents. Will never return if a failed agent is restarted with :clear-actions true."

9:38 gfrlog: technomancy: thx :)

9:38 technomancy: np

9:38 gfrlog: okay, so instead of using swap!, I use send + await

9:39 which is effectively swap! + side-effects, if I'm not missing anything

9:39 fliebel: gfrlog: I think that as soon as you use agents and promises as a queue, you are better of using a real queue.

9:39 gfrlog: you say it's a queue because I want the functions to execute once and synchronously?

9:40 fliebel: gfrlog: agent is serial, so then you might as well just lock the whole file then.

9:40 gfrlog: fliebel: I wouldn't use the agent for the whole operation, just for opening and closing

9:40 fliebel: gfrlog: explain that please.

9:41 gfrlog: kay one sec

9:42 fliebel: https://gist.github.com/964497

9:44 I'm starting to like that solution more, because then I get the added benefit that do-stuff can return before the resource is closed

9:46 fliebel: gfrlog: okay… I wonder what magic goes inside *-resource-user, because that will have to decide whether the resource is already open/closed and if others are using it or not. So do you want to maintain a counter and the state of the resource inside the agent?

9:46 gfrlog: exactly

9:46 the agent keeps a counter

9:46 when it drops to 0, it closes the resource

9:47 if it's at zero when register is called, it opens the resource, else just increments the counter

9:48 fliebel: okay, that might work. What I had in mind uses AtomicInteger to do about the same thing, but without the agent.

9:49 gfrlog: and like I said before, with the agent I get a quicker return

9:49 so maybe I'll go with that

9:50 fliebel: (locking at-int (when (zero? (.getAndIncrement at-int)) (open))))

9:51 don;t forget to use a try-finally block, or you might get the thing into a weird state.

9:51 gfrlog: yep :)

9:52 fliebel: thanks for the thinkings

9:52 fliebel: np :)

9:53 desertWalker: test

9:53 gfrlog: test passed

9:54 Ran 1 test containing 0 assertions.

9:54 0 failures, 0 errors.

9:54 fliebel: desertWalker: You failed for punctuation though.

9:54 gfrlog: what should he have punctuated?

9:55 fliebel: gfrlog: Because most sentences are supposed to start with a capital and end with a dot, but apparently these rules don't apply on IRC.

9:56 gfrlog: I guess you take it as a sentence because it could be an imperative?

9:58 jedi: using plain ol' gnu emacs seems to work a lot better than aquamacs

9:58 fliebel: … maybe? It wasn't an assertion at least :) Anyway, I'm glad he got his charset right. Or at least he did not pick one of those ancient ones that even have the first 255 all scrambled,

9:59 technomancy: I mean you could also try Chewy Ranch Emacs, but the Original Flavour is preferred by thousands of hackers.

9:59 jedi: yum

10:47 dnolen: Datalog used to detect race conditions in concurrent Java programs - http://code.google.com/edu/languages/index.html#_java_racedetect, yet not a single Functional, or Logic programming language in their list of PLs.

12:20 micahmartin: technomancy: Is the leiningen IRC channel dead?

12:22 dakrone: people still occasionally ask questions in it, if that's what you meant

12:22 micahmartin: yeah. It

12:23 It's just that I get leiningen questions answered more in this channel these days

12:25 dnolen: wow Google App Engine for Go, that's a big endorsement...

12:25 ejackson: lol !

12:26 technomancy: the #leiningen channel is more about developing lein than using it

12:27 just doesn't make sense to keep things in a separate channel when it's general usage questions I guess

12:27 dakrone: not everyone knows there's a separate channel for it either

12:30 fliebel: dnolen: Meh, why not OCaml :P

12:32 dnolen: one valid criticism of OCaml is that it really didn't get on the concurrency bandwagon until just recently.

12:34 micahmartin: technomancy: So I'm been thinking about the way leiningen is distributed and used by plugins... and I kept coming back the one question: Why doesn't leiningen live in a maven repo like all the other libraries?

12:35 technomancy: because it's not a library

12:35 it's an application

12:35 micahmartin: it's a library for plugins

12:36 technomancy: plugins are libraries

12:36 micahmartin: yes... libraries that depend on leiningen

12:37 Why don't you want leiningen to be a library. It'd make my life easier

12:38 in fact.. I might even say that my hair is about to catch on fire.

12:38 dakrone: what are you trying to do that you need lein as a library for?

12:39 technomancy: supporting a library is a very different thing from supporting an application

12:39 micahmartin: build a shell wrapper that uses leiningen functionality

12:39 technomancy: I'd rather not sign up to support more use cases if it can be avoided

12:40 micahmartin: But becoming a library is a natural path for a build tool.

12:40 Ant is a library, Rake is a library.

12:41 technomancy: gem isn't

12:42 micahmartin: ah... good point... So leiningen is both a build tool and library management tool

12:43 Can the build tool aspect be extract out into a library?

12:44 technomancy: maybe. seems like it's a whole lot easier to just call leiningen from the shell wrapper though.

12:45 micahmartin: okay... I can do that... but then I have to maintain the shell script which leiningen so nicely generated before.

12:45 dependencies, version numbers, they all get duplicated

12:46 no_mind: I have a function in a given namespace. I have the name of the namespace and function available as strings. How do I call the reuiqred function in the given namespace ?

12:47 amalloy: why do you have them available as strings? are you reading user input and then eval'ing it?

12:49 no_mind: amalloy: nope, its part of menu system. The path and corresponding namespace/function name is stored in db and I have to callback required function for given path

12:50 whidden__: no_mind: you might want to look at ns-resolve as a starting point

12:51 no_mind: whidden__: I have used ns-resolve but it wont callback the function

12:51 technomancy: micahmartin: shouldn't need to duplicate dep list in the shell wrapper; just include %s and the classpath will get inserted.

12:51 amalloy: no_mind: huh? it returns a var to you; you just (optionally) dereference the var, and call the result as a function

12:51 ,(doc ns-resolve)

12:51 clojurebot: "([ns sym]); Returns the var or Class to which a symbol will be resolved in the namespace, else nil. Note that if the symbol is fully qualified, the var/Class to which it resolves need not be present in the namespace."

12:52 amalloy: ,(@(ns-resolve 'inc) 1)

12:52 clojurebot: java.lang.IllegalArgumentException: Wrong number of args (1) passed to: core$ns-resolve

12:52 amalloy: ,(@(ns-resolve *ns* 'inc) 1)

12:52 clojurebot: 2

12:52 no_mind: well I tried this ((resolve (symbol (str ns "/" fn)))) but it is throwing nullpointerexception

12:53 amalloy: that / is wrong

12:53 &(namespace (symbol "foo/bar"))

12:53 sexpbot: ⟹ "foo"

12:54 amalloy: hm

12:54 ,((resolve (symbol "clojure.core/inc")) 1)

12:54 clojurebot: 2

12:54 amalloy: if that doesn't work for you, you're doing something else wrong

12:56 whidden__: no_mind: other things to look for is that fn is really defined in the ns. I always have spelling trouble in cases like this.

12:57 no_mind: the fn is defined cause I can call it directly...

12:59 amalloy: no_mind: post a gist of you calling it directly and failing to call it indirectly

13:01 whidden__: &(resolve (symbol "foo"))

13:01 sexpbot: java.lang.SecurityException: You tripped the alarm! resolve is bad!

13:03 whidden__: &(ns-resolve 'user (symbol "foo"))

13:03 sexpbot: java.lang.SecurityException: You tripped the alarm! ns-resolve is bad!

13:03 whidden__: ,(ns-resolve 'user (symbol "foo"))

13:03 clojurebot: nil

13:03 no_mind: switched to ns-resolve from resolve and now getting this error java.lang.String cannot be cast to clojure.lang.Symbol>

13:03 amalloy: whidden__: ns-resolve wants a namespace as a first arg, not a symbol

13:04 no_mind: you can keep making vague complaints or you can paste some actual output so someone can see why the "works for us" solution isn't working for you

13:06 whidden__: no_mind: if 'ns' is a string then you can make it a symbol by calling symbol.. and getting something like (ns-resolve (symbol ns) (symbol fn)), where ns and fn are strings with the appropriate names.

13:08 amalloy: whidden__: ns-resolve still wants a namespace as its first arg like i said a moment ago

13:08 ,(ns-resolve 'clojure.core 'inc)

13:08 clojurebot: #'clojure.core/inc

13:08 amalloy: dang. apparently i'm wrong again

13:08 clojurebot: thanks for keeping me honest

13:09 clojurebot: thanks for your suggestion, but as usual it is irrelevant

13:09 kzar: if Clojure is a bit to slow on Android does anyone know of a good Lisp that works well?

13:09 too*

13:10 whidden__: kzar: have you looked at ecl?

13:10 kzar: maybe someone is already porting sbcl over to android ;)

13:11 kzar: heh well I guess as long as it's not Java

13:12 technomancy: people have run sisc on it IIRC

13:13 whidden__: kzar: what's the arch of android? if its close to ppc, amd then sbcl might not be that hard to port.

13:13 dnolen: kzar: yeah until phones get more memory and a bit faster, Clojure won't have much luck. Fortunately that's probably summer 2012.

13:13 whidden__: kzar: for what its worth, I got ecl running on the gumstick eval board.

13:17 fliebel: Pattern matching is awesome :)

13:20 kzar: heh ok thanks everyone

13:23 dnolen: fliebel: heh, what makes you say that?

13:30 fliebel: dnolen: Reading about erlang :) I gues the same is true for OCaml and Prolog, pattern matching is everywhere!

13:34 dnolen: fliebel: totally. Erlang got it from Prolog, Erlang was originally written in Prolog and retaining the Prolog-y syntax.

13:34 s/retaining/retained

13:34 sexpbot: <dnolen> fliebel: totally. Erlang got it from Prolog, Erlang was originally written in Prolog and retained the Prolog-y syntax.

13:36 fliebel: dnolen: To bad they don;t do the real prolog stuff anymore :)

13:37 dnolen: fliebel: well ... Prolog had a reputation for being too slow for many common tasks. Mitigated now by things like CHR, but it's hard to shake an image.

14:20 no_mind: how can I load a namespace from a file ? I tried using (load "ns") but it looks for file relative to classpath. Can I load a namespace from a file using absolute path ?

14:23 dnolen: no_mind: did you try using an absolute path?

14:23 no_mind: yes

14:24 fliebel: no_mind: load-file?

14:26 gigamonkey: Is there consensus on what's the best Clojure book?

14:27 jlf`: gigamonkey: idk about consensus but the joy of clojure is quite good

14:27 * technomancy concurs

14:27 gigamonkey: jlf`: have you read others and prefer that one?

14:28 jlf`: i've also read programming clojure, yeah

14:28 technomancy: gigamonkey: depends on the audience

14:28 programming clojure is introductory

14:28 fliebel: joc contains more stuff I should know ;)

14:28 * hugod still refers to pcl :)

14:29 * gigamonkey smiles at hugod

14:29 dnolen: hugod: heh, those were the days.

14:30 cemerick: …when men were men, and sbcl seemed like the best possible option… :-)

14:35 gigamonkey: What do you folks who like JoC like about it?

14:38 technomancy: gigamonkey: the bibliography, for starters =)

14:41 gigamonkey: technomancy: hmmm.

14:44 dnolen: gigamonkey: I think people like the fact that JoC is a deeper dive, assumes you've already read something introductory or spent enough time w/ the lang.

15:04 cemerick: speaking of which, you should get that blurb about Clojure fixed on Amazon.

15:05 cemerick: dnolen: tell me about it :-|

15:05 (we didn't write it)

15:05 dnolen: ooph

15:05 Closure, and mentioned Ruby and Python even though JRuby and Jython exist.

15:06 cemerick: a far better description is on the O'Reilly catalog page at this point http://oreilly.com/catalog/0636920013754/

15:08 dnolen: cemerick: in anycase, it's exciting that O'Reilly is a doing a Clojure book. Never thought I'd see the day they'd put a Lisp book out.

15:08 cemerick: that is much nicer.

15:08 cemerick: dnolen: Barriers broken, indeed.

15:09 Now the question is, what's the latency between ORM and AMZN

15:12 gigamonkey: cemerick: who's your editor? Loukides?

15:12 technomancy: cemerick: are you coming to the meetup on thursday?

15:13 cemerick: gigamonkey: He got things through the pub board. Julie Steele is with us now.

15:13 technomancy: Vaguely possible.

15:14 hah

15:15 technomancy: though I'm strikingly bad at the hackfest format.

15:15 Looks like it's full anyway.

15:19 technomancy: cemerick: yeah, I'm not sure how the seajure recipe is going to translate to this setting

15:21 where did you see it's full?

15:21 cemerick: I'm a fish out of water in such models regardless of setting.

15:21 http://www.meetup.com/Boston-Clojure-Group/events/17395470/

15:21 technomancy: well I mean at our meetings we rarely have more than ten

15:21 cemerick: ah

15:21 Probably going to be 5-10 hacking at the problem, with the rest eating pizza and bs-ing.

15:22 technomancy: that'd work too =)

15:24 fliebel: How do you organize these hackathons over there? At the Amsterdam Clojurians we moslty go pizza, blabla, end.

15:26 technomancy: fliebel: well we only do a hack project every other meeting or so when someone has a nice juicy idea that's small enough

15:26 but I guess the coffee helps

15:27 fliebel: technomancy: So it's just that someone brings up an idea that you can finish in one meetup, and you all work on that?

15:27 technomancy: fliebel: yeah, and there's a tmux session everyone joins over SSH

15:28 fliebel: technomancy: You mean you work with 10 people in one session?

15:28 technomancy: "swarm coding", like pair programming

15:28 yeah

15:28 chouser: technomancy: how many people per session?

15:28 oh, wow.

15:28 technomancy: 7 or 8 on average

15:29 chouser: so, does that mean 1 person typing, one or two actively suggesting things, and 4 or 5 just watching?

15:30 cemerick: …or eating more pizza. :-)

15:30 jweiss: if i do (def x [1 2 3]) (defmacro blah [nums] `(apply + ~nums)) - can i get it to actually insert the vector [1 2 3] at compile time, not just a symbol pointing to a var containing it?

15:30 fliebel: I was at a Python hackathon recently, and there everyone just tell about their plans, and then start doing it. Which led to small groups clusters around laptops.

15:31 * fliebel lost his grammar, have you seen it?

15:31 technomancy: chouser: usually there are only 3 or 4 people actively involved, yeah

15:32 fliebel: yeah, I don't know if it scales

15:32 chouser: seems like it could scale sideways. 30 people show up and split into 6 totally unrelated projects

15:33 fliebel: technomancy: What is the level of Clojure expertise there? Amsterdam has a lot of starters I think. I'm trying to get them to do some more hacking :)

15:33 technomancy: yeah, we will probably split the group for this boston one

15:33 hiredman: then it becomes a graph labeling problem

15:33 technomancy: fliebel: it's about half newbies maybe

15:35 fliebel: Okay, well, I'll see what happens tomorrow.

15:39 jweiss: if i want to pass a symbol to my macro and have my macro have access to the data stored in that var (at compile time), should i use eval?

15:41 raek: jweiss: one approach is to not send it as a parameter. you can still access its value in the body of the macro

15:41 fliebel: jweiss: Should you do that at all? Well, maybe.

15:41 raek: jweiss: another one is to use resolve to get the var, and then deref to get its current value

15:42 jweiss: raek: i'm generating java classes and methods here, so i think it's necessary

15:42 yeah that was the other technique - resolve and var-get

15:42 but then i can't use a literal

15:42 so maybe eval is what i want here

15:44 timvisher: hey all

15:44 i'm having trouble getting a command line program i'm working on working

15:44 http://pastie.org/1886262

15:44 raek: (def x {'foo '+}) (defmacro bar [] (cons 'do (for [[name f] x] `(defn ~name [& args#] (apply ~f args#))))

15:44 jweiss: ^

15:45 then x can be any value

15:45 timvisher: i call that from the command line after `lein install`ing with `:shell-wrapper true` in the project.clj

15:45 like so: `wallpaper-manager-cli wallpaper-seq`

15:45 and it complains that it can't resolve the symbol `wallpaper-seq` in this context

15:46 jweiss: raek: ok thanks

15:46 timvisher: whereas if i comment out the doseq line

15:46 the manual call to `(wallpaper-seq)` runs exactly as i expect

15:46 whatcha think?

15:49 raek: timvisher: where is wallpaper-seq defined?

15:50 timvisher: in wallpaper-manager-core.core

15:51 technomancy: timvisher: if you can, I'd avoid eval

15:52 timvisher: technomancy: would you simply map string inputs to their corresponding function calls?

15:52 technomancy: what you're doing looks a bit like the command loop in mire; maybe you could try a similar approach? https://github.com/technomancy/mire/blob/master/src/mire/commands.clj

15:52 timvisher: that's actually not a bad idea

15:52 technomancy: yeah

15:52 timvisher: I think I like that better than what i was planning on doing anyway

15:52 but what's confusing in this situation is that i wrote an incredibly similar app, with a core and then a cli

15:53 and the exact same construct works in that context

15:53 except that I call (load-file ...) before evaling

15:53 I guess that load-file probably puts the relevant functions into the current namespace

15:53 but then why would the direct (wallpaper-seq) call work?

15:54 wallpaper-seq is clearly in the namespace, although i've proven clearly in the path that haven't the foggiest understanding of what namespaces really are

15:54 technomancy: yeah, that is bizarre

15:56 gfrlog: so I guess it's not always the case that (-> ob pr-str read-string (= ob))?

15:56 dnolen: interesting, SymbolicWeb lives! https://github.com/lnostdal/SymbolicWeb

15:57 chouser: gfrlog: no not always. objects for which that holds are sometimes called "printable"

15:57 gfrlog: chouser: so keywords aren't printable?

15:57 chouser: gfrlog: it is possible to create keywords that aren't printable

15:57 lnostdal: dnolen, i think it's migrating to Clojure actually

15:58 gfrlog: I like ruby's syntax

15:58 dnolen: lnostdal: hullo. SymbolicWeb and Webblocks are what got me excited about Lisp in the first place.

15:58 chouser: ,(keyword "foo bar")

15:58 clojurebot: :foo bar

15:58 chouser: gfrlog: that's an "unprintable" keyword, for example

15:59 gfrlog: ruby would print it as :"foo bar"

15:59 cemerick: gfrlog: there are lots of objects that are not printable, including "manually created" keywords as well as most Java objects.

15:59 gfrlog: which as far as I can tell would be an unambiguous addition to the syntax

15:59 chouser: and an open issue, which I think is most likely to be resolved by some new reader syntax for awkward keywords and symbols

15:59 gfrlog: yeah, that strikes me as not at all bad

16:00 gfrlog: chouser: probably not anything that elegant for symbols though

16:00 chouser: |this has been| suggested

16:00 gfrlog: I stand corrected

16:00 lnostdal: dnolen, yeah, the dsl thing is just too awesome to miss out on i think .... :)

16:00 cemerick: chouser: Quotes leading to keywords is odd. |funny symbol| and :|funny keyword| is better IMO.

16:00 chouser: cemerick: yeah, that has a nice symmetry

16:01 cemerick: I can't imagine that's going to happen before the reader is clojure-ified though.

16:01 * chouser shrugs

16:01 gfrlog: cemerick: okay, so a symbol that starts with a colon is |\:colon-symbol|?

16:02 cemerick: I wouldn't think so. Why escape the colon there?

16:03 only constituent pipes would need to be quoted

16:03 dnolen: lnostdal: it's cool to see an experienced CLer hacking on some Clojure :D

16:05 gfrlog: cemerick: because |:colon symbol| looks like (keyword "colon symbol")

16:07 jweiss: grr. the difference between a symbol for a class, and a class, is *painful*. they both look exactly the same.

16:07 gfrlog: ,(class 'Double)

16:07 clojurebot: clojure.lang.Symbol

16:07 gfrlog: jweiss: you mean how they're printed?

16:08 cemerick: gfrlog: no reason to make more work. In any case,

16:08 jweiss: gfrlog: no, now they're interpreted

16:08 how can my macro spit out this: ^{org.testng.annotations.Test {:groups ["blockedByBug-703528"], :description "Test that invalid URL is rejected."}, org.testng.annotations.Test {:groups ["providers" "validate"]}}

16:08 chouser: jweiss: yeah, it can be confusing. especially in literal metadata

16:08 cemerick: |sym| and :|kw| more accurately conveys the relationship between the two

16:08 jweiss: and then fail to evaluate it due to duplicate keys

16:09 gfrlog: cemerick: what's the difference between (symbol ":foo bar") and (keyword "foo bar") then?

16:09 cemerick: if nothing, then the syntax is ambiguous or incomplete

16:09 jweiss: chouser: yeah literal metadata is what i'm working with here

16:09 cemerick: gfrlog: The first returns a symbol that starts with a colon. The second returns a keyword.

16:10 gfrlog: I mean what's the difference in the piping syntax?

16:10 dnolen: ,{0 1 0 1}

16:10 clojurebot: Duplicate key: 0

16:10 dnolen: jweiss: do you expect to not get a duplicate key error?

16:10 ,{'a 'b 'a 'b}

16:10 clojurebot: Duplicate key: (quote a)

16:10 jweiss: dnolen: the value above was the result of deep-merge-with.

16:10 cemerick: gfrlog: well, there is no piping syntax, this is all hot air :-)

16:10 dnolen: ,{String 0 String 1}

16:10 clojurebot: Duplicate key: String

16:10 gfrlog: cemerick: I know, but if there was then you would want |\:colon symbol|

16:11 jweiss: dnolen: so clearly that deep-merge-with fn didn't think they were the same key

16:11 gfrlog: else you couldn't express symbols that begin with colons because they would be interpreted as keywords

16:11 jweiss: or they would have been merged.

16:11 (which is what i wanted!)

16:11 cemerick: gfrlog: so then pipes would evaluate to symbols *or* keywords, depending on the first constituent character? Bleh.

16:11 chouser: jweiss: how are you generating that map? and are your printing and then re-reading, or is the map passed directly to eval?

16:11 gfrlog: cemerick: I thought that's what you suggested.

16:11 * gfrlog scrolls up

16:11 chouser: gfrlog: |:foo bar| vs. :|foo bar|

16:11 dnolen: ,(merge {String 0} {String 1})

16:11 cemerick: No; |funny symbol| vs. :|funny keyword|

16:11 clojurebot: {java.lang.String 1}

16:12 gfrlog: I'm getting smileys

16:12 so I guessed at what it meant

16:12 jweiss: chouser: i'm merging 2 maps - 1 is a literal passed to my macro, (not evaled), the other is metdata from a literal that is eval'd

16:12 chouser: ,{String 0, `String 1, 'String 2}

16:12 clojurebot: {java.lang.String 0, java.lang.String 1, String 2}

16:12 cemerick: gfrlog: damn smileys! :-)

16:13 jweiss: yeah that ^^

16:13 if you eval it, you get duplicate key

16:13 chouser: jweiss: ah, I see. yep. because although a symbol and a class *are* different, both evaluate to the class

16:13 gfrlog: cemerick: chouser: http://imgur.com/rg7WG

16:14 so I still have no idea what the suggested syntax was :)

16:14 chouser: gfrlog: you might want to fix your IRC client

16:14 gfrlog: oh I bet it was colon and then pipe?

16:14 jweiss: chouser: ok, that's good to know, that will help me get them to match

16:14 chouser: gfrlog: yes. : then | for a keyword

16:14 dnolen: ,(eval (merge `{~String 0} `{String 1}))

16:14 clojurebot: DENIED

16:14 cemerick: gfrlog: yes; you need yourself a better irc client or something ;-)

16:14 gfrlog: chouser: okay thanks

16:14 dnolen: jweiss: (merge `{~String 0} `{String 1}), works, eval'ing fails.

16:15 gfrlog: smileys disabled

16:15 not sure why I thought uploading a screenshot would be easier than that

16:15 cemerick: I have a little key macro that toggles them off when necessary

16:16 chouser: jweiss: If you know the user is passing a symbol that represents a class, I'd recommend using 'resolve' to fetch the appropriate class (or generate an error) at macroexpand time

16:17 jweiss: chouser: yeah, i had been trying to preserve the symbol, but looks like i'll go the other way :)

16:17 chouser: well, you could create a symbol from the class, but then you have String vs. java.lang.String to worry about

16:19 jweiss: chouser: yup, had that problem and had been fully qualifying, which i had wanted to fix, and this is apparently going to fix it :)

16:19 chouser: hm, I wonder if dealing with class objects can run afoul of classloader issues. bleh. anyway, that's not a problem I've actually experienced

16:20 ...and I've done a rather unfortunate amount of class-wrangling in macros

16:20 jweiss: chouser: i haven't noticed any problem either

16:22 markoman: i forgot how to see, if some item exists on a list? (:x [:x :y :z])

16:22 gfrlog: ,(some #{:x} [:x :y :z])

16:22 clojurebot: :x

16:25 markoman: thx

16:25 gfrlog: np

16:25 yes, it oughta be nicer than that

16:26 chouser: (.contains [:x :y :z] :x)

16:26 ,(.contains [:x :y :z] :x)

16:26 clojurebot: true

16:26 chouser: ,(#{:x :y :z} :x)

16:26 clojurebot: :x

16:26 gfrlog: chouser: is java interop the official recommendation there?

16:27 chouser: no

16:27 :-)

16:27 gfrlog: ,(some #{false} [false nil ""])

16:27 clojurebot: nil

16:27 gfrlog: ,(.contains [false nil ""] false)

16:27 clojurebot: true

16:28 chouser: Most of the time I find it worth while to keep such things in a set instead of in a vector or list

16:28 gfrlog: I guess the (some) route doesn't even solve the problem in edge cases

16:28 chouser: and when not, 'some' seems to do the trick nicely

16:28 gfrlog: ,(#{false nil ""} false)

16:28 clojurebot: false

16:28 gfrlog: chouser: you have to admit that for a language that has mapcat in the core, it's a glaring empty spot

16:29 chouser: ,(#{nil ""} false :not-found}

16:29 clojurebot: Unmatched delimiter: }

16:29 chouser: d'oh

16:29 ,(#{nil ""} false :not-found)

16:29 clojurebot: java.lang.IllegalArgumentException: Wrong number of args (2) passed to: PersistentHashSet

16:29 chouser: oh!

16:29 gfrlog: (and that's only the obscurest function I could think of without thinking about it)

16:29 chouser: ,(get #{nil ""} false :not-found)

16:29 clojurebot: :not-found

16:29 chouser: huh

16:30 ,8)

16:30 clojurebot: 8

16:30 gfrlog: wth

16:30 chouser: sorry

16:30 paste fail

16:30 gfrlog: I guess it parses the first object and stops

16:30 chouser: that's just the bot

16:30 gfrlog: ,(readstring ",8)")

16:30 clojurebot: java.lang.Exception: Unable to resolve symbol: readstring in this context

16:30 chouser: ,({1 2} 3 :not-found)

16:30 clojurebot: :not-found

16:30 gfrlog: ,(read-string ",8)")

16:30 clojurebot: 8

16:30 chouser: that's what I meant. Map as a function takes a :not-found arg, but set as a fn does not.

16:31 I hadn't realized that.

16:31 gfrlog: even the not-found option is insufficient if your domain is all objects

16:32 chouser: (let [not-found (Object.)] (identical? not-found (get my-set my-key not-found)))

16:32 but yes, this certainly gets tedious

16:33 gfrlog: do you think contains? wins the most-missing-from-core contest?

16:34 dnolen: chouser: why don't you use a namespaced keyword there?

16:35 gfrlog: ,:clojure.core/kw

16:35 clojurebot: :clojure.core/kw

16:37 jweiss: chouser: i think resolving all symbols and replacing those that resolve to classes with the class has fixed it.

16:37 lnostdal: does clojure have weak references/pointers and weak hash-tables?

16:37 chouser: dnolen: that's theoretically still gameable, but (Object.) and identical should be impossible to thwart

16:38 lnostdal: Java does, and they are useful in Clojure.

16:39 dnolen: gfrlog: one benefits I'm really beginning to appreciate about Clojure's design is that easy to reason about the computational cost of a piece of Clojure code. contains? as people want it would break that reasoning model.

16:40 gfrlog: dnolen: by that reasoning nth should also not exist

16:40 technomancy: dnolen: that doesn't mean the current name is well-chosen

16:40 dnolen: chouser: heh, tho no more/less gameable than people some how messing around with interned symbols while your macro is expanding right?

16:40 technomancy: the only reason contains? exists as in its current form is to trick newbies into thinking about O(n)

16:41 gfrlog: ,(doc contains?)

16:41 clojurebot: "([coll key]); Returns true if key is present in the given collection, otherwise returns false. Note that for numerically indexed collections like vectors and Java arrays, this tests if the numeric key is within the range of indexes. 'contains?' operates constant or logarithmic time; it will not perform a linear search for a value. See also 'some'."

16:41 gfrlog: I forgot that existed.

16:41 dnolen: technomancy: you're basically agreeing w/ what I said.

16:42 gfrlog: ,(doc has-key?)

16:42 clojurebot: Huh?

16:42 gfrlog: ,(doc key?)

16:42 clojurebot: Cool story bro.

16:42 gfrlog: either of those would be clearer

16:42 technomancy: dnolen: I'm not saying it shouldn't exist, it's just a crappy name

16:43 gfrlog: technomancy: I think he was saying there should not be a has? function

16:43 or equivalently that there should not be an appropriately named contains? function

16:46 dnolen: technomancy: I agree I could have lived w/ has-key?, but some is fine, it's clearly means search.

16:46 technomancy: "some" implies a plural result

16:47 "give me some of that" "ok, here's one" "wait, what?"

16:47 gfrlog: dnolen: and I think we wouldn't want the has? function to always search

16:47 if I happened to have a set I'd prefer it not to be treated like a seq

16:47 maybe that's going too far though

16:47 I can imagine people already yelling at me

16:48 dnolen: technomancy: some to me means - at least *one* such thing exists that satisfies a condition. but it's my bias.

16:48 gfrlog: dnolen: why not (any?)?

16:49 dnolen: gfrlog: why not (exists?)?

16:49 technomancy: gfrlog: as a predicate, any? is great

16:49 some isn't a predicate though

16:49 gfrlog: I know

16:49 but I've never used its output beyond its truthiness

16:50 and anyhow we may as well have both, if we're allowed sugary things like nnext

16:52 technomancy: yeah, you have to wonder how common non-predicate some usage is. I'd guess rare.

16:53 gfrlog: let's start a lib called c.c.mantle for all things that are inexplicably not in core

16:53 dnolen: gfrlog: i fell like that nnext et al is there to make the code bearable up to the point that destructuring appears.

16:54 technomancy: either that or to silence the people complaining about the loss of car/cdr

16:54 gfrlog: dnolen: okay, but I'm sure I could find some other strange functions in core

16:56 dnolen: gfrlog: it would be entertaining to make a list of the most useless core fns.

16:57 gfrlog: yeah. It'd be highly relative though. My 3 minutes of thought say that it'd be worth swapping out mapcat for any?, if we have to remove something

16:58 dnolen: gfrlog: no way, mapcat is great.

16:58 gfrlog: :-| I didn't say it wasn't great

16:58 half the stuff in clojure.string and clojure.sets is great too

17:06 ,(prn [[] '() #{} {} "" (keyword "") (symbol "") #""]

17:06 clojurebot: EOF while reading

17:06 gfrlog: ,(prn [[] '() #{} {} "" (keyword "") (symbol "") #""])

17:06 clojurebot: [[] () #{} {} "" : #""]

17:12 dnolen: well Clojure isn't the only one that struggle with names, Haskell chose Monoid over Appendable.

17:13 hugod: technomancy: so what do you use to get the first element that matches a predicate?

17:14 technomancy: hugod: I destructure a filter call. but that's not even what some does.

17:15 hugod: (some #(and (some-pred? %) %) col)

17:16 technomancy: yeah, I find filter+first or filter+destructuring much clearer

17:58 so has anyone tried the lein search task yet?

17:58 spoiler alert: it's pretty rad.

18:00 dakrone: technomancy: hasn't been working for me

18:00 still get Could not locate clucy/core__init.class or clucy/core.clj on classpath after installing it with lein plugin install

18:01 technomancy: have you tried the one that's built-in now?

18:01 gfrlog: technomancy: my old version of lein doesn't have it. Why can't doesn't the future feature lein time-machine take care of this for me?

18:01 s/can't//

18:01 sexpbot: <gfrlog> technomancy: my old version of lein doesn't have it. Why doesn't the future feature lein time-machine take care of this for me?

18:02 technomancy: gfrlog: don't worry; it'll be implemented in a future version

18:02 gfrlog: oh good

18:02 dakrone: technomancy: I haven't run from git, so I don't have it

18:02 technomancy: dakrone: ok, that should solve it

18:25 dakrone: technomancy: works really well, thanks for this

18:29 technomancy: dakrone: great

18:29 I'm wondering if it should collapse all the different versions

18:30 probably not worth bothering with

18:30 need to add better pagination though

18:30 dakrone: pipe it into $PAGER ?

18:31 technomancy: hmm... I wonder if there's a way to make that play nice with laziness on the clojure side =)

18:32 as it is it takes a list of max results, so you can always just bump that way up

18:32 good enough, I guess

18:33 dakrone: not too bad to lazily fetch pages it's not too bad: https://gist.github.com/843310

18:34 excuse my poor grammar typo there

18:37 amalloy: technomancy: arriving late here, i guess, but "some" absolutely does not imply plurality

18:37 "let x be some even integer. then it is true that x is divisible by two"

18:39 gfrlog: amalloy: clearly that is an exception, because I define it to be one.

18:39 amalloy: I quite like that example actually

18:39 amalloy: gfrlog: that's where the name came from

18:40 what *I* think it implies is that (some even? (range)) should return 0, not true

18:40 gfrlog: okay, so you have some beef with it as well. just different beef.

18:40 amalloy: yeah

18:41 gfrlog: what should (some beef? [amalloy]) return?

18:42 there was another poorly name function that we discussed but now I can't remember what it was

18:42 oh contains?

18:43 do you have an explanation for that one?

18:45 pyr: hi

18:46 gfrlog: pyr: hi

18:46 pyr: dear lazyweb, is there a way to do 'mod' in clojure

18:46 numerator works on a ratio

18:46 but not on int's

18:47 so i could do the instance testing dance

18:47 but there might be a faster way

18:47 that i don't know of

18:47 gfrlog: $findfn 19 5 4

18:47 sexpbot: [clojure.core/rem clojure.core/mod clojure.core/unchecked-remainder]

18:47 gfrlog: ,(rem 19 5)

18:47 clojurebot: 4

18:47 pyr: :/

18:47 gfrlog: not what you meant?

18:47 pyr: ok, thank

18:47 s

18:47 yes, should've looked better

18:47 sorry

18:47 gfrlog: no prob

21:58 zrilak: If I want to perform several update-in or assoc-in modifications of a map, should I just do (let [s1 (update-in s ...) s2 (assoc-in s1 ...) ...], or is there a "more Clojure" way?

21:59 brehaut: (-> s (update-in …) (associ-in …))

21:59 zrilak: ah, THAT's what threading is for! :)

21:59 thanks :)

22:00 facepalm

23:14 gfrlog: $findfn (constantly 5) 5

23:14 sexpbot: [clojure.core/trampoline]

23:24 symbole: Can swank-clojure work with SLIME from its original source, or does it depend on the version in the Marmalade repo?

23:24 amalloy: symbole: cvs trunk of slime is frequently broken or incompatible

23:26 symbole: Probably what's causing my problems.

Logging service provided by n01se.net