#clojure log - May 27 2013

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

0:00 bmentges: echo-area: Hmm thank you! I've seen this book in a lot of places and never gave it a try. I will look on it.

0:04 Shambles_: bmentges: The dirty, 'operational semantics', easy to understand explanation of recursion is: Imperative programs always create call stack frames when a function calls itself. This allows code after the recursive call (the 'continuation') to run.

0:04 bmentges: It's handy for when you want to 'try something, then back up and try something else if it didn't work' like the recursive maze solving algorithm.

0:06 bmentges: Functional programming languages usually don't create stack frames when there isn't anything to do after the recursive call returns (i.e. when there is no 'continuation'). This is called tail call elimination (or sometimes tail call optimization). Or to be a bit more direct about it, they use functions that call themselves to write loops, rather than having separate syntax for loops.

0:08 bmentges: If Clojure is giving you a hard time with recursion, but you understand what I just said, it may be because Clojure doesn't just let you write a function that calls itself and treat it as a loop. It has special syntax. The explanation I've heard is it has something to do with how the JVM handles security, and for that reason tail call elimination isn't safe to do automatically.

0:08 bmentges: The advantage is if you try to use Clojure's syntax in a non-tail-call way it will complain, so at least in theory it catches some errors.

0:08 bmentges: Shambles_: yeah, this exchange from loops to recursion is what keeps making my head spin... I am having a hard time on this issue and I can't solve some problems because I cant find a recursive way to answer it... its seems way harder than the old loop (for, while) way.

0:09 Shambles_: bmentges: Changing a straightforward loop into recursion is pretty easy.

0:09 bmentges: If you want a while loop (test at the start) stick a if-then test at the start of your function, and put the body of the loop in the "then" part.

0:10 bmentges: If you want a 'until' loop, stick the test at the end, and have the function call itself.

0:10 bmentges: For loops are just a special case of a while loop.

0:10 bmentges: That covers all the 'normal' loops.

0:12 bmentges: This might get me flamed if I said it in certain language channels, but it /may/ not be a good thing to use one notation to express two different things. That was the argument against GOTO. When you look at a recursive function it's not immediately obvious it's a 'loop'.

0:12 bmentges: Shambles_: thanks :) ... I know i must keep on going, when I solved the "reverse collection" koan, I had to look at (source reverse) and find out the (reduce conj () collection) solution... it's beautiful, it's simple, but I, right now, dont think I could get to that solution. I need to study more on clojure and its list / vector functions... maybe its just time and getting used to the language and its tools

0:13 Shambles_: bmentges: Non-self tail-recursive functions (e.g. A calls B calls A...) spread the control flow that /would/ be all in one place in normal loop syntax throughout the various functions.

0:14 bmentges: As for why functional programming languages do it that way, it's because they don't have much choice if they want to avoid mutation. They use 'call yourself with the arguments we just calculated' to express the 'change these variables' parts of the loop that lets the loop terminate. It's not so much because it's /pretty/ as because it's the only way to stay in the paradigm.

0:15 bmentges: As for the argument for why it may be better to use mutations in these contexts, see things like the loop contracts in Eiffel that will throw a nice exception for debugging if your loop goes off the rails, by checking the loop variant and loop invariant assertions on each pass.

0:17 bmentges: For what it's worth, Clojure (and most Lisp's) lets you use mutation when you want. It just makes it not-the-default most of the time, which I /do/ think is a good idea. Mutation should be used sparingly, to maintain your sanity. Mutation is what makes global variables problematic.

0:18 bmentges: I hope that helps.

0:18 bmentges: Shambles_: Thank you for the explanations, it helped me a lot to better understand the functional paradigm

0:19 Shambles_: and I think you nailed it. I wasnt understanding the recursive as ways to represent loops...

0:20 Shambles_: bmentges: Right now functional is 'in'. Folks that are old enough are chuckling, because there was a time in the past when it was popular (mostly in the form of Lisp) commercially. The truth is the real benefit of functional programming is it makes testing/debugging code simpler, and multithreading much easier.

0:21 bmentges: And you could achieve the same things in conventional imperative programming languages by keeping all your functions pure /from the external world point of view/ (mutate locals to your heart's content, just ONLY locals, and arguments are not locals!), and refusing to mutate anything on the heap. Keep your global variables few. You'll need at least one to pass state between event handlers.

0:21 bmentges: :)

0:22 Shambles_: bmentges: In another 15 years it'll probably be logic programming or push-dataflow that's supposed to save the industry. ;)

0:22 And at one point (in the 80's) Prolog was supposed to do that, though I don't think it ever got that popular in business, unlike Lisp, well, outside Japan anyway.

0:23 bmentges: now im going to go back to clojure study... I'll try to use what you taught me :)

0:23 thanks

0:23 Shambles_: Have a good night.

0:44 akurilin: Quick question: is there some kind of construct that'd be more elegant than tested if-lets? Basically I'd like to check if the first binding is true, and if so do the same check for a second binding and so on

0:53 brehaut: theres a monad for that

0:53 several infact

0:53 possibly also an applicative functor

1:03 akurilin: brehaut, I'm not familiar with the concept. Could you point me in the right direction so I could start looking into understanding it?

1:03 brehaut: http://www.clojure.net/2012/02/13/Maybe/

1:06 akurilin: Great, thanks!

1:31 Quick compojure/rest question. Is 400 the right code to return for a POST-initiated creation of a resource that is missing mandatory attributes for the creation to be successfully completed?

1:31 403 sounds a bit too authorization-specific

1:32 amalloy: akurilin: 400 looks right to me

1:32 akurilin: amalloy, do you ever get the feeling that 400 is almost like a big catch-all bucket for all sorts of very different errors?

1:33 Seems like HTTP mostly gives you 2 options: you are not authorized, or the request cannot be completed for some other issue that's not a server problem (that'd be under the 5xx)

1:34 akhudek: akurilin: and really, you are not authorized should be used sparingly

1:34 it tells potential attackers that there is something there to attack in the first place

1:35 dobry-den: are there any resources for how to organize FP code? i have some books on OOP design that i love, but i'm sucking as at my FP design

1:35 akurilin: That's a good point. Even error messages themselves returned in the body of a 400 can be very helpful to attackers, right?

1:36 akhudek: akurilin: that's right.

1:36 akurilin: akhudek, I imagine a good strategy is to just give everybody a blanket 403 if they're trying to hit a route that requires authentication they don't have, regardless of whether a corresponding resources exists or not. Would that work?

1:37 akhudek: akurilin: though for a public API it would be ok to give errors related to the public api itself. In general, you should just return 404 for private routes that people shouldn't access unless logged in.

1:37 Preferebly the exact same 404 used throughout your app.

1:38 dobry-den: I have no good resources to point you to, but what helped me was to look at every function larger than 2-3 lines and ask myself if I can't refactor it into multiple functions that are smaller.

1:39 akurilin: Fair enough. I'll definitely have to spend some time making less helpful error messages. Odd thing to say, but I guess that's the price to pay for increase security.

1:41 r0bgleeson: i'd argue you shouldn't do that, there's no need to obsure your API and not be semantic in the interest of security. the 404 for a private route makes sense, but if parameters are missing or the body is unparseable, it makes sense to behave like a sensible API and tell the client whats wrong.

1:44 akhudek: r0bgleeson: I'd agree with that. Public api's are public anyways.

1:44 dobry-den: akhudek: that's actually my problem. i find it trivial to unroll functions into smaller functions with the functional code i end up with in clojure. but then my file gets really aimless and it's hard for me to draw the lines

1:45 akhudek: dobry-den: try to separate it into logical namespaces

2:26 arrdem: is there a good way to detect what namespace is invoking your code?

2:27 I'm trying to come up with a clean way to associate .html fragment files with a clojure namespace :/

2:33 mthvedt: arrdem: *ns* ?

2:37 arrdem: mthvedt: that's what I'm hacking on now :/

2:39 mthvedt: yep, (:name (bean *ns*)) and some regexes...

3:10 callen: dobry-den: I paint with a big brush.

3:36 yunfan: the korma library's document made me confuse

3:52 dabd: I am invoking 2 external commands using clojure.java.shell. How can I make sure the second command is executed only after the first has finished? Thanks

3:52 augustl: dabd: a queue could work

3:54 dabd: can you elaborate

3:58 i think i can use future for this

3:58 (future command1) then deref it so it blocks if the command has not finished. Then command2

3:59 augustl: dabd: if you put the operations in a fifo queue, they'll execute one at a time

3:59 yunfan: anyone could give me an example of using sqlkorma doing (-> create-db build-tables insert-records selecting-stuff ... )

3:59 augustl: and it's easy to add a third command when you need that

4:00 dabd: but how exactly?

4:00 yunfan: want to build my first website with clojure

4:01 ucb: dabd: can you not do something like (doseq [[cmd args] [all-cmds]] (apply cmd args)) for instance?

4:02 dabd: you'd then have all-cmds be something like '(['some-cmd '(arg1 arg2...)] ...)

4:02 dabd: but do i have the guarantee they are executed in sequence given they are launched in different threads?

4:02 ucb: dabd: where 'some-cmd is a function that receives parameters and executes cmd using java.shell

4:02 dabd: doseq is not multi-threaded afaik

4:03 ,(doc doseq)

4:03 clojurebot: "([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."

4:03 ucb: ,(doc doall)

4:03 clojurebot: "([coll] [n coll]); When lazy sequences are produced via functions that have side effects, any effects other than those needed to produce the first element in the seq do not occur until the seq is consumed. doall can be used to force any effects. Walks through the successive nexts of the seq, retains the head and returns it, thus causing the entire seq to reside in memory at one time."

4:07 dabd: this seems to work @@(doall [(sh/sh "sleep" "5") (println "hello")])

4:07 how to evaluate expressions inlline?

4:07 augustl: dabd: you should perform the work inside the block, not in the bindings

4:08 dabd: i am using doall no bindings

4:08 can't i use doall instaed of doseq?

4:08 augustl: dabd: for example, (doall [n (repeat 2)] (sh/sh "sleep" "5") (println (str "Hello from " n)))

4:09 dabd: but doall accepts no bindings

4:10 ucb: if you're going to go down that route, why not just (do ...) ?

4:10 dabd: yes do seems simpler

4:10 augustl: dabd: ah, you're right

4:11 dabd: and do serves perfectly

4:12 augustl: doall is for realizing lazy sequences

4:14 dabd: yes for some reason I was convinced that sh would run in parallel with with a sequence of expressions using do

4:14 ucb: (do ...) is fine if you don't need to keep track of the return values, etc.

4:21 mindbender1: how do I make a namespace globally referred?

4:23 Raynes: Don't. Stop.

4:24 callen: ^^

4:24 Raynes: Oh hi callen. Are you in Los Angeles yet?

4:24 callen: Raynes: no, thinking of driving up tomorrow.

4:24 mindbender1: You mean that's a bad idea?

4:24 callen: Raynes: would you be up for hanging out tomorrow night?

4:24 Raynes: mindbender1: Horrible one.

4:24 callen: mindbender1: correct. don't.

4:25 mindbender1: Just for dev I want clojure.repl to walk with me

4:25 Raynes: callen: It's after 1AM. Is 'tomorrow' Tuesday, or Monday night?

4:25 :p

4:25 mindbender1: how do I do that?

4:25 callen: Raynes: sorry for ambiguity - Monday.

4:26 Raynes: callen: Sure. What do you want to do?

4:27 mindbender1: I don't want to have us to (:use 'clojure.repl) at each namespace I move to

4:27 Raynes: mindbender1: I think you technically cannot have it referred in every single namespace.

4:27 callen: Raynes: what I always do, eat and talk. I'm into coffee, wines, sake, tea, food, etc.

4:27 Raynes: I mean, you could hack things to shit.

4:27 callen: Raynes: I'm sure having a fresh territory to subject Yelp to might be fun.

4:27 mindbender1: ok

4:27 callen: Raynes: open to suggestions as well

4:28 Raynes: callen: Sure, we can go eat things. I'm about as knowledgeable about places serving food here as you are though.

4:28 callen: You've never been to the third street promenade?

4:29 We can go there and hunt a place to eat. Maybe hop down to the beach.

4:29 callen: Raynes: never been to anywhere in LA. That sounds good.

4:29 Raynes: callen: Did you decide where to stay yet?

4:30 callen: Raynes: probably the hotel, I might change my mind tonight or tomorrow morn.

4:30 Raynes: Where is the hotel?

4:31 callen: Raynes: uhm, it's the hilton between west la and hollywood. don't remember exactly, have to bring up bookmark.

4:31 Raynes: No worries.

4:31 Was wondering about general area.

4:32 I should be on your way to the promenade. You can either hop by and pick me up (I'll give you a tour of my vast, empty apartment) or I can bus down there and meet you.

4:33 callen: Raynes: I'll pick you up, not much point in owning a passenger car if I can't use it to spare people the agony of public transport.

4:33 Raynes: Appreciated. <3

4:37 callen: If you enjoy movies, there is a reasonably nice theater on the promenade as well.

4:40 Hollywood is also a fun area to play around in. You can go skip along the walk of fame.

4:40 And dodge tourist projectile vomit, possibly.

4:42 I don't know how long you're staying, but Malibu is pretty great if you want to hop down there one day. Point Dume is all kinds of pretty.

4:42 I'd happily do it with you (very excitedly so) if I didn't have to do that pesky work thing all week.

4:43 callen: hrm.

4:43 Raynes: heh, much appreciated.

4:49 Raynes: I did want to visit Hollywood and poke around.

4:49 Raynes: I've got a couple of clojurians I'd like to meet while I'm in town too.

4:49 Raynes: Factual guys?

4:49 :D

4:50 They're fun.

4:51 callen: I'd like to, I was actually thinking of santiago.

4:52 Raynes: Also good guy.

4:52 :D

4:52 I'm sure he'll share your sadness with templating engines, callen.

4:52 I can't give that to you. I can only give you the promenade.

4:52 :p

5:12 callen: Also, http://www.youtube.com/watch?v=qplBVqPhbBY

5:13 NSFW though. Just the content of the vocals.

5:13 That's a warning to non-callen people.

5:13 callen's a man, he can take it.

5:14 callen: fucking lol

5:14 Raynes: Except that was sexist and I didn't realize it.

5:14 So, to clarify, callen is a rough around the edges person and thus can take it.

5:14 :D

5:18 callen: Raynes: I'm having a hard time getting past the band. I don't usually like these people.

5:19 Raynes: callen: I'm not a fan either. This particular song is just so outrageous that I can't help but enjoy it.

5:20 callen: I definitely see what you mean.

5:20 Or hear.

5:20 Raynes: callen: I'm a fan of shock music and comedic songs.

5:21 ucb: Raynes: do you like The Tiger Lillies?

5:21 callen: somehow I am not surprised they're from LA

5:21 Raynes: I have never heard of this before.

5:21 callen: So is everything.

5:21 ucb: Raynes: http://www.youtube.com/watch?v=zhrGspR0yQo perhaps of interest

5:22 callen: Raynes: well except for the stuff from SF and NYC.

5:22 Raynes: callen: Sure, you can have your 3 good bands.

5:22 ~guards

5:22 clojurebot: SEIZE HIM!

5:22 Raynes: ucb: Okay, good work, I lost it when he started making sounds with his face.

5:23 ucb: Raynes: heh

5:24 Raynes: callen: http://www.youtube.com/watch?v=Owk5YXluv9M You may enjoy this.

5:24 And they're from Vegas (like all my favorite bands, I guess).

5:25 r0bgleeson: Raynes: i like that

5:25 Raynes: :D

5:26 * ucb goes back to listening to Alice in Chains

5:26 Raynes: r0bgleeson: One of the comments on that video: "Shake that tambourine you perfect little bitch"

5:26 o.o

5:26 callen: LOL

5:26 Raynes: Why oh why do I read youtube comments.

5:26 callen: making me choke on my sake

5:27 Raynes: lol

5:28 callen: I am excited to my very bones about Nico Vega and Imagine Dragons on Wednesday.

5:28 Thoroughly tickled, in fact.

5:29 r0bgleeson: Raynes: haha

5:29 callen: I haven't been to a big concert in ages, really looking forward to it.

5:30 Raynes: callen: A buddy took me to a KMFDM concert. Was my first concert. I couldn't hear for a day. I ended up in a mosh pit for hours.

5:30 callen: Those sorts of concerts are always fun.

5:30 Industrial for a first concert is a good way to begin.

5:30 Raynes: Before taking me to it he actually told me in the car, and I quote, "I'm popping your concert cherry in a fuckin' BRUTAL fashion, bro.". This was an accurate statement, I later learned.

5:30 callen: I'm envious.

5:31 best show I've been to in the past few years was WITTR

5:31 most bombastic show was probably this winter line up years ago of numetal bands. T'was nuts.

5:32 Raynes: Holy shit, Hayley Williams did a cover of Use Somebody http://www.youtube.com/watch?v=Re_gJkRkHLQ

5:32 Surprised I haven't seen this.

5:34 ddellacosta: How do you execute raw SQL query/insert using clojure.java.jdbc? Alternatively, how do I use range types using clojure.java.jdbc?

5:35 Raynes: I don't know what 'raw' means.

5:35 You mean how do you execute SQL strings?

5:36 ddellacosta: Raynes: yeah, sorry, that's what I mean.

5:36 Raynes: No worries, just clarifying.

5:36 * callen squirms in his chair and tries not to interject

5:36 ddellacosta: callen: why are you not interjecting? haha

5:36 Raynes: ddellacosta: Well, to start off, callen wants to yell KORMA! at your face.

5:36 callen: Raynes: I used to date a girl obsessed with Paramore...that's all I have to contribute at this time. Movie at 10.

5:37 Raynes: I'm going to actually help you.

5:37 callen: yeah I'm definitely not here to help anybody. But I will fwack a noobie over the head with refheap when they link pastebin.

5:37 ddellacosta: haha

5:37 Raynes: :p

5:37 callen: Raynes: I really like this cover.

5:37 Raynes: I really like Paramore.

5:38 ddellacosta: btw, I don't care if I use Korma or clojure.java.jdbc at this point, I just want to be able to manipulate freaking range types using Clojure somehow.

5:38 Raynes: I haven't done enough SQL to know what a range type is, so can't help you there

5:39 ddellacosta: http://www.postgresql.org/docs/9.2/static/rangetypes.html

5:39 callen: Raynes: have I linked you the boss yet?

5:39 Raynes: in case I've failed at life: http://www.youtube.com/watch?v=xzQvGz6_fvA

5:39 ddellacosta: Postgres specific I guess.

5:39 Raynes: You linked me to this, callen.

5:40 callen: good, I'm not a total failure then.

5:40 Raynes: ddellacosta: Actually I'm using an old version where this was easy and they've changed everything to make it impossible to figure out.

5:40 callen: ddellacosta: you'll have to write something regardless, the question becomes is where you want it to live.

5:41 Raynes: So not sure I can help you after all.

5:41 callen: I'm always in favor of people writing toys for Korma.

5:41 Raynes: Ah!

5:41 ddellacosta: Raynes: no worries!

5:41 Raynes: ddellacosta: http://clojure.github.io/java.jdbc/#clojure.java.jdbc/query This is for querying with strings.

5:41 callen: I've been pondering 'partition by' of late.

5:42 ddellacosta: callen: yeah, I've come to that conclusion. Right now we are pretty jdbc heavy, which is why I'm leaning in that direction.

5:42 Raynes: thanks. Actually I tried that but can't figure out how to properly format the range types so that it doesn't complain. :-(

5:42 callen: ddellacosta: well, the thing is, I understand how Korma works well enough to know how to generate the kind of SQL postgres uses for this

5:43 ddellacosta: but cjj not so much.

5:43 ddellacosta: callen: gotcha…just my luck. haha

5:43 callen: sorry I could avoid being perpetually useless. It must be my karma.

5:43 couldn't*

5:43 ddellacosta: but at least you've put a bug in my ear.

5:43 ddellacosta: callen: or would that be your KORMA OH I KILL ME sorry it's been a long day

5:43 callen: now I've got two things I want.

5:43 ddellacosta: LOL. Cheers. :)

5:44 ddellacosta: haha

5:44 yeah, I mean, when I get to this point usually it's good to take a step back and think about what I'm trying to do and the best way to approach it. But thank you, seriously!

5:45 callen: ddellacosta: the only concern I have is that people might get upset if I start shitting up Korma with my personal toys.

5:45 ddellacosta: (I'm a PG user too)

5:45 (so I therefore want to use the goodies PG includes)

5:46 ddellacosta: callen: ah, haha…well, yeah, I mean what about a PG-specific Korma extension? I feel like I know a lot more folks using PG in the Clojure community than…other stuff, but that's probably confirmation bias.

5:46 that and Datomic of course

5:46 Raynes: I use mongodb.

5:46 Nobody likes me.

5:46 ddellacosta: haha

5:46 it's okay Raynes. We still like you. ;-)

5:47 callen: I used to use MongoDB for side projects and some less-side ones, but I decided I should pretend to care about my data.

5:47 ddellacosta: It just seems like everywhere I got someone is bashing MongoDB. I honestly don't know enough about it to say though

5:47 callen: ddellacosta: well, thanks to how awful MySQL is, there's a precedent in Korma for db-specific namespaces and functions.

5:47 ddellacosta: got -> go

5:47 callen: it's a very small and limited precedent, but there you go.

5:47 ddellacosta: yeah, unsurprising. I mean, to be fair most every database has it's own specific stuff I suppose.

5:48 callen: ddellacosta: MongoDB is really nice for rapid prototyping without having to cope with migrations. it works fine more often than its detractors like to indicate. It's still a bad idea for things you give a damn about.

5:48 Korma is a much smaller library than most people seem to think, there's very little that is db specific beyond the connection stuff and that stupid MySQL thing.

5:48 Raynes: I give some damns about refheap pastes.

5:48 I have automated backups all the time.

5:49 ddellacosta: callen: interesting. I will have to check it out. The only "NoSQL" (shivers) db I've used in any depth is CouchDB, which seems interesting, and GAE's Big Table, which I found frustrating for reasons unrelated to its performance (GQL can die).

5:49 callen: ddellacosta: also Refheap doesn't need to "scale" and doesn't have any ACID requirements, so it's fine there.

5:49 Raynes is smart and does automated backups, so he's not likely to get bit.

5:49 Raynes: Refheap can totally scale.

5:49 callen: unless he's only rsyncing the filesystem, then he will have a problem.

5:49 Raynes: dump snapshots right?

5:49 Raynes: callen: Snapshots stored on the same machine. :D

5:49 Now everyone really hates me.

5:50 ddellacosta: yeah, the main thing I've heard as a criticism is that MongoDB can be tough to manage if you don't take precautions to properly index, and yes, backup

5:50 callen: ddellacosta: I've done a lot of 'scale' ish stuff and NoSQL. I've written long long comments comparing the various NoSQL solutions on HN. CouchDB and GAE are very bad representatives for the category.

5:50 Raynes: (Planning to also set up backups to another machine asap)

5:50 callen: Raynes: just set up a cron rsync.

5:50 ddellacosta: interesting.

5:50 callen: Raynes: takes like 5 minutes broskie.

5:50 ddellacosta: in general, NoSQL is about specialization and using the right tool for the right job.

5:50 Raynes: callen: Did you see the new refheap features?

5:51 callen: ddellacosta: like Kafka, which is a job queue rather than a message queue. Too many people try to use message queues as job queues, and they fall over.

5:51 Raynes: no, vut?

5:51 Raynes: callen: https://www.refheap.com/15050 Look at the URLs.

5:51 No more */paste/*

5:51 ddellacosta: callen: yeah, sounds appropriate. I know SQL/Postgres well enough that I haven't needed anything else…yet.

5:51 Raynes: Shorter URLs.

5:51 callen: ddellacosta: or Cassandra, which is excellent for super-sparse schemas, fat datum, and high write availability.

5:51 Raynes: Also, counting views.

5:51 callen: Raynes: oh sweet.

5:51 Raynes: A new page to display all forks of a given paste.

5:51 callen: ddellacosta: MongoDB and RethinkDB are good for JSON'y doc stores when you need rapid prototyping.

5:52 ddellacosta: callen: oh, I just heard someone raving about Cassandra the other day, gotta check that out too.

5:52 callen: ddellacosta: Riak is a dynamo-esque KV store that shards and replicates very easily.

5:52 ddellacosta: uhm, well, just try to realize that most NoSQL stores aren't something you can "appreciate" in the small.

5:52 Raynes: callen: And my personal favorite, anonymous users can delete and edit pastes and if you create pastes anonymously and then log in later, they get associated with your account!

5:52 ddellacosta: called, Raynes: this was interesting, did you see it? My boss showed me the other day: https://wiki.postgresql.org/images/b/b4/Pg-as-nosql-pgday-fosdem-2013.pdf (warning, kinda potentially flamebaity)

5:52 callen: ddellacosta: for the most part, anyway. you need a NoSQL'ish problem to solve before it makes a ton of sense. Except for MongoDB/RethinkDB which are very accessible.

5:53 ddellacosta: I'm familiar with the PG as NoSQL meme, it misses the point in the extrmee.

5:53 extreme*

5:53 ddellacosta: it just changes around the schematization requirements and querying semantics without changing the core storage engine behavior, which is much more to the point. Cf. what I said about high write availability.

5:53 also HStore is awful.

5:54 JOINs with highly normalized schemas are faster by default in Postgres :P

5:54 ddellacosta: callen: ah, good to think about. I like reading these kinds of pieces, but I like hearing from people with an educated counterpoint too.

5:55 callen: ddellacosta: I've done some OLAP/hadoop stuff before as well.

5:55 ddellacosta: callen: that's awesome. I really need to get more experience with some of these systems, I just haven't had the chance yet. Thanks for the summary though, this is useful.

5:56 *sigh* alright, speaking of Postgres, I guess I better get back to this mess...

5:56 callen: ddellacosta: another good example of a "NoSQL" use-case would be an API exposing aggregate data across analytics comprising 10+ TBs but response times need to be 10 ms or lower. Obviously you can't COUNT(*), so you have an OLAP system asynchronously and continuously doing data roll-ups across date/column/etc and caching the data in a KV store or database.

5:56 ddellacosta: cheers and good luck.

5:57 incidentally, DataStax has a super-handy stack for the above use-case.

5:57 ddellacosta: callen: thanks! Thanks again for the info and help. Good stuff.

6:01 Raynes: callen: Do you want my phone number or something or will you ping me on IRC tomorrow when you get to LA?

6:01 callen: Raynes: lets do a phone number

6:28 mthvedt: so i guess there's a bug where if you have a delay within a delay, locals will be randomly set to nil without warning.

6:29 would have been nice to know that several hours ago

6:30 i guess it's if one of the delays throws an exception

6:34 amalloy: mthvedt: the nested-ness of delays is irrelevant

6:34 $google clojure jira delay npe

6:34 lazybot: [[#CLJ-1175] NPE in clojure.lang.Delay/deref - Clojure JIRA] http://dev.clojure.org/jira/browse/CLJ-1175

6:35 mthvedt: amalloy: i was looking at http://dev.clojure.org/jira/browse/CLJ-1053?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel

6:36 callen: bahahaha, found a prismatic bug

6:36 [95, 86, 100, 105, 122, 88, 122, 97, 92, 81, 127, 75, 68, 117, 79, 100, 110, 82, 99, 102, 117...

7:25 sandbags: okay now i understand why paredit is useful, first time i've needed to move one form inside another and...

7:28 if i need, say, 64 somethings i tend to do "(map #( ..generate a something..) (range 64))" is that idiomatic?

7:30 xificurC: sandbags: maybe have a look at repeatedly

7:30 sandbags: xificurC: so something like (take 64 (repeatedly #(..)))

7:30 ah, or (repeatedly 64 #(..))

7:31 xificurC: sandbags: yes

7:31 sandbags: nice, thanks

7:31 xificurC: glad to help

7:40 clgv: sandbags: or (repeat 64 ...) if there are no sideeffects

7:41 sandbags: clgv: thanks... turns out i actually need an index so i've had to go back to map/range

7:42 xificurC: how do you switch parenthesis style with paredit, e.g. you have (a b c) and you want [a b c]

7:46 hyPiRion: well, this is how I tend to do it

7:49 |(a b c), '[': |[](a b c), 'C-f': [|](a b c), 'C-)': [|(a b c)], 'C-f': [(|a b c)], 'M-s': [|a b c]

7:49 There's probably a better way though

7:51 xificurC: hyPiRion: thanks

7:51 clgv: hyPiRion: recording that into a macro and giving that macro a shortcut?

7:52 hyPiRion: clgv: hmm, I don't tend to use it frequently though. But not a bad idea

7:53 Just omit the first step ('[') so that you can arbitrarily pick delimiters

8:01 xificurC: or get it in paredit :)

8:09 hyPiRion: heh

8:26 sandbags: i've just taken a first stab at implementing random boolean networks using Clojure. I'm a CLJ beginner and would appreciate any constructive criticism about my code, thanks https://gist.github.com/mmower/10ca3d5acaf7a8033916#file-gistfile1-txt

8:27 (it's only 50 lines or so... there's not reams of it :))

8:28 Ember-: sandbags: looks quite good imho. I think though that it's irrelevant to define and-oper and or-oper

8:29 hyPiRion: sandbags: #(:state %1) could be replaced with :state, #(make-cell %1) could be replaced with make-cell

8:29 Ember-: `or` and `and` are macros though, you can't pass them around and call them

8:30 Ember-: ah, very true

8:30 sandbags: Ember-: thanks, yes as hyPiRion said I needed those to avoid the macro issue

8:30 hyPiRion: ah yeah, thanks

8:30 is there anything particularly un-idiomatic?

8:30 Ember-: nothing that strikes out into the eye immediately at least

8:30 sandbags: i've spent 8 years in Ruby so although I am familiar with a lot of list operations, functional style is very new to me

8:31 ta

8:31 augustl: sandbags: "size" is unused, in evolve-network

8:31 hyPiRion: sandbags: well, there are some few things, although not unidiomatic I would say

8:31 sandbags: augustl: yep

8:31 augustl: well spotted

8:31 hyPiRion: mind if I fork and give my take on the same problem?

8:32 sandbags: gonna have to get used to keywords being functions

8:32 hyPiRion: i'd be grateful if you would

8:32 augustl: seems there's a general trend towards using "let" a lot when you're new (I'm including myself in that set), but more experienced clojure programmers use destructuring and threading macros and stuff

8:32 Ember-: augustl: I was just about to say the exact same thing :)

8:32 sandbags: one thing i do need to do is add a structure for the network itself

8:32 clojurebot: Alles klar

8:32 Ember-: that I'm going more for threading macros and destructuring these days instead of let :)

8:33 been writing clojure full time since last december now

8:33 sandbags: yeah i've been watching stuart holloway & neal fords videos and they introduce the -> and ->> macros ... quite an eye opener

8:33 Ember-: hadn't really done any clojure before

8:33 or well, clojure AND javascript :)

8:33 augustl: such as using (let [[x & xs] list]) instead of (let [x (first list) xs (rest list)])

8:33 sandbags: my next step is to CLJS this and draw it using raphel.js

8:35 Chousuke: hmm

8:35 sandbags: this actually turned out quite tidy, i can even almost read it back :)

8:35 Foxboron: augustl: might be because destruction is a bit more "advanced" and takes more time to master then let, which is simple.

8:36 Ember-: complex destructurings can get a bit unreadable imho

8:36 augustl: it's nice to avoid having to name everything :)

8:36 Chousuke: that code has mostly stylistic issues except for the unnecessary hash-map call in evolve-cell

8:36 sandbags: Chousuke: unnecessary?

8:36 Chousuke: it could be replaced with (assoc cell :state new-state)

8:36 sandbags: ah

8:36 nice

8:37 oh that's cute, yes, thank you

8:37 Chousuke: that way, cell and its new version will also share the unchanged structure

8:37 sandbags: beautiful

8:38 that also resolves my problem with wanting that to share code with make-cell-fun

8:39 Chousuke: in that function, using a literal map instead of the hash-map function would be more idiomatic I think but either is fine

8:40 sandbags: right

8:41 jtoy: do i need to do anything special to be able to call any method from the commandline to a project that I uberjarred ?

8:41 sandbags: so here's v2 https://gist.github.com/mmower/10ca3d5acaf7a8033916#file-gistfile1-txt

8:41 hyPiRion: sandbags: oh, here's my take

8:41 https://gist.github.com/hyPiRion/3704bbe71921b73e694d

8:42 Just noticed people commented on stuff here too, hrm.

8:42 augustl: jtoy: with the "java" cli you mean?

8:42 sandbags: hyPiRion: thank you

8:42 ah, rand-nth is going to save me so much time :)

8:43 ab

8:43 n

8:43 ah, you use for

8:43 hyPiRion: sandbags: yeah. Believe me, it's very weird to do it in the beginning

8:43 sandbags: i defn have to remember to use assoc

8:44 hyPiRion: yeah... watching Holloway using 'for' i was a bit non-plussed... i don't really like the DSL part of it at first glance

8:44 jtoy: augustl: what is the java cli? I am just trying to productioniez my code, typically i have just ran the repl and call my methods by hand, but i want to have the methods be calling from the cli

8:44 hyPiRion: sandbags: well, you can use `map` for it if you'd like, though it actually is convenient at times

8:44 sandbags: i guess it's one of those things that, as a beginner, i should force myself to use it until i can decide from an informed perspective

8:45 hyPiRion: ,(for [x [-1 0 1], y [-1 0 1] :when (not= x y)] [x y])

8:45 clojurebot: ([-1 0] [-1 1] [0 -1] [0 1] [1 -1] ...)

8:45 sandbags: hyPiRion: yeah i saw that example in the O'Reilly clojure book and I can see the utility

8:45 hyPiRion: the cheatsheet's always handy, I think: http://clojure.org/cheatsheet

8:45 sandbags: perhaps i just need to get used to seeing it

8:46 hyPiRion: Well, unless you do "for all elements in x and all elements in y..." it's completely possible to do just a simple map

8:46 augustl: jtoy: just trying to understand your question :) By "the java cli" I'm referring to the "java" command. I'm not sure how to invoke arbitrary methods, I'm only familiar with the options you need to pass in order to invoke the "main" of some class

8:46 sandbags: is there some convention about whether to put function args on the same line as the func name, or on a sep line?

8:47 Chousuke: not really

8:47 augustl: sandbags: I put them on a separate line.. It scales better for enterprisey function names :P

8:47 sandbags: augustl: :)

8:47 Chousuke: just do whatever looks good

8:48 sandbags: cool

8:48 ah rand-nth is my savouir

8:48 Chousuke: but try not to forget the space after function name and the argument vector :P

8:48 mefesto: this is an etiquette and naming convention question. if i fork a project and send a pull request, is it bad manners to upload a temp build to clojars under your own group-id? also, how would you specify the version for it if it's based on v1.0 would you put 1.0-SNAPSHOT or 1.0-mypatch-name? I'd like to make use of my changes while the pull request is being evaluated. i could install it locally but i'd like other people im working with

8:48 to not have to know that they need to install this or that locally

8:48 Chousuke: I sometimes see (defn foo[a b c] and it's really annoying for some reason

8:48 +)

8:49 sandbags: yeah that looks not right to me too, but i am in general, a fan of ws

8:49 perhaps unusually among rubyists i tend to favour spaces inside parens and so on

8:49 ah damnit, i think i've managed to screw up defn again

8:50 this is the one serious problem i've had with LightTable so far

8:50 occasionally it evals half a form and screws up something essential

8:50 Chousuke: in Haskell I find it amusing how defining functions like (a,b,c) -> d allows you to call them as f(1,2,3)

8:50 augustl: mefesto: why add temp build to clojars though? It's pretty easy to set up your own mvn repo

8:51 foodoo: sandbags: So LT has overwritten "defn" with some other value?

8:51 sandbags: foodoo: i'm not entirely sure but i was getting "unknown symbol defn" errors

8:51 hyPiRion: mefesto: Hmm, never heard of people doing that. I would assume it's okay as long as it's with a different group-id. I would assume you use the same SNAPHOT-version as the project SNAPSHOT version.

8:52 foodoo: sandbags: (use 'clojure.core) is part of the file?

8:52 mefesto: augustl: my only experience with maven has been through leiningen. how do you setup your own mvn repo? is it just a web server with a copy of your ~/.m2/repo dir ?

8:52 sandbags: foodoo: no

8:52 i fixed it by closing & re-opening the file a couple of times

8:52 augustl: mefesto: it's useful to learn how to set up a http://www.sonatype.org/nexus/

8:52 mefesto: it's free, and you just need to add :repositories entries to your project.clj

8:53 there are probably less enterprisey repo solutions too, but nexus is pretty standard, and pretty easy to set up (just run a shell script on your server)

8:53 mefesto: augustl: thanks! i'll look this over

8:54 augustl: mefesto: one common setup is to have all the dependencies you use downloaded into sonatype, as well as your in-house proprietary dependencies

8:54 it lets you deploy and build even if central repos are down

8:55 mefesto: augustl: im guessing it's nexus oss?

8:56 augustl: mefesto: probably :) Don't remember..

8:58 mefesto: augustl: definintely looks easy to setup. thanks again. this will help keep me from polluting clojars :)

8:58 augustl: ^^

8:59 maksim_: Hello, is there a quick way to have clojure mode working on emacs ? any link or something ..

9:00 augustl: maksim_: are you new to emacs?

9:02 mefesto: maksim_: use elpa which is included with the latest emacs. M-x list-packages

9:02 maksim_: then search for clojure-mode and install by typing: i then x

9:04 or i guess you could do M-x package-install clojure-mode

9:07 which reminds me. is there a command for listing emacs packages that need to be updated? analagous to to homebrew's `brew outdated`

9:10 maksim_: augustl: am relatively new

9:10 am trying to learn emacs in parallel with clojure

9:12 Foxboron: maksim_: i am doing the same :)

9:12 mefesto: maksim_: what version of emacs are you using?

9:13 augustl: maksim_: http://edward.oconnor.cx/2009/07/learn-emacs-in-ten-years :)

9:34 maksim_: in 10 years!!

9:36 sandbags: thanks for your help hyPiRion, Ember-, Chousuke, augustl, foodoo - much appreciated

9:36 hyPiRion: no problem sandbags, happy to be of help

9:36 augustl: what hyPiRion said!

9:37 sandbags: augustl: nice to see another refugee from the ruby world :)

9:37 augustl: sandbags: ^^

10:34 loliveira: could anybody help me with a bizarre problem? I am using [cheshire "5.1.1"], and everything works just fine in my development environment. But in production, I am having the following error: crawler.core=> (cheshire.core/parse-string "")

10:34 ArityException Wrong number of args (5) passed to: parse$parse clojure.lang.AFn.throwArity (AFn.java:437)

10:35 I already deleted all jars in ~/.m2/repository and the error still occurs. =(

10:35 mefesto: is your local env running a clean build?

10:35 loliveira: yes

10:35 mefesto: is production running clean as well?

10:35 loliveira: yes.

10:35 mefesto: not just .m2/repo but `lein clean && lein uberjar`

10:36 loliveira: i downloaded i fresh copy from git.

10:36 I downloaded one fresh copy from git*

10:37 mefesto: that sounds good but you never know. if someone doesn't have a proper .gitignore then artifacts that shouldn't have been committed -- might in fact be in the repo

10:37 a lein clean is a safe and easy thing to try

10:37 loliveira: here is the stack trace: https://www.refheap.com/15062

10:37 mefesto: the whole `works on my machine` comment makes me think it's a dirty build

10:38 if you have a local repl i'd kill it, do a lein clean, then start a fresh repl

10:38 i'd expect your local env to then get the same error

10:38 loliveira: wow

10:39 lein clean resolved.

10:39 \o?

10:39 mefesto: cool probably an old artifact laying around.

10:39 loliveira: thank you

10:39 noahlz: I saw odd errors like this when I was seq'ing a string

10:40 so {"a":1} got turned into \{ \" \a \" etc. and passed to parse

10:40 but maybe not relevant

10:40 (also working on a json -> clojure thing here)

10:40 Am I missing something or is there no way to destructure from a map that has string keys

10:41 loliveira: (let [{:strs [a b c]} map))

10:41 noahlz: right.

10:41 ##(let [m {"x" 1 "y" 2} x (get m "x") y (get m "y") ] [x y])

10:41 lazybot: ⇒ [1 2]

10:41 hyPiRion: noahlz: it's possible

10:42 ,(let [{a "a" b "b"} {"a" 1 "b" 2}] [a b])

10:42 clojurebot: [1 2]

10:42 noahlz: ok so no reason to keywordize string keys parsed from a json input from a user

10:43 hyPiRion: well, keywords are functions, so may be useful

10:43 noahlz: destructuring continues to amaze me

10:43 hyPiRion: ,(map :time [{:a 1 :time 12}, {:a 3, :time 36}])

10:43 noahlz: I'm looking at this issue:

10:43 clojurebot: (12 36)

10:44 loliveira: ##(let [{:strs [a b]} {"a" 1 "b" 2}] [a b])

10:44 lazybot: ⇒ [1 2]

10:44 noahlz: https://github.com/ngrunwald/ring-middleware-format/issues/16

10:44 concern by the middleware author is that json could be used for DoS attack if strings are keywordized by default

10:45 potentially a reason why you would never want to expose an API with Content-Type: application/edn to the Internet

10:45 bbloom: he goes on to say that was fixed in 1.3

10:45 however, it's still true of cljs

10:46 or rather it's not true of cljs, but MIGHT become true of it

10:47 noahlz: seems like you would need a validation layer to detect and reject a (maybe unintentional) DoS due to spam of bad keywords

10:48 is there a middleware or ring util that sanitizes or pre-validates POST/GET parameters?

10:48 bbloom: in clj 1.3, the keywords are in a weak reference map, so it's relatively safe

10:48 noahlz: i.e. for length etc.

10:48 bbloom: cool thanks

11:30 Pupnik-: Raynes, lazybot seems to lose its mind and max a core indefinately if your connection drops, even after reconnecting

11:34 djwonk: i noticed I can force my project to use a newer version of a dependency with lein. by default, are all deps >=? where is this documented?

11:34 also, I was curious if a dependency could still, say, use an old version of ring, while my code could use a new version. that may not make any sense, that's why I'm asking :)

11:35 noahlz: i'm trying to get a sequence of all the metadata for my ns-publics, is there a more concise way and/or util function to do the following?

11:35 hyPiRion: Pupnik-: yeah, I realized that as well some day

11:35 noahlz: (->> (ns-publics 'stringly.core) vals (map meta))

11:35 hyPiRion: my bot just suddenly ate all my stuff one day

11:35 noahlz: (->> (ns-publics *ns*) vals (map meta))

11:35 rather

11:36 ##(first (->> (ns-publics 'stringly.core) vals (map meta)))

11:36 lazybot: java.lang.SecurityException: You tripped the alarm! ns-publics is bad!

11:36 noahlz: hmmm

11:36 maybe I shouldn't be using ns-publics in my code

11:37 I basically want to automatically generate an IDL for a web-based API from a namespace using ns-publics

11:37 I'm guessing that's not a good practice....?

11:38 djwonk: noahlz: i grepped over 'ns-publics' in clojure.core, didn't see any util functions like yours

11:38 noahlz: hmm

11:38 djwonk: noahlz: what is an IDL?

11:38 noahlz: what about using ns-publics in general?

11:39 Interface Description Language. Welcome to the wild world of Enterprise Web Applications (tm)

11:39 I.e. Thrift IDL

11:39 maybe I'm using that term

11:39 I suck with acronyms

11:39 djwonk: noahlz: as to whether using ns-publics is a good or bad idea -- or if there is a better way, I dunno

11:40 noahlz: Think I am liking about clojure: metadata far more intuitive and powerful than annotations

11:41 anyway, just wondering. I'm guessing there have to libraries out there that generate for example, webservices WSDL from clojure code, using metadata

11:41 haven't looked around yet

11:43 djwonk: i've been reading a lot of clojure code so I can learn, sometimes I search github for a term; e.g. https://github.com/search?q=extension%3Aclj+ns-publics&type=Code&ref=searchresults

11:43 noahlz ^

11:43 noahlz: ah good point

11:44 djwonk: noahlz: almost all of the results over appeared to be about code completion

11:44 over -> above

11:44 which sort of makes sense

11:45 i tried adding a "-completions" to weed those out but GitHub's search didn't like that

12:25 iamdrw: hello, how can I map over js array?

12:29 bbloom: ##(doc amap)

12:29 lazybot: ⇒ "Macro ([a idx ret expr]); Maps an expression across an array a, using an index named idx, and return value named ret, initialized to a clone of a, then setting each element of ret to the evaluation of expr, returning the new array ret."

12:29 bbloom: iamdrw: i'm pretty sure that works in cljs

12:30 tomjack: it's not quite what js people may expect though

12:31 in that it always goes from 0 to (count a)

12:58 Kowboy: if I parse an xml stream using the clojure.data.xml/parse function (nested lazy map) and pass that to xml-seq, is the result still lazy?

12:59 iow, can I process very large files this way if I'm using filter on the xml-seq?

13:08 noidi: ,(doc xml-seq)

13:08 clojurebot: "([root]); A tree seq on the xml elements as per xml/parse"

13:08 noidi: ,(doc tree-seq)

13:08 tomjack: do syntax-quote and data readers interact in a reasonable way?

13:08 clojurebot: "([branch? children root]); Returns a lazy sequence of the nodes in a tree, via a depth-first walk. branch? must be a fn of one arg that returns true if passed a node that can have children (but may not). children must be a fn of one arg that returns a sequence of the children. Will only be called on nodes for which branch? returns true. Root is the root node of the tree."

13:09 noidi: Kowboy, so I'd guess yes

13:10 looking at xml-seq's source it does use tree-seq, even though the docstring is ambiguous about that

13:10 tomjack: looks like the data reader receives stuff with unquote and unquote-splicing inside

13:10 interesting..

13:17 EatACake: is it hard to learn clojure if you know haskell and a little bit of scheme, but no knowledge of OOP or java

13:17 ?

13:18 tomjack: lack of java knowledge may slow you down when you do need to use something from java, but haskell and scheme experience are much more suitable for understanding the important parts of clojure than OOP and java, I think

13:19 no knowledge of OOP is a blessing

13:19 EatACake: okey good, i know a little bit of C if that adds something, ive heard java was supposed to be "a better C" or sth

13:20 enquora: need to implement a production rule system that runs on server and in web browser. Anyone know of existing work in pure clj other than mimir?

13:23 Kowboy: noidi, thanks

13:25 mjburgess: is there any material (pref. videos) on rule-based programming in clojure?

13:25 rich hickey is always on about it; i get basic prologue. i'm curious to see prologuey clojure, and the point of it

13:27 tomjack: mjburgess: have you looked at core.logic?

13:29 bbloom: mjburgess: prolog et al aren't really the essence of why "rule based programming" is interesting. they are just one view of it

13:30 mjburgess: check out datomic's query language/engine for an example of datalog in action too

13:37 maio: I would like to use: (if-let [errors (validator)] ...) but validator returns {} if there are no errors. is there some nice way to convert {} -> nil? :)

13:38 amalloy: &(doc not-empty)

13:38 lazybot: ⇒ "([coll]); If coll is empty, returns nil, else coll"

13:39 maio: ha, I knew it! :) thanks amalloy

13:41 Clojure commercial - "There's A Function For That" :)

13:49 Foxboron: maio, just like Python's "There is a lib for that"

13:49 ?

13:50 tomjack: hmm.. if not zippers, what? https://www.refheap.com/dad9bbbaa527e0ba2c98cc8c7

13:50 bbloom: "nomify" sounds delicious.

13:51 i'm glad i learned the word "nominal" it's surprisingly useful in other contexts…. i feel like that a lot: learning words for ideas you didn't know needed words can really improve your thinking

13:51 tomjack: now what are you tryign to do?

13:52 tomjack: I think it's known as 'labelling' a tree

13:53 bbloom: ok so that code works & you want something cleaner? is that the idea?

13:53 tomjack: a vector (or seq) form has operator and operands, I want to replace all symbol operands with noms (or numbers or whatever) keeping the state (just remembering fresh noms, or the counter or whatever)

13:53 yeah

13:54 and that doesn't deal with binding at all

13:54 bbloom: ok so i did something like this recently

13:54 i dunno if it's a good idea or not, but here's what i did:

13:54 tomjack: the rewriting lib?

13:55 bbloom: my zipper creation function creates a thing that's like {:state foo :node bar} and my children function copies the state down to the children. then my make-node form merges the state back up

13:55 tomjack: oh I remember you talking about that, I didn't understand it

13:56 bbloom: it doesn't really work right for your case though b/c you want to thread a state through each child in order, right?

13:56 i only wanted parent -> child and children -> parent

13:56 i didn't need sibling -> next sibling

13:56 maio: Foxboron: yes :) also http://www.youtube.com/watch?v=szrsfeyLzyg

13:56 bbloom: so, now i'm gonna recommend something crazy, but you might like it b/c you're a crazy sort of guy

13:56 tomjack: yeah if two sibling operators are the same symbol they need to get the same label

13:57 bbloom: https://github.com/brandonbloom/fipp/blob/master/src/fipp/printer.clj#L54-L55

13:57 tomjack: implement a traversal that turns your tree into a sequence and then reduce over that sequence

13:58 it's just crazy enough to work :-)

13:59 whatever was recursion becomes an explicit stack, it's quite pleasant in practice

13:59 tomjack: hmm..

14:02 jro_: is there some threading macro to transform form (aget (aget a-map "key") "key2") to (... a-map "key" key2")

14:02 tomjack: [and x y] -> [{:op :begin} {:op :operator :name and} {:op :var :name x} {:op :var :name y} {:op :end}]

14:03 bbloom: tomjack: yup, and then you just (case (:op message) …return new state...)

14:03 tomjack: on begin, you push a scope map, on end you pop it

14:03 (case op :end (update-in state [:scope] pop))

14:04 tomjack: that should also help with binding

14:04 thanks, I'll give it a shot

14:04 bbloom: bonus: debuggable via reductions!

14:04 :-)

14:04 tomjack: I see you cite oleg

14:04 timvishe`: why do fogus and chouser say in chapter 5 of the joy of clojure that clojure.lang.PersistentQueue should not be used as a workflow abstraction?

14:04 bbloom: i'm giving a talk on all this at clojure nyc next month :-)

14:05 timvishe`: without recalling anything specific about that chapter, i suspect they are talking about pipelines/processes/whatever & would recommend something from java's concurrent collections

14:05 timvishe`: see also the new core.async stuff

14:05 kanwei: in my app, how do I check which leiningen profiles are active?

14:10 bbloom: tomjack: you might want to stick the extra info on the begin and end nodes. so like your :and operation might be part of a begin

14:11 tomjack: yeah just did that in my wip

14:11 bbloom: this also lets you interleave work within a single traversal -- you can create a pipeline of functions that annotate the traversal stream & then reconstitute the tree at the end w/ the new information

14:12 so you can create two passes that execute in one traversal, but are decoupled code

14:12 timvishe`: bbloom: maybe i'm just not understanding the purpose of a queue datastructure that isn't meant to be a workflow mechanism. my understanding of queues was that they were a collection with fifo semantics which meant that they were solely useful as workflow mechanisms. i'm coming up short on when they'd be useful as logical mechanisms.

14:13 bbloom: timvishe`: here's just one example: you could use a persistent queue for a breadth first traversal of a tree

14:13 timvishe`: bbloom: good example. :)

14:13 bbloom: timvishe`: but you wouldn't use a synchronized mutable queue for that

14:14 timvishe`: on the other side of the coin, you'd want a synchornized mutable queue for passing data from one process to another on another thread or machine or whatever

14:15 timvishe`: bbloom: got it. so blockingqueue from java land provides the workflow semantics by allowing you to specify how threads reading off the queue or putting work onto the queue should act while persistentqueue just provides the fifo semantics.

14:15 bbloom: also worth noting: in many cases you can get away with concat and lazy seqs instead of persistent queue. that's probably why it's not in core yet

14:15 timvishe`: yeah, you got it. persistentqueue also provides Counted and a few other things too

14:16 timvishe`: bbloom: thanks!

14:17 bbloom: ,(let [q (into clojure.lang.PersistentQueue/EMPTY [1 2 3])] ((juxt vec counted?) (conj q 4 5 6)))

14:17 clojurebot: [[1 2 3 4 5 ...] true]

14:17 bbloom: also fifo, but no counted:

14:18 ,(let [q '(1 2 3)] ((juxt vec counted?) (concat q [4 5 6])))

14:18 clojurebot: [[1 2 3 4 5 ...] false]

14:18 bbloom: generally, i haven't found a use for persistent queue that i haven't been able to handle with a regular lazy seq. amalloy and i were just discussing it at length in the irc logs a few days ago

14:18 gfredericks: bbloom: probably awkwardly structured as a data structure to (the concats)

14:18 prone to stack overflows and such

14:19 s/to/too

14:19 tomjack: bbloom: https://www.refheap.com/2b083fc678e3eb7af2dab3707 seem roughly on track?

14:20 bbloom: gfredericks: i can't find it in the logs, but amalloy and i just talked about that & analyzed it in depth

14:21 gfredericks: bbloom: I kind of want to call it a concat-queue

14:22 conquat?

14:24 bbloom: Raynes: forgive me, i'm curling your logs :-)

14:27 tomjack: hmm, now I see why I need map-state

14:28 bbloom: map-state is just a convenience over reduce really

14:28 you don't NEED it if you don't mind keeping the full tree in memory

14:28 which is unlikey to be a problem for code analysis, but was a design goal of fipp: to print large docs w/ bounded memory

14:30 gfredericks: grep over Raynes' logs locally found the discussion in 5 seconds :-)

14:31 gfredericks: search http://www.raynes.me/logs/irc.freenode.net/clojure/2013-05-14.txt for "careful"

14:39 gfredericks: if you can't find something out by grepping Raynes' logs then you probably don't need to know it in the first place

14:43 bbloom: oooh ooh, a terrible way to fake a queue is to use subvecs!

14:44 bbloom: gfredericks: i'm not sure why you are so excited about how terrible that is :-)

14:45 gfredericks: I find the intersection of clever and terrible to be terribly exciting

14:45 clojurebot: swearjure is the intersection of clever and terrible

14:45 clojurebot: Ok.

14:46 bbloom: heh

14:48 hyPiRion: ~swearjure

14:48 clojurebot: Swearjure is http://hypirion.com/swearjure

14:48 hyPiRion: oh

14:49 gfredericks: clojurebot: hyPiRion is an anagram of "swearjure"

14:49 clojurebot: Ack. Ack.

14:49 mthvedt: ~hypirion

14:49 clojurebot: hyPiRion is <hyPiRion> ,#(`%%%)

14:49 hyPiRion: gfredericks seems to be ignored by clojurebot today. :o

14:49 ~hypirion

14:49 clojurebot: hyPiRion is an anagram of "swearjure"

14:49 hyPiRion: oh, there it is

14:50 gfredericks: come on man you know how clojurebot works by now

14:50 ,#(`%%%)

14:50 clojurebot: #<IllegalStateException java.lang.IllegalStateException: arg literal must be %, %& or %integer>

14:51 hyPiRion: yeah, it is borked since 1.5

14:51 damn you rhickey, killing all my Swearjure plans

14:52 Hmm, I wonder if I can make a rb tree in Swearjure

14:52 gfredericks: if you're gonna do swearjure research why not do the SKI calculus so we know for sure it's turing complete

14:53 hyPiRion: oh right

14:53 Welp, I've derailed a lot lately.

14:56 gfredericks: ,#(`%-2)

14:56 clojurebot: #<sandbox$eval58$fn__59 sandbox$eval58$fn__59@831dff>

14:56 gfredericks: haha it wasn't kidding about the "integer" part

14:57 ,'#(%-2)

14:57 clojurebot: (fn* [] (p-2__88#))

14:57 gfredericks: ,'#(%0)

14:57 clojurebot: (fn* [] (p0__117#))

14:57 gfredericks: ,'#(%1)

14:57 clojurebot: (fn* [p1__146#] (p1__146#))

14:57 hyPiRion: ,'#(%-3.14)

14:57 clojurebot: (fn* [] (p-3__175#))

14:58 gfredericks: ,'#(%15e2)

14:58 clojurebot: (fn* [p1__205# p2__206# p3__207# p4__208# p5__209# ...] (p1500__204#))

14:58 gfredericks: ,#(%15e2)

14:58 clojurebot: #<CompilerException java.lang.RuntimeException: Can't specify more than 20 params, compiling:(NO_SOURCE_PATH:0:0)>

14:59 hyPiRion: oh what

14:59 gfredericks: ,'#(%17.0)

14:59 clojurebot: (fn* [p1__3261# p2__3262# p3__3263# p4__3264# p5__3265# ...] (p17__3260#))

14:59 hyPiRion: ,#(%1e64) ;o

14:59 clojurebot: Execution Timed Out

15:00 gfredericks: I guess ideally the reader would reject anything higher than 20?

15:00 hyPiRion: yeah, and less than 1

15:01 gfredericks: bbloom: why were you saying the other day that putting metadata on fns is bad for perf?

15:05 bbloom: gfredericks: i was talking about putting it on ALL functions, instead of on just the vars

15:05 gfredericks: it increases how much memory a function needs

15:06 gfredericks: sure. similar order of magnitude though, right?

15:06 maybe 2x or 3x more metadata in the system?

15:06 bbloom: it's a bigger issue for CLJS

15:06 gfredericks: ah true

15:06 bbloom: because functions in CLJS are just JS functions

15:06 if you want to stick metadata on them, then they have to be wrapped in a deftype with invoke and all that jazz

15:06 which means there is additional calling overhead

15:06 too

15:07 gfredericks: they do? can't just fake it with a property on the function object?

15:07 bbloom: well you can, but then you need to special case that when doing dispatch to make protocols work, which is already done to some extent

15:08 and then if you're gonna put that metadata on lexically defined functions too? like (fn [x] …) or whatever, then you're gonna incur the cost of allocating a map on each iteration

15:08 and you're thwarting lambda/closure lifting in the google closure compiler

15:09 * gfredericks wouldn't want to thwart

15:09 bbloom: meanwhile, most apps don't need that metadata & if they did, they generally only need it statically, be it at macro expansion or compilation time

15:10 gfredericks: bbloom: rich has talked about adding more knobs to clojure for things like that, right? that could apply to cljs too?

15:10 bbloom: gfredericks: probably

15:10 gfredericks: bbloom: cool; thx for the explain

15:10 bbloom: so what people don't realize about static vs dynamic is that it's a multidimensional spectrum

15:11 in the case of clojure, vars are statically known most of the time

15:11 in cljs, they are statically known ALL of the time

15:11 which means you don't need to pay the deref cost that clj must pay for the indirection through vars

15:11 gfredericks: they're dynamic in the underlying JS vm aren't they?

15:11 bbloom: by sticking metadata on vars instead of on fns, you're making a decision about what information is known at compile time vs what's known at runtime

15:12 gfredericks: or are you talking about the compiler?

15:12 bbloom: google closure compiler has a type system

15:12 gfredericks: oh weird

15:12 bbloom: and function signatures are static in that type system

15:12 tomjack: bbloom: not too happy about this but I think it just needs refactoring. your idea seemed to work well, thanks https://www.refheap.com/6aeac9616576e92d9d3308965

15:12 bbloom: the type system is critical to achieving the optimizations that make cljs possible

15:12 gfredericks: bbloom: so this is a property of a restricted kind of JS

15:13 bbloom: yes, but it's symptomatic of a more fundamental issue: the same sort of optimizations and analysis occurs in VMs

15:13 google closure compiler doesn't help nearly as much as it used to…… for V8

15:13 b/c V8 does many of the things that the compiler does… but it does them at runtime

15:14 V8 analyses code, makes some assumptions about what is static about things, and inserts some checks to make sure those things don't change / become dynamic. if they don't change, then it takes the fast path

15:14 the closure compiler analyses things that CAN NOT CHANGE and then generates fast path code

15:14 see also: partial evaluation & abstract interpretation

15:16 tomjack: cool. yeah, this sort of thing is kinda a new idea to me, so it requires some exploration of idioms & utility functions, but the mental model of linearizing & reducing a command buffer is sound

15:17 tomjack: I'm trying to understand the relation to Traversable

15:17 bbloom: tomjack: i don't think traversable emits begin/end nodes

15:18 it's sorta like clojure.zip/next though in that you get a sequence from a traversable, but you can insert explicit begin & end elements in the seq to give you more control over pre and post node traversal logic

15:19 better ways to analyze and process trees is a bit of a new obsession of mine :-)

15:21 gfredericks: clojurebot: bbloom is a dendrologist

15:21 clojurebot: Alles klar

15:21 bbloom: gfredericks: lol thanks

15:21 tomjack: right traversables have a reducer of data and the shape is completely separate

15:21 so reducing over a command buffer is more expressive I guess

15:22 for one thing you can change the arities in the tree

15:24 not to mention produce an invalid command buffer as output?

15:29 gdev: is there a kid friendly ide for clojure or should I just teach my son to use emacs?

15:30 gfredericks: clojure for kids is already rather radical. Why not throw emacs in too? :)

15:31 s/radical/ambitious/

15:32 gdev: gfredericks: i know its odd, but he's bombarded all day at school with infix notation and I want him to see there is another way

15:33 gfredericks: man it'd be super cool if the biggest problem with schools generally was bombardment with infix notation

15:34 gdev: gfredericks: agreed, but one thing at a time right

15:34 gfredericks: totally I didn't mean it as any kind of criticism :) just a humorous thought

15:34 * gfredericks considers proposing armed security guards to protect against infix notation

15:35 gdev: gfredericks: armed guards? if we just gave the teachers the tools to protect against it themselves you wouldn't need that

15:36 gfredericks: man I should stop making fun of schools it just makes me sad :(

15:38 gdev: gfredericks: agreed, let's get back to brainstorming clojure for kids ide

15:39 I think that will be my summer of lisp project

15:39 gfredericks: a basic-er version of light-table?

15:39 gdev: s/summer of lisp/lisp in summer

15:40 gfredericks: yes! good idea. dragn-n-drop light-table...brilliant

15:40 gfredericks: oh man sexps would be great for drag-n-drop

15:40 maybe.

15:40 sorta.

15:42 paredit for mouse

15:44 gdev: yes, we'll have a little picture of a mouse wearing a parachute...para-mouse mode

15:45 also, a Clojure Atlas style window for exploring the core functions

15:48 alandipert: gdev: http://celeriac.net/iiiiioiooooo/

16:03 gdev: alandipert: that's cool looking. is he still developing it?

16:04 alandipert: gdev: don't know, but i hope so

16:04 gdev: it would be sweet to clojure on ipad with something like that maybe

16:05 dnolen: gfredericks: bbloom: you can't just attach metadata directly to fns in CLJS

16:05 alandipert: did you see my tweent about :static-fns true?

16:05 tweet

16:06 bbloom: dnolen: sure you can, i created that patch & you applied it

16:06 alandipert: dnolen: i did, and thanks

16:06 dnolen: bbloom: and it was replaced

16:06 alandipert: did that solve your problem

16:06 bbloom: dnolen: bwha? why?

16:06 dnolen: because it wasn't any good

16:06 direct mutation of fns

16:06 gfredericks: dnolen: I know cljs doesn't currently let you do it, I was asking about the implications of approaching it that way

16:06 bbloom: :-(

16:06 gfredericks: which bbloom answered quite well

16:06 alandipert: dnolen: it's not clear yet, but the way it works seems related to the way advance mode is blowing up

16:06 bbloom: dnolen: my patch didn't mutate fns, it reified and implemented IFn

16:07 dnolen: bbloom: oh right, if that was your patch then yes that's the way to do it :)

16:07 bbloom: haha, wasn't sure about the backlog

16:07 bbloom: someone had proposed directly modifying properties on fns in the past, that is of course broken

16:07 bbloom: dnolen: lol, you were scaring/confusing me for a moment there

16:08 https://github.com/clojure/clojurescript/commit/6ce3b1cef3824fd36e75402f5a8ed5053252b15e

16:08 jtoy: is there a simple way to have (= 0 0.0) be true? I just ran into this bug

16:08 alandipert: dnolen: btw any particular reason you do [xs].join instead of interleaving + in the str compiler macro?

16:08 gfredericks: jtoy: ##(== 0 0.0)

16:08 lazybot: ⇒ true

16:09 dnolen: alandipert: historically .join is faster

16:09 alandipert: dnolen: i ask because interleaving + seems Faster (tm)

16:09 gfredericks: jtoy: it's not a bug

16:09 dnolen: alandipert: if you want to put togther a jsperf demonstrating that + is faster for everyone please do.

16:09 alandipert: and we can revisit

16:09 jtoy: what is the difference between = and == in clojure?

16:09 dnolen: jtoy: == is for numbers

16:10 jtoy: i thought in clojure there is no == because = is ==

16:10 akhudek: whoa, I thought = and == was just a performance thing, didn't realize there where semantic differences

16:10 alandipert: dnolen: nbd because :simple unrolls into concats

16:10 jtoy: which is faster? = or == ?

16:10 bbloom: alandipert: were you testing with string literals? it's likely that runtimes will concat at "compile" time

16:10 dnolen: jtoy: == is faster if you have numbers, behavior undefined for anything else

16:10 alandipert: bbloom: yeah it was concat'ing the literal

16:11 dnolen: alandipert: nbd?

16:11 alandipert: "no big deal"

16:11 jtoy: good to know i guess

16:11 gfredericks: jtoy: == also has semantic differences w.r.t. floats vs precise numbers

16:11 bbloom: alandipert: yeah, then the concat will occur once at parse instead of every iteration of your benchmark loop

16:11 alandipert: i tried it because i was doing experiments with FF GC to see if array allocs wer triggering

16:11 dnolen: alandipert: FF GC is really bad btw this is true

16:12 bbloom: dnolen: alandipert was having some serious FF perf issues. do you think the constants changes we discussed would help him?

16:12 dnolen: bbloom: alandipert: yes I think the constants work will be huge win for idiomatic code

16:12 akurilin2: Unrelated to what you guys are talking about: I'm trying to decide between wrap-json-params and wrap-json-body. Is there a compelling reason not to smush everything into the :params map?

16:12 alandipert: we don't know what the problem is exactly though

16:13 or do we?

16:13 dnolen: bbloom: I thought about it some more, we really should make constants for every collection we encounter - i.e. nested nes

16:13 nested ones

16:13 gfredericks: all of a sudden my nrepl.el start showing function signatures in the minibuffer while I type

16:13 bbloom: dnolen: i don't have the mental bandwidth to consider that atm

16:14 dnolen: we'll just have to get together and hack again soon

16:14 dnolen: bbloom: yep

16:14 bbloom: alandipert: not that that helps you right now :-)

16:14 alandipert: we need to go work at mozilla and write their GC for them

16:15 not that i could do better probly though, lol. maybe you guys could :-)

16:15 dnolen: bbloom: re, V8 vs. Closure, some of the advanced compilation stuff actually hurts perf since there's a balance between perf and code size.

16:15 alandipert: it sounded like pieces of the generational gc are in -trunk but i was seeing the problem there too. with any luck over the next 6 months this will fix itself

16:16 tomjack: bbloom: with your fn metadata patch, though, (with-meta f {}) is no longer a 'function', right?

16:16 dnolen: alandipert: there's actually a mozilla ticket open for addressing some of the perf gaps for CLJS between JSC V8 vs. FireFox

16:17 alandipert: I'd like to write some pure JS versions of the persistent data structures so it's easier for them to isolate / benchmark

16:17 alandipert: my hunch is that at this point it's really GC that differentiates whether CLJS runs fast or slow on the JS engines.

16:18 well idiomatic CLJS anyway

16:18 alandipert: dnolen: those are my findings after much micro benching various things

16:18 bbloom: tomjack: hence IFn and fn? vs ifn?

16:19 dnolen: tomjack: well it's a CLJS function, but no longer a native function - this is actually another perf thing I'd like to address

16:19 being able to specialize code depending on what you have

16:23 tomjack: dnolen: i.e. make reify w/ Fn emit a native function?

16:23 dnolen: tomjack: no

16:23 tomjack: the is more subtle

16:24 currently at all higher order call sites we check whether a fn implements a particular arity

16:24 "the issue is more subtle"

16:25 I don't think there's anyway for generic code that interops to avoid that

16:25 but maybe you should be able to say that the fn is not native for inner loops

16:26 tomjack: I see

16:26 bbloom: tomjack: basically dnolen wants a type system that allows us to generate more efficient code by skipping code paths that can be statically proven to never happen at a particular site

16:26 alandipert: dnolen: http://jsperf.com/plus-vs-join2

16:26 bbloom: tomjack: which is precisely what type hints do: they generate direct casts, which are faster than reflection lookups

16:27 alandipert: dnolen: my first jsperf thing so i don't know if i did it right, but + appears to win for literals at least

16:27 dnolen: alandipert: ah this is for the templating use case?

16:27 bbloom: tomjack: and there is already very limited inference of type hints, but you could imagine a much more complex system which can enable us to make much smarter optimizations

16:27 alandipert: dnolen: right w/ https://gist.github.com/alandipert/5658827

16:28 dnolen: alandipert: more than happy to take a patch for it, it's pretty simple just fix the str macro

16:28 bbloom: dnolen: alandipert: i don't think that would be a win overall

16:29 dnolen: bbloom: .join perf is really an old school think - most engines fixed the behavior of +

16:29 bbloom: you'd be better off doing NEITHER the join nor the +, if the macro could concat adjacent literal strings at compile time

16:29 dnolen: old school thing

16:29 gfredericks: alandipert: do you have to be careful about numbers? (3 + 4) vs [3,4].join()

16:30 alandipert: i'm indifferent to changing str because :simple and higher seems to compile-time concat when it can, and also not expert on engines. just throwing it out there

16:30 bbloom: gfredericks: you just put `"" +` at the beginning, since + binds to the left

16:30 alandipert: gfredericks: in this case no because every arg gets str called on it

16:31 gfredericks: ah right

16:31 dnolen: alandipert: well try it, benchmark and open a ticket if it looks better ;)

16:32 alandipert: I'm not against patches which improve :simple since I know there are cases where that might be desirable for various reasons

17:00 tomjack: is there a heuristic for deciding which goal should be the head of a conde clause?

17:01 I guess I need to just reread TRS, probably if you understand conde you don't need a heuristic..?

17:01 dnolen: tomjack: the head should probably be the main "predicate", this matter more with conda / condu of course

17:01 matters

17:03 tomjack: I tend to make the head the thing I think when running the relation forward, but then I wonder about when the relation is running backward..

17:03 gfredericks: tomjack: I never understood why the talked about a head wrt conde, since it isn't distinguished

17:03 dnolen: tomjack: in the future we're likely to index the first clause so that's something to consider

17:03 gfredericks: s/the/they

17:03 dnolen: I mean the head of the clause

17:04 tomjack: oh so now it doesn't really matter at all?

17:04 gfredericks: right

17:04 tomjack: I assumed there was some performance or search order implication

17:04 gfredericks: well probably so

17:04 search order I mean

17:04 dnolen: tomjack: it doesn't matter in miniKanren, but it will likely matter in the future for core.logic

17:04 tomjack: gfredericks: oh right, clearly..

17:28 gfredericks: does clojure.walk preserve metadata?

17:30 tomjack: (outer (apply list (map inner form)))

17:30 &(meta (empty (with-meta {} {:foo 3})))

17:30 lazybot: ⇒ {:foo 3}

17:31 tomjack: depends

17:31 gfredericks: aw geez

17:31 so specifically for lists it loses it

17:32 tomjack: and seqs

17:32 gfredericks: brilliant

17:32 let's see if switching to prewalk still works

17:34 once you figure out the stack overflow it does okay :)

17:48 ,(let [| (constantly '(|)] (|))

17:48 clojurebot: #<RuntimeException java.lang.RuntimeException: Unmatched delimiter: ]>

17:48 gfredericks: ,(let [| (constantly '(|))] (|))

17:48 clojurebot: (|)

17:51 bbloom: i haven't succeeded in using clojure.walk yet without (almost immediately) replacing it with something else

17:51 gfredericks: I was looking through tickets yesterday and didn't see anything about the metadata issue; I guess there should be one?

17:58 should be easy to patch

18:59 phyrephox: has anyone here gotten nailgun to work with leiningen?

19:01 mthvedt: phyrephox: you probably don't want a persistent jvm with leningen. some people use drip which spins up spare jvms in the background

19:01 phyrephox: hmm

19:01 ok

19:02 i'm just trying to get `lein run` to execute faster

19:02 would drip help to that end?

19:02 adu: this nailgun? http://martiansoftware.com/nailgun/index.html

19:02 phyrephox: ya

19:04 mthvedt: drip looks great, thanks for the tip!

19:05 mthvedt: phyrephox: np

19:24 technomancy: nailgun is designed around Java; it doesn't really make sense for Clojure

19:25 phyrephox: there's a "Faster" page on the Leiningen wiki you should check out

19:30 adu: drip sounds good, since it doesn't require a persistent JVM

19:58 poindontcare: question, a clojure vector of strings to a java primitive array of strings ?

19:59 hyPiRion: ,(into-array String ["a" "b" "abc"])

20:00 clojurebot: #<String[] [Ljava.lang.String;@1b0b3bb>

20:00 hyPiRion: poindontcare: ^

20:00 poindontcare: ah k

20:00 hyPiRion: thanks

20:00 hyPiRion: happy to be of help :)

20:35 ambrosebs: gsoc projects have been announced http://www.google-melange.com/gsoc/org/google/gsoc2013/clojure_dev

20:37 nightfly: isn't it too late for anyone to apply?

20:37 tomjack: ambrosebs: congrats

20:37 ambrosebs: tomjack: cheers

20:37 nightfly: ah, I see

20:39 n_b: Neko improvements! Very excited to see how that turns out

20:40 ambrosebs: CinC! CinC! CinC! :)

20:50 akhudek: The Algebraic Expressions project looks cool.

20:58 Raynes: Michal is still around? :D

20:59 technomancy: http://oauth.io/

21:00 technomancy: It is very likely that Raynes is gonna make refheap work with github auth now.

21:18 tomjack: dnolen: what if a var has a domain in both the fd and set stores?

21:19 e.g. should let-dom and sort-by-member-count be rewritten to accomodate this possibility?

21:24 technomancy: Raynes: did you see how easy it was to add oauth to syme?

21:24 12, maybe 15 lines?

21:25 https://github.com/technomancy/syme/blob/master/src/syme/web.clj#L24

21:26 mthvedt: +1 for man who was thursday reference

21:26 brehaut: technomancy: i was expecting more emoticons

21:27 or at least a url to a snarky but apropos comic

22:07 gfredericks: (dec endianness)

22:07 lazybot: ⇒ -1

22:21 clojure-new: hello

22:21 auser: hey clojure-new

22:21 clojure-new: how one can implement macrol et in clojure?

22:21 macrolet*

22:21 amalloy: $google clojure macrolet

22:21 lazybot: [clojure/tools.macro · GitHub] https://github.com/clojure/tools.macro

22:22 clojure-new: amalloy: great, thanks.

22:51 tomjack: I wonder if the letfn in macrolet is necessary

22:52 if it could be done some other way it would seem macrolet would be perfect for core.async's symbol translations

23:11 phyrephox: i'm a little confused

23:12 are the arguments to a macro evaluated?

23:12 or passed in quoted

23:20 djwonk: phyrephox: since some macros can delay evaluation, I would not see how evaluating the arguments before expansion would work

23:22 phyrephox: step 1 is macro expansion, then the form is evaluated

23:24 nightfly: phyrephox: Macros are expanded at compile time. This is very important to conceptualize

23:27 djwonk: I've forked a project, now I want to use it in my app. Is it recommended to publish to clojars with a different group id?

23:28 ah, just read: https://github.com/ato/clojars-web/wiki/Groups

23:55 akurilin: ring-json question: the library offers both a wrap-json-body and wrap-json-params middlewares. Do most people use wrap-json-params to be consistent with how other media types are handled with middleware such as wrap-params?

23:55 gfredericks: I wonder what "problems and confusion" the maven naming convention causes, according to the clojars wiki

23:55 tomjack: dnolen: consider a memberc constraint for CLP(Set). I'm basing my draft on fd/-domc. unlike fd, we can't implement -member? for all set domains

23:56 should -memberc dispatch to a set domain protocol method which returns another constraint?

23:56 I should study the constraint stuff more closely, I don't understand how that would work

Logging service provided by n01se.net