#clojure logs

2013-05-10

00:04djwonkI want to wrap function calls to handle a SQLException. I'd like to do it without writing a macro if possible.
00:05djwonk`apply` gets me part of the way there, but not completely
00:06djwonkbut since `try` is a special form, is it reasonable to think I can create a custom try that is not a macro?
00:07darrickwdjwonk: do you want to wrap the function so that you can call it later but the wrapper handles the exception?
00:08djwonkdarrickw: not sure I understand your question. I want the wrapper to contain the try/catch
00:08djwonkI mean… to abstract out the try/catch
00:09djwonkI don't think I need to wrap the original function (possibly exception-causing function) to call it later
00:09darrickwOk so you want to do the wrapping in place where you call the function then?
00:11darrickwYou just need a regular function to do that
00:11djwonkdarrickw: sounds about right
00:12darrickw(defn a-wrapper [the-fn-to-wrap & args] (try (apply the-fn-to-wrap args) (catch TheException ex (do-something ex))))
00:12darrickwsomething like that could do it
00:13darrickwthen you call it like this: (a-wrapper the-fn arg1 arg2)
00:13djwonkdarrickw: thanks
00:13djwonkI'm running into a double apply situation with jdbc/create-table, but I can figure it out
00:19gdevdjwonk:) what database are you using?
00:55n_bsis there a way to break out of a doseq?
01:00technomancyn_b: doseq has a :while clause; it should stop once that is fasy
01:00technomancyfalsy
01:01n_bAh, didn't see that! That's perfect, thanks technomancy
01:01n_bSame clauses as for, always forget
01:02technomancythere are a lot
01:09amalloydoseq doesn't necessarily do what you want, there, if you're iterating through multiple sequences
01:11amalloyeg, (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])
01:11lazybot⇒ ([1 0] [2 0] [2 1] [3 0] [3 1] [3 2] [4 0] [4 1] [4 2] [4 3])
01:12amalloyunintuitive, but much more useful than the alternative. anyway, n_b, technomancy: just a thing to keep in mind
01:12technomancynutty
01:13gdevthe more you know ...*
01:13n_bAh, interesting
01:14n_bFortunately 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
01:14n_bbetter go write that down
01:17amalloytechnomancy: 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
01:19gdevI 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
01:19technomancyamalloy: I suppose so, but it'd be really easy to write code that does a lot more checks than it looks like
01:19technomancythough I suppose the correctness isn't affected
01:44muhoowhat's the new latest-jdbc-approved, non-deprecated method of doing a couple jdbc operations inside a transaction?
01:44gdevnice, 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.
01:45muhooi've seen examples or using transaction, but that's deprecated, and haven't gotten my brain around the new db-transaction replacement
01:45muhoolooking for an example somewhere
01:48gdevmuhoo:) the sql dsl that he wrote i thought was what replaced transaction
01:48muhoothe dsl is optional, i think.
01:49muhooi'm using honeysql and i like that way better. but it still uses jdbc as transport
01:49muhoothere's a function db-transaction*, looks like what replaced it, but the usage is kinda weird.
01:50muhoothe 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
01:50muhooanyway, i think i got it, it just looks ugly to me.
01:52mthvedtwhat can cause "abstractmethoderror: null"
01:52gdevmuhoo:) can you post what you got on refheap? I always like seeing different ways to do things
01:53muhoogdev: it's a one-liner: (jdbc/db-transaction* db-handle #(do (i have to) (do it this way weird)))
01:53gdevalso, honeysql gets my vote for best name of a sql dsl library
01:54muhooworks, just feels dirty. the macro version feels dirtier, because it expects bindings like the old transaction macro used to. ain't no thing.
01:54muhooand db-do-commands may be the right way
01:56muhooi'm a total honeysql fanboi now. i only wish it did update! and insert! but i guess i can submit! patches! at some point
01:56gdevmuhoo:) 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
01:59muhoothis stuff is just weird. the jdbc library looks like it kind of grew organically
02:00muhoodidn'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?
02:01gdevwow a truly global usage search huh
02:02muhooit was a very cool idea, and he had something working IIRC
02:03muhoooh, here's the docs i was looking for: https://github.com/clojure/java.jdbc/tree/master/doc/clojure/java/jdbc
02:04gdevone of those says "using sql" is that referring to the optional dsl or the core library?
02:05muhooaha! (j/db-transaction [t-con db] (something t-con) (something-else t-con)) very nice
02:05muhooTHAT is what i was looking for.
02:06muhooi think the binding is unnecessary, but whatevs
02:06muhooredndant, why bind db to t-con, why not just use db?
02:07gdevmuhoo:) have you read the clojure data analysis cookbook?
02:08muhoono, link?
02:09gdevhttp://www.amazon.com/Clojure-Data-Analysis-Cookbook-Rochester/dp/178216264X
02:12muhoohmm. did you like it?
02:14gdevYeah, I like what I've read so far and I typically don't like cookbooks
02:29gdevokay, now that my phone has some charge i can load the kindle app and see what the book says about jdbc transactions
02:42gdevlooks 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
03:26muhoo,doc empty?
03:26clojurebot#<CompilerException java.lang.RuntimeException: Can't take value of a macro: #'clojure.repl/doc, compiling:(NO_SOURCE_PATH:0:0)>
03:26muhoo,(doc empty?)
03:26clojurebot"([coll]); Returns true if coll has no items - same as (not (seq coll)). Please use the idiom (seq x) rather than (not (empty? x))"
03:27muhoo,(doc not-empty?)
03:27clojurebotPardon?
03:27muhooaha! y you not named not-empty?
03:27muhoo,(doc not-empty)
03:27clojurebot"([coll]); If coll is empty, returns nil, else coll"
03:27muhooi think that's the first naming inconsistency i've found in clojure
03:29esmo_it's not a predicate (doesn't return a boolean)
04:02muhoointeresting. actually docstring says that not-empty isn't the same as (not (empty?)), and it says
04:02muhooPlease use the idiom (seq x) rather than (not (empty? x))
04:03muhooso i guess, that
08:20pellishi all, i'm looking for a way to mount ring handlers on urls (no need for routing, just mounting handlers)
08:20pellisanyone bumped into how to do this?
08:21weavejesterWhat's the difference between routing and mounting ring handlers on urls?
08:23pellisweavejester, well i don't want to waste cycles on a routing matcher that checks my http method, or tries a regex against it
08:24pellisjust /v1/api goes to handlerfoo, /v2/api goes to handlerfoo-2
08:24weavejesterSo you could just use a case statement
08:25weavejesterOr, I guess in this case you want to match against a prefix?
08:25weavejesterSo...
08:25pellisyes
08:25pellisi'm looking for the equivalent of rack-mount from ruby world
08:26weavejester(cond (.startsWith (:uri request) "/v1/api") (handler request) ...)
08:26weavejesterBut that's probably overkill
08:26weavejesterYou could just use Compojure. Regexs are fast enough.
08:26pellisok
08:27weavejester(routes (ANY "/v1/api" [] handlerfoo) (ANY "/v2/api" [] handlerfoo-2))
08:29pellisweavejester, is that compojure?
08:30weavejesterpellis: Yep
08:30pellisI'm wondering how much overhead in performance will that take
08:30weavejesterpellis: Let me run some numbers for you, as I'm curious myself
08:30rasputnikhi all, i need to filter a seq of maps by testing keys - what functions should i be looking at?
08:31pellisi 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.
08:31rasputnik# it's a map of ssl keys and i want to return those with an expiry date less than a given number of days
08:32pellisweavejester, 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)
08:34pjstadigrasputnik: something like (filter (fn [key] (< (get-exp-days key) the-date)) keys)
08:34ucb,(doc filter)
08:34ucbrasputnik: ^
08:34clojurebot"([pred coll]); Returns a lazy sequence of the items in coll for which (pred item) returns true. pred must be free of side-effects."
08:34pjstadigor if you want to be fancier (filter #(< (get-exp-days %) the-date) keys)
08:35rasputnikpjstadig, ucb : cheers both.
08:35weavejesterpellis: Okay, I'm just writing out a quick benchmark. Should be a few minutes.
08:36pellisweavejester, cool!
08:51weavejesterpellis: 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.
08:51weavejesterpellis: I'll give you my REPL logs in a gist
08:51pellisweavejester, thanks, very nice of you !
08:53weavejesterHuh, gists aren't working...
08:54pellisyes, i think they have a security bug
08:54pellisi thought i'm the only one. looks like a redirect loop, and then some blurb about login/authentication errors
08:54weavejesterpellis: https://www.refheap.com/paste/14390
08:55pellismight also be stale cookies
08:55redline6561lam
08:55redline6561ahem, excuse me
08:56pellisweavejester, that's very useful. i think - when you'll see a bigger difference will be with big urls
08:56pellisweavejester, for example /api/v1?<some 1000 characters>
08:56pellisunless regex are smart enough to not glob when it's just "*"
08:57weavejesterpellis: Anything after ? is the query string and not matched, but regexes are pretty optimised.
08:57pelliswell then /api/v1/foo/<some 1000 chars>
08:58weavejesterpellis: I suspect that you'd still see little difference. But lets try it :)
08:58pellisweavejester, you might be surprised, most websites can be ddos'ed with just very big urls.
08:58pellisespecially if you have double captures like v1/*foo*bar
08:59pellisif 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
09:00pellisplus, i've seen such attacks live in production 3 years ago :)
09:00juhu_chapaHi all. Is there anything like a blocking queue in clojure?
09:01weavejesterjuhu_chapa: Typically you can just use the Java blocking queues
09:03juhu_chapa:D
09:07vijaykiranmu4e
09:10weavejesterpellis: 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.
09:10pellisweavejester, yes, like i suspected :)
09:11weavejesterpellis: With a URL of length 1000, it's a difference of 4us to 40us
09:11pellisweavejester, i guess this is the conceptual difference between mount and route - O(1) vs O(n)
09:11weavejesterweavejester: I suspect that if Compojure *wasn't* capturing it the wildcard, that we wouldn't see a difference.
09:13weavejesterpellis: 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.
09:13pellisweavejester, i understand
09:13weavejesterpellis: But given the implementations at the moment, yes, you're correct.
09:15pellisok, so I'll opt for your first suggestion - thanks for the help :)
09:54learnerHello 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?
09:57AimHereThat sounds like you want to crack open a book on algorithms
09:58AimHereFirst 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:00learnerAimHere: Yes, may be I should go and read algorithms. Wondering if I can find any help from the community who experienced similar problems.
10:01pppaullearner sorted?
10:02learnerpppaul: No, not sorted. But fixed size strings
10:03pppaulbrute force + memoize :)
10:04pppaulyou can use partition + map indexed
10:04AimHereMy 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:04AimHereBasically sieve it
10:05pppaulyou can put this data in a mem datomic and use it's fulltext search
10:05pppaulindex the strings first [{:index 0 :body "my string"}]
10:05learnerpppaul: 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:07pppaullearning, make this problem constant time, or fit it into pmap, or fit it into reducers
10:07edbond_learner, you need map-indexed
10:07pppaulpersonally, i would use constant time lookup
10:07pppaulmap-indexed + groupby
10:07edbond_pppaul, he needs only index of that string
10:08pppaul?
10:08AWizzArdAnyone here who has a K10, K20 or K20x?
10:08edbond_,(first (drop-while nil? (map-indexed (fn [i x] (if (> x 10) [i x])) (range 30))))
10:08clojurebot[11 11]
10:08pppaul?
10:09edbond_first is index, second is value
10:09edbond_change (> x 10) (= x "lookup-string")
10:10learnerpppaul: 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:10pppaul,(first (group-by :body (map-indexed #(hash-map :index %1 :body %2) ["lalal" "bababa"])))
10:10clojurebot["lalal" [{:index 0, :body "lalal"}]]
10:10dnolenlearner: if you have a lazy sequence and a trivial computation I'm skeptical using thread will help.
10:11pppauli don't think that 20 mil is a lot
10:11dnolenyou 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:12pppauli have gigs coming out my wazoo
10:12learnerdnolen: 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:12dnolenlearner: when you say slow, how slow is your current solution?
10:13dnolenlearner: your explanation leaves out to many details. if you actually have an expensive computation, *maybe* pmap could help
10:13pppaulreducers!
10:14pppauli don't even know what i'm talking about anymore
10:14pppaulput the data in a DB and let it do the hard work
10:14learneredbond_: 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:15learnerpppaul: ha ha. Sorry If I have confused you
10:15dnolenlearner: what is the source of the data? can you not partition it ahead of time?
10:15pppaullearner, pmap has helped me, but it gets tricky if you don't want to work on the whole set
10:16learnerdnolen: 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:16pppaullearner, put this stuff in lucene or something
10:17dnolenlearner: is your guess based on how slow your code is on a small data set?
10:17pppaullearner pmap isn't going to help you
10:17pppaul4 days is nuts
10:18pppaullearner look into storm
10:18learnerdnolen: My guess is based on how big dataset is. Source is https://github.com/clojure/math.combinatorics combinations
10:19learnerpppaul: 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:19pppaullearner your problem hasn't been described well enough
10:19dnolenlearner: are you saying you're going to use math.combinatorics?
10:20pppaulto me, it sounded like you have your data, and it's static
10:20pppaulbut now it sounds like you are generating your data in real time
10:20pppaulwhat the fuck are you doing?
10:20edbond_learner, if you can load whole sequence in memory you can partition and process in parallel
10:20dnolenfor 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:20learnerpppaul: I am doing a little research project
10:21pppaullearner that doesn't help me understand your problem
10:22pppaulseriously, 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:22pppaulthat's really not enough to go on
10:22pppaulthere are a million ways to solve such a problem, you need to be much more specific
10:23pppaulthe less specific you are the more of our time you are wasting
10:24dnolenlearner: 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:25pppaulit 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:25learnerpppaul: 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:25learnerpppaul: I need to find out how I can do it in clojure/scala/groovy & plain java
10:26pppaulhmm
10:27learnerpppaul: I am a completely newbie and learning lot of stuff while implementing the suggestions you guys are offering
10:28pppaulhack the combinatorics thing to put indices on it's output, then send this job out to a bunch of computers via storm
10:29pppaulwell, i guess you don't need to hack the combinatorics thing
10:29pppaulyou 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:29learnerpppaul: Are you talking about this ? https://github.com/nathanmarz/storm
10:29pppaulyes
10:30learnerpppaul: Thanks. I will give a try
10:30pppaulif you are dealing with completely lazy sequences then this should be easy
10:30learnerpppaul: It's a lazy sequence
10:31pppaulstorm should work fine, and it has a good development/testing story
10:32pppauli would be very interested to see this working when you are done with it
10:37devnmuhoo: 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:40gdevdevn:) 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:40gdev(inc devn)
10:40lazybot⇒ 6
11:03rbxbxdevn: heh, getclojure doesn't like it when you pass an empty string
11:03rbxbxlooks like it's coming along nicely though :)
11:10jtoy_is there a more idiomatic way to write this? (map (fn [x] ((meta x) :target )) data )
11:11dakrone(map (comp :target meta) data)
11:11bbloomor (map #(-> % meta :target) data)
11:12jtoy_thanks, i havent seen comp before
11:12ToxicFrog,(doc comp)
11:12clojurebot"([] [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:13jtoy_is comp basically the opposite direction of -> ?
11:14bbloomjtoy_: you can think of it that way, but comp is a function, -> is a macro
11:15bbloomjtoy_: (comp x y) is (x (y …)) and (-> x y z) is (z (y x))
11:15justin_smithwith comp you would not provide the other args to the functions unless you create lambdas
11:15justin_smithwith -> you don't need to create the lambdas manually
11:16jtoy_right , i see, ill try with comp for now
11:49matkoQuestion: should I be using ! in my function names for functions that alter state (through swap!, send, alter, etc)?
11:55noidi_matko, "Use the bang! only for things not safe in an STM transaction." http://dev.clojure.org/display/design/Library+Coding+Standards
11:55matkothank 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:56matkobut not for every destructive operation
11:56matkois there another obvious way to point out that my functions are destructive?
12:00bbloomdestructive ops aren't safe to use in STM :-P
12:00noidi_unless they're idempotent
12:00bbloomtrue
12:00noidi_e.g. emptying a mutable collection is destructive but idempotent
12:01matkoanything wrapped in a (dosync) is safe to call from within a transaction though, right?
12:01bbloomi don't think that idempotence is sufficent though, since a transaction can permanently fail
12:01matkoand anything send to an agent is only run on successful completion of a transaction
12:01bbloomgenerally, if you have a library that is all mutable ops, then you don't really need ! on every single function
12:02bbloomif 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:04matkoright, sounds good
12:31gdevj/ #probablywrong
12:31gdevderp
12:31gdevj/ dislexics_anonymous
12:31gdevdoh >_<
12:37learnerpppaul: I will let you know after trying storm. Thanks for your continued help
12:47moquist(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:48moquistGoogle 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:48justin_smithmoquist: str?
12:48moquistSorry -- (str y) returns "clojureql.core.RTable@567ae64a"
12:49justin_smith(with-output-to-string (prn y)) ?
12:49justin_smiththat should return the string prn would have printed
12:49justin_smithsorry
12:49justin_smithwith-out-str
12:49justin_smith,(with-out-str (prn :a))
12:49clojurebot":a\n"
12:50justin_smithahh!
12:50justin_smith,(prn-str :a)
12:50clojurebot":a\n"
12:50justin_smithseems like a common enough usage to have its own fn
12:50weavejesterI'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:50moquistjustin_smith: yes! That's more like it. Thanks!
12:53Wild_Cat`weavejester: aren't there Clojure libs for BSON or msgpack?
12:54weavejesterWild_Cat`: I wanted something that would retain all the Clojure data structures
12:54hiredmanweavejester: fressian?
12:54weavejesterhiredman: No Clojure library for that, unless you count the stuff in the tests
12:55hiredmanweavejester: :/
12:55dnolena 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:56weavejesterhttps://www.refheap.com/paste/14401
12:57weavejesterThere's not much to choose between Nippy and Carbonite.
12:57weavejesterNippy seems to have the more straightforward API, though
13:10mpenet+1 for Nippy, it's really a gem.
13:14devnrbxbx: could you make an issue on the repo?
13:24rbxbxdevn: sure.
13:36devnrbxbx: and then could you fix it and submit a PR? ;)
13:37rbxbxdevn: ... probably.
13:37rbxbxdevn: especially if you wanted to pair :p
13:37devnrbxbx: yeah, you got time this afternoon?
13:37rbxbxdevn: I jest. It's probably low-hanging enough that I could tackle it alone.
13:37rbxbxand no, not really. Maybe this evening though.
13:37devnrbxbx: there's other stuff I could use a second pair of eyes on
13:38rbxbxSome of us have to work on Fridays :p
13:38devnha! the solution as I'm sure you're aware is to simply quit your job.
13:38rbxbxsshhh, my co-workers are in here.
13:39gfredericksso 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:40devnrbxbx: 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:41rbxbxdevn: maybe. I'm a bit over-extended right now :|
13:41devnalso, 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:41rbxbxright, we'd discussed this before.
13:42rbxbxI looked into that... but I didn't understand nearly enough of anything :)
13:42devnyeah i know i know, everyone is busy. either way, talk to you later, im off to go hack on that.
13:43rbxbxdevn: cheers sir :)
14:12devnWhere does the foo-1 naming pattern come from for reduce functions?
14:12ToBeReplacedwhat do people do when they want (need?) try-let (or try-catch-else)?
14:16bbloomToBeReplaced: where "else" is "run this only if an exception is not thrown"?
14:16bbloomdevn: what foo-1 things are you talking about?
14:16ToBeReplacedyeah, presumably using a value from the try
14:17bbloomToBeReplaced: 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:17ToBeReplacedjava doesn't support it... you can hack it by storing a boolean and using the finally clause, but that's gross
14:18technomancyI don't get it; why would you need a separate else clause?
14:18bbloom(defn get-foo [x] (try (.getFoo x) (catch Exception e :error)))
14:19bbloomtechnomancy: http://stackoverflow.com/questions/855759/python-try-else
14:19ToBeReplacedyeah that link will explain better than me :)
14:20bbloomToBeReplaced: like i said: just avoid having exception handling logic bleed into your normal logic
14:20technomancyhuh
14:20ToBeReplacedyeah seems like the way to go
14:20bbloomToBeReplaced: if you need to handle an error case at the site of the error, it's not really exceptional, is it?
14:21bblooma wrapper function that returns {:status some-keyword, :result some-value} will do the trick
14:21ToBeReplacedbbloom: 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:22ToBeReplacedin 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:23bbloomToBeReplaced: well the reason they recommend that is b/c they have embraced exceptions for control flow…. ie StopIteration exceptions!
14:23bbloomToBeReplaced: if you "look before you leap" you have a race condition
14:24bbloomgolang 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:24ToBeReplacedright
14:29technomancyo_O
14:33Glenjaminerror codes: exceptions you can ignore
14:34tieTYT2current 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:35weavejesterWhat does everyone think of having a deref-able type initialized from a no-argument function?
14:35weavejesterKinda like a derived reference
14:36bbloomweavejester: do you mean a thunk? like ##(doc delay) ?
14:36lazybot⇒ "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:36ohpauleezweavejester: Why not use a promise that you pass into the initializing function?
14:36weavejesterbbloom: Yes, but one that's tied to another ref, so the result isn't cached.
14:36ohpauleezah
14:37bbloomoh, like a pointer to a pointer?
14:37Glenjaminallowing you to use @foo instead of (bar) ?
14:37matthavenertieTYT2: how is that different from a reduce?
14:37weavejesterGlenjamin: Right
14:37Glenjaminwhy not just call the function? :p
14:37weavejesterI'm not convinced it's a hugely good idea, but here's my use-case
14:38weavejesterI have a world data structure that represents the state of a game world
14:38bbloom,@(clojure.lang.Delay. (fn [] :done))
14:38matthavenertieTYT2: (reduce mystery-fun (first coll) (rest coll))
14:38tieTYT2matthavener: apparently it is, I'm using reduce
14:38clojurebot:done
14:38weavejesterAnd I have an scene data structure that represents what the user can see
14:39weavejesterSo I connect the world to the scene with a watch. When the world changes, the scene alters as well.
14:39matthavenertieTYT2: 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:39trptcolinis 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:39tieTYT2matthavener: since mystery-fun returns a sequence, won't the result of the reduce be a sequence of sequences of sequences...?
14:39matthavenertieTYT2: sure, but like i said, you can wrap mystery-fun in a 'last' if you only care about the last
14:40weavejesterSo I can handle this with a set of world->scene functions
14:40tieTYT2matthavener: how do I keep the butlast of it?
14:40weavejesterOr I could populate the scene with references to the world, and deref-all the scene
14:40weavejesterKinda a push/pull approach
14:40matthavenertieTYT2: i'm not sure what you mean by that, specifically "keep the 'butlast' of what you've got so far"
14:40dnolentrptcolin: you don't want to extend to js/Object, extend-type object
14:40matthavenertieTYT2: what do you mean by "what you've got so far" ?
14:41bbloomweavejester: 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:41trptcolindnolen: awesome, thanks
14:41weavejesterbbloom: I'm glad I'm not the only one thinking about this :)
14:41tieTYT2ok 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:41patchworkbbloom: You have both views depend on the same data source?
14:42tieTYT2see how the o1 is still in the result? that what I mean by keeping what you've got so far
14:42bbloompatchwork: more accurately, i have a document translation
14:42patchworkthe two views don't need to know about each other, updates flow from the data source
14:42matthavenertieTYT2: i think i see, you can just make your reduction a tuple
14:42ohpauleezweavejester: Is is possible (or advantageous) for the "scene" to be a function that takes the world and produces a slice?
14:42bbloompatchwork: 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:42ohpauleezrather than a data structure of the slice
14:42dnolentrptcolin: generally true for all the real JS languages natives
14:43trptcolingotcha, i was extrapolating to assume that just now :)
14:43tieTYT2matthavener: and the first part is a sequence that grows?
14:43weavejesterohpauleez: Maybe… at the moment it's an atom, which seems like it's a little more transparent I guess.
14:43weavejesterPlus the UI isn't necessarily dependent on the world.
14:43ohpauleezand then the watcher can deliver a future, that you can deref when you need to use the "scene" slice
14:44weavejesterI'm experimenting with a Leiningen-like profiles approach
14:45matthavenertieTYT2: https://www.refheap.com/paste/14402
14:45weavejesterBut… Hum… I'd like to deal with data rather than function composition.
14:45ohpauleezat the end of the day you're dealing with data
14:45ohpauleezthe slice you get back is data
14:46weavejesterOr do I? I could have a bunch of middleware-like functions I compose that generate the final app data structure.
14:46ohpauleezright
14:46ohpauleezyes
14:46ohpauleezand so you start modeling it as core game data, and ways to derive your various game states
14:46ohpauleezand build it intoa dataflow
14:47tieTYT2matthavener: hm, what if r is a sequence with a count of 1?
14:48matthavenertieTYT2: then (rest r) is empty
14:48tieTYT2matthavener: also, you're not doing anything with sofar. Is that intentional?
14:48weavejesterI might have to change the way I handle events...
14:48tieTYT2you're passing the first element into mystery-fun, not the last
14:48matthaveneri guess? i'm only trying to implement what you're describing
14:49matthaveneryeah i suppose you should replace 'rest' with 'butlast' and 'first' with 'last'
14:50weavejesterAt the moment I have: {:type :button, :on-click (fn [event] …}}
14:50weavejesterBut maybe it should be: {:type :button, :state :clicked}
14:51weavejesterMaybe my problem is the way I'm mixing event handlers in with my data structure.
14:51ohpauleezweavejester: In a system of flows, C2-event or pub/sub fits well (in my experience). So yes, i'd make that change
14:51bbloomweavejester: 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:51ohpauleezthen let anyone who wants to know about the "click" subscribe and do something
14:51ohpauleezpassing more data back into the bus, or down through the flow
14:51weavejesterbbloom: It is hard! I think I've changed it twice already :)
14:52kephaleweaverjester: if you don't mind my asking, are you talking about a 3D rendered world?
14:52weavejesterI tried maintaining an event bus and a data structure, but it didn't really worlk well.
14:52kephaleweavejester*
14:52weavejesterkephale: Yep.
14:53weavejesterkephale: I basically have a (run-app (atom …)) function that's at the core of this framework/game I'm building.
14:53kephaleweavejester: ok, is yours open source? i'm at alpha/beta with my 3d simulator which has a modified penumbra under the hood
14:54weavejesterkephale: No, but I'll probably open-source bits of it later. It's using jMonkeyEngine.
14:54ohpauleezweavejester: What was the issue you ran into with the bus?
14:55kephaleweavejester: 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:55kephaleincluding some of the UI handling
14:56kephalegotta run for now… "brevis" on github
14:56hiredmanbbloom: have you played with pedestals model (not sure what to call it) at all? I guess event sourcing?
14:56kephaleciao
14:57bbloomhiredman: pedestal kinda stops short at the view layer
14:57hiredmanbbloom: sure
14:57bbloomhiredman: i haven't studied it too deeply, but it just feels a little heavyweight
14:58bbloomhiredman: i need to study it a bit more, but i'm coming at it from a pretty different angle
14:58weavejesterohpauleez: 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:58weavejesterohpauleez: It felt like I was dealing with two systems, when I really wanted one.
14:58gdevbbloom:) the documentation explains that it was developed to handle hard problems that other lighter frameworks dont do well
14:58weavejesterI'm beginning to think I don't actually need events...
14:59hiredmanbbloom: I write a little thing in it, and I ended like the sort of event transforming stuff, but not the rendering.cljs bits
14:59hiredmanwrote a
14:59hiredmanended up liking
14:59hiredman:/
14:59bbloomhugod: ok there is a fip 0.3.0 release now
14:59bbloomtechnomancy: should i backup my gpg key? heh
14:59gdevmentioning 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:00ohpauleezhaha
15:00weavejesterJust encode events in the state. Like instead of having a :tick event, have a counter that we watch for changes.
15:00bbloomgdev: 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:01technomancybbloom: yeah, but not in a network-attached location
15:01bbloomtechnomancy: 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:01gdevbbloom:) don't shoot the peanut gallery ;)
15:01technomancybury an SD card in your back yard =)
15:01hugodbbloom: thanks! hope the gpg experience wasn't too painful
15:01bbloomtechnomancy: i live in NYC… what's a back yard?
15:02bbloomhugod: the docs were surprisingly helpful. good job technomancy & team!
15:02technomancybbloom: hmm... do you have community gardens over there? =)
15:02bbloomhiredman: the rendering bit of course is gonna suck no matter what b/c it's html & css :-P
15:02hiredmanweavejester: 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:02gdevbbloom:) it's like a park but it's attached to your house and has less hobos and dead hookers buried in it
15:03rkneufeldgdev: sorry, I was out for coffee ;)
15:03bbloomtechnomancy: what happens if i lose my key? i just can't publish new software?
15:03bbloomtechnomancy: (i know what happens if it is stollen)
15:03bbloomtechnomancy: or do i just have to make a new key & people need to trust whoever that asshole future brandon claims to be
15:04ohpauleezhiredman 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:04bbloomhiredman: what did you like about the event transforming bits?
15:04bbloomhiredman: you didn't find that to be a bit onerous ?
15:05bbloomtechnomancy: also, should i check in pom.xml and/or pom.xml.asc ?
15:05weavejesterhiredman 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:05tomojwhen I found the square root example, I stopped looking at pedestal for the day
15:05ohpauleezyes, it's hard to do both - it's like double book keeping
15:05tomojbut maybe it's only onerous for trivial apps?
15:06hiredmanbbloom: it was onerous, but I liked that it is a small set of primitives
15:06bbloomhiredman: yeah, i'm just not convinced that it's sane to expose those primitives to users...
15:06bbloomtomoj: i'm looking at the sqrt example now… wutdafaq?
15:06ohpauleezbbloom: Why not?
15:06tomojyou should be sure to look at the new one
15:07tomojhttps://github.com/pedestal/pedestal/blob/master/app/test/clj/io/pedestal/test/app.clj#L476
15:07tomojthe version 1 models are even wackier
15:07bbloomohpauleez: because it means hand coding a complex static topology that implies your information hierarchy
15:08tomojmy guess was that the plan was to do something like core-async and compile out to those primitives from a more accessible representation
15:08bbloomi don't think it is reasonable to assume that your view state will every be large enough to justify virtualizing it
15:08ohpauleezI agree that means hand coding the static topology, but how does it imply the information hierarchy
15:08bbloomsure, 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:09bbloomwith 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:09tomoj:(
15:10bbloomohpauleez: the virtual tree is (most often, not not necessarily) isomorphic to your view hierarchy
15:10bbloomallow 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:11bbloomi expect i will get some first hand experience with it soon, but my initial reaction was "why would i want a VIRTUAL tree?"
15:11weavejesterI think I'm going to represent my game as a function that transforms frame_n -> frame_n+1
15:11tomojeither way, it's a tree of places, right?
15:11ohpauleezweavejester: I think that's smart
15:11tomoj(or a place with a tree in it, I'd argue these are isomorphic..)
15:11bbloomweavejester: conceptually, that's what you want. the trick is doing that efficiently :-)
15:12tomojI for one would not like to write a function frame_n -> frame_n+1
15:12weavejesterThat's kinda what I'm doing anyway, just with an atom instead.
15:12bbloomtomoj: you don't WRITE that function. you generate it from a description of the behavior of the world :-)
15:12weavejesterI have a bunch of aggressively cached functions in the background that map a data structure into a 3D world.
15:12tomojyeah, right :)
15:13noncomweavejester: 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:13weavejesterWell, the function frame_n -> frame_n+1 would be the result of composing a bunch of smaller functions.
15:13weavejesterAlthough composed functions are a little opaque.
15:13Pupnik-the thing that unsettles me with that weavejester is you have to pass around some sort or gigantic data structure
15:14tomojframe_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:14weavejesterPupnik-: So?
15:14bbloomweavejester: you compose a data structure & your next-frame function is an abstract machine which accepts current-frame and program-to-transform-frame
15:15weavejestertomoj: Well, I guess to be more accurate it would be frame_n+1(with no change) -> frame_n+1(with change)
15:16weavejestertomoj: 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:16noncomso its like state_n+1 = state_n + delta. what is delta?
15:16tomojah right, so basically like requestAnimationFrame, the current time is being passed in to each next-frame call
15:17weavejesterCurrently I have a tick event, like: {:type :tick, :tbf 0.0215}
15:17weavejesterWhere tbf is the time between frames, so I can use it to calculate position from velocity and so forth.
15:17tomojeventually 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:18tomojjust because of the nightmares I've had working with (bad, so this may be unfair) code that deals with that info
15:19bbloomhttp://blogs.msdn.com/b/shawnhar/archive/2007/07/25/understanding-gametime.aspx
15:19bbloom^^ really good info about game time steps
15:19tomojI guess a whole lot of the nightmare was the unrestricted mutation involved
15:20weavejesterMaintaining a fixed game step time sounds difficult.
15:21weavejesterAnd often you want to change position in time with your draw steps
15:21weavejesterOkay, 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:22tomojso what's option 1? I've been trying to discover it :P
15:23FoxboronSo, i got some time on my hands. Is there any Clojure projects wich could use a clojure newb for bug hunting?
15:23weavejestertomoj: 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:24tomojhmm
15:24tomojI was thinking the atom there that you swap! every tick makes it not 'fully functional'
15:24tomojbut it's basically the same as an iterate seq?
15:25noncomi 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:25weavejestertomoj: Oh yeah, it's not fully functional at the moment. I'd do away with the atom if I went with this approach.
15:25tomojno, it's not an iterate seq because information about user events etc magically shows up
15:25noncomits an io monad?
15:26weavejestertomoj: Yeah, the user events magically showing up is concerning me.
15:26weavejestertomoj: Do I need two data structures? (fn [previous-frame events] …)
15:26weavejesterOr is that just another way of thinking about an event bus
15:27noncomweavejester: what are you trying to acheive after all?
15:27weavejesternoncom: I don't know anymore :)
15:27weavejesternoncom: I guess to get a good way of representing a 3D application with data.
15:27weavejesternoncom: So a data-driven 3D app.
15:28noncomyeah i read that in the jmonkey thread
15:29noncomweavejester: so wahts the problem with making it data-driven? you want to eliminate state and mutations???\
15:29tomoj(reduce next-frame initial-frame input-events) ?
15:29weavejesterCurrently 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:30weavejestertomoj: Hum...
15:30weavejestertomoj: Interesting.
15:30tomojjust extrapolating from your suggestion
15:30weavejesternoncom: I don't want to eliminate state and mutation - just constrain them.
15:30tomojI don't know what you're trying to achieve either :)
15:31weavejesterFundamentally in any functional language, you want to reduce mutation to a minimum.
15:31weavejesterIdeally, you have one function that hides all the mutation, and everything else is functional.
15:32weavejesterSo I guess that's my goal
15:33tomojso you have input and output?
15:33tomojor just output?
15:33weavejestertomoj: Input and output
15:33weavejesterWhich I guess is the root of the problem
15:33weavejesterAs I have input -> events
15:33weavejesteroutput -> atom
15:34weavejesterI'm dealing with input using an event bus, and then swapping an atom for output.
15:34weavejesterI need to go one route or the other, I think.
15:35noncomweavejester: i don't really see a problem here
15:35tomojthere's basically two operations, obtain and render?
15:35tomoj@ and whatever that thing rich was talking about is called
15:36tomojmaybe conj! if that got broken out of transients
15:36weavejesternoncom: What do you mean?
15:37noncomweavejester: are you trying to realize how to acheive that theoretically or how to code it in clojure?
15:37weavejesternoncom: Coding it in Clojure
15:37noncomoh, i see then
15:37noncomi thought you were more after finding some theoretical basis for that
15:38tomojbbloom: is a non-virtual tree just a map?
15:38Pupnik-weavejester, you have some good options for gamedev with clojure, like libgdx or slick2d
15:39weavejesterPupnik- I'm already using jMonkeyEngine behind the scenes. The internals aren't the issue so much.
15:39Pupnik-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:40weavejesterPupnik-: Oh, I can get the time frame easily. I'm just trying to find the right way to model it.
15:40weavejesterIs it a series of asynchronous events?
15:40weavejesterOr a functional transformation of frames?
15:40noncomthis is a matter of POV
15:41bbloomtomoj: yeah, a map of maps of maps
15:41n_bOn testing, the clojure.test is the community preferred option, right?
15:42noncomweavejester: 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:43weavejesternoncom: I guess the issue is the amount of references I'm currently passing around...
15:43ucbn_b: clojure.test is the standard, but there are others like midje which are interesting to explore
15:44weavejesterOkay, simple example: you click a box and it turns red.
15:44tomojhey, great, I already have a red box
15:44weavejesterSo if the box mutates, maybe you put it in a ref. Does that mean all objects in your scene are refs?
15:44tomojbut no user input yet
15:44n_bucb: 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:45Pupnik-weavejester, you don't need mutation to turn your box red
15:45weavejesterDo I have an event like: {:type :click :object (ref my-box)}
15:45weavejesterPupnik-: Can you elaborate?
15:46ucbn_b: I've used (and still use) midje with no complaints; but YMMV, it all depends on what you want and need really :)
15:46noncomweavejester: so, you *do not* have your world fully functionaly developing on each frame, you rely on pure state where possible?
15:47Pupnik-its state is part of the 'game state' that is re-generated each frame through the (new-state) function
15:47weavejesternoncom: Currently the world is a ref, and the current application state is a ref.
15:48weavejesterPupnik-: Right, so alternatively, I could represent the box like: {:shape :box, :state :clicked}
15:48weavejesterAnd then have a function that iterates through the world looking for clicked boxes and turning them red.
15:48Pupnik-well, ultimately you will need to tell your renderer what to do
15:49weavejesterHowever… that sounds expensive.
15:49Pupnik-but your clojure code can be immutable
15:49Pupnik-watch some videos about clojure data structures :)
15:49Pupnik-of course, maybe it will be too much at 60fps
15:49Pupnik-I havent tried making a game yet, but i will soon
15:49dnolenweavejester: why not just thread the world state through the game? I liked ztellman's early experiments along those lines with penumbra
15:49weavejesterPupnik-: I am acquainted with Clojure data structures :)
15:50Pupnik-it shouldn't be too bad, its jmonkey that will do the rendering
15:51weavejesterdnolen: Hm...
15:51weavejesterI guess I need to clear my mind on this.
15:52weavejesterThanks everyone for listening to me ramble
15:52weavejesterYou've made me understand I'm really confused, and don't have a clear plan
15:52dnolenuser events can go into a queue and you can assoc them onto the world state before calling into the main handler
15:52weavejesterSo… the first step to enlightenment is complete.
15:53noncom:D
15:53weavejesterdnolen: Yeah, I was thinking about that. But doesn't that, I don't know, taint the world a little...
15:53dobladezEmacs question: to show eldoc messages, emacs expands and shrinks the "echo area", which is quite annoying. Anybody knows how to fix that?
15:54noncomweavejester: there is a need for a clear view i think
15:54dnolenweavejester: http://github.com/mjg123/pacman/blob/gh-pages/src/pacman/core.cljs#L321
15:54dobladezI tried customizing option 'Eldoc Echo Area Use Multiline', but it doesn't seem to make a difference
15:54Pupnik-you can't keep the world state compeltely pure, it will always need to read things like frame time
15:55Pupnik-well, not always maybe your game doesnt care about that
15:55Pupnik-but usually
15:55tomojhuh?
15:55tomoj"world state" and "frame time" seem very disconnected, semantically, to me
15:55Pupnik-if you need to run a physics simulation, you need frame time
15:56tomojif you describe the equations of the system being simulated, does the frame time play a role?
15:57weavejesterI currently want to keep the app (i.e. what the user sees) separate from the world (i.e. what the server simulates)
15:57weavejesterThe app contains the UI, the 3D scene, the HUD, and so forth.
15:57weavejesterAn event might trigger a change in the world, or a change in the app.
15:58tomojoh 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:58tomojor just not in sync frame-by-frame with eachother anyway
15:58Pupnik-tomoj, it will be server tick rate in this case
15:58tomojyeah, right
15:58Pupnik-since the server will run the simulation
15:58tomojbut still, does it show up in the equations? if not, I don't want to write it in my code :)
15:58weavejestertomoj: Yes. The world is potentially external (although there will be a local copy), the app is internal.
15:58pandeirois there an easy way to use long-polling with jetty?
15:59Pupnik-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:00weavejesterCurrently an event will trigger a function, which can update the app or update the world, or both.
16:00weavejesterBut currently I'm taking a HTML DOM-like approach, and assigning event handles by adding :on-click attributes to the app.
16:01weavejesterWhich is leading to a circular dependency.
16:01ztellmanweavejester: I wrote this ages ago about writing a "functional" game: http://ideolalia.com/creating-a-simple-game-in-clojure/index.html
16:01tomojyou need frame time somewhere, but I want it in the background, not in my world data/logic
16:01ztellmanbasically callbacks are pure functions on the world state, except for the display callback, which only performs side-effects
16:02noncomi 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:03weavejesterztellman: 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:03tomojasteroids is a great example
16:03weavejesterztellman: Currently both are refs an event handler can update.
16:03tomojsource link is dead, new one https://github.com/ztellman/penumbra/blob/master/test/example/game/asteroids.clj
16:03ztellmanweavejester: any reason to not have them just be entries in the same block of state?
16:03ztellmantomoj: I'll fix that, thanks
16:04tomojI do not envy the people why find github links with "master" in their only promising search result - irc logs
16:04tomojwho.
16:05tomojalmost feels like it should be a redirect..
16:05tomojwith a 'copy link to master' button with a red exclamation point and a tooltip..
16:05weavejesterztellman: 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:06ztellmanweavejester: ah, ok, all my callbacks were in response to in-process events
16:06ztellmanmakes sense to differentiate
16:06gfrederickshow can I run clojure.test tests without leiningen?
16:07weavejesterztellman: Clojure's refs provide a nice way of taking a per-frame snapshot of a changing data structure.
16:07tomojbbloom: did you coin 'virtual' in the context of pedestal?
16:07bbloomtomoj: i'm speaking from memory. i think they called it a logical tree
16:08ztellmanweavejester: yeah, if you look at the post I linked to, there were multiple concurrent processes updating the blob of state
16:08ztellmanchecking for collisions, checking if the exhaust should be emitted, etc
16:08ztellmanall interacting with an atom
16:08mikerodIs this expected behavior of `flatten`?
16:09tomojsuppose you break the state up into a bunch of little atoms/refs
16:09mikerod,(flatten (java.util.Collections/unmodifiableList [1]))
16:09clojurebot()
16:09mikerod(flatten (seq (java.util.Collections/unmodifiableList [1])))
16:09weavejesterztellman: Maybe I'm looking at the wrong thing… what do your callbacks look like?
16:09mikerod,(flatten (seq (java.util.Collections/unmodifiableList [1])))
16:09clojurebot(1)
16:09ztellmanthe callbacks are registered at https://github.com/ztellman/penumbra/blob/master/test/example/game/asteroids.clj#L384
16:10ucbgfredericks: you mean in a repl?
16:11tomojinstead of (assoc state :foo (foo' foo)) you have (swap! state/foo foo') say
16:11tomojwhat did you lose?
16:11weavejesterztellman: Is the world state internal to the app? So the callbacks never see it directly?
16:11gfredericksucb: sure
16:11gfredericksucb: I'm debugging why my tests hang and thought I would rule out or implicate leiningen
16:12ztellmanweavejester: notice that each of the callbacks have a 'state' parameter
16:12ucbgfredericks: there's (run-tests...)
16:12ztellmanand they return a modified state
16:12ucb,(doc run-tests)
16:12clojurebotExcuse me?
16:12ucbbleh
16:12mikerod,(= (flatten (seq (java.util.Collections/unmodifiableList [1]))) (flatten (java.util.Collections/unmodifiableList [1])))
16:12clojurebotfalse
16:12technomancybbloom: I don't think losing your key needs to be handled differently from having it compromised
16:12weavejesterztellman: The {:dim *dim*} - is that the initial state?
16:12weavejesterztellman: So (app/start callbacks initial-state) ?
16:13technomancybasically before it's lost you generate a revocation cert; if it's lost/compromised you publish that with the date it was lost
16:13bbloomtechnomancy: which assumes i don't lose the revocation cert....
16:13technomancyheh, yep. some people recommend printing it out and filing it.
16:14technomancythis is why we give keys an expiry date =)
16:14bbloomtechnomancy: 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:14technomancyto limit the damage that can be done if it's compromised and can't be revoked
16:14bbloomtechnomancy: i know security people hate when smart folks say stuff like that :-)
16:15bbloomcan 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:15tomojit's basically a manual state monad, right? so what is lost if you just use state?
16:15technomancybbloom: it's a big step up from not doing any signing =)
16:15tomoj(fn [state] (foo (update-state state) (update-state state))) becomes difficult?
16:15technomancybbloom: checking a pom or pom .asc in usually isn't a great idea. using signed git tags is though.
16:16bbloomtechnomancy: signed git tags?
16:16tomoj..I guess everything becomes difficult?
16:16technomancybbloom: just use the -s arg to git tag
16:16bbloomtechnomancy: release management is a PITA….. stupid software… heh
16:16weavejestertomoj: Updating a state via a return value doesn't seem particularly tricky.
16:17technomancybbloom: brb; screw this going back to rubygems, etc =)
16:17bbloomtechnomancy: ha
16:17bbloomtechnomancy: i mean, lein has to wait for the JVM to start, soooo who cares if rake takes 45 seconds to initialize?
16:17ztellmanweavejester: sorry, stepped away for a second. Yes, that's correct.
16:18linuxosclojure uses just long for storing integers. even for small counters?
16:18tomojwell 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:19tomojso 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:20Pupnik-its the time slice approach
16:21Pupnik-the progress of time is represetned by a series of immutable states
16:21clojurebotc'est bon!
16:21chessguysalutations and other such pleasantries
16:21weavejesterPupnik-: Well, really, that's always the case
16:22Pupnik-weavejester, except normally those states are modified in place and you lose access to the old ones
16:22Pupnik-if you wanted to know a players velocity was 5 seconds ago
16:22Pupnik-you cant check
16:22weavejesterztellman: It seems that by changing the state through a callback, you lose some of the control a ref would give you.
16:23weavejesterPupnik-: Yeah, that's the main difference
16:23tomojPupnik-: how do you gain that ability?
16:23tomojif you just have an atom with the current state, you don't have that ability, do you?
16:23ztellmanweavejester: by only using callbacks, it gives the game loop more control over when these things happen
16:23Pupnik-no
16:23ztellmanwhich I found to be useful
16:24Pupnik-or at least, i dont think so
16:24ztellmanthat may or may not prove true for you
16:24Pupnik-i know much more about how games work than about clojure
16:26tomojI guess pedestal addresses this by making the current state a view of an append-only collection?
16:26linuxosclojure is dealing with longs as default .. is this to make it simple with no conversion back and forth despite greater memory consumption?
16:26tomoj(also datomic..)
16:28linuxos"Clojure 1.3 constructs a new Long around
16:28linuxosan int instead, because rich has decided he prefers longs and doubles
16:28linuxosto ints and floats.
16:28linuxos"
16:29weavejesterbrb food
16:30tomojif 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:30tomoj..other than whatever it actively remembers in the state
16:32tomojwe have one nice solution already for deciding what needs to be remembered and automatically remembering it for those who need it - GC
16:44jtoy_anyone know of a simpel library that will do cross validtion for me in clojure?
16:48tomojjtoy_: 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:48tomojfor k-fold
16:48augustlthinking 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:49tomojwell you'd want to compute n from k
16:51technomancyaugustl: it's easiest just to add ring-jetty-adapter and a 5-line -main defn
16:55augustltechnomancy: I'll miss the auto reloading :)
16:55augustlprobably easy to pull that in manually too, I guess
16:55technomancyaugustl: nrepl
16:56jtoy_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:56augustltechnomancy: ah good, another reason for our one remaining IntelliJ dev to switch ;)
16:59tomojjtoy_: oh wait, looks like incanter has it
16:59tomoj"simple"? not sure
17:03owengalenjonesanyone ever see this https://www.refheap.com/paste/14406
17:04jtoy_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:04tomojyeah
17:04ucbowengalenjones: I don't think :1 is a valid keyword
17:05owengalenjonesucb: (keyword? :1) => true :)
17:06ucbowengalenjones: ugh :)
17:06ucbI honestly thought it wasn't a valid keyword :)
17:06arohner,(keyword "foo "bar")
17:06clojurebot#<RuntimeException java.lang.RuntimeException: EOF while reading string>
17:06arohner,(keyword "foo bar")
17:06clojurebot:foo bar
17:06owengalenjonesO_o
17:07arohner,(keyword ":foo")
17:07clojurebot::foo
17:08gfredericksucb: you've really exposed my tendency to not put the smallest amount of effort into figuring things out for myself
17:08ucbgfredericks: I'm a sinner as well :)
17:17kathy1Holaaa
17:19jtoy_tomoj: evaluate in your example just means call my function?
17:41satch5150hi 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:22tomojjtoy_: right
18:22tomojwhich returns your metric on the validation data after training
18:34Apage43man, 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:35Apage43in 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:36Apage43in vim the worst I'll do is delete some of the file I'm working on, which is easy enough to undo
18:38ohpauleezApage43: Why not use fireplace in vim?
18:39tomojdoes pedestal's :continue violate the epochal time model?
18:39Apage43I do. It's fantastic as far as those things go, and I like it better when I'm working on some things.
18:39ohpauleezfireplace + paredit + surround makes for a pretty competent setup
18:39ohpauleezahh cool
18:39tomojor it just makes the epochs sub-transaction?
18:39Apage43what 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:40ohpauleezApage43: It'll timeout and drop it
18:40ohpauleezbut you'll have to restart the jvm - as you would in emacs too
18:40Apage43it does that and frees up my vim session yeah, but my nrepl sessions typically is still hung
18:40hiredmantomoj: continue is just a loop
18:40ohpauleezright, I guess I always have my repl instance running in another tmux pane or window
18:41Apage43nrepl.el C-c c-c will actually .stop the thread
18:41Apage43which even works some of the time
18:41ohpauleezahh gotcha
18:41Apage43same as what Ctrl-C does in lein repl/reply
18:41tomojhiredman: oh, yes, I was thinking each transaction was doing multiple messages despite having just read that each message gets a transaction
18:41Apage43of course emacs still barfs all over the place if I accidentally eval something that prints too much
18:43tomojhmm "It returns a sequence of messages which will be processed within the same transaction." what?
18:44arrdemApage43: really? I've seen the colors and formatting go bad, but I've never seen emacs actually break
18:45tomojI've sometimes felt like I wanted something like :continue in datomic
18:46Apage43arrdem: 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:46Apage43and sometimes it's just faster to kill emacs and bring it all back up
18:46linuxoscan i get a long unsigned in clojure?
18:46tomojfor 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:47tomojbut I suspect there is a very good reason datomic doesn't allow this..
18:47bbloomlinuxos: you can't get an unsigned anything in java
18:47Apage43most 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:47arrdemApage43: is there a better logging lib than good ol' println?
18:47hiredmantomoj: 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:48Apage43probably
18:48hiredmanand what happens is there is a watch on the queue ref, so if put something in it runs the processing transaction there
18:48Apage43I'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:49hiredmanand 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:49tomojok, yeah
18:49hiredman(I haven't looked at how it is actually implemented, some kind of atom thing)
18:49tomojdatomic does not allow any intransaction stuff
18:49arrdemApage43: looks like timbre and clojure/tools.logging are the options
18:50arrdemand they're both pretty srs bizness logging
18:50hiredmanwell, you can have transaction functions
18:50tomojright but they only get the pre-transaction db as input
18:50tomojso that there can be no causality between datoms within a transaction
18:52tomojthough 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:53tomojapp.clj and dataflow.clj seem delightfully simple in any case
18:53shriphanihi. 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:57tomojhiredman: so under normal circumstances when the queue watcher fires, the queue is always going just have the one message in it?
18:58hiredmantomoj: yeah, and you could add some kind of fanciness to ensure that sort of thing
19:14lynaghk`Does anyone know if ruby has something akin to "pr-str"?
19:15gfrederickslynaghk`: #inspect I think is it
19:16gfredericks$findfn pos? [-1 2 -3 4 -5] [[2 4] [-1 -3 -5]]
19:16lynaghk`gfredericks: ohh, awesome. thanks!
19:16lazybot[]
19:20hyPiRion,((juxt filter remove) pos? [-1 2 -3 4 -5])
19:20clojurebot[(2 4) (-1 -3 -5)]
19:20hyPiRion~amalloy
19:20clojurebotamalloy is <amalloy> just use juxt, it'll be great
19:21gfredericksturned out I wanted group-by anyways
19:21gfredericksbut prior to that I did recall the olde Amalloy Adage
19:22irctc305I have a map that I want to concat to a list of maps -> (concat [{:a 2}] {:b 3 :h 5} [{:c 4}])
19:22irctc305However the above adds the map as a map entry ({:a 2} [:b 3] [:h 5] {:c 4})
19:23irctc305How can I just add a map to a list of maps at the start and end ?
19:24gfredericks(concat [some-map] a-list-of-maps [some-other-map])?
19:25hiredman(concat [{:a 2}] {:b 3 :h 5} [{:c 4}]); one of these three args is not like the others
19:25gfredericksone of these args just doesn't belong
19:26benkayhey y'all, a question about loading data from the filesystem:
19:27benkayI 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:27irctc305thanks for the pointer, just enclosing the second arg as a vector solves it ! now all args are of the same type
19:28benkayis there an obvious thing i'm missing about what i'm trying to do here?
19:29hiredmannever heard of clj-crypto
19:29benkaybouncycastle wrapper
19:29hiredmanbut my guess is you are doing character io using bytes
19:29hiredmanspit is not the way to go for reliable io
19:29benkaywould that look like nonsense when I open the file?
19:29hiredmanhave you actually looked at the contents your .pem?
19:29benkayoh yeah, it's just a string.
19:30benkay<RSAPublicKeyImpl ...
19:30hiredmanjust a string?
19:30hiredmanah
19:30gfredericksnot a very good public key
19:30hiredmanyou haven't even gotten to io yet
19:30hiredman(clj-crypto/public-key keypair) is just returning a key object
19:30hiredmanyou'll need to do some more work to get actual bytes
19:30hiredmanspit is just calling toString on the object
19:31benkaysounds like you're suggesting writing the bytes to disk and then reading them back off?
19:32gfredericksyeah for crypto stuff you'll want to use bytes not strings
19:32benkaythanks gfredericks, hiredman
19:33benkayis there something like spit that writes bytes?
19:33hiredmanforget spit
19:34hiredmango look at the code for clj-crypto or the java docs for bouncy castle
19:34hiredmanfigure out what it is that clj-crypto returns
19:34hiredmanfigure out how to turn that in to bytes
19:35hiredmanby the time you are done I imagine you will be ready to ditch clj-crypto because you will be comfortable using bc directly
19:36hiredmanyou will most likely need the javax.crypto java docs too
19:36hiredmanhttp://docs.oracle.com/javase/6/docs/api/java/security/interfaces/RSAPublicKey.html
19:39Apage43if you have some type of Key, .getEncoded is on the Key interface (for java.security.Key) which gets you bytes
19:42amalloy(inc hyPiRion)
19:42lazybot⇒ 14
19:48shriphanihi I have a question about enlive. How do I do [:div.class_name] only class_name has a space in it...
19:49benkaythanks Apage43!
20:03weavejesterMay I ask what everyone uses for note-taking? I usually use emacs and a text or markdown file…
20:04tieTYT2google drive?
20:04technomancyweavejester: org-mode
20:04tieTYT2or a program on my cell phone called AK notepad
20:04weavejestertechnomancy: I was hoping someone would say that :)
20:05technomancyweavejester: I basically use org like outline-mode though
20:05weavejestertechnomancy: 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:05hiredmanweavejester: what do you want for note-taking?
20:05technomancyweavejester: the ability to collapse outlines is the main thing I use it for
20:05hiredmanwhat are the component features of note-taking for you
20:06hiredmanorg-mode tables are like be able to embed little spreadsheets, but the formulas can be in elisp
20:06weavejesterhiredman: 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:07hiredmanweavejester: yeah, but you asked for features over a text file, org-mode has 1e100 features
20:08technomancyliterally the largest lisp file on my hard drive
20:08technomancyprobably the largest non-autogenerated lisp file on github
20:08hiredmanyou 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:08tieTYT2i 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:08weavejesterhiredman: Well, I don't really know what features I'd want, without know which ones there are...
20:08bbloomi just use a text file in vim
20:08bbloomi have a directory called notes & there are about 20+ files in there
20:08hiredmanorg-mode lets you create a list of times with various todo status and sort the lists based on the todo status
20:08technomancytieTYT2: the official story is that pattern matching is closed, while predicate dispatch is open.
20:09bbloomi mostly never read them lol
20:09technomancytieTYT2: I don't really buy that though
20:09weavejestertieTYT: There's core.match, so pattern matching is only left out of the core language
20:09scottjweavejester: btw, org-mode was originally for note-taking. the other things came later.
20:09technomancycore.match has issues =\
20:09hiredmanorg-mode will renumber your lists for you if you put an element in the middle of a numbered list
20:09tieTYT2technomancy: I don't know what either of those mean
20:09tieTYT2what do you mean by closed?
20:09tieTYT2weavejester: let me check that out
20:09technomancytieTYT2: compare it to cond vs defmulti
20:09technomancytieTYT2: cond only works on values known up-front; defmulti can be extended after the fact
20:10tieTYT2so cond is called "closed"?
20:10technomancyyeah
20:10technomancytieTYT2: note that I do not find this justification persuasive at all
20:10hiredmanyou 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:11tieTYT2why can't you have both?
20:11bbloomyou can only be open or closed with respect to something…. cond is closed to adding cases at runtime
20:11tieTYT2I never thought of defmulti as an answer to pattern matching. I always thought of destructuring as an answer to pattern matching
20:12technomancytieTYT2: I only brought up defmulti as an example to explain closed/open
20:12tieTYT2technomancy: ohh
20:12clojurebottechnomancy is to blame for all failures
20:12technomancyyou can certainly have both
20:12hiredmanorg-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:12technomancyclojurebot: you're one to talk
20:12clojurebotHuh?
20:12bbloomtieTYT2: pattern matching is desructuring plus ordered choice. i think that the ordered choice bit is the bit that rich doesn't like
20:12weavejesterHas anyone made much use of watches on refs?
20:12hiredmanI use them for a debugging a lot
20:13tieTYT2bbloom: what's the downside to that?
20:13amalloyweavejester: i've watched a couple of atoms, but not for very good reasons
20:13bbloomtieTYT2: consider a complex cond block… you can't re-order statements without considering logical implications of the conditions/predicates
20:14bbloomtieTYT2: 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:15weavejesterI think I'm going to try and use watches in place of an event queue.
20:15bbloomif you re-order the clauses, you are changing the meaning. that's not true of multimethods for example
20:15tieTYT2true
20:16bbloompattern matching is most useful when you want to do exhaustive case analysis. like in haskell where you have algebraic data types
20:16bbloomin which case, you really want a switch b/c that lets you reorder the clauses
20:16bbloomi've seen some haskell code that makes some pretty subtle assumptions based on the order of patterns. i can be confusing
20:16tieTYT2in 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:16tieTYT2and destructuring is not related
20:16bbloomhe said that in a talk at one point
20:17tieTYT2bbloom: the one on simple made easy?
20:17tieTYT2yeah I noticed that, but I didn't understand why
20:17bbloomhe said something to the effect that pattern matching complects name binding and ordered choice while remaining closed to adding cases at runtime
20:17bbloomdestructuring, as implemented in clojure, is closed with respect to adding new pattern types
20:18tieTYT2he says that, but I don't see him giving an alternative
20:18tieTYT2or something better
20:18bbloomso the "better" thing is predicate dispatch
20:18bbloombut predicate dispatch is still somewhat of an open research problem
20:18tieTYT2eg: cond?
20:19tieTYT2or defmulti?
20:19bbloom*shrug* cond is just so simple & so often useful that you kinda gotta have it
20:19tieTYT2for me: http://stackoverflow.com/questions/5671627/what-is-predicate-dispatch
20:20bbloomthe real hard part of predicate dispatch is determining logical implication
20:20tieTYT2i never thought of using multimethods this way
20:20tieTYT2wouldn't it be frowned upon to use it when you could use pattern matching?
20:20tieTYT2i've been told it's pretty slow
20:20bbloomit's only really slow when dispatching on the java type hierarchy
20:20bbloomit's reasonably fast otherwise
20:20bbloomnot as fast as protocols & simple branches, but still pretty quick
20:21tieTYT2i see. I've written two small programs that use multi methods and they both dispatch on symbols
20:21bbloomsee http://homes.cs.washington.edu/~mernst/pubs/dispatching-ecoop98-abstract.html
20:21tieTYT2or contents of a string
20:23tieTYT2thanks
20:24tieTYT2i 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:25bbloomtieTYT2: 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:25bbloomor cond even
20:25tieTYT2yeah that's pretty much what I ended up doing
20:25bblooma multimethod is useful when you want other folks to be able to add cases
20:25tieTYT2yeah I don't have that situation
20:25bbloomyou need to ask the question "do i need open dispatch?"
20:25bbloomif the answer is no, choose something simpler
20:25tieTYT2whereas pattern matching is useful even if you don't need open dispatch
20:26tieTYT2it would have been good in this situation. I think a case/cond was more complicated than pattern matching would have been
20:27bbloomso 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:27bbloomfewer branching constructs in your code is generally easier to understand & pattern matching inherently adds one branch point per pattern
20:27tieTYT2perhaps you're right. I only used haskell for 1-2 months so I wouldn't have discovered that by then I think
20:29bbloomi 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:29tieTYT2but IME, the pattern matching reduces your overall code so it makes up for that issue
20:31technomancyI agree
20:31technomancyI would use core.match if it didn't break AOT
20:32tieTYT2that's an intimidating restriction
20:32tieTYT2i'm not experienced enough to knwo if I need that
20:32pjstadigmeh
20:32pjstadigAOT is kinda broken already
20:32clojurebotIn Ordnung
20:32pjstadig~AOT
20:32clojurebotAOT is kinda broken already
20:32pjstadighaha
20:32technomancypjstadig: not for libraries obvs
20:33technomancyI mean I wouldn't use it for libs
20:33technomancybut I always AOT before deployment
20:33technomancy(not on my own box of course)
20:34hiredmansomeone could just fix core.match
20:35hiredmanugh, the jira issues doesn't have a reproducable case
20:35tieTYT2http://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:35hiredmanah, this other issue has a reproducable case
20:36tieTYT2is it always fixable?
20:38hiredmanother 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:38hiredmanqed
20:38hiredmanit just may mean embedding a haskell or ml compiler in a clojure macro
20:39bbloomheh.
20:43hiredmanthe 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:44tieTYT2this is over my head
20:44hiredmanwhich makes sense for more complicated macros that are really source to source compilers
20:48amalloyi haven't looked at core-futures myself, but i heard it was SSA, from someone who was puzzled that it wasn't CPS
20:49hiredmansomeone showed that cps and ssa are equivalent, but cps is used a lot for functional languages
20:52hiredmanthe guile guy had a blog post a few years ago
20:53hiredmanhttp://wingolog.org/archives/2011/07/12/static-single-assignment-for-functional-programmers/
21:18qbg_hiredman: Do you have link describing core-futures?
21:22hiredmanhttp://dev.clojure.org/display/design/Async+blocks
21:24qbg_nice
21:24tomojreally more core-async
21:25tomojcore-futures will I think be replaced
21:25tomojor maybe they'll stick with it, but I remember a note somewhere saying "this is temporary, TODO decide on future implementation" or something
21:27tomojdelightfully there is only one small spot in core-async that depends on core-futures
21:27dnolentomoj: i believe they are two distinct and necessary pieces
21:27tomojindeed
21:28tomojI just mean "Async blocks" and the work on the relevance branch is more about core-async than core-futures
21:28tomojoh but the branch is called core-futures, heh
21:28tomoj«Note: the implementation of futures should be considered in "draft" phase, it will change radically before an alpha is released.»
21:32qbgthat is beautiful