# #clojure log - Feb 10 2011

The Joy of Clojure
Main Clojure site
IRC
List of all logged dates

0:03 mec_: is there a good way to map subvec across a vector for windowing?

0:08 tomoj: mec__: what are you going to do with the windows?

0:08 I mean, do you really need vector windows?

0:09 vs something like ##(partition 3 1 [1 2 3 4 5 6]) ?

0:09 sexpbot: ⟹ ((1 2 3) (2 3 4) (3 4 5) (4 5 6))

0:12 mec__: thats what i want, but i figured subvec would be a lot faster if I specifically had a vector

0:15 tomoj: well..

0:17 probably depends on window size and what you do with the windows

0:17 for window size 3, it looks like partition is faster at generating the windows

0:18 while for window size 10, subvec seems faster

0:19 map is variadic, so you can (map #(subvec v %1 %2) x y) where x and y are seqs of the appropriate indices

0:20 mec__: oh didnt think of that at all, thanks

0:21 tomoj: oh, wow

0:22 (partition n 1 v) is O(n) for fixed v

0:23 mec__: how is that possible? it creates a seq that touches the whole thing

0:23 tomoj: I mean, ignoring that factor

0:24 mec__: its O(n) or O(count v)

0:24 tomoj: I think (partition w 1 v) is O(n*w) if v has n elements

0:24 mec__: ah

0:24 tomoj: 'n' was a bad choice for window size

0:24 subvec has a constant (or log32?) factor instead of w, I think, but for small w it's worse

0:25 constant according to subvec's docs

0:26 can you do better than O(n*w) on seqs in general for the step=1 case?

0:28 mec__: i wouldnt think so, but subvec is deffinitly constant

0:32 tomoj: well, you can generate a seq of the windows in O(n) with something like (->> s (iterate next) (take-while identity) (drop-last (dec w)) (map #(take w %))), but that might be cheating compared to (partition w 1 s)?

0:32 amalloy: tomoj: constant according to the source too. it just creates an object storing the parent vector and the indices, and does the appropriate translated nth lookups in the parent when you access a subvec element

0:35 tomoj: I've been thinking lately about doing something like that for permutations

0:36 sound feasible?

0:37 mec__: Hard to say if it would be any faster, wouldnt you need a map for the old to new indices?

0:37 tomoj: yeah, but looking up the new index is practically constant while creating a new vector from scratch is O(n), yes?

0:38 mec__: true but would creating the map be O(n) anyway?

0:38 tomoj: amalloy: thanks, I hadn't realized that's what subvec did, I'll look there for inspiration

0:38 well, I only have one permutation

0:38 and its inverse

0:38 and need to apply them many times to many vectors with thousands of elements

0:38 so I can have the maps already sitting around beforehand

0:41 ooh, even with more permutations (say, hundreds), I can memoize all the combinations to avoid multiplying the log32 vector access

0:54 oh, now I remember the problems I ran into.. it's really simple if you never change a permuted vector, not so simple if you do

0:55 maybe I can get away with only implementing the read-only stuff for a while..

1:04 no_mind: how do I produce html using compojure. When I call (html0 function, I get a compile time error

1:04 (html)

1:04 .(html)

1:10 puredanger: let's just hypothetically say that I have a deep aversion to every Java logger ever invented and that I want to do some logging from a Clojure app

1:10 technomancy: puredanger: it's simple, just use this logging abstraction framework

1:10 puredanger: is there a Clojure lib that does very basic logging? (not c.c.logging)

1:11 technomancy: you can plug in any logging implementation or even other logging abstraction frameworks!

1:11 puredanger: technomancy: <headdesk>

1:11 technomancy: (just ignore the fact that there are only two logging implementations in existence and at least three logging abstractions)

1:12 puredanger: technomancy: I see you share my love of Java logging f/ws

1:13 khaliG: anyone familiar with miglayout? i wish to use the do-layout function, but the compiler says java.lang.IllegalAccessError: do-layout does not exist

1:14 oh i see it's an internal function

1:34 tomoj: would a feature that allowed you to delegate all unimplemented methods in a deftype to one of its fields be evil? not suggesting this feature, just want it now but suspect that it's evil

1:39 amalloy: tomoj: that sounds exactly like extending a class: implementation inheritance

1:39 so i suspect the two are equally evil

1:41 tomoj: when you say it that way this sounds even more evil

1:50 no_mind: how can I install enlive using lein ? It gives me an error for dependency on org.apache.maven:super-pom:jar:2.0

1:52 rata_: can you search for something like *blah* in emacs history?

1:54 tomoj: no_mind: paste the entire output somewhere (not here)

1:55 amalloy: tomoj: it was not an accident :)

2:17 sritchie: hey all -- I've got a first draft of a function to walk a matrix with a window size and a step of 1, returning all window x window submatrices. would anyone be up for taking a look?

2:18 the output is correct, but i suspect there's a cleaner way of doing this

2:22 amalloy: sritchie: plus reduce and conj aren't lazy

2:22 raek: sritchie: check out the torus-window function: http://www.bestinclass.dk/index.clj/2009/10/brians-functional-brain.html

2:23 sritchie: this line: "Everytime we are applying rules to a cell we need to consider 9 cells in total: The target and his 8 neighbors." is exactly what I was going for

2:23 awesome, thanks, raek

2:24 amalloy: except it sounds like you don't actually want a torus

2:25 raek: then using a window function like this might work: (defn window [coll] (partition 3 1 coll))

2:26 the number of windows will then be (- (count coll) 2)

2:27 sritchie: this is for a nearest neighbor analysis, so I do need to walk in both dimensions, with the window

2:27 getting a lazy sequence of 2d vectors, ideally

2:27 raek: that'll let me walk along 1d, right?

2:28 raek: yes, but the 'step' function uses it twice to get 2d

2:29 hrm. also consider using 'for' instead of 'map' + anonymous function

2:29 IMHO the code tends to be easer to read then

2:30 sritchie: raek: okay, good advice

2:30 amalloy: raek: agreed, i was gonna put something together with for

2:31 sritchie: raek: for looks a lot clearer, that's great

2:32 is torus window lazy, here?

2:32 raek: yes

2:32 partition is lazy

2:33 rata_: sritchie: I haven't read the blog post yet, but this works for me: (mapcat (comp (partial apply map vector) (partial map (partial partition w 1))) (partition w 1 m))

2:34 sritchie: rata_: ah, so that gets rid of my reduce conj step

2:35 rata_: it does more than that I think

2:35 amalloy: brehaut: another one for the point-free brigade, it seems

2:36 sritchie: rat sorry, I meant mapcat got rid of that

2:36 rata_: it's completely lazy and it doesn't use count

2:36 yes

2:37 raek: the map vector step can't be lazy

2:37 rata_: amalloy: what's the point-free brigade? those that don't like/use java interop?

2:38 raek: but map is lazy

2:38 amalloy: rata_: heh, no. point-free is a style that is popular with haskell programmers. (partial (comp foo bar) 10) rather than #(foo (bar 10 %&))

2:39 rata_: ah hahaha ok =)

2:39 amalloy: ie, "talking" about functions and gluing them together without mentioning their actual params

2:39 rata_: yes, I prefer that style... that % looks dirty

2:39 raek: you have something like (1 2 3 4) and turn it into [1 2 3 4]?

2:40 amalloy: i like point-free myself, and brehaut and Raynes are always teasing me that i should try haskell

2:40 rata_: raek: no, that's vec

2:40 for what I know about haskell, I like it... but I haven't done a project in haskell yet

2:41 amalloy: same

2:42 \$heval take 10 \$ let fib = 1 : 1 : zipWith (+) fib (tail fib) in fib

2:42 sexpbot: ⟹ [1,1,2,3,5,8,13,21,34,55]

2:42 amalloy: rata_: brehaut tells me this is how all the cool kids generate fibonacci numbers

2:42 rata_: amalloy: yes, that's pure beauty =)

2:43 I loved it the first time I saw it

2:43 amalloy: *chuckle* well, i'm off to bed. i'll try to dream of parens instead of \$ and .

2:44 rata_: hahahaha

2:44 good night amalloy

2:44 do you guys know what's the best way to do ajax with clojure?

2:45 best intended in a very subjective way of course

2:46 Scriptor: rata_: I prefer to just keep my server code strictly separated, jquery for the ajax calls, and maybe have a clojure handler return json

2:49 rata_: Scriptor: so make the website in html+javascript and maybe call some clojure fns?

2:49 Scriptor: er, the front-end is in html+js, the backend would still use clojure

2:50 so yes, just send an ajax request to a url and have that url be tied to whatever callback you want

2:51 rata_: have you any examples at which I could give a look?

2:51 Scriptor: not off the top of my head, and also not really with clojure

2:52 but you don't have to learn much, just how to send a request using javascript and how to return json in clojure

2:53 since otherwise a request is still just a request

2:54 rata_: yes... do you know where I can learn those things?

2:55 raek: in ring, you can just respond with {:status 200, :headers {"Content-Type" "application/json"} (clojure.contrib.json/json-str some-data)}

2:55 rata_: have you done server-side web programming in clojure?

2:56 rata_: no... I know a bit of html and that's all

2:56 Scriptor: rata_: how much programming experience do you have in general?

2:57 rata_: ~8 years

2:57 clojurebot: Pardon?

2:57 raek: ~test

2:57 clojurebot: lastest is 1135

2:57 Fossi: :D

2:58 rata_: I do "scientific" programming mainly (I don't know if that's a good name for what I do)

2:59 Scriptor: rata_: start off with some basic web apps using compojure or something like that, then start learning javascript and a little jquery

3:00 or whatever js framework you want

3:00 rata_: ok... do you use compojure?

3:00 Scriptor: not personally

3:00 rata_: what do you use?

3:00 Scriptor: don't really use clojure, really :p

3:00 raek: I usually use Ring + Moustache + Enlive

3:00 Fossi: yeah, any combination should do actually

3:00 rata_: Scriptor: ah ok =)

3:01 raek: Ring + Compojure + Hiccup is another very common combo

3:01 rata_: Scriptor: which language do you use?

3:01 raek: web programming in clojure is *very* modular

3:01 rata_: raek: what's moustache and enlive for?

3:01 Scriptor: rata_: mainly php and python, but I've been learning lisp on the side

3:01 rata_: ok

3:01 Scriptor: the principles of web dev are often the same

3:01 raek: moustache is for routing (mathcing URLs and HTTP methods), enlive is for html templating

3:02 actually, enlive can do html scraping too

3:02 rata_: raek: I thought ring was for routing

3:02 raek: it reads html from a file into a clojure datastructure, lets you transform it and turn it back into a html stream again

3:03 brehaut: rata_: ring is the HTTP to clj to HTTP translation layer

3:03 raek: ring is the standard for what a request and a response looks like

3:03 Fossi: it's so awesome that clojure has ring

3:03 raek: it comes with a web server that implements that contract

3:03 Fossi: java containers are a mess :>

3:07 rata_: so, if I get it right, you put the html+js part in using enlive?

3:08 raek: if the html never changes, you don't pass it through enlive

3:08 brehaut: raek: enlive is a much more strongly seperated `templating system` than is typical

3:08 you put your html and js into an html file

3:09 raek: (i.e. the web site uses ajax to transfer *all* data)

3:09 brehaut: and then you use ring to update that file for a particular resource

3:11 that was at rata_ sorry

3:12 rata_: mmm... then if I'm using ajax I'm not going to need enlive raek?

3:13 brehaut: rata_: ajax is a pretty vague term, but, as a term it usually refers to the client side program

3:13 you dont 'need' anything on the server to do ajax

3:14 rata_: you just have to write some route handlers that return data in a format your client side can handle (typically json these days, originally xml)

3:14 raek: rata_: that can be true.

3:14 depends on how you do it.

3:15 rata_: brehaut: but using ajax you can ask the server to compute something and then render it in the webpage without have to refresh it, right?

3:15 brehaut: rata_: correct

3:15 rata_: and route handlers are clojure fns?

3:16 brehaut: yeah; you use either moustache or compojure to map a url to a fn

3:16 that stage is route handling

3:17 rata_: ok, so the client request the result of a computation asking for a url?

3:17 and then renders it within the same page

3:17 brehaut: rata_: it doesnt as for the result of a computation; it asks for a resource - all urls map to resources in http.

3:17 dont think of it as an RPC system

3:18 theres two primary methods for accessing a resource: GET and POST (there is also PUT and DELETE, but for a variety of reasons they are not as common)

3:18 GET purely gets; its an idempotent action

3:18 POST is server specific

3:19 rata_: resources sounds like there something in the server already... I need to compute something based on what the client put in the forms

3:19 brehaut: rata_: they dont have to be

3:19 rata_: *there's

3:19 ok

3:19 so I do a GET or POST and get the result I need

3:19 brehaut: rata_: does the result of the calculation ever change?

3:20 rata_: no, but there are infinite possible inputs

3:20 brehaut: sorry, i wasnt clear.

3:20 rata_: (not sure if infinite, but huge anyway)

3:20 khaliG: the indenting behaviour of slime is really annoying

3:21 it keeps trying to push my fns all the way across the screen

3:21 brehaut: rata_: if you pass the same inputs to the fun, will it always produce the same result

3:21 rata_: yes

3:21 brehaut: then a GET on a resource with query parameters is completely fine

3:21 which is nice because its super easy

3:21 rata_: =)

3:23 it's not a problem that the query parameters are long strings?

3:23 brehaut: how long?

3:24 from memory you can safely assume 1024 characters for your url on any compliant HTTP server or proxy

3:24 rata_: it can be longer than that I think

3:25 brehaut: sad; safer to go with a post then

3:25 even though you'd proably never run into it in the real world

3:26 rata_: there's no size limitation with post then

3:26 brehaut: rata_: have you got a non-ajax version of the web app going ?

3:26 rata_: no... should I do that first?

3:26 brehaut: rata_: nope, post you send the arguments in the body of the request

3:26 yeah i would recommend it

3:27 ajax builds on all the basic ideas

3:27 as a tutorial

3:27 rata_: thanks =)

3:27 brehaut: heres the thing: the difference between an 'ajax' resource and a 'web page' resource is the content type it sends back

3:28 you can legitimately have a page say, /hello/name

3:28 that returns "<html><h1>Hello, name!</h1></html>"

3:29 for a web browser (or default)

3:29 and then returns "{"message":"Hello, name!"}" for 'ajax' requests

3:30 rata_: so it's easy to ajaxify a non-ajax webpage?

3:30 brehaut: yes

3:30 theres no reason your ajax version cant just consume the HTML version

3:30 rata_: ok, thanks a lot =)

3:31 brehaut: and then just find the appropriate nodes in the DOM

3:31 no problem

3:31 tomoj: wat

3:31 brehaut: tomoj: ?

3:32 tomoj: were you recommending generating html, then parsing that to generate json?

3:32 brehaut: tomoj: not recommending it per se

3:33 tomoj: ok

3:33 brehaut: i just didnt want rata_ to think that ajax was somehow magical or something special

3:33 Fossi: it's pretty easy and nice to have two output methods for your data though

3:35 rata_: so then I'll have to make my fns to return json instead of html?

3:35 brehaut: yeah you can switch on the accepts header, or theres a header that libs like jquery add to ajax 'X-Request-With: ajax" i think?

3:36 rata_ its really easy though; ring will provide you a request map which will have a key :headers which maps to a map

3:37 that map will likely have an :accepts header, and maybe :x-requested-with

3:38 rata_: but the main difference is you use enlive to return html, but not for json

3:39 Scriptor: rata_: right, json is pretty easy to generate, you can find json libs online

3:40 brehaut: c.c.json or clj-json will take standard clojure datastructures and generate json string for you

3:40 rata_: ok, thanks again

3:41 brehaut: rata_: mmcgrana has another tutorial of interest http://mmcgrana.github.com/2010/08/clojure-rest-api.html

3:41 shows you how to do json-responses

3:42 rata_: I'll read it too

3:42 tomoj: huh. I think if I switch to clj-json from clojure-json I'll have to rename generate-string and parse-string to encode and decode

3:43 brehaut: win :)

3:44 tomoj: eh, I only considered it because it says "fast", but clojure-json isn't even close to a bottleneck anyway

3:44 brehaut: i wonder if i should change necessary-evil to use the same terms as clj-json before anyone actually starts depending on it

3:45 parse and unparse are a bit clunky

3:46 tomoj: I like em better than those long things with their "-string"s sticking out

3:48 brehaut: i guess

3:48 not particularly nice either way

3:52 meltingwax: hi

3:52 brehaut: night

3:57 meltingwax: is closure compatible with common lisp libraries?

3:58 opqdonut: no, it's a different language on a different platform

4:00 meltingwax: what if i really needed it

4:01 ejackson: you can try prayer...

4:02 meltingwax: thank you, i will try that

4:03 opqdonut: :D

4:03 ejackson: meltingwax: some claim it to be a pattern.

4:04 opqdonut: 541052.14 meltingwax\$ thank you, i will try that

4:04 oops

4:14 rata_: good night

4:14 see you

5:16 fliebel: morning

5:23 no_mind: is there a working example of compojure and enlive ?

5:30 bobo: i think most examples with enlive are with moustache instead of compojure :-/

5:31 Dranik: bobo, are there any?

5:33 bobo: examples of enlive + compojure? i have never seen any. but shouldnt be any problem reading about enlive with moustache and then change to compojure

5:33 no_mind: I think I have found the title for my next book... "Clojure for humans"

5:34 bobo: they are not working with compojure...

5:34 btw suggestion for any other templating engine to be used with compojure ?

5:34 preferably something that can read files from hdd

5:35 bobo: no_mind: in what way are they not working? point me to some example you are reading and il see if i can compojurise it

5:35 no_mind: bobo: take any example

5:35 I am getting Null pointer exception

5:36 bobo: is your template working without compojure? if you just call it?

5:36 null pointers with enlive usualy mean you point to a non existing .html

5:37 no_mind: the .html is accesible from the route

5:38 bobo: yes, but does enlive find it? thats not the same thing

5:38 enlive looks from your src folder

5:38 no_mind: k

5:38 clojurebot: package.el is part of Emacs now: http://repo.or.cz/w/emacs.git/blob_plain/HEAD:/lisp/emacs-lisp/package.el

5:41 Dranik: bobo, how about mustache + enlive? are there any examples or tutorials?

5:42 the first is probably the better one, since i wrote the second :-p

5:43 raek: no_mind: it does not matter whether you use enlive with compojure or moustache.

5:43 Dranik: thanks

5:44 raek: I usually put my html templates in resources/ rather than src/, since they're not code

5:45 Dranik: bobo, the first is not available

5:47 bobo: Dranik: its not? im looking at it?

5:48 Dranik: wow!

5:48 This webpage is not available

5:48 that's what I've got

5:48 oh its working now

5:49 bobo: no_mind: https://gist.github.com/820290

5:49 index.html is in my src folder there, but as raek said they should be in resources in the end.

5:50 no_mind: k

5:51 bobo: raek: whats the best way to point the template to the resources folder?

5:51 just wrap-file ?

5:52 raek: deftemplate looks for files on the classpath and both src/ and resources/ are on it

5:52 bobo: ah

5:52 you learn every day!

5:59 raek: it would be nice if wrap-file could look for static files on a subdirectory of the classpath too...

6:56 cwb: startups

7:16 TobiasRaeder: morning

7:19 gfrlog: good morning

7:20 ,(let [good-+ (fn [& args] (apply + (shuffle args)))] (good+ 7 8 9))

7:20 clojurebot: java.lang.Exception: Unable to resolve symbol: good+ in this context

7:20 gfrlog: ,(let [good+ (fn [& args] (apply + (shuffle args)))] (good+ 7 8 9))

7:20 clojurebot: 24

7:22 TobiasRaeder: is there some kind of idiomatic wrapper for dates in clojure?

7:23 fliebel: TobiasRaeder: I encountered Yoda-time a few times. It's used in sexpbot for example.

7:23 TobiasRaeder: then ill check that out how its done there, thanks

7:24 fliebel: TobiasRaeder: Oh, sorry, it's clj-time, which uses Yoda

7:25 TobiasRaeder: @fliebel clj-time looks nice :)

7:26 bobo: think its called joda-time with a j

7:54 no_mind: using enlive, how can I create a list element <li> dynamically from database? Given the template has a placeholder <ul. eleement.

7:55 fliebel: no_mind: I think you define one placeholder li, and repeat-for on a snippet of that li..

7:57 bobo: no_mind: https://gist.github.com/820462

8:09 no_mind: bobo: did you create a placeholder for <li> under <ul> in the template ?

8:10 bobo: no_mind: eh yes i belive so

8:10 no_mind: thnxs

8:10 i stole it from my post about it

8:13 jkdufair: i'm looking for advice

8:13 i'm building a RESTful app on top of compojure

8:14 i need a way to represent data across this web app and also an iPhone app and an AJAXy web app

8:14 use JSON or some representation of s-expressions?

8:16 bobo: i would use json

8:17 jkdufair: bobo: are you aware of any clojure libs that serialize to JSON?

8:17 bobo: clojure.contrib/json

8:18 or something, there is one in contrib

8:18 json-str and read-sjon

8:18 jkdufair: super. thanks so much.

8:28 Cozey: is it possible to do something like (let [field 'staticField] (. SomeClass field)) ?

8:28 clgv: How can I make clojure inline a very often called function? I saw snippets somewhere - is there any documentation on that?

8:29 jkdufair: Cozey: I would think you'd need to write a macro for that

8:30 fliebel: clgv: Sounds interesting. What does inlining do? I know some functions use :inline in the meta, but I doubt it's the same thing.

8:30 clgv: fliebel: I think that's what I saw too. But I didn't find documentation on it

8:31 fliebel: clgv: I did, somewhere on the assemba space I think.

8:31 raek: Cozey: at runtime, you need reflection for that

8:31 clgv: I have function that is called around 4,000,000 times in 10 iterations. so it would be a good candidate ;)

8:32 Cozey: jkdufair: but when I make a macro and pass a variable to it, say: field, and then unquote it with ~foo, i still get (. Class field), and not the value of field

8:32 jkdufair: Cozey: oh boy. that's when i usually start drinking to truly understand macro expansion

8:33 Cozey: i know you're right

8:33 but i feel like i'm missing some 'deref' or something similar

8:33 raek: macros are just functions that transform code in form of data structures

8:34 raek: Cozey: . is a special form and cannot be "applied" at runtime. the compiler needs to know the name of the field when the code is complied

8:34 *compiled

8:34 jkdufair: yes and rockets are just tubes with propellants that go up in the sky :-)

8:35 fliebel: clgv: So, no direct documentation, but a few issues mentioning the feature.

8:35 Cozey: so is it possible to get a field by name known during runtime, without resolving to eval ?

8:35 raek: Cozey: use clojure.lang.Reflector/getInstanceField if you need to do it at runtime https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Reflector.java#L238

8:36 clgv: fliebel: guess I have to check clojure source to see where it is used

8:36 Cozey: raek: ok thanks, this seems to be what i needed!

8:37 clgv: fliebel: exactly the one I just clicked ;)

8:37 so well. it seems I have to repeat the definition in the inline statement

8:37 raek: Cozey: macros can be an alternative too (and would yield more performant code). it depends on how you are going to use it.

8:38 clgv: or define a macro for it ;)

8:38 fliebel: clgv: I think it's like definline for functions :)

8:39 Cozey: raek: yes but with macros i would need to know all the fields on compile time?

8:39 without using Reflector

8:39 raek: (defmacro field-accessor [field-name] `(fn [instance#] (. instance# ~field-name)))

8:40 Cozey: yes, but if the macro can figure out the field name at compile time (you have the whole clojure language at your disposal) then it would work

8:40 Cozey: agreed

8:42 clgv: fliebel: definline seems about right

8:42 AWizzArd: definline is the correct choice.

8:52 pdk: (doc definline)

8:52 clojurebot: "([name & decl]); Experimental - like defmacro, except defines a named function whose body is the expansion, calls to which may be expanded inline as if it were a macro. Cannot be used with variadic (&) args."

8:53 clgv: the syntax is a bit odd. seems you have to wrap the body into syntaxquotes

8:54 and use unquotes for the params everywhere

8:55 pdk: makes it just like macros already then!

8:56 clgv: I think it should be possible to do it without

8:58 fliebel: \$source definline

8:58 sexpbot: definline is http://is.gd/bNmEu0

8:58 fliebel: It actually adds the thing to the meta data.

8:59 clgv: This just works: (definline blah [foo] (println foo))

9:00 clgv: fliebel: my code with let-statement and more, does not ;)

9:00 fliebel: code?

9:00 clojurebot: peepcode is a commercial screencast series; see the Clojure one at http://peepcode.com/products/functional-programming-with-clojure by technomancy

9:01 clgv: I did wrap it into syntax quotes now.

9:03 I have to check both versions for a performance comparison now

9:04 chouser: definline essentially defines both a macro and a function with the same name

9:05 then Clojure chooses which to use at compile time based on how it's used.

9:06 fliebel: chouser: I guess that does not mean I can do macro tricks, and still use it as a function?

9:06 And, in which cases is the macro used?

9:07 clgv: chouser: yes, that's what I saw. The question is: do I really need to use syntaxquotes? It didnt compile with out them

9:07 chouser: you *can* do (some) macro tricks, but they may only do what you mean in the macro version

9:09 clgv: I don't need macro tricks - inlining is sufficient^^

9:09 fliebel: clgv: Can you paste an example of why you need syntax quotes?

9:10 Ah, I see...

9:11 clgv: clgv: no minimal that you can run since there are a lot of dependencies. just try to use a let and an if-statement with several comparisons and additions.

9:11 fliebel: clojure.lang.Symbol cannot be cast to java.lang.Number

9:12 chouser: the macro version is used when the var is named literally at the head of a list

9:12 so (foo ...) uses the macro, (map foo ...) and ((identity foo) ...) use the fn

9:12 clgv: hmm performance benchmark show no significant improvement. seems the function call is no overhead for this case

9:13 chouser: clgv: the HotSpot JVM will inline function calls at runtime

9:13 clgv: I had about 230000 calls

9:13 chouser: it seems to do a pretty good job here.

9:14 fliebel: chouser: So what is a good use case for definline?

9:14 chouser: the reason definline exists is to allow for unboxed primitives. Of course there's new support for those in 1.3a4

9:15 fliebel: So, definline is useless as of 1.3?

9:15 clojurebot: I don't understand.

9:15 chouser: I wouldn't be shocked if Rich removes :inline, but I would miss it. It's fun to exploit.

9:15 clgv: lol poor bot ;)

9:16 fliebel: chouser: Exploit? You mean makinf the fn do something unexpected when inlined?

9:16 chouser: yeah.

9:18 (definline add [a b] (if (and (number? a) (number? b)) (+ a b) `(+ ~a ~b)))

9:19 can you see what that does?

9:20 AWizzArd: This is evil!

9:20 clgv: good question. first case adds the numbers second case returns code that is an add statement

9:21 AWizzArd: First case is doing the addition at macro expansion time.

9:21 clgv: second-case is only used in macroexpansion time

9:21 chouser: everyone's right!

9:21 Chousuke: that's evil.

9:21 chouser: yes, evil.

9:21 AWizzArd: The second case calls a function + which is probably defined for a specific NS, where cores + is excluded.

9:21 chouser: well, useless at least

9:22 AWizzArd: nah, that's fine as clojure.core/+

9:22 Chousuke: but hm

9:23 how does it work when you call it as a function?

9:23 AWizzArd: Chousuke: second case.

9:23 chouser: definline uses the macro with symbol arguments it provides itself in order to create the function version

9:24 AWizzArd: It is just a hack for something that the compiler potentially could do: replace literals.

9:24 chouser: It is the compiler! :-D

9:24 clgv: on repl it seems to have a "good" behavior

9:24 fliebel: chouser: I can't get it to work wrong.

9:25 chouser: yeah, it may not be evil. Closer to useless.

9:25 fliebel: makeing one of them * would be evil :)

9:25 chouser: so (add 1 2) does the addition at macroexpand time, putting 3 literally in the resulting code

9:26 (let [a 1] (add a 2)) still calls the macro version, but sees that a isn't a number and puts (+ a 2) in the code

9:27 with (map add [1 2] [3 4]), the compiler sees it can't call add as a macro and uses the function version, which of course is essentially (fn add [a b] (+ a b))

9:28 AWizzArd: And Clojures + can not be optimized in such a way that (+ 1 2) is replaced by a literal 3.

9:29 chouser: I have used similar techniques to examine at compile time var values, do Java reflection, and generate substantially faster code, but fall back on perfectly acceptable runtime reflection when used as a function.

9:29 AWizzArd: why is that?

9:30 though I now think that's probably too much magic, despite how much fun it was. It's probably better to provide separate macro and function and let the user choose in such cases.

9:31 AWizzArd: Clojure can not know what + means until the program runs, because there is no defconstant.

9:31 (def + -)

9:31 (+ 10 2)

9:31 clojurebot: *suffusion of yellow*

9:31 AWizzArd: ,(let [+ -] (+ 10 2))

9:31 clojurebot: 8

9:31 AWizzArd: Dynamically typed.

9:32 chouser: the compiler can tell the difference there

9:32 and in fact does so.

9:32 AWizzArd: What about (in-ns 'clojure.core) (def + -) (in-ns 'my.ns)

9:33 Functions can be changed at runtime in Clojure.

9:33 This means that during compile time it is not known what a call will actually do.

9:33 chouser: Clojure assumes vars don't change from being macros to functions or vice-versa at runtime.

9:34 AWizzArd: Yes okay, macros will stay macros, fns will stay fns. However, the value of the var may change.

9:35 I can do a (defn foo [] 1) and then after this (defn foo [] 2)

9:35 I can eval things at runtime that changes the code. So during compile time we can not optimize such things away without using your definline trick, which is able to do it.

9:37 chouser: Clojure could inline such things if it also inlined a check to make sure the value of the var hasn't changed.

9:38 AWizzArd: (foo x) could mean anything at runtime.

9:38 Its meaning could change constantly.

9:38 chouser: no, foo must be either a var or a local

9:39 AWizzArd: Vars can be def'ed.

9:39 chouser: if it's a var, it's known at compile time to be a specific var in a specific namespace

9:39 AWizzArd: Yes, but it's value is not known.

9:40 chouser: usually it's value *is* known at compile time, and usually it won't change.

9:40 so Clojure could inline the current value, preceeding that inlined code with a check to make sure the var's value hasn't changed.

9:40 if it has, it would have to call out to a slower path instead of using the inlined version.

9:40 AWizzArd: usually yes, in nearly all cases

9:40 fdaoud: its value

9:41 AWizzArd: But it is not known 100%.

9:41 In a loop foo could change constantly (if (= user-input 10) (defn foo [] 1) (defn foo [] 2))

9:41 chouser: in practice, Clojure doesn't have to do this because HotSpot already does.

9:41 AWizzArd: Yes, HotSpot can do it at runtime.

9:42 With more (static) information during compiletime however it could be done by the compiler.

9:42 chouser: I just exaplained how it could be done at compile time by the compiler.

9:42 AWizzArd: For example I sometimes wished there was a defconstan.

9:43 Yes, the compiler can add an if.

9:43 If it were known at compile time that a function could never change then this if would not be required too.

9:43 chouser: this gives you the benefit of inline performance in the most common cases without giving up the features of dynamic redefinition when you really need it.

9:44 even if you didn't know you were going to need it when you wrote that code

9:44 AWizzArd: Yes.

9:45 chouser: Clojure 1.3 now reduces the overhead required in that 'if' even more, and is part of the general speed improvement people are seeing there.

9:45 AWizzArd: My point is that your definline can do an optimization during macro expansion time which can not be done as long we want a dynamic system.

9:46 How does it reduce an overhead in 'if'?

9:48 mtopolnik: i'm having a hard time with lazy-xml

9:49 as soon as i access an element, it eagerly parses its whole contents

9:49 chouser: the details grow fuzzy in my head. I think it has something to do with in 1.2 each var had it's own volatile while in 1.3 all non-dynamic vars share a single global "var version" counter

9:50 mtopolnik: e.g. <root><first/><second><a/><a/><a/>......</second></root>

9:50 as soon as i reach second, it parses all the a's

9:50 even if i just ask for the :tag of second

9:51 i've tried with xml-zip as well, but same problems

9:54 is this behavior expected?

9:56 AWizzArd: chouser: I see.

10:45 fliebel: \$seen dnolen

10:45 sexpbot: dnolen was last seen quitting 18 hours ago.

10:59 mattmitchell: i'm attempting to build up a string, conditionally. this is harder than i thought due to immutable state. the only thing i can think of is to use nested "let"s.

10:59 does that seem like an ok solution?

11:01 fliebel: mattmitchell: A let binding can refer to previous bindings. ##(let [a 1 b (+ 1 a)] b)

11:01 sexpbot: ⟹ 2

11:01 cemerick: mattmitchell: probably, but others may be better. e.g. str ignores nil arguments, so…

11:01 &(apply str ["foo" (when false "bar") "baz"])

11:01 sexpbot: ⟹ "foobaz"

11:02 mattmitchell: interesting

11:02 pdk: if you're building it up iteratively see if you can translate that into some recursive form with each call adding another piece to the return value

11:02 fliebel: You should also look at -> ##(-> "foo" (str "bar") (str "baz"))

11:02 sexpbot: ⟹ "foobarbaz"

11:02 raek: I guess one way could be to let each part of the string to be constructed to, either to some string value if it's going to be included, or to the empty string if it's not, and then just concatenate all the parts

11:02 pdk: or if you really think it'll be best to just do it iteratively stick the string value inside an atom which you can handle mutably

11:03 mattmitchell: wow thanks. good stuff.

11:03 cemerick: pdk: I can't say I've ever seen a scenario where that would make sense.

11:06 raek: (let [h (if-not (zero? hours) (format "%02d:" hours) ""), m (if-not (or (zero? hours) (zero? minutes)) (format "%02d:" minutes) ""), s (format ":%02d" seconds)] (str h m s))

11:22 mattmitchell: raek: thanks. nice example.

11:25 ,(contains? [1 2] 1)

11:25 clojurebot: true

11:25 fliebel: Has anyone here worked with Logos? I mean, you know, did some actual stuff with it.

11:25 mattmitchell: ,(contains? [1] 1)

11:25 clojurebot: false

11:25 mattmitchell: ... what's up with (contains? [1] 1) being false?

11:25 fliebel: mattmitchell: Common pitfall, contains? checks for index.

11:25 mattmitchell: fliebel: ah :)

11:26 fliebel: Try ##(some #{1} [3 4 5 1])

11:26 sexpbot: ⟹ 1

11:26 mattmitchell: ,(some [1] [1])

11:26 clojurebot: java.lang.IndexOutOfBoundsException

11:27 fliebel: with a set, not a vector.

11:28 mattmitchell: ,(set [12])

11:28 clojurebot: #{12}

11:28 mattmitchell: ,(some (set [1]) 1)

11:28 clojurebot: java.lang.IllegalArgumentException: Don't know how to create ISeq from: java.lang.Integer

11:28 fdaoud: ,(contains? [4 5] 1)

11:28 clojurebot: true

11:28 fdaoud: goof

11:28 mattmitchell: ,(some (set [1]) [1])

11:28 clojurebot: 1

11:29 chouser: ,(#{4 5} 1)

11:29 clojurebot: nil

11:29 chouser: ,(#{4 5} 5)

11:29 clojurebot: 5

11:30 sritchie: pandora

11:30 whoops, sorry, quicksilver kind of abandoned me there

11:30 fliebel: Are there javadocs for clojure.core? I'd be interested in the "known subclasses", so I can tell everything in Clojure that implements IFn.

11:48 Vinzent: Is it correct that (symbol "") returns something?

11:49 and not throws exception

11:50 raek: &(some (fn [x] (if (even? x) [:found-it x] nil))) [1 3 5 6 7])

11:50 sexpbot: java.lang.IllegalArgumentException: Wrong number of args (1) passed to: core\$some

11:50 raek: &(some (fn [x] (if (even? x) [:found-it x] nil)) [1 3 5 6 7])

11:50 sexpbot: ⟹ [:found-it 6]

11:50 raek: &(symbol "")

11:50 sexpbot:

11:51 raek: &(class (symbol ""))

11:51 sexpbot: ⟹ clojure.lang.Symbol

11:51 raek: Vinzent: seems like it returns a symbol, whose name is the empty string...

11:51 Fossi: nifty

11:51 &(symbol "a")

11:51 sexpbot: ⟹ a

11:52 sexpbot: java.lang.ClassNotFoundException: clojure.java.javadoc

11:53 raek: &(require 'clojure.java.javadoc)

12:05 What does a MapEntry do when called?

12:06 dnolen: wow, Google 'thread-local binding' and the first thing that comes up is Clojure. Neat idea that also seems to have origin in Mozart/Oz, seems like you could easily build Computation Spaces as described in CTM as a result.

12:07 chouser: whoa, the readers are IFns? I had never noticed.

12:07 fliebel: Hey dnolen! The Reasoned Schemer arrived yesterday. Could you shine some light on the differences between that and Logos?

12:08 dnolen: fliebel: logos.minikanren is a faithful implementation of the original ideas with considerable changes to get better performance, as well a solution to the fact that Clojure does support pairs.

12:08 Clojure doesn't support pairs I mean.

12:09 fliebel: dnolen: what pairs?

12:09 dnolen: fliebel: (a . b) where b is not a proper tail is allowed in Scheme/Common-Lisp, not allowed in Clojure

12:09 fliebel: I also noticed that fresh seems to be replaced by exist?

12:11 * fliebel does not even know what that dot is supposed to do. Is it like cons?

12:14 chouser: (1 . 2) is what is returned by (cons 1 2)

12:14 fliebel: ah

12:14 chouser: I've always found the syntax to be confusing

12:15 (1 2 3 4) is the same as (1 . (2 . (3 . (4 . nil)))) I believe

12:15 fliebel: dnolen: And what is this solution?

12:15 chouser: In Scheme, or in Clojure as well?

12:15 chouser: Clojure doesn't support dotted pairs. the "rest" of a seq is always a seq or nil, never a number or anything else.

12:16 ,(cons 1 2)

12:16 clojurebot: java.lang.IllegalArgumentException: Don't know how to create ISeq from: java.lang.Integer

12:16 fliebel: &(cons 1 (cons 2 nil))

12:16 sexpbot: ⟹ (1 2)

12:17 chouser: right. well-behaved lists, not dotted pairs of arbitrary values.

12:17 fliebel: I still don't understand the dots, then we could just as well start writing (1 + 1)

12:17 dnolen: fliebel: oh yeah, my version is based on the version in William Byrd's thesis (2009). The Reasoned Schemer is based on a earlier version (2005)

12:18 chouser: in general I think where you would use pairs in other lists, you use vectors in Clojure.

12:18 dnolen: fliebel: main differences, is fresh -> exist and they committed to interleaving search and abandoned Prolog depth-first option

12:18 chouser: fliebel: yes, the syntax is confusing. Maybe it helps to think of ( . ) as the whole thing. The parens there don't really mean the same as they do in a regular list.

12:19 would be less confusing if pairs were written as <1 2> or something. So <1 <2 <3 nil>>> is (1 2 3)

12:20 fliebel: dnolen: Is the later an implementation detail, or something I'm going to need to worry about?

12:20 dnolen: fliebel: the solution was to come up with with a new datastructure called LConSeq. This supports the tail being something other than a proper seq - in particular an un-ground logic variable.

12:20 fliebel: chouser: Yea.

12:20 dnolen: LConsSeq I mean.

12:21 chouser: dnolen: record or type?

12:21 pdk: i thought clojure forced all lists to be proper lists

12:21 dnolen: fliebel: Prolog depth-first has issues. interleaving search prevents certain forms of divergence that exist in Prolog.

12:21 chouser: pdk: it does. Sorry to confuse, I'm talking about other lisps here.

12:21 dnolen: chouser: type. record adds a bunch of Seq stuff I don't want.

12:21 * chouser nods

12:24 fliebel: dnolen: Thanks :) I only just did the first chapter of The Reasoned Schemer, and I'm really enjoying it. I'm trying to use Logos to try things out.

12:24 fdaoud: ,(let [a + + 2] (a + 4))

12:24 clojurebot: 6

12:24 dnolen: fliebel: cool, careful there's one major bug I haven't had time to tackle not sure if it'll crop up w/ their examples.

12:26 fliebel: dnolen: What is it? Surely not the set/map unification mentioned in the issue on github.

12:27 dnolen: fliebel: no, set/map unification works now. sets are a bit slow tho. issue is a bit hard to explain, but it has to do with cond-e.

12:29 fliebel: dnolen: I think you said something about a blog post about connecting the ends, any news on that? (I see what you meant with the book layout now :)

12:30 dnolen: fliebel: TRS is particularly sweet in that you come to understand the fundamental idea behind Prolog in about ~200 LOC. The hardest 200 LOC I've ever read :)

12:32 fliebel: I'll need to find some time, but the book glosses over half of the implementation. Unification/substitution is a tough topic, they cover that. Then they completely skip over how they produce the stream of solutions. William Byrd's thesis covers that, but their implementation is dense.

12:34 fliebel: I think my version is easier to follow, since Clojure has real type dispatch.

12:35 dmiles_afk: my dream intepretor is LISP+PROLOG+CLOJURE on a JVM

12:35 or even .NET

12:35 oh but making it very efficient :)

12:39 fliebel: dnolen: Cool, awesome work :) gtg now. I think I'll have loads of questions for you later, when I catch you here the next time :)

12:58 What are RestFn and PersistentTreeMap?

12:58 phenom_: hey everyone, i was having a convo with a colleague and he points out that multimethods make explicit use of casting to dispatch and casting is wrong ... how do i respond ?

12:59 fliebel: phenom_: Casting?

13:00 amalloy: phenom_: i suggest telling him he is crazy

13:01 __name__: good morning

13:01 Scriptor: morning __name__

13:01 phenom_: amalloy: I need more than that :P I try to explain that we separate the decision process from the code acting on the parameters, which he responds with "well, just because they're separate, doesn't mean it's not effectively a huge if/else check"

13:02 raek: phenom_: like in java? if (x instanceof Foo) { Foo y = (Foo) x; ... }

13:02 chouser: where is casting being done? what's wrong with casting? what's wrong with a huge if/else check?

13:02 I'm clearly confused.

13:02 __name__: can you include a route as a subdirectory of a route in compojure? so, e. g., foo/* is matched as * in another route?

13:02 amalloy: phenom_: the difference is it's not centralized like an if/else

13:03 phenom_: but it still is just a large if/else check for any types i want to handle right ?

13:03 amalloy: if apache released a clojure library with a multimethod in it, i could add my own types of objects and have them handled flawlessly by the existing multi

13:03 try doing that with a "real" if/else

13:03 dmiles_afk: if (x instanceof Foo) ((Foo)x).bar(); benches way faster than just ((Foo)x).bar(); btw

13:04 phenom_: so it's a sort of dynamic if/else

13:04 dmiles_afk: after JIT

13:04 phenom_: i can add as I like

13:04 raek: phenom_: I think that two of the points with multimethods are that their implementations is an open set (can be extended by others) and they don't have to be defined inside a type in order for it to be able to participate

13:05 amalloy: dmiles_afk: really? that's surprising

13:05 raek: also, the hierarchy used for selecting the method does not have to be the java class hierarchy

13:05 amalloy: even if x is always a Foo?

13:05 dmiles_afk: amalloy: CHECKCAST is removed in the ifelse

13:05 phenom_: but to participate, for most scenarios I'll need to do a cast

13:05 (eg. vector? seq? etc)

13:06 raek: clojure is dynamically typed, so you don't cast more than usual

13:06 hiredman: that is not a cast

13:06 dmiles_afk: but what saddens me is that ((Foo)x).bar(); is faster than x.bar();

13:06 chouser: I'm so confused.

13:06 dmiles_afk: if "Foo" inherits the method

13:07 raek: phenom_: what do you mean by "cast"?

13:07 phenom_: eek, isn't a call to vector? a class check ?

13:07 dnolen: multifns use a dispatch table and they cache lookups. I don't know where if/else or casting comes into the picture.

13:07 phenom_: ^

13:08 dmiles_afk: so hopfully in bytecode clojure if/else casts to the actual implmneting type

13:09 raek: for me, a (dynamic) cast is the operation of turning an Animal reference into a Cat reference when you know it is one

13:09 dmiles_afk: so hopfully in bytecode clojure if instanceofs and then casts to the actual implmneting type

13:10 raek: clojure does casts when doing java method invocations. clojure fns are Objects -> Object

13:10 dmiles_afk: thats good it does assume coercions

13:11 thats good it DoesNT assume coercions

13:11 phenom_: dnolen: i mean deciding which function to call is done with a class check (instanceof) ... get (vector?)

13:12 amalloy: phenom_: no

13:12 raek: phenom_: a multimethod has a dispatch function that yields a dispatch value when passed the arguments of the invocation. this function can be 'type'

13:12 dmiles_afk: i'd kinda hope that (vector? ..) means it implements a IClojureVector or somesuch

13:12 amalloy: pseudocode: (let [dispatch-fns {Vector vector-fn, List list-fn}] ((dispatch-fns (class arg)) arg))

13:13 chouser: phenom_: when a multimethod is called, your dispatch function is invoked first. It is not uncommon for the dispatch fn to get the class of the first arg, but it can do whatever you want.

13:13 dmiles_afk: as in instanecof IClojureVector

13:13 amalloy: but it doesn't have to be a class-based dispatch

13:13 raek: phenom_: then you define implementations for some dispatch values (e.g. String, Integer, Keyword, etc)

13:13 dmiles_afk: ah thats nice its not bound to java class structure

13:14 phenom_: right, so I am checking the class ... i understand you can dispatch on anything and return any value also

13:14 chouser: if you ask for the class of the object, that's what you get. Note this is not instanceof.

13:14 amalloy: somewhere around here i have a multimethod that dispatches on the size of its argument with (defmulti blah count)

13:15 chouser: after your dispatch fn returns something (such as a class), clojure does a (memoized) heirarchy lookup to find the appropriate defmethod to call.

13:15 phenom_: but even for functions like get .. internally it needs to check class type (PersistentVector or PersistentMap) to properly dispatch ?

13:15 amalloy: chouser: as a side note, i imagine it dumps out the whole memoization cache if you add a new dispatch fn

13:16 chouser: amalloy: I believe that's correct. or if you change the heirarchy. :-)

13:16 dmiles_afk: one day i am sure it could be surgicall dumped

13:16 phenom_: is there a detailed book that goes into the internals? or is it just a learn by reading code kinda thing ?

13:17 amalloy: phenom_: the internals are not very interesting. you are ascribing properties to them that they do not have

13:17 raek: the comparison would be more like x.getClass == c rathern than x instanceof C

13:17 chouser: phenom_: clojure.core/get is not a multimethod.

13:17 amalloy: in pseudo-java: switch (foo.getClass()) {case List: foo.length(); case Map: foo.size();}

13:18 and because you can add new case statements at any time, it's a million times less brittle than an if/else or actual switch

13:18 chouser: phenom_: clojure.core/get currently has an if/else inside to do the right thing. It may later be done with a protocol, which would amount to much the same thing.

13:19 amalloy: chouser: really? i would have expected that it casts to IAssociative and calls the interface method or something

13:19 phenom_: chouser: RT.get does instance checks no ?

13:19 *class check

13:20 dnolen: phenom_: getting a class and an isa? check is like the fastest thing possible on the JVM. you can do that a billion times in less than a second. also you can us a class as a map key, if you don't find it, then you do the isa? check on all keys, once you find it, you cache it.

13:20 chouser: amalloy: it does, but besides supporting ILookup and IPersistentSet, get supports java.util.Map, strings and arrays.

13:20 dnolen: ,{(class []) :look-ma-a-class-as-a-key}

13:20 clojurebot: {clojure.lang.PersistentVector :look-ma-a-class-as-a-key}

13:20 amalloy: chouser: yeah, i'm reading it now

13:21 chouser: amalloy: note the splitting of the 'get' method into 'getFrom'? I think that's to support better inlining by hotspot and/or branch prediction in the CPU.

13:23 amalloy: chouser: hm, i wonder why IPersistentSet doesn't extend ILookup

13:23 chouser: It may just be historical. I think ILookup is newer.

13:24 I need to write a ticket to extract Sequential from ISeq

13:32 mattmitchell: (doc select-keys)

13:32 clojurebot: "([map keyseq]); Returns a map containing only those entries in map whose key is in keys"

13:32 mattmitchell: ,(select-keys {:one 1 :two 2 :three 3} [:two :one])

13:32 clojurebot: {:one 1, :two 2}

13:33 mattmitchell: hmm, is there a way to specify the keys you want, in order?

13:33 oh oops... what i mean is, is there a way to specify the values you want, in order?

13:33 chouser: ,(map {:one 1 :two 2 :three 3} [:two :one])

13:33 clojurebot: (2 1)

13:33 mattmitchell: chouser: awesome thanks

13:34 amalloy: chouser, mattmitchell: also ##((juxt :two :one) {:one 1 :two 2 :three 3})

13:34 sexpbot: ⟹ [2 1]

13:34 mattmitchell: ,(doc juxt)

13:34 clojurebot: "([f] [f g] [f g h] [f g h & fs]); Alpha - name subject to change. Takes a set of functions and returns a fn that is the juxtaposition of those fns. The returned fn takes a variable number of args, a...

13:35 mattmitchell: cool

13:35 amalloy: &(doc juxt)

13:35 sexpbot: ⟹ "([f] [f g] [f g h] [f g h & fs]); Alpha - name subject to change. Takes a set of functions and returns a fn that is the juxtaposition of those fns. The returned fn takes a variable number of args, and returns a vector containing the result of applying each fn to the... http://gist.github.com/821050

13:35 mattmitchell: ,(prn "test")

13:35 clojurebot: "test"

13:35 mattmitchell: &(prn "test")

13:35 sexpbot: ⟹ "test" nil

14:10 markskilbeck: Hi, all. Say I have a vector of 10 elements, and I want to change 2 random elements of it. How would I go about writing a function to do that?

14:10 dotimes?

14:12 amalloy: markskilbeck: do you actually want to change them in place, or return a modified copy?

14:12 (if the former, reconsider because that is evil)

14:12 markskilbeck: A modified copy, I suppose.

14:12 rata_: hi

14:12 markskilbeck: As is the way of clojure.

14:12 Sup, rata_.

14:12 amalloy: in that case, you don't want anything that starts with "do" - those usually just perform side effects

14:13 markskilbeck: Noted.

14:14 amalloy: markskilbeck: you probably want to select two indices at random, then perform the swaps. you might be interested in the discussion fliebel and i had a week or two ago about shuffling

14:14 dnolen: ,(-> [1 2 3 4] (assoc (rand-int 4) 'foo) (assoc (rand-int 4) 'bar))

14:14 clojurebot: [1 bar foo 4]

14:14 dnolen: no so thing as changing a vector in place anyway

14:14 s/so/such

14:14 sexpbot: <dnolen> no such thing as changing a vector in place anyway

14:14 clojurebot: Gabh mo leithscéal?

14:15 markskilbeck: dnolen: That's fine, though if I then want to modify 3 indices, I've got to duplicate code.

14:15 amalloy: markskilbeck: iterate

14:15 markskilbeck: Ah!

14:15 Bob's your mother's brother.

14:16 amalloy: &(nth (iterate #(assoc % (rand-int (count %)) 'foo) [1 2 3 4 5 6] 3)

14:16 sexpbot: java.lang.Exception: EOF while reading

14:16 amalloy: &(nth (iterate #(assoc % (rand-int (count %)) 'foo) [1 2 3 4 5 6]) 3)

14:16 sexpbot: ⟹ [foo 2 foo 4 5 foo]

14:16 amalloy: but this might result in hitting up the same index multiple times, resulting in fewer than N elements changing

14:17 markskilbeck: That's fine.

14:21 So the (nth ... 3) takes the third? iteration?

14:22 amalloy: markskilbeck: it takes the fourth entry in the list, where the zeroth entry is the original vector

14:23 https://gist.github.com/805747 is several different approaches to a very similar problem that you might be interested in

14:23 and http://www.raynes.me/logs/irc.freenode.net/clojure/2011-02-01.txt contains a discussion of the above

14:24 markskilbeck: Brill. Thanks.

14:25 Wait, why the 4th entry? I wanted to modify only 2 indices, but wouldn't that modify (possibly) 4?

14:25 amalloy: markskilbeck: it will modify up to three

14:26 0th entry modifies 0, 1st entry 1, 2nd entry up to 2...

14:26 i think my original statement was poorly worded

14:26 markskilbeck: I see, I see.

14:27 amalloy: &(take 5 (iterate #(conj % 10) []))

14:27 sexpbot: ⟹ ([] [10] [10 10] [10 10 10] [10 10 10 10])

14:27 markskilbeck: amalloy: you're most helpful

14:28 amalloy: markskilbeck: you're welcome!

14:31 markskilbeck: And that is a _long_ discussion.

14:32 amalloy: markskilbeck: well it's an interesting topic :)

15:13 rata_: LauJensen: I'm reading your post http://www.bestinclass.dk/index.clj/2009/10/brians-brain-echoes-from-the-web.html and don't understand why the 1d vector for the board representation is not accurate

15:13 LauJensen: rata_: Because there is no way to tell from a single index where exactly on the board you are, ie. left isn't simply -1 as it might move you up one row. It creates pretty patterns but its not Brians Brain anymore

15:18 rata_: LauJensen: oh ok =)

15:21 LauJensen: but the important thing was that using a 1d vector instead of a matrix made the performance improvement, so it's maybe worth fixing the neighbours fn

15:21 LauJensen: rata_: See Christophes follow-up posts for major performance boosts

15:21 He made it even faster than the CL version

15:21 rata_: using clojure?

15:23 LauJensen: where can I find Christophes follow-up posts?

15:23 LauJensen: did he use clojure?

15:24 LauJensen: http://clj-me.cgrand.net/page/2/

15:26 rata_: thanks

16:10 LauJensen: do you know if it's possible to make the rendering and the computation run at 25fps? I don't want to miss frames

16:10 interesting optimizations has done cgrand to your code btw

16:19 amalloy: markskilbeck: out of curiosity what method did you end up using?

16:40 edoloughlin: Is there any hope of attaching clojure source to a referenced JAR file in Counterclockwise (e.g., clj-record)?

16:54 cinch: Moooooo

17:00 _2x2l: do the TheDeadline guys hang out around here?

17:06 cinch: (whois _2x2l)

17:19 TimMc: I've been using the *warn-on-reflection* flag, and was surprised to see that @dereferences do not carry their :tag metadata through.

17:21 amalloy: TimMc: @foo is sugar for (deref foo). how would you type-hint the deref function to make that work?

17:21 TimMc: Good question.

17:22 I guess I'm still kind of fuzzy on how type hinting works.

17:23 amalloy: TimMc: it would require type-inference that clojure doesn't really have (yet?)

17:25 TimMc: So (. obj method arg) will not need reflection if arg is :tagged explicitly, and (. obj method (producer)) works similarly... but @arg is hiding a function call.

17:26 I suppose you'd have to have some mechanism to say "my type is the same as parameter 3's type" or somesuch. :-/

17:28 amalloy: TimMc: indeed, and java's generics do that

17:29 public <T> T deref(IDeref<T> obj) {return obj.deref();}

17:31 TimMc: Oof, I really shouldn't be :tagging those (ref)s anyway -- it's their *contents* that I want to hint.

17:33 dnolen: TimMc: question is, what are you putting in refs that need type-hinting ?

17:33 TimMc: AffineTransform instances.

17:34 dnolen: TimMc: for what benefit?

17:34 TimMc: My graphics app needs to update those as the viewport changes.

17:35 I don't want my coordinate transforms to get out of sync with the rotation, scaling, etc.

17:35 I suppose that as long as they are only modified from the event loop I don't really need the transactions...

18:01 mattmitchell: how can i check if a string starts with a regexp?

18:02 amalloy: &(doc re-find)

18:02 sexpbot: ⟹ "([m] [re s]); Returns the next regex match, if any, of string to pattern, using java.util.regex.Matcher.find(). Uses re-groups to return the groups."

18:02 brehaut: use an start anchor in the regexp

18:02 amalloy: &(map #(re-find #"^blah" %) ["blahtwer" "wablah"])

18:02 sexpbot: ⟹ ("blah" nil)

18:10 tomoj: xb

18:58 TimMc: I'm implementing an undo/redo buffer for my program. I think I should move my def'd userdat variables into a map, and then I can push the current map onto the undo buffer before I change data in response to the user.

18:59 So, question: Is there a way to keep the :doc metadata?

18:59 (on the individual wads of state that I keep for the user)

19:00 brehaut: ,(meta ^{:doc "foo"} {:a 1})

19:00 clojurebot: {:doc "foo"}

19:00 tomoj: are you sure you want vars there?

19:00 TimMc: brehaut: I want doc on :a. :-/

19:01 Am I asking for something that doesn't exist?

19:02 tomoj: yes, keywords can't have metadata

19:02 brehaut: TimMc: if you want it on a keyword then yes

19:02 TimMc: That is, by consolidating a bunch of (def ^{:doc "stuff"} foo ()) into (def userdata {:foo ()}), I lose individual docstrings?

19:03 brehaut: ,^{:doc "foo"} :a

19:03 for instance

19:03 clojurebot: Metadata can only be applied to IMetas

19:03 TimMc: Hmm, OK.

19:03 tomoj: are users of your program familiar with clojure?

19:03 brehaut: is clojurebot going to throw me the exception?

19:03 tomoj: that's the only way it makes sense to me for that stuff to be in vars

19:03 TimMc: tomoj: This is internal stuff.

19:04 tomoj: better question: does your program include a clojure repl?

19:04 TimMc: tomoj: What is the alternative? (This is an interactive graphics program using Swing, to give some context.)

19:05 tomoj: so how do you change the data in response to the user?

19:05 TimMc: I have components that have event listeners that call functions (to update state) that need to refer to the components.

19:05 tomoj: what I mean is, how do you update the state

19:06 def, again? alter-var-root? what?

19:06 TimMc: def

19:06 (again)

19:06 tomoj: ok, pretty sure what you're doing is evil then

19:06 TimMc: Hah, OK.

19:06 tomoj: maybe an atom would be better suited?

19:07 hard to say since I still don't really get what you're doing. but vars aren't variables, and if you're treating them like the variables you're used to, it's probably bad

19:08 TimMc: I've done some functional programming in the past, but I've never had to deal with this much mutable state in that context before.

19:08 tomoj: the only reason you're even allowed to redef is for development

19:08 TimMc: OK, I will definitely keep that in mind!

19:08 brehaut: im also wondering if you are abusing the metadata stuff?

19:09 tomoj: the other state abstractions to look into are atoms, refs, and agents

19:09 brehaut: metadata is largely for tooling (or so i understand)

19:10 TimMc: brehaut: I doubt it. I just like using machine-discoverable doc syntax.

19:10 If I ever use a smart IDE to work on my code, this *should* make it easier to work with.

19:11 tomoj: I tried refs, but I think they're more high-powered than I need. Agents look scary and alien, but I will learn what to use them for at some point.

19:12 tomoj: with (def userdata (atom {:foo ()}))

19:12 brehaut: TimMc: refs are always a good safe bet

19:13 tomoj: you can do things like (swap! userdata update-in [:foo] conj 3)

19:13 then (:foo @userdata) is (3)

19:13 brehaut: they have additonal coordination semantics so if you ever need to access two refs, they can be transactional

19:14 TimMc: STM, yeah

19:14 brehaut: however, if you just have a undo stack, current doc, redo stack structure (perfect case for a zipper) then all you'd need is an atom

19:15 TimMc: zipper... heard of, but never used one of those before! Exciting.

19:15 brehaut: TimMc: basically its a double linked singlely ended list

19:16 TimMc: Aren't they more like tree+cursor?

19:16 brehaut: descibed as a pair of singly linked list

19:16 completely persistent

19:16 i think there may be a couple of things with the same name

19:17 or the tree version is a generalisation of the list version

19:18 TimMc: hmm

19:18 brehaut: i am trying to look it up to find some docs for you, but my internet is running slow as mollasas

19:20 TimMc: brehaut: Thanks, but I don't know if I need a dedicated data structure for this -- a couple of functions oughta take care of this.

19:24 brehaut: TimMc: im not sure i understand; an undo / redo stack and current state in a world with persistent data structures is exactly this thing

19:25 TimMc: Sure, but I can just use two lists and conj/rest.

19:25 I'd effectively implement the same thing myself.

19:26 brehaut: yeah thats the bit i dont understand

19:26 TimMc: Well, I don't know the name of the thing I'd want to use instead, or if Clojure has it.

19:29 If I find out, I'll happily switch to using it. :-)

19:30 (Since I am very much still learning Clojure, I don't consider it a waste of time to try to reimplement things that I could just grab libraries for.)

19:42 amalloy: brehaut: i had a good non-tooling use of metadata. maybe it was evil, i dunno

19:42 brehaut: amalloy: im sure they exist, but im sure its the minority

19:42 amalloy: brehaut: agreed. i think it's the first time i've had a reason

19:42 for meta of any kind

19:48 if anyone's interested, i wanted to wrap up "get this from the database" in a function so i could pass it to non-db-aware code; i attached meta to the function about what kinds of things it was looking for so i could use it to write to the database if i needed to

20:17 rata_: brehaut and amalloy: I use metadata for storing the connected components of a graph and not have to recompute them... don't know if that's considered evil

20:17 brehaut: rata_: my rule of thumb is 'is it actual data for my program'

20:19 if its actual data, then i'd use a map or record

20:20 bytecolor: rata_: isn't that sort of how clojure.zip is implemented?

20:20 rata_: it's not any additional data... it's computable from just the data it goes with

20:21 bytecolor: I don't know... haven't looked at clojure.zip implementation

20:27 brehaut: bytecolor: zip attaches the functions used to create the zipper (eg branch? end? etc) but the actual path and context information is part of the zipper itself

20:28 bytecolor: ah, ok. I'd only peeked at the code a couple times.

20:28 amalloy: brehaut: "actual data" and "my program" seem almost too vague to be useful here

20:29 bytecolor: I think I've learned clojure mostly from reading the core and contrib source.

20:30 waiting on the dead tree version of the joy of clojure to come out

20:30 no_mind: Someone explain to me what exactly is this code snippet doing (map #(section-model % link-model) sections)

20:31 wha tis % operator ? I cant find it even in cheatsheet

20:32 amalloy: no_mind: anonymous function shorthand

20:32 phenom_: how do i add classes or dirs to the class path when i launch cake's swank ?

20:32 amalloy: #(foo % 10) === (fn [x] (foo x 10))

20:33 no_mind: amalloy: is anonymous function shorthand #() ?

20:34 amalloy: er...yes, i guess? i don't understand the question

20:38 TimMc: no_mind: It's not an operator.

20:38 no_mind: k

20:39 TimMc: no_mind: #(... % ...) is equivalent to something like (fn [x] ... x ...)

20:39 no_mind: k

20:39 TimMc: It's the single argument to the anonymous function.

20:39 brehaut: no_mind: http://clojure.org/reader

20:39 under macro characters, dispatch

20:41 TimMc: no_mind: Note that I forgot an important pair of parens in my expansion.

20:45 brehaut: If you're at all curious, I finally pushed my in-progress graphics app to github: https://github.com/timmc/CS4300-HW3/blob/master/src/timmcHW3/core.clj

20:48 (I should add a "n00b at work" warning in the readme.)

20:49 brehaut: TimMc: im not sure why you need a seperate ref for past and future

20:50 (def history (ref [[], []])) would suffice

20:50 TimMc: True. What's the advantage?

20:50 brehaut: simplicity

20:51 TimMc: And I suppose some conceptual atomicity as well.

20:51 brehaut: yes

20:51 i dont think you need 3 ref-sets; you should be able to get by with one

20:52 ffirst on your history ref will give you the current state

20:53 TimMc: Yeah, I did debate on whether to have the current state as part of the undo history or not.

20:53 I need to think about that some more.

20:53 brehaut: it makes the updating of the undo and redo stack trivial

20:53 you dont have to sidestep through the current state

20:56 TimMc: I've also been considering whether I want a more complex undo/redo system.

20:56 brehaut: no, you want to get your program working first :P

20:56 TimMc: Notice how most word processors will undo chunks of typing at a time?

20:58 True.

20:58 pdk: hey uh

20:58 which libraries are clojurebot/sexpbot using for irc interaction again

20:58 TimMc: I wasn't planning on doing fancy skiplist history quite yet.

21:00 pdk: clojurebot appears to be using PircBot, a Java thingy.

21:01 I bet both are open source on github.

21:09 pppaul: anyone home?

21:09 i'm feeling really stupid with a simple clojure problem i have regarding maping over a dictionary

21:10 brehaut: pppaul: oh?

21:10 pppaul: (map identity (vals v))

21:10 ({:id 6822400, :name "Adam Tran"} {:id 43535, :name "Sdfsfsd"})

21:10 solve360.name-fixer> (map #({:id (:id %), :name (:name %)}) (vals v))

21:10 the last line gives an error

21:10 brehaut: pppaul: maps return MapEntries for seqs

21:10 they look like pairs

21:11 pppaul: um

21:11 how can i get a visual on that?

21:11 or is there a better way to do what i want?

21:11 brehaut: ,(map identity {:a 1 :b 2 :c 3})

21:11 clojurebot: ([:a 1] [:b 2] [:c 3])

21:11 pppaul: which is transforming a map

21:12 mattdw: pppaul: also, #({..}) is going to try to call the map, I believe, not return it

21:12 pppaul: oh

21:12 brehaut: mattdw: correct

21:12 pppaul: ok

21:13 mattdw: turn it into an (fn [v] ...) if you just want the map returned

21:14 pppaul: thanks

21:14 gfrlog: ,(seq {:a 1 :b 2 :c 3})

21:14 clojurebot: ([:a 1] [:b 2] [:c 3])

21:14 pppaul: i want to transform the map into a new map

21:14 what would be the best way to do this?

21:14 gfrlog: you want to map the map?

21:14 Kowboy: don't confuse the map the function and map the datatype

21:14 brehaut: (into {} (map f m))

21:14 pppaul: datamap to datamap

21:15 gfrlog: you want to change the keys, the values, or both?

21:15 pppaul: like XSLT

21:15 brehaut: f needs to take a pair and return a pair

21:15 pppaul: cool

21:15 Kowboy: the function map will return a sequence, not a data map

21:15 pppaul: a seq of datamaps is ok

21:16 brehaut: eg ##(into {} (map (fn [[k v] [(dec k) (inc v)]) {1 2 3 4 5 6}))

21:16 pppaul: that's what i'm starting with

21:16 gfrlog: ,(into {} (map (fn [[k v] [(dec k) (inc v)]) {1 2 3 4 5 6}))

21:16 clojurebot: Unmatched delimiter: )

21:16 gfrlog: ,(into {} (map (fn [[k v] [(dec k) (inc v)]) {1 2 3 4 5 6})

21:16 * brehaut wonders if he has done something to anger the bots today

21:16 clojurebot: Unmatched delimiter: )

21:16 Kowboy: can you give us an example of a 1 entry map and what you want it transformed into?

21:16 gfrlog: ,(into {} (map (fn [[k v] [(dec k) (inc v)]] {1 2 3 4 5 6}))

21:16 clojurebot: EOF while reading

21:16 pppaul: ({:id :name :etc....},{}) -> ({:id :name},{})

21:16 gfrlog: ,(into {} (map (fn [[k v] [(dec k) (inc v)]] {1 2 3 4 5 6})))

21:16 clojurebot: java.lang.RuntimeException: java.lang.Exception: Unsupported binding form: (dec k)

21:17 gfrlog: ,(into {} (map (fn [[k v]] [(dec k) (inc v)]) {1 2 3 4 5 6})))

21:17 clojurebot: {0 3, 2 5, 4 7}

21:17 gfrlog: ah finally

21:17 pppaul: interesting

21:18 Kowboy: can the bot tell me the doc string of (into)?

21:18 gfrlog: ,(doc into)

21:18 clojurebot: "([to from]); Returns a new coll consisting of to-coll with all of the items of from-coll conjoined."

21:18 gfrlog: clojurebot: thanks

21:18 clojurebot: thanks for your suggestion, but as usual it is irrelevant

21:19 gfrlog: I think (into) is kind of an ugly function for these purposes. But I don't think there's anything better at the moment

21:19 ,(into #{1 2 3} [2 3 4])

21:19 clojurebot: #{1 2 3 4}

21:20 brehaut: gfrlog: you could use hash-map or array-map

21:20 gfrlog: (doc hash-map)

21:20 clojurebot: "([] [& keyvals]); keyval => key val Returns a new hash map with supplied mappings."

21:20 Kowboy: curious, what is the purpose of splitting a multi-entry map into a bunch of single-entry maps?

21:20 gfrlog: Kowboy: I have no idea, who suggested that?

21:20 Kowboy: why wouldn't you just use a sequence of tuples (2 element sequences)?

21:20 gfrlog: ,(doc array-map)

21:20 clojurebot: "([] [& keyvals]); Constructs an array-map."

21:21 Kowboy: pppaul is trying to do that

21:21 pppaul: ({:id :name :etc....},{}) -> ({:id :name},{})

21:21 that is what i want

21:21 gfrlog: brehaut: we were talking about mapping a map -- is that what you were suggesting hash-map for?

21:21 pppaul: i'm braindead now, though

21:21 Kowboy: what's the difference between {:a 1} and [:a 1] if you aren't going to have multiple keys?

21:21 pppaul: i haven't worked with maps much

21:21 brehaut: gfrlog: as a replacement for into {}

21:22 gfrlog: Kowboy: I agree

21:22 pdk: (doc into)

21:22 clojurebot: "([to from]); Returns a new coll consisting of to-coll with all of the items of from-coll conjoined."

21:22 gfrlog: brehaut: so if I want {"jack" 12, "jill" 15} to be mapped to {:jack, 13, :jill, 16}

21:22 amalloy: &(map hash-map {1 2 3 4})

21:22 sexpbot: java.lang.IllegalArgumentException: No value supplied for key: [1 2]

21:22 amalloy: &(map (partial apply hash-map) {1 2 3 4})

21:22 sexpbot: ⟹ ({1 2} {3 4})

21:22 gfrlog: how would hash-map make that easier?

21:23 amalloy: but i agree with the others, it's sorta silly to want this

21:24 gfrlog: ,(into {} (fn [[k v]] [(keyword k) (inc v)]) {"jack" 12, "jill" 15})

21:24 brehaut: gfrlog: you said "I think (into) is kind of an ugly function for these purposes. But I don't think there's anything better at the moment"; i was suggesting the alternatives

21:24 clojurebot: java.lang.IllegalArgumentException: Wrong number of args (3) passed to: core\$into

21:24 gfrlog: ,(into {} (map (fn [[k v]] [(keyword k) (inc v)]) {"jack" 12, "jill" 15}))

21:24 clojurebot: {:jack 13, :jill 16}

21:24 pppaul: (map (fn [v] {:id (:id v) :name (:name v)} ) (vals v)) : my solution

21:24 gfrlog: brehaut: I guess I'm thinking that using hash-map would be more cumbersome

21:24 amalloy: gfrlog: (for) will be a lot cleaner than (map (fn))

21:24 pppaul: i don't know what it didn't work with #(%) format

21:24 brehaut: i think so to, hence my original use of into { }

21:24 gfrlog: ,(doc for)

21:24 clojurebot: "([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 e...

21:25 gfrlog: brehaut: oh, okay -- I thought you were suggesting hash-map as better than into {}

21:25 pppaul: how would i use for?

21:25 gfrlog: amalloy: I'm getting that feeling that I've been missing out on a whole function for a long time

21:25 zakwilson: I'm still not used to the pervasive destructuring in Clojure. I see people post examples like the above and I want to go refactor all my ugly code.

21:25 amalloy: &(into {} (for [[k v] {"jack" 11 "jill" 15}] {(keyword k) (inc v)}))

21:25 sexpbot: ⟹ {:jack 12, :jill 16}

21:26 pppaul: wow, that is over my head

21:26 "jack" -> :jack ???

21:26 gfrlog: pppaul: for isn't that bad

21:27 pppaul: i would really like a tutorial on for

21:27 brehaut: pppaul: ##(keyword "foo")

21:27 sexpbot: ⟹ :foo

21:27 gfrlog: pppaul: are you wondering what the :jack syntax means?

21:27 pppaul: i'm wondering how "jack" is transformed into :jack

21:27 gfrlog: ,(for [x (range 5)] [x (inc x)])

21:27 clojurebot: ([0 1] [1 2] [2 3] [3 4] [4 5])

21:28 brehaut: pppaul: the keyword function

21:28 gfrlog: ,(keyword "jack")

21:28 clojurebot: java.lang.StackOverflowError

21:28 pppaul: oooooooooh

21:28 gfrlog: ,(keyword "jack")

21:28 clojurebot: :jack

21:28 pppaul: damn i'm tired

21:28 amalloy: &(map (juxt identity inc) (range 5))

21:28 sexpbot: ⟹ ([0 1] [1 2] [2 3] [3 4] [4 5])

21:28 pppaul: :P

21:28 gfrlog: amalloy: I agree, I was trying to do a trivial use of (for)

21:28 amalloy: kk

21:29 gfrlog: It's juxt what I was trying to use for for

21:30 Kowboy: ,(for [[k v] {:id 12 :name "Bob"}] {k v} )

21:30 clojurebot: ({:id 12} {:name "Bob"})

21:30 Kowboy: still, I'd use a vector instead

21:30 gfrlog: I'd use a java.util.HashMap<String, String>

21:30 brehaut: pppaul: http://clojuredocs.org/clojure_core/clojure.core/for go read that

21:31 amalloy: gfrlog: barf

21:31 Kowboy: ,(for [x {:id 12 :name "Bob"} ] x)

21:31 clojurebot: ([:id 12] [:name "Bob"])

21:34 Kowboy: now I'm confusing myself on how map and for are different

21:35 amalloy: Kowboy: they treat multiple sequences differently

21:36 brehaut: pppaul: there are a couple of major uses: if you are doing multiple maps and/or filters for really tidys things up, and if you want the cross product of two or more collections

21:36 Kowboy: and for takes an expression/form while map takes a function?

21:36 brehaut: pppaul: the first example on that page shows a map and filter occuring in the same comprehension

21:36 amalloy: Kowboy: sure, that's mostly syntax sugar

21:36 brehaut: the second and third examples are crossproduces

21:37 Kowboy: for has more in common with mapcat than with map

21:37 Kowboy: it happens that when there is only a single sequence, it looks like map

21:38 arohner: has anyone used cron4j? Is it any good?

21:39 Kowboy: ok, found my equivalent expressions:

21:39 ,(map (fn [x] x) {:id 12 :name "Bob"})

21:39 clojurebot: ([:id 12] [:name "Bob"])

21:39 Kowboy: ,(for [x {:id 12 :name "Bob"} ] x)

21:39 clojurebot: ([:id 12] [:name "Bob"])

21:39 Kowboy: not sure if my map version can be done more simply

21:40 brehaut: Kowboy: use identity instead of (fn [x] x)

21:41 amalloy: brehaut: or vec

21:43 Kowboy: ,(== (map identity {:id 12 :name "Bob"}) (for [x {:id 12 :name "Bob"} ] x))

21:43 clojurebot: java.lang.ClassCastException: clojure.lang.LazySeq cannot be cast to java.lang.Number

21:44 Kowboy: darn

21:44 amalloy: Kowboy: =, not ==

21:45 Kowboy: ,(= (map identity {:id 12 :name "Bob"}) (for [x {:id 12 :name "Bob"} ] x))

21:45 clojurebot: true

21:45 Kowboy: wait, isn't = the assignment operator?

21:45 * Kowboy ducks

21:46 Kowboy: :-)

21:52 amalloy: at least clojure doesn't have ===

21:56 Kowboy: === is for when you REALLY mean it

21:57 that's it, I'm going to define === and add it to the clojure.core ns

21:57 shachaf: Kowboy: And redefine == to randomly return the wrong answer 10% of the time.

21:59 Kowboy: brilliant!

21:59 TimMc: It's not random! :-(

21:59 * TimMc hugs his javascript

21:59 TimMc: I can't speak for PHP, though.

21:59 Kowboy: how about !!=

22:00 the not-not-equal operator

22:00 amalloy: TimMc: php's implicit type conversions are even worse than javascript's, which are abominable

22:00 TimMc: amalloy: I think JS's == is not even transitive, which is awesome.

22:03 amalloy: really? e.g.?

22:04 TimMc: Ugh, can't find it now...

22:04 I'll get back to you if I can reproduce it.

22:05 amalloy: OK, here we go: '00' == 0 == '0'

22:05 but '00' != '0'

22:05 amalloy: nice

22:06 TimMc: I had forgotten that JS did string parsing for integer equality. Yuck.

22:07 amalloy: TimMc: in php: '00' == 0 == 'ojhgfklh'

22:07 * TimMc cries

22:08 TimMc: (defn == [a b] true)

22:10 rata_: hahaahaha

22:10 how do you change the size of the slime history?

22:12 gfrlog: barfbag2273

22:21 pdk: (doc read-line)

22:21 clojurebot: "([]); Reads the next line from stream that is the current value of *in* ."

22:30 Kowboy: ok, I have a tough one

22:30 I want a macro that can generate multiple functions

22:31 (make-call {:char-list "/chars" :foo "/foo" :bar "/bar" })

22:31 to result in definitions like: (defn foo [] (println "/foo"))

22:31 tomoj: if there are no more arguments, may I suggest dropping the {}?

22:31 Kowboy: but for each pair in the map

22:31 ok

22:32 tomoj: not that it matters much..

22:32 Kowboy: and bind them using let?

22:32 or for, rather

22:33 I actually am close

22:33 tomoj: no, just (defmacro make-call [& {:as foo}]) or whatever

22:33 Kowboy: right now, I get my defn's wrapped in a list

22:33 tomoj: just stick a 'do at the head

22:34 Kowboy: hmm...i tried that, maybe I did something wrong there

22:34 I know what I did

22:34 I should have done (list 'do ....

22:34 I just did ('do

22:35 tomoj: list* is often useful in situations like that

22:35 Kowboy: ,(doc list*)

22:35 clojurebot: "([args] [a args] [a b args] [a b c args] [a b c d & more]); Creates a new list containing the items prepended to the rest, the last of which will be treated as a sequence."

22:36 tomoj: ,(list* 'do (for [[k v] {:foo 3 :bar 4}] `(def ~k ~v)))

22:36 clojurebot: DENIED

22:36 tomoj: huh

22:36 oh, of course

22:37 ,(list* 'do (for [[k v] {:foo 3 :bar 4}] `(poop ~k ~v)))

22:37 clojurebot: (do (sandbox/poop :foo 3) (sandbox/poop :bar 4))

22:38 Kowboy: hah, it works!

22:38 thanks

22:41 tomoj: trying to strip the {}

22:41 amalloy: `(do ~@body) is a common idiom

22:41 Kowboy: so [& args]

22:41 how to I bind that to pairs?

22:42 amalloy: Kowboy: with the {} :P

22:42 tomoj: pff

22:42 amalloy: or if you really prefer it, you can (partition 2 args)

22:43 tomoj: I guess you probably don't want {:as crap} in your arglist

22:43 amalloy: &(partition 2 [1 2 3 4 5 6])

22:43 sexpbot: ⟹ ((1 2) (3 4) (5 6))

22:43 Kowboy: (make-call :foo "/foo" :bar "/bar")

22:44 so I need to iterate over the args in pairs

22:44 not seeing it

22:44 tomoj: well destructuring can do it for you

22:45 ..better not though

22:46 amalloy: &(let [args [:foo "/foo" :bar "/bar"]] `(do ~(map str (partition 2 args))))

22:46 sexpbot: ⟹ (do ("clojure.lang.LazySeq@5d847e33" "clojure.lang.LazySeq@5d2b26fe"))

22:46 amalloy: &(let [args [:foo "/foo" :bar "/bar"]] `(do ~(map (partial apply str) (partition 2 args))))

22:46 sexpbot: ⟹ (do (":foo/foo" ":bar/bar"))

22:47 amalloy: whoops, forgot the @ in ~@

22:48 tomoj: you prefer `(do ~@x) to (list* 'do x)?

22:48 Kowboy: ok, I get the :as option now

22:48 [& {:as calls}]

22:49 amalloy: tomoj: not especially. but (cons 'do x) is better

22:49 if you're going to do without `

22:50 tomoj: core.clj confirms this spectacularly

22:50 (if name (list* 'fn* name new-sigs) (cons 'fn* new-sigs))

22:50 amalloy: heh

22:52 tomoj: has bit-seq left anyone else seriously confused?

22:52 amalloy: &(doc bit-seq)

22:52 sexpbot: java.lang.Exception: Unable to resolve var: bit-seq in this context

22:52 tomoj: from gloss, I should say

22:52 Kowboy: so, basically I am deciding whether to use a macro, or currying for my needs

22:52 they accomplish the same thing, with the macro approach being more DRY and the currying approach being a little clearer

22:53 I am defining groups of functions which have similar arg lists, but each function is specifying one of the args

22:56 amalloy: Kowboy: i don't follow

22:57 Kowboy: instead of this: (geturl "/foo" 1 2 3) (geturl "/blah" 1 2 3), etc....

22:57 I'm turning that into (foo 1 2 3) and (blah 1 2 3)

22:57 so, using currying

22:58 (def foo (partial geturl "/foo"))

22:58 brehaut: Kowboy: thats not currying

22:58 thats partial application

22:58 Kowboy: I thought it was the same thing

22:58 brehaut: no

22:58 Kowboy: close?

22:58 amalloy: they're related, anyway

22:59 brehaut: implict partial application is a property of curried functions

22:59 TimMc: I don't think you can have currying and variadic functions in the same language.

22:59 brehaut: TimMc: should i point you to the printf implemention in haskell?

23:00 canonical example: (fn [a b c] (…)) curried would be

23:00 TimMc: brehaut: How does it know when to stop?

23:00 brehaut: (fn [a] (fn [b] (fn [c] (…)))

23:00 amalloy: TimMc: someone posted automatic currying of non-variadic defns on the clojure ng a month or two ago

23:00 brehaut: TimMc: the magic of type classes

23:00 TimMc: brehaut: Hrmf. GO figure, it's more Haskell magic. :-P

23:00 Kowboy: still not sure I see the difference

23:01 brehaut: Kowboy: the former would be called as (f 1 2 3)

23:01 the latter as (((f 1) 2) 3)

23:01 Kowboy: ok, so currying is a chain of functions with a single argument

23:01 brehaut: yes

23:02 well

23:02 a curried function is

23:02 Kowboy: subtle difference

23:02 brehaut: yes

23:02 but its important

23:03 you can have partial application without currying, but in a language with proper curried functions there are a lot of optimisations that can be made

23:03 [end of curry/partial rant]

23:04 amalloy: brehaut: don't proclaim that so soon

23:04 Kowboy: ok, so back to my decision, macros vs. partially applied functions

23:04 (def foo (partial geturl "/foo"))

23:04 vs

23:04 (make-call :foo "/foo" :bar "/bar")

23:05 any thoughts?

23:05 amalloy: Kowboy: they both sound kinda crazy to me tbh

23:05 TimMc: I have heard "avoid using macros when functions will do" as good Clojure style.

23:05 TimMc: Not sure if that's just for debugging difficulty, readability, or what.

23:05 Kowboy: well, I would be doing a lot of code duplication otherwise

23:06 amalloy: TimMc: and reusability/composability

23:07 TimMc: ooh, composability, right

23:07 Kowboy: the only reason to use partially applied functions is to avoid having to state the parameter list over and over again

23:07 TimMc: brehaut: Ohhh, does it know when to stop by reading the format string?

23:07 brehaut: TimMc: in this case yes but also magic ;)

23:07 TimMc: haha

23:07 Of course magic.

23:08 Kowboy: magic - it's a feature of the language

23:11 brehaut: the primary piece of magic is actually 'pretty simple'; type classes can be polymorphic on the return type of functions

23:12 Kowboy: haven't learned Haskell yet

23:12 will someday, though

23:12 it's on my list

23:14 amalloy: Kowboy: i just don't think you need to do any top-level defs to get the partial/curried versions of your functions

23:14 the eventual result you want is like (partial (partial (partial (partial get-url "/foo") 1) 10) 12), right?

23:15 that looks like a job for reduce

23:16 Kowboy: sorry, the args after the url are parameters to a web service

23:16 amalloy: (reduce partial get-url ["/foo" 1 10 12])

23:16 Kowboy: I just used integers for readability

23:17 ie, (get-url "/foo" username password account-num)

23:18 amalloy: Kowboy: uh-huh...the type of the args doesn't really matter

23:18 Kowboy: so I'm making methods like (foo username password account-num)

23:19 well, hell, why don't I just link the code ;-)

23:22 this is my first attempt at useful clojure code

23:23 so be gentle ;-)

23:23 technomancy: clojurebot: arrows is http://ro-che.info/ccc/12.html

23:23 clojurebot: Ok.

23:25 amalloy: Kowboy: my point is why are you def-ing these to vars in the first place?

23:26 Kowboy: as opposed to?

23:28 amalloy: (def account-calls (into {} (for [[name url] {"character-list" "CharacterList" ...}] {name (partial account-call (str "/account/" url ".xml.aspx"))})))

23:29 i mean, your service is going to be going through a list of account-based calls anyway, and looking through vars won't do it any good - it will want a map or a multimethod anyway

23:30 Raynes: I was going to be clever and say "Your first mistake is using Mercurial." but decided against it, because I'm a nice guy.

23:31 Kowboy: I guess there's not much of an Emacs vs Vim flame here, so you have to go for the git vs Mercurial ;-)

23:31 brehaut: Raynes: you are only allowed to use that joke with people still using svn

23:31 Raynes: Kowboy: Don't tell me you're using Vim as well? God, I wont be able to contain myself.

23:32 Kowboy: no, I'm using emacs

23:32 Raynes: Highest of fives.

23:32 brehaut: Raynes: yeah he uses vi, hg, win, and lein

23:32 * Raynes runs off before he causes trouble.

23:32 * TimMc is using Pico Editor, which isn't even the editor you think it is

23:32 amalloy: hahaha

23:32 Kowboy: is there a lein debate?

23:32 amalloy: Kowboy: lein/cake

23:32 TimMc: It is the only sexp-aware editor I could find that uses C-s for save. :-P

23:32 brehaut: Kowboy: raynes is young and polarised :P

23:33 Kowboy: I know the type

23:33 brehaut: Kowboy: yeah, any nerd under the age of 55

23:33 the ones over 55 arent polarised, just stuck in their ways

23:33 Kowboy: hey!

23:33 I must be between the 2 then ;-)

23:34 I see your point amalloy

23:34 but I'm writing an api others may use, and I think they may only care about a subset of the functions

23:35 in which case they will probably want to call the functions by name

23:35 amalloy: Kowboy: i don't see why. they can write ((account-call "character-list") more-args)

23:36 and if you want, you can wrap that up in some defns with a macro

23:36 Kowboy: hmmm

23:36 amalloy: but the underlying functionality should be a map or a multi or something

23:37 Kowboy: a multi doesn't fit here does it?

23:37 unless you are talking about the different types of calls

23:37 amalloy: meh, i guess not

23:37 Kowboy: account, anonymous, character, etc

23:38 amalloy: yeah multi doesn't make a lot of sense here

23:38 Kowboy: I could wrap all those into one api call with multis

23:38 amalloy: but a map!

23:43 Kowboy: (derive ::character-list ::account-call)

23:43 I could use something like that for the dispatching

23:43 amalloy: Kowboy: maybe so

23:44 what's up with the http:/asdf.com ?

23:45 (the single slash)

23:45 Kowboy: I just recently learned about multis, so I may explore that

23:46 is there a shortcut version (macro) for derive that associates multiple child tags with a parent?

23:46 amalloy: Kowboy: just use doseq. you don't need a specific macro

23:46 Kowboy: wouldn't be much to write one

23:47 amalloy: it definitely shouldn't be a macro. a function is more than enough

23:47 Kowboy: yeah, not much to it really

23:48 just seems like something that would be pretty common

23:48 amalloy: Kowboy: not as far as i've seen

23:49 if you're defining a multi you usually expect methods to come from all over, so having a way to consolidate is not useful most of the time

23:50 Kowboy: you lost me there

23:52 amalloy: multimethods let anyone add methods at any time

23:52 brehaut: a multimethod that is not open to extension is probably better served by (say) cond

23:54 tomoj: defn: ##(.getPath (java.io.File. "foo//bar"))

23:54 sexpbot: ⟹ "foo/bar"

23:54 tomoj: &(.getParent (java.io.File. "http://google.com"))

23:54 sexpbot: ⟹ "http:"

23:54 tomoj: should be removed from the example as it's terribly misleading

23:54 amalloy: haha tomoj that is awful

23:57 brehaut: more likely case or a raw map than cond, but i agree with your general point

23:58 (not surprising since you were kindly making my point for me)

23:58 Kowboy: ok, chat with you guys later

Logging service provided by n01se.net