#clojure log - May 10 2013

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

0:04 djwonk: I want to wrap function calls to handle a SQLException. I'd like to do it without writing a macro if possible.

0:05 `apply` gets me part of the way there, but not completely

0:06 but since `try` is a special form, is it reasonable to think I can create a custom try that is not a macro?

0:07 darrickw: djwonk: do you want to wrap the function so that you can call it later but the wrapper handles the exception?

0:08 djwonk: darrickw: not sure I understand your question. I want the wrapper to contain the try/catch

0:08 I mean… to abstract out the try/catch

0:09 I don't think I need to wrap the original function (possibly exception-causing function) to call it later

0:09 darrickw: Ok so you want to do the wrapping in place where you call the function then?

0:11 You just need a regular function to do that

0:11 djwonk: darrickw: sounds about right

0:12 darrickw: (defn a-wrapper [the-fn-to-wrap & args] (try (apply the-fn-to-wrap args) (catch TheException ex (do-something ex))))

0:12 something like that could do it

0:13 then you call it like this: (a-wrapper the-fn arg1 arg2)

0:13 djwonk: darrickw: thanks

0:13 I'm running into a double apply situation with jdbc/create-table, but I can figure it out

0:19 gdev: djwonk:) what database are you using?

0:55 n_b: sis there a way to break out of a doseq?

1:00 technomancy: n_b: doseq has a :while clause; it should stop once that is fasy

1:00 falsy

1:01 n_b: Ah, didn't see that! That's perfect, thanks technomancy

1:01 Same clauses as for, always forget

1:02 technomancy: there are a lot

1:09 amalloy: doseq doesn't necessarily do what you want, there, if you're iterating through multiple sequences

1:11 eg, (doseq [a (range 5) b (range 10) :while (< b a)] (...)) doesn't abort the entire doseq. it stops going through b, and starts up with the next a. ##(for [a (range 5) b (range 10) :while (< b a)] [a b])

1:11 lazybot: ⇒ ([1 0] [2 0] [2 1] [3 0] [3 1] [3 2] [4 0] [4 1] [4 2] [4 3])

1:12 amalloy: unintuitive, but much more useful than the alternative. anyway, n_b, technomancy: just a thing to keep in mind

1:12 technomancy: nutty

1:13 gdev: the more you know ...*

1:13 n_b: Ah, interesting

1:14 Fortunately I'm only going through one seq, but I'm sure I'll get bitten by that somewhere down the line and come back here to be reminded of it

1:14 better go write that down

1:17 amalloy: technomancy: not actually nutty at all. if you want a "global" stop parameter, you can just (doseq [[x y] (take-while keep-going? (for [x xs, y ys] [x y]))] ...) or something similar, whereas if doseq/for had a global-stop built in instead, you couldn't easily get the current behavior

1:19 gdev: I know I should be using jdbc library to batch update my database, but I was doing a doseq to create my update statements, I wonder if thats why the database had to parse each statement instead of pulling it straight from cache like is supposed to happen with bind variables

1:19 technomancy: amalloy: I suppose so, but it'd be really easy to write code that does a lot more checks than it looks like

1:19 though I suppose the correctness isn't affected

1:44 muhoo: what's the new latest-jdbc-approved, non-deprecated method of doing a couple jdbc operations inside a transaction?

1:44 gdev: nice, looks like I don't need to pull an all-nighter; company bbq canceled due to weather, will get a lot of alone time at the repl tomorrow.

1:45 muhoo: i've seen examples or using transaction, but that's deprecated, and haven't gotten my brain around the new db-transaction replacement

1:45 looking for an example somewhere

1:48 gdev: muhoo:) the sql dsl that he wrote i thought was what replaced transaction

1:48 muhoo: the dsl is optional, i think.

1:49 i'm using honeysql and i like that way better. but it still uses jdbc as transport

1:49 there's a function db-transaction*, looks like what replaced it, but the usage is kinda weird.

1:50 the macro wants bindings, but i'm not a bindings kind of guy, i like passing db handles in explicitly instead of with-foo-earmuffs stuf

1:50 anyway, i think i got it, it just looks ugly to me.

1:52 mthvedt: what can cause "abstractmethoderror: null"

1:52 gdev: muhoo:) can you post what you got on refheap? I always like seeing different ways to do things

1:53 muhoo: gdev: it's a one-liner: (jdbc/db-transaction* db-handle #(do (i have to) (do it this way weird)))

1:53 gdev: also, honeysql gets my vote for best name of a sql dsl library

1:54 muhoo: works, just feels dirty. the macro version feels dirtier, because it expects bindings like the old transaction macro used to. ain't no thing.

1:54 and db-do-commands may be the right way

1:56 i'm a total honeysql fanboi now. i only wish it did update! and insert! but i guess i can submit! patches! at some point

1:56 gdev: muhoo:) i'm still struggling to get batch updates to act right, so it's better to feel dirty when your stuff works than to feel dumbfounded even though your code is pertty

1:59 muhoo: this stuff is just weird. the jdbc library looks like it kind of grew organically

2:00 didn't devn write a tool that would search github for all instances of a function or identifier and deliver a bunch of code examples of its usage in the wild?

2:01 gdev: wow a truly global usage search huh

2:02 muhoo: it was a very cool idea, and he had something working IIRC

2:03 oh, here's the docs i was looking for: https://github.com/clojure/java.jdbc/tree/master/doc/clojure/java/jdbc

2:04 gdev: one of those says "using sql" is that referring to the optional dsl or the core library?

2:05 muhoo: aha! (j/db-transaction [t-con db] (something t-con) (something-else t-con)) very nice

2:05 THAT is what i was looking for.

2:06 i think the binding is unnecessary, but whatevs

2:06 redndant, why bind db to t-con, why not just use db?

2:07 gdev: muhoo:) have you read the clojure data analysis cookbook?

2:08 muhoo: no, link?

2:09 gdev: http://www.amazon.com/Clojure-Data-Analysis-Cookbook-Rochester/dp/178216264X

2:12 muhoo: hmm. did you like it?

2:14 gdev: Yeah, I like what I've read so far and I typically don't like cookbooks

2:29 okay, now that my phone has some charge i can load the kindle app and see what the book says about jdbc transactions

2:42 looks like the book is only concerned with reading data from the database. makes sense I guess, it's a book about analysis not database programming. That would probably be a book on its own

3:26 muhoo: ,doc empty?

3:26 clojurebot: #<CompilerException java.lang.RuntimeException: Can't take value of a macro: #'clojure.repl/doc, compiling:(NO_SOURCE_PATH:0:0)>

3:26 muhoo: ,(doc empty?)

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

3:27 muhoo: ,(doc not-empty?)

3:27 clojurebot: Pardon?

3:27 muhoo: aha! y you not named not-empty?

3:27 ,(doc not-empty)

3:27 clojurebot: "([coll]); If coll is empty, returns nil, else coll"

3:27 muhoo: i think that's the first naming inconsistency i've found in clojure

3:29 esmo_: it's not a predicate (doesn't return a boolean)

4:02 muhoo: interesting. actually docstring says that not-empty isn't the same as (not (empty?)), and it says

4:02 Please use the idiom (seq x) rather than (not (empty? x))

4:03 so i guess, that

8:20 pellis: hi all, i'm looking for a way to mount ring handlers on urls (no need for routing, just mounting handlers)

8:20 anyone bumped into how to do this?

8:21 weavejester: What's the difference between routing and mounting ring handlers on urls?

8:23 pellis: weavejester, well i don't want to waste cycles on a routing matcher that checks my http method, or tries a regex against it

8:24 just /v1/api goes to handlerfoo, /v2/api goes to handlerfoo-2

8:24 weavejester: So you could just use a case statement

8:25 Or, I guess in this case you want to match against a prefix?

8:25 So...

8:25 pellis: yes

8:25 i'm looking for the equivalent of rack-mount from ruby world

8:26 weavejester: (cond (.startsWith (:uri request) "/v1/api") (handler request) ...)

8:26 But that's probably overkill

8:26 You could just use Compojure. Regexs are fast enough.

8:26 pellis: ok

8:27 weavejester: (routes (ANY "/v1/api" [] handlerfoo) (ANY "/v2/api" [] handlerfoo-2))

8:29 pellis: weavejester, is that compojure?

8:30 weavejester: pellis: Yep

8:30 pellis: I'm wondering how much overhead in performance will that take

8:30 weavejester: pellis: Let me run some numbers for you, as I'm curious myself

8:30 rasputnik: hi all, i need to filter a seq of maps by testing keys - what functions should i be looking at?

8:31 pellis: i might sound to you like the naive hysteric premature optimizer - but I assure you i'm not. this specific project needs to be carefully handled with LOCs unfortunately.

8:31 rasputnik: # it's a map of ssl keys and i want to return those with an expiry date less than a given number of days

8:32 pellis: weavejester, I chose Clojure because it won over Go and Node.js, (however didn't test it against the newer Go betas and RCs that are not famously performant)

8:34 pjstadig: rasputnik: something like (filter (fn [key] (< (get-exp-days key) the-date)) keys)

8:34 ucb: ,(doc filter)

8:34 rasputnik: ^

8:34 clojurebot: "([pred coll]); Returns a lazy sequence of the items in coll for which (pred item) returns true. pred must be free of side-effects."

8:34 pjstadig: or if you want to be fancier (filter #(< (get-exp-days %) the-date) keys)

8:35 rasputnik: pjstadig, ucb : cheers both.

8:35 weavejester: pellis: Okay, I'm just writing out a quick benchmark. Should be a few minutes.

8:36 pellis: weavejester, cool!

8:51 weavejester: pellis: Both approaches look to be about the same speed. There's maybe a microsecond between them, but I'd guess hotspot is doing a good job at optimising things out.

8:51 pellis: I'll give you my REPL logs in a gist

8:51 pellis: weavejester, thanks, very nice of you !

8:53 weavejester: Huh, gists aren't working...

8:54 pellis: yes, i think they have a security bug

8:54 i thought i'm the only one. looks like a redirect loop, and then some blurb about login/authentication errors

8:54 weavejester: pellis: https://www.refheap.com/paste/14390

8:55 pellis: might also be stale cookies

8:55 redline6561: lam

8:55 ahem, excuse me

8:56 pellis: weavejester, that's very useful. i think - when you'll see a bigger difference will be with big urls

8:56 weavejester, for example /api/v1?<some 1000 characters>

8:56 unless regex are smart enough to not glob when it's just "*"

8:57 weavejester: pellis: Anything after ? is the query string and not matched, but regexes are pretty optimised.

8:57 pellis: well then /api/v1/foo/<some 1000 chars>

8:58 weavejester: pellis: I suspect that you'd still see little difference. But lets try it :)

8:58 pellis: weavejester, you might be surprised, most websites can be ddos'ed with just very big urls.

8:58 especially if you have double captures like v1/*foo*bar

8:59 if you're not building-in protection, then you're limited to browser's 8k characters at the url. but anyone smart enough can just not use the browser and bombard you with 50k of url string

9:00 plus, i've seen such attacks live in production 3 years ago :)

9:00 juhu_chapa: Hi all. Is there anything like a blocking queue in clojure?

9:01 weavejester: juhu_chapa: Typically you can just use the Java blocking queues

9:03 juhu_chapa: :D

9:07 vijaykiran: mu4e

9:10 weavejester: pellis: Looks like the URL length does affect the time. My guess is because Compojure is capturing the * part in a matching group, whereas the .startsWith can just discard it.

9:10 pellis: weavejester, yes, like i suspected :)

9:11 weavejester: pellis: With a URL of length 1000, it's a difference of 4us to 40us

9:11 pellis: weavejester, i guess this is the conceptual difference between mount and route - O(1) vs O(n)

9:11 weavejester: weavejester: I suspect that if Compojure *wasn't* capturing it the wildcard, that we wouldn't see a difference.

9:13 pellis: Well, it doesn't have to be that way. I've been toying around with the idea of just discarding *, as if you really wanted it, you'd give it a name.

9:13 pellis: weavejester, i understand

9:13 weavejester: pellis: But given the implementations at the moment, yes, you're correct.

9:15 pellis: ok, so I'll opt for your first suggestion - thanks for the help :)

9:54 learner: Hello Gurus. A newbie question here. I have a huge lazy sequence (say 2 or 20 Million strings). Among all, I am interested in finding only one particular string position (just need a rough value). I can use loop, recur updating an atom (count). But it's slow. Since I don't need exact position, I can use Threads. But I am not sure how to. Any hints?

9:57 AimHere: That sounds like you want to crack open a book on algorithms

9:58 First find the most efficient known way of doing it, then worry about the details of which bits are threaded and whether to use recur or whatever later

10:00 learner: AimHere: Yes, may be I should go and read algorithms. Wondering if I can find any help from the community who experienced similar problems.

10:01 pppaul: learner sorted?

10:02 learner: pppaul: No, not sorted. But fixed size strings

10:03 pppaul: brute force + memoize :)

10:04 you can use partition + map indexed

10:04 AimHere: My naive guess as to how to do it would be to check the first character of all strings - then you discard all the nonmatches and you've a considerably smaller set to sift through for the second pass, and the second character

10:04 Basically sieve it

10:05 pppaul: you can put this data in a mem datomic and use it's fulltext search

10:05 index the strings first [{:index 0 :body "my string"}]

10:05 learner: pppaul: Yeah, brute force is the only way. And memorize may not be required because all strings are fixed size, unique. I am thinking of kicking off some 20 threads (fixed) on collection each taking one string and comparing with the String I want. If found, update atom flag. If flag=true no more new threads should be created. But not sure how to do that!

10:07 pppaul: learning, make this problem constant time, or fit it into pmap, or fit it into reducers

10:07 edbond_: learner, you need map-indexed

10:07 pppaul: personally, i would use constant time lookup

10:07 map-indexed + groupby

10:07 edbond_: pppaul, he needs only index of that string

10:08 pppaul: ?

10:08 AWizzArd: Anyone here who has a K10, K20 or K20x?

10:08 edbond_: ,(first (drop-while nil? (map-indexed (fn [i x] (if (> x 10) [i x])) (range 30))))

10:08 clojurebot: [11 11]

10:08 pppaul: ?

10:09 edbond_: first is index, second is value

10:09 change (> x 10) (= x "lookup-string")

10:10 learner: pppaul: edbond: AimHere: Ex:- I have a sequence something like ('abc 'cba 'aaa 'bbb 'bca 'ccc 'bac 'cab...............) I want to find the index of 'ccc which is 5. If I can find a program which gives me 4 or 6 is also fine as I don't need exact index. But I need to be sure that string exist + I need rough index. And the sequence in reality is so huge

10:10 pppaul: ,(first (group-by :body (map-indexed #(hash-map :index %1 :body %2) ["lalal" "bababa"])))

10:10 clojurebot: ["lalal" [{:index 0, :body "lalal"}]]

10:10 dnolen: learner: if you have a lazy sequence and a trivial computation I'm skeptical using thread will help.

10:11 pppaul: i don't think that 20 mil is a lot

10:11 dnolen: you could put the whole thing in memory but that will take time at it seems like ~1GB for say a vector + whatever memeory those strings take up.

10:12 pppaul: i have gigs coming out my wazoo

10:12 learner: dnolen: My problem is to go and do some more validations with the string I find. Once I find the string, I have some other checks to do. I was just trying give an example so that everybody understands what I need

10:12 dnolen: learner: when you say slow, how slow is your current solution?

10:13 learner: your explanation leaves out to many details. if you actually have an expensive computation, *maybe* pmap could help

10:13 pppaul: reducers!

10:14 i don't even know what i'm talking about anymore

10:14 put the data in a DB and let it do the hard work

10:14 learner: edbond_: Your example is perfect. But it does sequentially. It may take couple of days to complete the processing of the lazy queue I have. so looking for thread style

10:15 pppaul: ha ha. Sorry If I have confused you

10:15 dnolen: learner: what is the source of the data? can you not partition it ahead of time?

10:15 pppaul: learner, pmap has helped me, but it gets tricky if you don't want to work on the whole set

10:16 learner: dnolen: if I process the lazy sequence (which has millions of strings & combinations) sequentially. I guess it may take 3 or 4 days on a dev machine

10:16 pppaul: learner, put this stuff in lucene or something

10:17 dnolen: learner: is your guess based on how slow your code is on a small data set?

10:17 pppaul: learner pmap isn't going to help you

10:17 4 days is nuts

10:18 learner look into storm

10:18 learner: dnolen: My guess is based on how big dataset is. Source is https://github.com/clojure/math.combinatorics combinations

10:19 pppaul: Yes lucene option is cool. But how can I extract out from lazy sequence and put it into lucene. Sequentially? Hmm no. Is there any way I can run fixed number of threads to do it

10:19 pppaul: learner your problem hasn't been described well enough

10:19 dnolen: learner: are you saying you're going to use math.combinatorics?

10:20 pppaul: to me, it sounded like you have your data, and it's static

10:20 but now it sounds like you are generating your data in real time

10:20 what the fuck are you doing?

10:20 edbond_: learner, if you can load whole sequence in memory you can partition and process in parallel

10:20 dnolen: for 20,000,0000 strings over 4 days, this means you can only process ~58 strings per second, this seems absurd unless the processing of those 58 strings is very complex.

10:20 learner: pppaul: I am doing a little research project

10:21 pppaul: learner that doesn't help me understand your problem

10:22 seriously, i don't have a clue what your problem is, cept that you believe that you need to optimize some calculation you are doing

10:22 that's really not enough to go on

10:22 there are a million ways to solve such a problem, you need to be much more specific

10:23 the less specific you are the more of our time you are wasting

10:24 dnolen: learner: anyways based on the small amount of information given, I assume the processing each string is expensive, perhaps pmap+partition will work for you.

10:25 pppaul: it would help a lot if you could tell us if these 20million strings is your total dataset, or if this is the dataset per calculation

10:25 learner: pppaul: To keep it short. I will have a fixed string (generated dynamically). For now say it is "clojure" and when I have the word I will know the length. I have to generate various combinations using combinatorics and run through it until I hit the word I want. Kind of Brute force. But I need to get the possible range (that's the tricky thing). Since I need only rough index of the word, I can use threads.

10:25 pppaul: I need to find out how I can do it in clojure/scala/groovy & plain java

10:26 pppaul: hmm

10:27 learner: pppaul: I am a completely newbie and learning lot of stuff while implementing the suggestions you guys are offering

10:28 pppaul: hack the combinatorics thing to put indices on it's output, then send this job out to a bunch of computers via storm

10:29 well, i guess you don't need to hack the combinatorics thing

10:29 you just need to have 100s of computers working on this to get it fast if you think it'll take 4 days for 1 computer to finish the calculation

10:29 learner: pppaul: Are you talking about this ? https://github.com/nathanmarz/storm

10:29 pppaul: yes

10:30 learner: pppaul: Thanks. I will give a try

10:30 pppaul: if you are dealing with completely lazy sequences then this should be easy

10:30 learner: pppaul: It's a lazy sequence

10:31 pppaul: storm should work fine, and it has a good development/testing story

10:32 i would be very interested to see this working when you are done with it

10:37 devn: muhoo: http://getclojure.org is what you were thinking of. it's getting some love today. adding the ability for users to create ratings on examples

10:40 gdev: devn:) that's awesome, I was just talking to someone at work about that...*puts on aluminum helmet to keep devn out of his head*

10:40 (inc devn)

10:40 lazybot: ⇒ 6

11:03 rbxbx: devn: heh, getclojure doesn't like it when you pass an empty string

11:03 looks like it's coming along nicely though :)

11:10 jtoy_: is there a more idiomatic way to write this? (map (fn [x] ((meta x) :target )) data )

11:11 dakrone: (map (comp :target meta) data)

11:11 bbloom: or (map #(-> % meta :target) data)

11:12 jtoy_: thanks, i havent seen comp before

11:12 ToxicFrog: ,(doc comp)

11:12 clojurebot: "([] [f] [f g] [f g h] [f1 f2 f3 & fs]); Takes a set of functions and returns a fn that is the composition of those fns. The returned fn takes a variable number of args, applies the rightmost of fns to the args, the next fn (right-to-left) to the result, etc."

11:13 jtoy_: is comp basically the opposite direction of -> ?

11:14 bbloom: jtoy_: you can think of it that way, but comp is a function, -> is a macro

11:15 jtoy_: (comp x y) is (x (y …)) and (-> x y z) is (z (y x))

11:15 justin_smith: with comp you would not provide the other args to the functions unless you create lambdas

11:15 with -> you don't need to create the lambdas manually

11:16 jtoy_: right , i see, ill try with comp for now

11:49 matko: Question: should I be using ! in my function names for functions that alter state (through swap!, send, alter, etc)?

11:55 noidi_: matko, "Use the bang! only for things not safe in an STM transaction." http://dev.clojure.org/display/design/Library+Coding+Standards

11:55 matko: thank you, I just found that too. so that means I should do it if I use swap!, but not any of the other ones

11:56 but not for every destructive operation

11:56 is there another obvious way to point out that my functions are destructive?

12:00 bbloom: destructive ops aren't safe to use in STM :-P

12:00 noidi_: unless they're idempotent

12:00 bbloom: true

12:00 noidi_: e.g. emptying a mutable collection is destructive but idempotent

12:01 matko: anything wrapped in a (dosync) is safe to call from within a transaction though, right?

12:01 bbloom: i don't think that idempotence is sufficent though, since a transaction can permanently fail

12:01 matko: and anything send to an agent is only run on successful completion of a transaction

12:01 bbloom: generally, if you have a library that is all mutable ops, then you don't really need ! on every single function

12:02 if you have 1 destructive evil op in a sea of 100 others… then i say stick a ! on it, naming guidelines are guidelines for a reason, right?

12:04 matko: right, sounds good

12:31 gdev: j/ #probablywrong

12:31 derp

12:31 j/ dislexics_anonymous

12:31 doh >_<

12:37 learner: pppaul: I will let you know after trying storm. Thanks for your continued help

12:47 moquist: (class y) returns 'clojureql.core.RTable. (prn y) outputs "SELECT * FROM sometable". What I want in my code is that SQL string, because I need to send it somewhere else; I can't query directly. How does 'prn get the string representation of an object?

12:48 Google has not helped me with this yet; looking at https://github.com/LauJensen/clojureql/blob/master/src/clojureql/core.clj has also not yielded an answer so far.

12:48 justin_smith: moquist: str?

12:48 moquist: Sorry -- (str y) returns "clojureql.core.RTable@567ae64a"

12:48 * moquist forgot to mention this

12:49 justin_smith: (with-output-to-string (prn y)) ?

12:49 that should return the string prn would have printed

12:49 sorry

12:49 with-out-str

12:49 ,(with-out-str (prn :a))

12:49 clojurebot: ":a\n"

12:50 justin_smith: ahh!

12:50 ,(prn-str :a)

12:50 clojurebot: ":a\n"

12:50 justin_smith: seems like a common enough usage to have its own fn

12:50 weavejester: I've just been testing Clojure binary serialization libraries, and was quite impressed with deep-freeze, until I discovered it was serializing the data wrong :)

12:50 moquist: justin_smith: yes! That's more like it. Thanks!

12:53 Wild_Cat`: weavejester: aren't there Clojure libs for BSON or msgpack?

12:54 weavejester: Wild_Cat`: I wanted something that would retain all the Clojure data structures

12:54 hiredman: weavejester: fressian?

12:54 weavejester: hiredman: No Clojure library for that, unless you count the stuff in the tests

12:55 hiredman: weavejester: :/

12:55 dnolen: a good small example of using core.logic's featurec http://stackoverflow.com/questions/15821718/how-do-i-de-structure-a-map-in-core-logic

12:56 weavejester: https://www.refheap.com/paste/14401

12:57 There's not much to choose between Nippy and Carbonite.

12:57 Nippy seems to have the more straightforward API, though

13:10 mpenet: +1 for Nippy, it's really a gem.

13:14 devn: rbxbx: could you make an issue on the repo?

13:24 rbxbx: devn: sure.

13:36 devn: rbxbx: and then could you fix it and submit a PR? ;)

13:37 rbxbx: devn: ... probably.

13:37 devn: especially if you wanted to pair :p

13:37 devn: rbxbx: yeah, you got time this afternoon?

13:37 rbxbx: devn: I jest. It's probably low-hanging enough that I could tackle it alone.

13:37 and no, not really. Maybe this evening though.

13:37 devn: rbxbx: there's other stuff I could use a second pair of eyes on

13:38 rbxbx: Some of us have to work on Fridays :p

13:38 devn: ha! the solution as I'm sure you're aware is to simply quit your job.

13:38 rbxbx: sshhh, my co-workers are in here.

13:39 gfredericks: so I like "C-u C-x C-e", which writes the result to the buffer. What's the most straightforward way to get that to pprint to the buffer instead?

13:40 devn: rbxbx: if you're interested in helping out I'd like to rip out the hiccup templates and use laser or something instead. I have some really nice comps for the site and I want to just tell them to make me the static version and then i can just do transforms on what they hand me.

13:41 rbxbx: devn: maybe. I'm a bit over-extended right now :|

13:41 devn: also, it needs ratings. because if you search for comp the top result is (comp comp comp comp comp comp ...) -- not exactly the most useful or idiomatic example

13:41 rbxbx: right, we'd discussed this before.

13:42 I looked into that... but I didn't understand nearly enough of anything :)

13:42 devn: yeah i know i know, everyone is busy. either way, talk to you later, im off to go hack on that.

13:43 rbxbx: devn: cheers sir :)

14:12 devn: Where does the foo-1 naming pattern come from for reduce functions?

14:12 ToBeReplaced: what do people do when they want (need?) try-let (or try-catch-else)?

14:16 bbloom: ToBeReplaced: where "else" is "run this only if an exception is not thrown"?

14:16 devn: what foo-1 things are you talking about?

14:16 ToBeReplaced: yeah, presumably using a value from the try

14:17 bbloom: ToBeReplaced: i prefer to avoid exception handling in my primary code paths. i'd wrap up functions that can fail and have them return maps or keywords or whatever that describe their result

14:17 ToBeReplaced: java doesn't support it... you can hack it by storing a boolean and using the finally clause, but that's gross

14:18 technomancy: I don't get it; why would you need a separate else clause?

14:18 bbloom: (defn get-foo [x] (try (.getFoo x) (catch Exception e :error)))

14:19 technomancy: http://stackoverflow.com/questions/855759/python-try-else

14:19 ToBeReplaced: yeah that link will explain better than me :)

14:20 bbloom: ToBeReplaced: like i said: just avoid having exception handling logic bleed into your normal logic

14:20 technomancy: huh

14:20 ToBeReplaced: yeah seems like the way to go

14:20 bbloom: ToBeReplaced: if you need to handle an error case at the site of the error, it's not really exceptional, is it?

14:21 a wrapper function that returns {:status some-keyword, :result some-value} will do the trick

14:21 ToBeReplaced: bbloom: that's the general perspective, yeah, so i tend to agree with you -- hence why it doesn't seem to come up often in clojure

14:22 in python the etiquette is very much "try and ask for forgiveness"... there's less overhead in try-except than an if-statement if you rarely hit the exception

14:23 bbloom: ToBeReplaced: well the reason they recommend that is b/c they have embraced exceptions for control flow…. ie StopIteration exceptions!

14:23 ToBeReplaced: if you "look before you leap" you have a race condition

14:24 golang has it right: if you have error cases, use status codes. if you don't know what to do: panic & abort an entire process at a prompt/barrier/watever-you-want-to-call it

14:24 ToBeReplaced: right

14:29 technomancy: o_O

14:33 Glenjamin: error codes: exceptions you can ignore

14:34 tieTYT2: current thing I'm dealing with: http://stackoverflow.com/questions/16488423/reducing-a-sequence-into-a-shorter-sequence-while-calling-a-function-on-each-adj

14:35 weavejester: What does everyone think of having a deref-able type initialized from a no-argument function?

14:35 Kinda like a derived reference

14:36 bbloom: weavejester: do you mean a thunk? like ##(doc delay) ?

14:36 lazybot: ⇒ "Macro ([& body]); Takes a body of expressions and yields a Delay object that will invoke the body only the first time it is forced (with force or deref/@), and will cache the result and return it on all subsequent force calls. See also - realized?"

14:36 ohpauleez: weavejester: Why not use a promise that you pass into the initializing function?

14:36 weavejester: bbloom: Yes, but one that's tied to another ref, so the result isn't cached.

14:36 ohpauleez: ah

14:37 bbloom: oh, like a pointer to a pointer?

14:37 Glenjamin: allowing you to use @foo instead of (bar) ?

14:37 matthavener: tieTYT2: how is that different from a reduce?

14:37 weavejester: Glenjamin: Right

14:37 Glenjamin: why not just call the function? :p

14:37 weavejester: I'm not convinced it's a hugely good idea, but here's my use-case

14:38 I have a world data structure that represents the state of a game world

14:38 bbloom: ,@(clojure.lang.Delay. (fn [] :done))

14:38 matthavener: tieTYT2: (reduce mystery-fun (first coll) (rest coll))

14:38 tieTYT2: matthavener: apparently it is, I'm using reduce

14:38 clojurebot: :done

14:38 weavejester: And I have an scene data structure that represents what the user can see

14:39 So I connect the world to the scene with a watch. When the world changes, the scene alters as well.

14:39 matthavener: tieTYT2: and if you only want the 'last' of the retval of 'mystery-fun' just wrap it in a function that calls (last) on the retval

14:39 trptcolin: is it expected in cljs that if you extend a protocol to js/Object, a fresh (js-obj) will have key/value pairs? i guess i expected the data for protocol implementations to live elsewhere.

14:39 tieTYT2: matthavener: since mystery-fun returns a sequence, won't the result of the reduce be a sequence of sequences of sequences...?

14:39 matthavener: tieTYT2: sure, but like i said, you can wrap mystery-fun in a 'last' if you only care about the last

14:40 weavejester: So I can handle this with a set of world->scene functions

14:40 tieTYT2: matthavener: how do I keep the butlast of it?

14:40 weavejester: Or I could populate the scene with references to the world, and deref-all the scene

14:40 Kinda a push/pull approach

14:40 matthavener: tieTYT2: i'm not sure what you mean by that, specifically "keep the 'butlast' of what you've got so far"

14:40 dnolen: trptcolin: you don't want to extend to js/Object, extend-type object

14:40 matthavener: tieTYT2: what do you mean by "what you've got so far" ?

14:41 bbloom: weavejester: yeah, this is a hard category of problems that i've been thinking about a lot: how to synchronize two views of the same data

14:41 trptcolin: dnolen: awesome, thanks

14:41 weavejester: bbloom: I'm glad I'm not the only one thinking about this :)

14:41 tieTYT2: ok let's say calling (mystery-fun o1 o2) returns [o1 o2]. What I want to do next is compare [o1 (mystery-fun o2 o3)] and flatten that

14:41 patchwork: bbloom: You have both views depend on the same data source?

14:42 tieTYT2: see how the o1 is still in the result? that what I mean by keeping what you've got so far

14:42 bbloom: patchwork: more accurately, i have a document translation

14:42 patchwork: the two views don't need to know about each other, updates flow from the data source

14:42 matthavener: tieTYT2: i think i see, you can just make your reduction a tuple

14:42 ohpauleez: weavejester: Is is possible (or advantageous) for the "scene" to be a function that takes the world and produces a slice?

14:42 bbloom: patchwork: it's one way: you have some source value & it is transformed to some view of it and chagnes to the source value need to be reflected efficently in the view

14:42 ohpauleez: rather than a data structure of the slice

14:42 dnolen: trptcolin: generally true for all the real JS languages natives

14:43 trptcolin: gotcha, i was extrapolating to assume that just now :)

14:43 tieTYT2: matthavener: and the first part is a sequence that grows?

14:43 weavejester: ohpauleez: Maybe… at the moment it's an atom, which seems like it's a little more transparent I guess.

14:43 Plus the UI isn't necessarily dependent on the world.

14:43 ohpauleez: and then the watcher can deliver a future, that you can deref when you need to use the "scene" slice

14:44 weavejester: I'm experimenting with a Leiningen-like profiles approach

14:45 matthavener: tieTYT2: https://www.refheap.com/paste/14402

14:45 weavejester: But… Hum… I'd like to deal with data rather than function composition.

14:45 ohpauleez: at the end of the day you're dealing with data

14:45 the slice you get back is data

14:46 weavejester: Or do I? I could have a bunch of middleware-like functions I compose that generate the final app data structure.

14:46 ohpauleez: right

14:46 yes

14:46 and so you start modeling it as core game data, and ways to derive your various game states

14:46 and build it intoa dataflow

14:47 tieTYT2: matthavener: hm, what if r is a sequence with a count of 1?

14:48 matthavener: tieTYT2: then (rest r) is empty

14:48 tieTYT2: matthavener: also, you're not doing anything with sofar. Is that intentional?

14:48 weavejester: I might have to change the way I handle events...

14:48 tieTYT2: you're passing the first element into mystery-fun, not the last

14:48 matthavener: i guess? i'm only trying to implement what you're describing

14:49 yeah i suppose you should replace 'rest' with 'butlast' and 'first' with 'last'

14:50 weavejester: At the moment I have: {:type :button, :on-click (fn [event] …}}

14:50 But maybe it should be: {:type :button, :state :clicked}

14:51 Maybe my problem is the way I'm mixing event handlers in with my data structure.

14:51 ohpauleez: weavejester: In a system of flows, C2-event or pub/sub fits well (in my experience). So yes, i'd make that change

14:51 bbloom: weavejester: i've been trying to come up with something clojure-y for UI handling for months. it's hard :-) hopefully i'll have something cool to show soon… we'll see

14:51 ohpauleez: then let anyone who wants to know about the "click" subscribe and do something

14:51 passing more data back into the bus, or down through the flow

14:51 weavejester: bbloom: It is hard! I think I've changed it twice already :)

14:52 kephale: weaverjester: if you don't mind my asking, are you talking about a 3D rendered world?

14:52 weavejester: I tried maintaining an event bus and a data structure, but it didn't really worlk well.

14:52 kephale: weavejester*

14:52 weavejester: kephale: Yep.

14:53 kephale: I basically have a (run-app (atom …)) function that's at the core of this framework/game I'm building.

14:53 kephale: weavejester: ok, is yours open source? i'm at alpha/beta with my 3d simulator which has a modified penumbra under the hood

14:54 weavejester: kephale: No, but I'll probably open-source bits of it later. It's using jMonkeyEngine.

14:54 ohpauleez: weavejester: What was the issue you ran into with the bus?

14:55 kephale: weavejester: ok cool, i'll look for you later to chat more. I thought about jMonkey but didn't like sticking to their API. currently i have a ODE + penumbra working pretty well together

14:55 including some of the UI handling

14:56 gotta run for now… "brevis" on github

14:56 hiredman: bbloom: have you played with pedestals model (not sure what to call it) at all? I guess event sourcing?

14:56 kephale: ciao

14:57 bbloom: hiredman: pedestal kinda stops short at the view layer

14:57 hiredman: bbloom: sure

14:57 bbloom: hiredman: i haven't studied it too deeply, but it just feels a little heavyweight

14:58 hiredman: i need to study it a bit more, but i'm coming at it from a pretty different angle

14:58 weavejester: ohpauleez: I was getting a problem reconciling the the event bus with my data structure. Like… say I have a FPS counter. I have to have something that subscribes to the event bus to catch each :tick event, but also I need to pass it the atom representing the application.

14:58 ohpauleez: It felt like I was dealing with two systems, when I really wanted one.

14:58 gdev: bbloom:) the documentation explains that it was developed to handle hard problems that other lighter frameworks dont do well

14:58 weavejester: I'm beginning to think I don't actually need events...

14:59 hiredman: bbloom: I write a little thing in it, and I ended like the sort of event transforming stuff, but not the rendering.cljs bits

14:59 wrote a

14:59 ended up liking

14:59 :/

14:59 bbloom: hugod: ok there is a fip 0.3.0 release now

14:59 technomancy: should i backup my gpg key? heh

14:59 gdev: mentioning Pedestal in the IRC triggers an alarm at Relevance so someone who knows more about it should be in here in 5..4..3..2...outOfBoundsException

15:00 ohpauleez: haha

15:00 weavejester: Just encode events in the state. Like instead of having a :tick event, have a counter that we watch for changes.

15:00 bbloom: gdev: i dunno what those "harder problems" are. i think even pretty basic UIs are pretty damn hard with the nightmare that is html/css/js for apps instead of for docs

15:01 technomancy: bbloom: yeah, but not in a network-attached location

15:01 bbloom: technomancy: i don't think i have any non-network attached locations… at least not any that wouldn't be destroyed in the same fire that destroys my laptop :-P

15:01 gdev: bbloom:) don't shoot the peanut gallery ;)

15:01 technomancy: bury an SD card in your back yard =)

15:01 hugod: bbloom: thanks! hope the gpg experience wasn't too painful

15:01 bbloom: technomancy: i live in NYC… what's a back yard?

15:02 hugod: the docs were surprisingly helpful. good job technomancy & team!

15:02 technomancy: bbloom: hmm... do you have community gardens over there? =)

15:02 bbloom: hiredman: the rendering bit of course is gonna suck no matter what b/c it's html & css :-P

15:02 hiredman: weavejester: pedestal seems to go the other way, you do everything has events and transforms of events, and behind the scenes it tracks the state that events ultimately alter or are a result of

15:02 gdev: bbloom:) it's like a park but it's attached to your house and has less hobos and dead hookers buried in it

15:03 rkneufeld: gdev: sorry, I was out for coffee ;)

15:03 bbloom: technomancy: what happens if i lose my key? i just can't publish new software?

15:03 technomancy: (i know what happens if it is stollen)

15:03 technomancy: or do i just have to make a new key & people need to trust whoever that asshole future brandon claims to be

15:04 ohpauleez: hiredman weavejester: I'm of that same school of thought. I'd embed fragments of state within the events. Build the entire state from the whole stream of events (which may produce new events), and take a view on the final state withe by slicing or by subscription

15:04 bbloom: hiredman: what did you like about the event transforming bits?

15:04 hiredman: you didn't find that to be a bit onerous ?

15:05 technomancy: also, should i check in pom.xml and/or pom.xml.asc ?

15:05 weavejester: hiredman ohpauleez: I think I definitely want to go one way or the other. My current implementation is suffering from being a bit of both.

15:05 tomoj: when I found the square root example, I stopped looking at pedestal for the day

15:05 ohpauleez: yes, it's hard to do both - it's like double book keeping

15:05 tomoj: but maybe it's only onerous for trivial apps?

15:06 hiredman: bbloom: it was onerous, but I liked that it is a small set of primitives

15:06 bbloom: hiredman: yeah, i'm just not convinced that it's sane to expose those primitives to users...

15:06 tomoj: i'm looking at the sqrt example now… wutdafaq?

15:06 ohpauleez: bbloom: Why not?

15:06 tomoj: you should be sure to look at the new one

15:07 https://github.com/pedestal/pedestal/blob/master/app/test/clj/io/pedestal/test/app.clj#L476

15:07 the version 1 models are even wackier

15:07 bbloom: ohpauleez: because it means hand coding a complex static topology that implies your information hierarchy

15:08 tomoj: my guess was that the plan was to do something like core-async and compile out to those primitives from a more accessible representation

15:08 bbloom: i don't think it is reasonable to assume that your view state will every be large enough to justify virtualizing it

15:08 ohpauleez: I agree that means hand coding the static topology, but how does it imply the information hierarchy

15:08 bbloom: sure, you can have a list view that would have 1000000 items in it, you'd want to virtualize that. but that's the exeception, not the rule. & you can only show a few hundred bits of information at once if any human has a hope of reading it

15:09 with that in mind, i think it makes sense to reify the view state into a single tree value, rather than some transient virtual tree thing

15:09 tomoj: :(

15:10 bbloom: ohpauleez: the virtual tree is (most often, not not necessarily) isomorphic to your view hierarchy

15:10 allow me to be clear: i have not studied pedestal in detail, so i'm somewhat talking out of my ass from what i recall from the clojure/west presentation

15:11 i expect i will get some first hand experience with it soon, but my initial reaction was "why would i want a VIRTUAL tree?"

15:11 weavejester: I think I'm going to represent my game as a function that transforms frame_n -> frame_n+1

15:11 tomoj: either way, it's a tree of places, right?

15:11 ohpauleez: weavejester: I think that's smart

15:11 tomoj: (or a place with a tree in it, I'd argue these are isomorphic..)

15:11 bbloom: weavejester: conceptually, that's what you want. the trick is doing that efficiently :-)

15:12 tomoj: I for one would not like to write a function frame_n -> frame_n+1

15:12 weavejester: That's kinda what I'm doing anyway, just with an atom instead.

15:12 bbloom: tomoj: you don't WRITE that function. you generate it from a description of the behavior of the world :-)

15:12 weavejester: I have a bunch of aggressively cached functions in the background that map a data structure into a 3D world.

15:12 tomoj: yeah, right :)

15:13 noncom: weavejester: that will surely be _the way_ when we have quantum computers and it will be the most natural thing to do - change state at once!

15:13 weavejester: Well, the function frame_n -> frame_n+1 would be the result of composing a bunch of smaller functions.

15:13 Although composed functions are a little opaque.

15:13 Pupnik-: the thing that unsettles me with that weavejester is you have to pass around some sort or gigantic data structure

15:14 tomoj: frame_n -> frame_n+1 still seems sorta weird to me, where is the information about the length of time that passed between frames, and who uses that info, how?

15:14 weavejester: Pupnik-: So?

15:14 bbloom: weavejester: you compose a data structure & your next-frame function is an abstract machine which accepts current-frame and program-to-transform-frame

15:15 weavejester: tomoj: Well, I guess to be more accurate it would be frame_n+1(with no change) -> frame_n+1(with change)

15:16 tomoj: You start out with a frame that contains the time, what keys were pressed, etc, then use that information to update the system… although… time between frames would be difficult to incorporate into that.

15:16 noncom: so its like state_n+1 = state_n + delta. what is delta?

15:16 tomoj: ah right, so basically like requestAnimationFrame, the current time is being passed in to each next-frame call

15:17 weavejester: Currently I have a tick event, like: {:type :tick, :tbf 0.0215}

15:17 Where tbf is the time between frames, so I can use it to calculate position from velocity and so forth.

15:17 tomoj: eventually I guess any answer will boil down to that, but I want to completely eliminate it from the part of the code I usually look at

15:18 just because of the nightmares I've had working with (bad, so this may be unfair) code that deals with that info

15:19 bbloom: http://blogs.msdn.com/b/shawnhar/archive/2007/07/25/understanding-gametime.aspx

15:19 ^^ really good info about game time steps

15:19 tomoj: I guess a whole lot of the nightmare was the unrestricted mutation involved

15:20 weavejester: Maintaining a fixed game step time sounds difficult.

15:21 And often you want to change position in time with your draw steps

15:21 Okay, so if option 1 is to go fully functional, option 2 is to go fully event based. I'm not sure exactly what that would look like, though.

15:22 tomoj: so what's option 1? I've been trying to discover it :P

15:23 Foxboron: So, i got some time on my hands. Is there any Clojure projects wich could use a clojure newb for bug hunting?

15:23 weavejester: tomoj: I guess at each game tick, deliver some static datastructure about the current game state, and use it to generate a new data structure.

15:24 tomoj: hmm

15:24 I was thinking the atom there that you swap! every tick makes it not 'fully functional'

15:24 but it's basically the same as an iterate seq?

15:25 noncom: i have a question: i have a function that accepts {:keys [key-1 key-2.....]}. and i want to execute a separate action for each key, if it is not nil. so i do a bunch of lines like `(if key-1 (action-1 ...))` and for each key. is there any way to automate it?

15:25 weavejester: tomoj: Oh yeah, it's not fully functional at the moment. I'd do away with the atom if I went with this approach.

15:25 tomoj: no, it's not an iterate seq because information about user events etc magically shows up

15:25 noncom: its an io monad?

15:26 weavejester: tomoj: Yeah, the user events magically showing up is concerning me.

15:26 tomoj: Do I need two data structures? (fn [previous-frame events] …)

15:26 Or is that just another way of thinking about an event bus

15:27 noncom: weavejester: what are you trying to acheive after all?

15:27 weavejester: noncom: I don't know anymore :)

15:27 noncom: I guess to get a good way of representing a 3D application with data.

15:27 noncom: So a data-driven 3D app.

15:28 noncom: yeah i read that in the jmonkey thread

15:29 weavejester: so wahts the problem with making it data-driven? you want to eliminate state and mutations???\

15:29 tomoj: (reduce next-frame initial-frame input-events) ?

15:29 weavejester: Currently it's an atom, but I'm mixing in :on-click events and stuff, which is probably bad. My model resembles a HTML DOM, in that it's data that can be mutated, and you can attach :on-blah events to elements.

15:30 tomoj: Hum...

15:30 tomoj: Interesting.

15:30 tomoj: just extrapolating from your suggestion

15:30 weavejester: noncom: I don't want to eliminate state and mutation - just constrain them.

15:30 tomoj: I don't know what you're trying to achieve either :)

15:31 weavejester: Fundamentally in any functional language, you want to reduce mutation to a minimum.

15:31 Ideally, you have one function that hides all the mutation, and everything else is functional.

15:32 So I guess that's my goal

15:33 tomoj: so you have input and output?

15:33 or just output?

15:33 weavejester: tomoj: Input and output

15:33 Which I guess is the root of the problem

15:33 As I have input -> events

15:33 output -> atom

15:34 I'm dealing with input using an event bus, and then swapping an atom for output.

15:34 I need to go one route or the other, I think.

15:35 noncom: weavejester: i don't really see a problem here

15:35 tomoj: there's basically two operations, obtain and render?

15:35 @ and whatever that thing rich was talking about is called

15:36 maybe conj! if that got broken out of transients

15:36 weavejester: noncom: What do you mean?

15:37 noncom: weavejester: are you trying to realize how to acheive that theoretically or how to code it in clojure?

15:37 weavejester: noncom: Coding it in Clojure

15:37 noncom: oh, i see then

15:37 i thought you were more after finding some theoretical basis for that

15:38 tomoj: bbloom: is a non-virtual tree just a map?

15:38 Pupnik-: weavejester, you have some good options for gamedev with clojure, like libgdx or slick2d

15:39 weavejester: Pupnik- I'm already using jMonkeyEngine behind the scenes. The internals aren't the issue so much.

15:39 Pupnik-: there just seemed to be a lot of fuss over frame time which is almost always provided by a lib if you use one

15:40 weavejester: Pupnik-: Oh, I can get the time frame easily. I'm just trying to find the right way to model it.

15:40 Is it a series of asynchronous events?

15:40 Or a functional transformation of frames?

15:40 noncom: this is a matter of POV

15:41 bbloom: tomoj: yeah, a map of maps of maps

15:41 n_b: On testing, the clojure.test is the community preferred option, right?

15:42 noncom: weavejester: is the only problem you have left is how to handle user input more functionally? is everything else (if there is no user input) already fully functional?

15:43 weavejester: noncom: I guess the issue is the amount of references I'm currently passing around...

15:43 ucb: n_b: clojure.test is the standard, but there are others like midje which are interesting to explore

15:44 weavejester: Okay, simple example: you click a box and it turns red.

15:44 tomoj: hey, great, I already have a red box

15:44 weavejester: So if the box mutates, maybe you put it in a ref. Does that mean all objects in your scene are refs?

15:44 tomoj: but no user input yet

15:44 n_b: ucb: I've seen people complaining about midje in here before, and while I don't know specifics I thought it was worth asking about before I go about open sourcing some stuff

15:45 Pupnik-: weavejester, you don't need mutation to turn your box red

15:45 weavejester: Do I have an event like: {:type :click :object (ref my-box)}

15:45 Pupnik-: Can you elaborate?

15:46 ucb: n_b: I've used (and still use) midje with no complaints; but YMMV, it all depends on what you want and need really :)

15:46 noncom: weavejester: so, you *do not* have your world fully functionaly developing on each frame, you rely on pure state where possible?

15:47 Pupnik-: its state is part of the 'game state' that is re-generated each frame through the (new-state) function

15:47 weavejester: noncom: Currently the world is a ref, and the current application state is a ref.

15:48 Pupnik-: Right, so alternatively, I could represent the box like: {:shape :box, :state :clicked}

15:48 And then have a function that iterates through the world looking for clicked boxes and turning them red.

15:48 Pupnik-: well, ultimately you will need to tell your renderer what to do

15:49 weavejester: However… that sounds expensive.

15:49 Pupnik-: but your clojure code can be immutable

15:49 watch some videos about clojure data structures :)

15:49 of course, maybe it will be too much at 60fps

15:49 I havent tried making a game yet, but i will soon

15:49 dnolen: weavejester: why not just thread the world state through the game? I liked ztellman's early experiments along those lines with penumbra

15:49 weavejester: Pupnik-: I am acquainted with Clojure data structures :)

15:50 Pupnik-: it shouldn't be too bad, its jmonkey that will do the rendering

15:50 * `fogus vouches for weavejester

15:51 weavejester: dnolen: Hm...

15:51 I guess I need to clear my mind on this.

15:52 Thanks everyone for listening to me ramble

15:52 You've made me understand I'm really confused, and don't have a clear plan

15:52 dnolen: user events can go into a queue and you can assoc them onto the world state before calling into the main handler

15:52 weavejester: So… the first step to enlightenment is complete.

15:53 noncom: :D

15:53 weavejester: dnolen: Yeah, I was thinking about that. But doesn't that, I don't know, taint the world a little...

15:53 dobladez: Emacs question: to show eldoc messages, emacs expands and shrinks the "echo area", which is quite annoying. Anybody knows how to fix that?

15:54 noncom: weavejester: there is a need for a clear view i think

15:54 dnolen: weavejester: http://github.com/mjg123/pacman/blob/gh-pages/src/pacman/core.cljs#L321

15:54 dobladez: I tried customizing option 'Eldoc Echo Area Use Multiline', but it doesn't seem to make a difference

15:54 Pupnik-: you can't keep the world state compeltely pure, it will always need to read things like frame time

15:55 well, not always maybe your game doesnt care about that

15:55 but usually

15:55 tomoj: huh?

15:55 "world state" and "frame time" seem very disconnected, semantically, to me

15:55 Pupnik-: if you need to run a physics simulation, you need frame time

15:56 tomoj: if you describe the equations of the system being simulated, does the frame time play a role?

15:57 weavejester: I currently want to keep the app (i.e. what the user sees) separate from the world (i.e. what the server simulates)

15:57 The app contains the UI, the 3D scene, the HUD, and so forth.

15:57 An event might trigger a change in the world, or a change in the app.

15:58 tomoj: oh right, frame time clearly has nothing to do with the world in your case, since you might have multiple views of the same world running at different framerates?

15:58 or just not in sync frame-by-frame with eachother anyway

15:58 Pupnik-: tomoj, it will be server tick rate in this case

15:58 tomoj: yeah, right

15:58 Pupnik-: since the server will run the simulation

15:58 tomoj: but still, does it show up in the equations? if not, I don't want to write it in my code :)

15:58 weavejester: tomoj: Yes. The world is potentially external (although there will be a local copy), the app is internal.

15:58 pandeiro: is there an easy way to use long-polling with jetty?

15:59 Pupnik-: unless you use a fixed time-step (which will cause the entire simulation to slow down if you can't hit your target), you need frame time or very strange things happen

16:00 weavejester: Currently an event will trigger a function, which can update the app or update the world, or both.

16:00 But currently I'm taking a HTML DOM-like approach, and assigning event handles by adding :on-click attributes to the app.

16:01 Which is leading to a circular dependency.

16:01 ztellman: weavejester: I wrote this ages ago about writing a "functional" game: http://ideolalia.com/creating-a-simple-game-in-clojure/index.html

16:01 tomoj: you need frame time somewhere, but I want it in the background, not in my world data/logic

16:01 ztellman: basically callbacks are pure functions on the world state, except for the display callback, which only performs side-effects

16:02 noncom: i think that user input is not something separate from the world. user input is an object of the world which has some interactions with other objects. however, it is not transperent for any object of the world - them can't see inside it. that is how i see it - it simply is an object of the world. and it's behavior inside the world is no different from other objects.

16:03 weavejester: ztellman: I've separated out internal state (like whether a UI window is displayed) from external state (like where the player is in the world)

16:03 tomoj: asteroids is a great example

16:03 weavejester: ztellman: Currently both are refs an event handler can update.

16:03 tomoj: source link is dead, new one https://github.com/ztellman/penumbra/blob/master/test/example/game/asteroids.clj

16:03 ztellman: weavejester: any reason to not have them just be entries in the same block of state?

16:03 tomoj: I'll fix that, thanks

16:04 tomoj: I do not envy the people why find github links with "master" in their only promising search result - irc logs

16:04 who.

16:05 almost feels like it should be a redirect..

16:05 with a 'copy link to master' button with a red exclamation point and a tooltip..

16:05 weavejester: ztellman: Well, the world can be updated over the network. I guess I could buffer network events per frame, but… that seems to be doing the job of a ref and dosync.

16:06 ztellman: weavejester: ah, ok, all my callbacks were in response to in-process events

16:06 makes sense to differentiate

16:06 gfredericks: how can I run clojure.test tests without leiningen?

16:07 weavejester: ztellman: Clojure's refs provide a nice way of taking a per-frame snapshot of a changing data structure.

16:07 tomoj: bbloom: did you coin 'virtual' in the context of pedestal?

16:07 bbloom: tomoj: i'm speaking from memory. i think they called it a logical tree

16:08 ztellman: weavejester: yeah, if you look at the post I linked to, there were multiple concurrent processes updating the blob of state

16:08 checking for collisions, checking if the exhaust should be emitted, etc

16:08 all interacting with an atom

16:08 mikerod: Is this expected behavior of `flatten`?

16:09 tomoj: suppose you break the state up into a bunch of little atoms/refs

16:09 mikerod: ,(flatten (java.util.Collections/unmodifiableList [1]))

16:09 clojurebot: ()

16:09 mikerod: (flatten (seq (java.util.Collections/unmodifiableList [1])))

16:09 weavejester: ztellman: Maybe I'm looking at the wrong thing… what do your callbacks look like?

16:09 mikerod: ,(flatten (seq (java.util.Collections/unmodifiableList [1])))

16:09 clojurebot: (1)

16:09 ztellman: the callbacks are registered at https://github.com/ztellman/penumbra/blob/master/test/example/game/asteroids.clj#L384

16:10 ucb: gfredericks: you mean in a repl?

16:11 tomoj: instead of (assoc state :foo (foo' foo)) you have (swap! state/foo foo') say

16:11 what did you lose?

16:11 weavejester: ztellman: Is the world state internal to the app? So the callbacks never see it directly?

16:11 gfredericks: ucb: sure

16:11 ucb: I'm debugging why my tests hang and thought I would rule out or implicate leiningen

16:12 ztellman: weavejester: notice that each of the callbacks have a 'state' parameter

16:12 ucb: gfredericks: there's (run-tests...)

16:12 ztellman: and they return a modified state

16:12 ucb: ,(doc run-tests)

16:12 clojurebot: Excuse me?

16:12 ucb: bleh

16:12 mikerod: ,(= (flatten (seq (java.util.Collections/unmodifiableList [1]))) (flatten (java.util.Collections/unmodifiableList [1])))

16:12 clojurebot: false

16:12 technomancy: bbloom: I don't think losing your key needs to be handled differently from having it compromised

16:12 weavejester: ztellman: The {:dim *dim*} - is that the initial state?

16:12 ztellman: So (app/start callbacks initial-state) ?

16:13 technomancy: basically before it's lost you generate a revocation cert; if it's lost/compromised you publish that with the date it was lost

16:13 bbloom: technomancy: which assumes i don't lose the revocation cert....

16:13 technomancy: heh, yep. some people recommend printing it out and filing it.

16:14 this is why we give keys an expiry date =)

16:14 bbloom: technomancy: i think i'm just gonna assume my key is safe-enough w/ my full drive encryption & not really worry all that much if i lose it.

16:14 technomancy: to limit the damage that can be done if it's compromised and can't be revoked

16:14 bbloom: technomancy: i know security people hate when smart folks say stuff like that :-)

16:15 can i add a comment to my key w/ a link to these IRC logs, so that anyone who is trying to decide whether or not to trust me can make a judgement call? :-)

16:15 tomoj: it's basically a manual state monad, right? so what is lost if you just use state?

16:15 technomancy: bbloom: it's a big step up from not doing any signing =)

16:15 tomoj: (fn [state] (foo (update-state state) (update-state state))) becomes difficult?

16:15 technomancy: bbloom: checking a pom or pom .asc in usually isn't a great idea. using signed git tags is though.

16:16 bbloom: technomancy: signed git tags?

16:16 tomoj: ..I guess everything becomes difficult?

16:16 technomancy: bbloom: just use the -s arg to git tag

16:16 bbloom: technomancy: release management is a PITA….. stupid software… heh

16:16 weavejester: tomoj: Updating a state via a return value doesn't seem particularly tricky.

16:17 technomancy: bbloom: brb; screw this going back to rubygems, etc =)

16:17 bbloom: technomancy: ha

16:17 technomancy: i mean, lein has to wait for the JVM to start, soooo who cares if rake takes 45 seconds to initialize?

16:17 ztellman: weavejester: sorry, stepped away for a second. Yes, that's correct.

16:18 linuxos: clojure uses just long for storing integers. even for small counters?

16:18 tomoj: well I'm imagining if you move the state ops down into all the leaves where you update a state map during an epoch. then everything is tricky, right? cus you're just in normal-java-variable land

16:19 so with a state map and (fn [state] state'), inside an epoch you're in sane-functional-land? but if you look at the program across many epochs, do you have to start using mutation-land reasoning again?

16:20 Pupnik-: its the time slice approach

16:21 the progress of time is represetned by a series of immutable states

16:21 clojurebot: c'est bon!

16:21 chessguy: salutations and other such pleasantries

16:21 weavejester: Pupnik-: Well, really, that's always the case

16:22 Pupnik-: weavejester, except normally those states are modified in place and you lose access to the old ones

16:22 if you wanted to know a players velocity was 5 seconds ago

16:22 you cant check

16:22 weavejester: ztellman: It seems that by changing the state through a callback, you lose some of the control a ref would give you.

16:23 Pupnik-: Yeah, that's the main difference

16:23 tomoj: Pupnik-: how do you gain that ability?

16:23 if you just have an atom with the current state, you don't have that ability, do you?

16:23 ztellman: weavejester: by only using callbacks, it gives the game loop more control over when these things happen

16:23 Pupnik-: no

16:23 ztellman: which I found to be useful

16:24 Pupnik-: or at least, i dont think so

16:24 ztellman: that may or may not prove true for you

16:24 Pupnik-: i know much more about how games work than about clojure

16:26 tomoj: I guess pedestal addresses this by making the current state a view of an append-only collection?

16:26 linuxos: clojure is dealing with longs as default .. is this to make it simple with no conversion back and forth despite greater memory consumption?

16:26 tomoj: (also datomic..)

16:28 linuxos: "Clojure 1.3 constructs a new Long around

16:28 an int instead, because rich has decided he prefers longs and doubles

16:28 to ints and floats.

16:28 "

16:29 weavejester: brb food

16:30 tomoj: if you have (fn [state] state') that could just be a vector of all the states, except you probably don't want to keep them _all_ around in memory. in pedestal you have to turn recording on and the app itself has no access to the past?

16:30 ..other than whatever it actively remembers in the state

16:32 we have one nice solution already for deciding what needs to be remembered and automatically remembering it for those who need it - GC

16:44 jtoy_: anyone know of a simpel library that will do cross validtion for me in clojure?

16:48 tomoj: jtoy_: I don't, but it shouldn't be too hard - if you have a (fn evaluate [train validation]), you can just do something maybe like this: https://www.refheap.com/paste/69451ef5033f9ec6c7743bb5b

16:48 for k-fold

16:48 augustl: thinking of moving from lein-ring and war files to self contained jetty. Does lein-ring support that, or do I have to make my own "lein run" namespace where I start jetty myself etc?

16:49 tomoj: well you'd want to compute n from k

16:51 technomancy: augustl: it's easiest just to add ring-jetty-adapter and a 5-line -main defn

16:55 augustl: technomancy: I'll miss the auto reloading :)

16:55 probably easy to pull that in manually too, I guess

16:55 technomancy: augustl: nrepl

16:56 jtoy_: tomoj: ok, I can try that, i've never written my own cross-fold library as I dont know 100% of the steps, but should be farily easy

16:56 augustl: technomancy: ah good, another reason for our one remaining IntelliJ dev to switch ;)

16:59 tomoj: jtoy_: oh wait, looks like incanter has it

16:59 "simple"? not sure

17:03 owengalenjones: anyone ever see this https://www.refheap.com/paste/14406

17:04 jtoy_: tomoj: if I understand properly, the whole algorithm is just cut into k slices, train on k-1 and test against k and do that for all combinations and then average the results?

17:04 tomoj: yeah

17:04 ucb: owengalenjones: I don't think :1 is a valid keyword

17:05 owengalenjones: ucb: (keyword? :1) => true :)

17:06 ucb: owengalenjones: ugh :)

17:06 I honestly thought it wasn't a valid keyword :)

17:06 arohner: ,(keyword "foo "bar")

17:06 clojurebot: #<RuntimeException java.lang.RuntimeException: EOF while reading string>

17:06 arohner: ,(keyword "foo bar")

17:06 clojurebot: :foo bar

17:06 owengalenjones: O_o

17:07 arohner: ,(keyword ":foo")

17:07 clojurebot: ::foo

17:08 gfredericks: ucb: you've really exposed my tendency to not put the smallest amount of effort into figuring things out for myself

17:08 ucb: gfredericks: I'm a sinner as well :)

17:17 kathy1: Holaaa

17:19 jtoy_: tomoj: evaluate in your example just means call my function?

17:41 satch5150: hi all, I am trying to figure out how to use cli from tools.clj; it all seems pretty staight forward, except I do not know how to use :parse-fn patterns; could someone point me to some appropriate documentation for that ?

18:22 tomoj: jtoy_: right

18:22 which returns your metric on the validation data after training

18:34 Apage43: man, going back and forth between emacs and vim recently, as I can get stuff done a bit faster w/ clojure in emacs, but still like vim for C and friends

18:35 in emacs when I'm whacking out one of these intricate incantations I feel like one wrong move could annihilate an entire civilization. I've already deleted files by fat-fingering a couple of them.

18:36 in vim the worst I'll do is delete some of the file I'm working on, which is easy enough to undo

18:38 ohpauleez: Apage43: Why not use fireplace in vim?

18:39 tomoj: does pedestal's :continue violate the epochal time model?

18:39 Apage43: I do. It's fantastic as far as those things go, and I like it better when I'm working on some things.

18:39 ohpauleez: fireplace + paredit + surround makes for a pretty competent setup

18:39 ahh cool

18:39 tomoj: or it just makes the epochs sub-transaction?

18:39 Apage43: what it doesn't handle very well is when I am evaling expressions that might get stuck in a loop and I need to kill them

18:40 ohpauleez: Apage43: It'll timeout and drop it

18:40 but you'll have to restart the jvm - as you would in emacs too

18:40 Apage43: it does that and frees up my vim session yeah, but my nrepl sessions typically is still hung

18:40 hiredman: tomoj: continue is just a loop

18:40 ohpauleez: right, I guess I always have my repl instance running in another tmux pane or window

18:41 Apage43: nrepl.el C-c c-c will actually .stop the thread

18:41 which even works some of the time

18:41 ohpauleez: ahh gotcha

18:41 Apage43: same as what Ctrl-C does in lein repl/reply

18:41 tomoj: hiredman: oh, yes, I was thinking each transaction was doing multiple messages despite having just read that each message gets a transaction

18:41 Apage43: of course emacs still barfs all over the place if I accidentally eval something that prints too much

18:43 tomoj: hmm "It returns a sequence of messages which will be processed within the same transaction." what?

18:44 arrdem: Apage43: really? I've seen the colors and formatting go bad, but I've never seen emacs actually break

18:45 tomoj: I've sometimes felt like I wanted something like :continue in datomic

18:46 Apage43: arrdem: I tend to have bad luck if I throw a (println) in a fast loop. It doesn't crash, it just moves -very slowly- while I try to kill the evaluation

18:46 and sometimes it's just faster to kill emacs and bring it all back up

18:46 linuxos: can i get a long unsigned in clojure?

18:46 tomoj: for like installing a bunch of schema tx-datas which maybe depend on each other but still being able to fail the entire thing (i.e. one transaction) if something goes wrong in a later tx-data

18:47 but I suspect there is a very good reason datomic doesn't allow this..

18:47 bbloom: linuxos: you can't get an unsigned anything in java

18:47 Apage43: most of this isn't an issue for the majority of the time. I only tend to eval expressions that are freezing and printing way too much if I'm debugging :P

18:47 arrdem: Apage43: is there a better logging lib than good ol' println?

18:47 hiredman: tomoj: you can think of the queue being (ref []) and processing the queue as being something like (dosync (loop [] (when (seq @queue) (do (do-stuff-with-qeueu-contents) (recur)))

18:48 Apage43: probably

18:48 hiredman: and what happens is there is a watch on the queue ref, so if put something in it runs the processing transaction there

18:48 Apage43: I'd specifically like something that will just not print if the receiving end can't take it. like .offer on a queue or something.

18:49 hiredman: and with the processing transaction you can alter the intransaction value of the queue ref, which results in more messages that are processing in the transaction

18:49 tomoj: ok, yeah

18:49 hiredman: (I haven't looked at how it is actually implemented, some kind of atom thing)

18:49 tomoj: datomic does not allow any intransaction stuff

18:49 arrdem: Apage43: looks like timbre and clojure/tools.logging are the options

18:50 and they're both pretty srs bizness logging

18:50 hiredman: well, you can have transaction functions

18:50 tomoj: right but they only get the pre-transaction db as input

18:50 so that there can be no causality between datoms within a transaction

18:52 though you can make a txfn that takes an entire tx-data and runs it with datomic.api/with, then use that to decide what to expand to, if you're OK with some overhead

18:53 app.clj and dataflow.clj seem delightfully simple in any case

18:53 shriphani: hi. I am looking for good data visualization libraries in clojure. I've found incanter so far. Are there any others that are particularly recommended?

18:57 tomoj: hiredman: so under normal circumstances when the queue watcher fires, the queue is always going just have the one message in it?

18:58 hiredman: tomoj: yeah, and you could add some kind of fanciness to ensure that sort of thing

19:14 lynaghk`: Does anyone know if ruby has something akin to "pr-str"?

19:15 gfredericks: lynaghk`: #inspect I think is it

19:16 $findfn pos? [-1 2 -3 4 -5] [[2 4] [-1 -3 -5]]

19:16 lynaghk`: gfredericks: ohh, awesome. thanks!

19:16 lazybot: []

19:20 hyPiRion: ,((juxt filter remove) pos? [-1 2 -3 4 -5])

19:20 clojurebot: [(2 4) (-1 -3 -5)]

19:20 hyPiRion: ~amalloy

19:20 clojurebot: amalloy is <amalloy> just use juxt, it'll be great

19:21 gfredericks: turned out I wanted group-by anyways

19:21 but prior to that I did recall the olde Amalloy Adage

19:22 irctc305: I have a map that I want to concat to a list of maps -> (concat [{:a 2}] {:b 3 :h 5} [{:c 4}])

19:22 However the above adds the map as a map entry ({:a 2} [:b 3] [:h 5] {:c 4})

19:23 How can I just add a map to a list of maps at the start and end ?

19:24 gfredericks: (concat [some-map] a-list-of-maps [some-other-map])?

19:25 hiredman: (concat [{:a 2}] {:b 3 :h 5} [{:c 4}]); one of these three args is not like the others

19:25 gfredericks: one of these args just doesn't belong

19:26 benkay: hey y'all, a question about loading data from the filesystem:

19:27 I just wrote a public key to disk using (spit "testpub.pem" (clj-crypto/public-key keypair)), but when I (clj-crypto/as-public-key (slurp "testpub.pem")) the crypto lib blows up not knowing how to convert the string back into a public key

19:27 irctc305: thanks for the pointer, just enclosing the second arg as a vector solves it ! now all args are of the same type

19:28 benkay: is there an obvious thing i'm missing about what i'm trying to do here?

19:29 hiredman: never heard of clj-crypto

19:29 benkay: bouncycastle wrapper

19:29 hiredman: but my guess is you are doing character io using bytes

19:29 spit is not the way to go for reliable io

19:29 benkay: would that look like nonsense when I open the file?

19:29 hiredman: have you actually looked at the contents your .pem?

19:29 benkay: oh yeah, it's just a string.

19:30 <RSAPublicKeyImpl ...

19:30 hiredman: just a string?

19:30 ah

19:30 gfredericks: not a very good public key

19:30 hiredman: you haven't even gotten to io yet

19:30 (clj-crypto/public-key keypair) is just returning a key object

19:30 you'll need to do some more work to get actual bytes

19:30 spit is just calling toString on the object

19:31 benkay: sounds like you're suggesting writing the bytes to disk and then reading them back off?

19:32 gfredericks: yeah for crypto stuff you'll want to use bytes not strings

19:32 benkay: thanks gfredericks, hiredman

19:33 is there something like spit that writes bytes?

19:33 hiredman: forget spit

19:34 go look at the code for clj-crypto or the java docs for bouncy castle

19:34 figure out what it is that clj-crypto returns

19:34 figure out how to turn that in to bytes

19:35 by the time you are done I imagine you will be ready to ditch clj-crypto because you will be comfortable using bc directly

19:36 you will most likely need the javax.crypto java docs too

19:36 http://docs.oracle.com/javase/6/docs/api/java/security/interfaces/RSAPublicKey.html

19:39 Apage43: if you have some type of Key, .getEncoded is on the Key interface (for java.security.Key) which gets you bytes

19:42 amalloy: (inc hyPiRion)

19:42 lazybot: ⇒ 14

19:48 shriphani: hi I have a question about enlive. How do I do [:div.class_name] only class_name has a space in it...

19:49 benkay: thanks Apage43!

20:03 weavejester: May I ask what everyone uses for note-taking? I usually use emacs and a text or markdown file…

20:04 tieTYT2: google drive?

20:04 technomancy: weavejester: org-mode

20:04 tieTYT2: or a program on my cell phone called AK notepad

20:04 weavejester: technomancy: I was hoping someone would say that :)

20:05 technomancy: weavejester: I basically use org like outline-mode though

20:05 weavejester: technomancy: I know org-mode can be used for todos and time-keeping, but does it have anything for note-taking over a text file?

20:05 hiredman: weavejester: what do you want for note-taking?

20:05 technomancy: weavejester: the ability to collapse outlines is the main thing I use it for

20:05 hiredman: what are the component features of note-taking for you

20:06 org-mode tables are like be able to embed little spreadsheets, but the formulas can be in elisp

20:06 weavejester: hiredman: Something to act as an external memory while I'm trying to solve a problem that's too large for me to hold all possible paths in my head reliably.

20:07 hiredman: weavejester: yeah, but you asked for features over a text file, org-mode has 1e100 features

20:08 technomancy: literally the largest lisp file on my hard drive

20:08 probably the largest non-autogenerated lisp file on github

20:08 hiredman: you can do org-capture which pops up a little buffer you type in to, then saves each little note as a bullet point in a larger file of todos

20:08 tieTYT2: i really liked haskell's pattern matching. Clojure was created after haskell but I believe RH was aware of it. Anyone know the decision to leave it out of clojure?

20:08 weavejester: hiredman: Well, I don't really know what features I'd want, without know which ones there are...

20:08 bbloom: i just use a text file in vim

20:08 i have a directory called notes & there are about 20+ files in there

20:08 hiredman: org-mode lets you create a list of times with various todo status and sort the lists based on the todo status

20:08 technomancy: tieTYT2: the official story is that pattern matching is closed, while predicate dispatch is open.

20:09 bbloom: i mostly never read them lol

20:09 technomancy: tieTYT2: I don't really buy that though

20:09 weavejester: tieTYT: There's core.match, so pattern matching is only left out of the core language

20:09 scottj: weavejester: btw, org-mode was originally for note-taking. the other things came later.

20:09 technomancy: core.match has issues =\

20:09 hiredman: org-mode will renumber your lists for you if you put an element in the middle of a numbered list

20:09 tieTYT2: technomancy: I don't know what either of those mean

20:09 what do you mean by closed?

20:09 weavejester: let me check that out

20:09 technomancy: tieTYT2: compare it to cond vs defmulti

20:09 tieTYT2: cond only works on values known up-front; defmulti can be extended after the fact

20:10 tieTYT2: so cond is called "closed"?

20:10 technomancy: yeah

20:10 tieTYT2: note that I do not find this justification persuasive at all

20:10 hiredman: you cannot extend a pattern match or a cond with rewriting the original code, but you can extend defmultis from new code without touch the old code

20:11 tieTYT2: why can't you have both?

20:11 bbloom: you can only be open or closed with respect to something…. cond is closed to adding cases at runtime

20:11 tieTYT2: I never thought of defmulti as an answer to pattern matching. I always thought of destructuring as an answer to pattern matching

20:12 technomancy: tieTYT2: I only brought up defmulti as an example to explain closed/open

20:12 tieTYT2: technomancy: ohh

20:12 clojurebot: technomancy is to blame for all failures

20:12 technomancy: you can certainly have both

20:12 hiredman: org-mode has org-babel which lets you put in little snippets of code (properly hilighted using the mode of your choice) and then execute the code and insert the result right in place in the document

20:12 technomancy: clojurebot: you're one to talk

20:12 clojurebot: Huh?

20:12 bbloom: tieTYT2: pattern matching is desructuring plus ordered choice. i think that the ordered choice bit is the bit that rich doesn't like

20:12 weavejester: Has anyone made much use of watches on refs?

20:12 hiredman: I use them for a debugging a lot

20:13 tieTYT2: bbloom: what's the downside to that?

20:13 amalloy: weavejester: i've watched a couple of atoms, but not for very good reasons

20:13 bbloom: tieTYT2: consider a complex cond block… you can't re-order statements without considering logical implications of the conditions/predicates

20:14 tieTYT2: for example if you had (cond (pos? x) :pos (even? x) :even) then what you reeaaaly mean is not :even, but :negative-and-even

20:15 weavejester: I think I'm going to try and use watches in place of an event queue.

20:15 bbloom: if you re-order the clauses, you are changing the meaning. that's not true of multimethods for example

20:15 tieTYT2: true

20:16 bbloom: pattern matching is most useful when you want to do exhaustive case analysis. like in haskell where you have algebraic data types

20:16 in which case, you really want a switch b/c that lets you reorder the clauses

20:16 i've seen some haskell code that makes some pretty subtle assumptions based on the order of patterns. i can be confusing

20:16 tieTYT2: in my mind, he chose destructuring instead of pattern matching. But it sounds like everyone here is saying he didn't want pattern matching because it can complicate things

20:16 and destructuring is not related

20:16 bbloom: he said that in a talk at one point

20:17 tieTYT2: bbloom: the one on simple made easy?

20:17 yeah I noticed that, but I didn't understand why

20:17 bbloom: he said something to the effect that pattern matching complects name binding and ordered choice while remaining closed to adding cases at runtime

20:17 destructuring, as implemented in clojure, is closed with respect to adding new pattern types

20:18 tieTYT2: he says that, but I don't see him giving an alternative

20:18 or something better

20:18 bbloom: so the "better" thing is predicate dispatch

20:18 but predicate dispatch is still somewhat of an open research problem

20:18 tieTYT2: eg: cond?

20:19 or defmulti?

20:19 bbloom: *shrug* cond is just so simple & so often useful that you kinda gotta have it

20:19 tieTYT2: for me: http://stackoverflow.com/questions/5671627/what-is-predicate-dispatch

20:20 bbloom: the real hard part of predicate dispatch is determining logical implication

20:20 tieTYT2: i never thought of using multimethods this way

20:20 wouldn't it be frowned upon to use it when you could use pattern matching?

20:20 i've been told it's pretty slow

20:20 bbloom: it's only really slow when dispatching on the java type hierarchy

20:20 it's reasonably fast otherwise

20:20 not as fast as protocols & simple branches, but still pretty quick

20:21 tieTYT2: i see. I've written two small programs that use multi methods and they both dispatch on symbols

20:21 bbloom: see http://homes.cs.washington.edu/~mernst/pubs/dispatching-ecoop98-abstract.html

20:21 tieTYT2: or contents of a string

20:23 thanks

20:24 i had this function that needed to do different things depending on the count of the sequence passed in. I didn't consider a multimethod as a good choice to implement that

20:25 bbloom: tieTYT2: if the count only falls into a fixed set of cases, like 0, 1, 2, or N… then case is the way to go

20:25 or cond even

20:25 tieTYT2: yeah that's pretty much what I ended up doing

20:25 bbloom: a multimethod is useful when you want other folks to be able to add cases

20:25 tieTYT2: yeah I don't have that situation

20:25 bbloom: you need to ask the question "do i need open dispatch?"

20:25 if the answer is no, choose something simpler

20:25 tieTYT2: whereas pattern matching is useful even if you don't need open dispatch

20:26 it would have been good in this situation. I think a case/cond was more complicated than pattern matching would have been

20:27 bbloom: so i agree that pattern matching is sometimes useful, but i think it's attractive syntax means that people tend to use it by default and that means creeping complexity in logical ordering of predicates

20:27 fewer branching constructs in your code is generally easier to understand & pattern matching inherently adds one branch point per pattern

20:27 tieTYT2: perhaps you're right. I only used haskell for 1-2 months so I wouldn't have discovered that by then I think

20:29 bbloom: i think pattern matching is absolutely a more concise notation for a lot of common patterns in code. however, i've found that prefer making an explicit decision between if, cond, case, when, etc. my code may be a couple lines longer, but it's easier to read & refactor. but that's just my opinion

20:29 tieTYT2: but IME, the pattern matching reduces your overall code so it makes up for that issue

20:31 technomancy: I agree

20:31 I would use core.match if it didn't break AOT

20:32 tieTYT2: that's an intimidating restriction

20:32 i'm not experienced enough to knwo if I need that

20:32 pjstadig: meh

20:32 AOT is kinda broken already

20:32 clojurebot: In Ordnung

20:32 pjstadig: ~AOT

20:32 clojurebot: AOT is kinda broken already

20:32 pjstadig: haha

20:32 technomancy: pjstadig: not for libraries obvs

20:33 I mean I wouldn't use it for libs

20:33 but I always AOT before deployment

20:33 (not on my own box of course)

20:34 hiredman: someone could just fix core.match

20:35 ugh, the jira issues doesn't have a reproducable case

20:35 tieTYT2: http://clojuredocs.org/clojure_core/clojure.core/for I really think the ordering of the two examples for ; Demonstrating difference between :when and :while should be swapped

20:35 hiredman: ah, this other issue has a reproducable case

20:36 tieTYT2: is it always fixable?

20:38 hiredman: other languages have pattern matching, proving pattern matching can be done ona turing machine, clojure is turing machine equiv, so clojure can do pattern matching, so it is fixable

20:38 qed

20:38 it just may mean embedding a haskell or ml compiler in a clojure macro

20:39 bbloom: heh.

20:43 hiredman: the core-futures stuff is inspiring in that regard, the macro turns clojure code in to some kind of traditional compiler formalism (SSA, CPS, ANF) does its thing on the formalism, then regenerates clojure code from the formalism

20:44 tieTYT2: this is over my head

20:44 hiredman: which makes sense for more complicated macros that are really source to source compilers

20:48 amalloy: i haven't looked at core-futures myself, but i heard it was SSA, from someone who was puzzled that it wasn't CPS

20:49 hiredman: someone showed that cps and ssa are equivalent, but cps is used a lot for functional languages

20:52 the guile guy had a blog post a few years ago

20:53 http://wingolog.org/archives/2011/07/12/static-single-assignment-for-functional-programmers/

21:18 qbg_: hiredman: Do you have link describing core-futures?

21:22 hiredman: http://dev.clojure.org/display/design/Async+blocks

21:24 qbg_: nice

21:24 tomoj: really more core-async

21:25 core-futures will I think be replaced

21:25 or maybe they'll stick with it, but I remember a note somewhere saying "this is temporary, TODO decide on future implementation" or something

21:27 delightfully there is only one small spot in core-async that depends on core-futures

21:27 dnolen: tomoj: i believe they are two distinct and necessary pieces

21:27 tomoj: indeed

21:28 I just mean "Async blocks" and the work on the relevance branch is more about core-async than core-futures

21:28 oh but the branch is called core-futures, heh

21:28 «Note: the implementation of futures should be considered in "draft" phase, it will change radically before an alpha is released.»

21:32 qbg: that is beautiful

Logging service provided by n01se.net