2015-03-23
| 00:02 | ben_vulpes | ahahaha |
| 00:02 | ben_vulpes | i very definitely wired a figwheel server into the reloaded/component/system flow. |
| 00:02 | ben_vulpes | yussss. |
| 01:46 | Seylerius | How d'you recurse an anonymous function? |
| 01:47 | TEttinger | Seylerius: give it a name. ##((fn rec [n] (if (> n 5) n (rec (inc n)))) 0) |
| 01:47 | lazybot | ⇒ 6 |
| 01:48 | Seylerius | Why the ##? |
| 01:48 | TEttinger | fn allows names for this exact purpose |
| 01:48 | TEttinger | just telling lazybot to eval |
| 01:48 | Seylerius | Shiny |
| 01:48 | TEttinger | ((fn rec [n] (if (> n 5) n (rec (inc n)))) 0) |
| 01:48 | TEttinger | is the actual snippet |
| 01:50 | Seylerius | Awesome, thanks. |
| 01:51 | Seylerius | Wow, my internet really slows down in the rain... |
| 01:52 | TEttinger | satellite internet? |
| 01:52 | TEttinger | or cellular of some kind? |
| 01:52 | Seylerius | Wireless. 802.11n over TDMA, essentially, broadcast from a tower at the head of the lake. |
| 01:53 | TEttinger | how far does this reach? wow |
| 01:56 | Seylerius | ##(fn flatify [coll] (loop [remainder coll result []] (if (empty? remainder) result (if (coll? (first remainder)) (recur (rest remainder) (concat result (flatify (first remainder)))) (recur (rest remainder) (conj result (first remainder))))))) |
| 01:56 | lazybot | ⇒ #<sandbox6330$eval45317$flatify__45318 sandbox6330$eval45317$flatify__45318@271546bb> |
| 01:56 | Seylerius | Wait... |
| 01:56 | Seylerius | Forgot to make it do something. |
| 01:56 | Seylerius | ##((fn flatify [coll] (loop [remainder coll result []] (if (empty? remainder) result (if (coll? (first remainder)) (recur (rest remainder) (concat result (flatify (first remainder)))) (recur (rest remainder) (conj result (first remainder))))))) [1 [2 3] 4]) |
| 01:56 | lazybot | ⇒ (4 1 2 3) |
| 01:56 | Seylerius | Hrm. |
| 01:57 | Seylerius | Ahah. |
| 01:58 | Seylerius | ##((fn flatify [coll] (loop [remainder coll result []] (if (empty? remainder) result (if (coll? (first remainder)) (recur (rest remainder) (concat result (flatify (first remainder)))) (recur (rest remainder) (concat result [(first remainder)])))))) [1 [2 3] 4]) |
| 01:58 | lazybot | ⇒ (1 2 3 4) |
| 01:58 | Seylerius | ^_^ |
| 01:59 | TEttinger | Seylerius, is this for 4clojure? |
| 01:59 | TEttinger | ~flatten |
| 01:59 | Seylerius | It is. |
| 01:59 | clojurebot | flatten is rarely the right answer. Suppose you need to use a list as your "base type", for example. Usually you only want to flatten a single level, and in that case you're better off with concat. Or, better still, use mapcat to produce a sequence that's shaped right to begin with. |
| 01:59 | Seylerius | Flatten is in fact the task. |
| 01:59 | TEttinger | that's a good solution though |
| 02:00 | Seylerius | Thanks. |
| 02:01 | TEttinger | ,(defn flatify [coll] (loop [remainder coll result []] (if (empty? remainder) result (if (coll? (first remainder)) (recur (rest remainder) (concat result (flatify (first remainder)))) (recur (rest remainder) (concat result [(first remainder)])))))) |
| 02:01 | clojurebot | #'sandbox/flatify |
| 02:02 | TEttinger | ,(flatify [:a :b {:a 0 :b #{1 2 3}}]) |
| 02:02 | clojurebot | (:a :b :a 0 :b ...) |
| 02:02 | TEttinger | ,(flatify [:a { :b #{1 2 3}}]) |
| 02:02 | clojurebot | (:a :b 1 3 2) |
| 02:02 | TEttinger | nice! |
| 02:03 | Seylerius | I'm a little prone to over-engineering things, but I prefer the fully generalized solution where possible. |
| 02:04 | amalloy | Seylerius: flatten is a lot easier to implement with mapcat than with loop/recur |
| 02:04 | Seylerius | amalloy: I'll take a look at mapcat. |
| 02:04 | Seylerius | Hmm... Interesting. |
| 02:05 | amalloy | ,((fn flatify [x] (if (coll? x) (mapcat flatify x) [x])) '[1 2 [3 [4] 5] [6 (7)]]) |
| 02:05 | clojurebot | (1 2 3 4 5 ...) |
| 02:05 | Seylerius | Nice. |
| 02:17 | Seylerius | ##((fn [string] (apply str (re-seq #"[A-Z]" string))) "HeLlO, WoRlD!") |
| 02:17 | lazybot | ⇒ "HLOWRD" |
| 02:19 | Seylerius | So, what's the deal with clojurebot and lazybot? Does lazybot eval any s-exp that starts with a double-# and discards after eval, while clojurebot expects the whole line to be a s-exp that starts with a comma, and it keeps state? |
| 02:34 | amalloy | Seylerius: close enough. lazybot also evals lines starting with &, and allows ##'(expressions) to appear mid-sentence |
| 02:34 | lazybot | ⇒ (expressions) |
| 02:34 | Seylerius | Neat. |
| 02:34 | Seylerius | And lazybot discards, while clojurebot doesn't? |
| 02:35 | amalloy | well, "discards". lazybot doesn't allow definitions |
| 02:36 | amalloy | clojurebot evals more or less anything, and throws away the whole VM every 15 minutes or so |
| 02:37 | Seylerius | Gotcha. Shiny. |
| 02:38 | Seylerius | What about the ,(inc amalloy) stuff? That get discarded? |
| 02:38 | Seylerius | Or is that maintained separately? |
| 02:38 | amalloy | Seylerius: it's a separate thing. not really clojure at all, just a regex that matches something like (inc|dec username) |
| 02:39 | Seylerius | Right. |
| 02:39 | amalloy | (inc Seylerius) |
| 02:39 | lazybot | ⇒ 1 |
| 02:39 | Seylerius | (inc amalloy) |
| 02:39 | lazybot | ⇒ 240 |
| 02:39 | Seylerius | For answering all these damn questions. |
| 02:51 | vas | can i upsert enumerated types in datomic? |
| 03:36 | dstockton | how would i get the metadata for a var defined in another namespace? |
| 03:39 | dysfun | dstockton: (meta #'namespace/var) |
| 03:39 | dstockton | dysfun: so i'd have to know the symbol of the var in that namespace |
| 03:40 | dstockton | its actually a fn argument, so in my current namespace has a completely different var |
| 03:40 | dysfun | if you don't manually attach metadata, it's attached to a symbol |
| 03:40 | dysfun | er to a var, sorry |
| 03:40 | dysfun | not to a value |
| 03:40 | dstockton | yeah, i guess i'll have to rethink what im doing then |
| 03:40 | dysfun | the user can quote it and you can use find-var, or you can wrap it in a macro to deal with the quoting |
| 03:41 | dstockton | im building some widgets, wanted to add configuration data to the component fns |
| 03:41 | dysfun | yes, perhaps start by explaining what you're trying to do :) |
| 03:41 | dstockton | like {::required true} |
| 03:41 | dysfun | widgets could be any number of things. could you be a little more specific? |
| 03:41 | dstockton | om component fns |
| 03:41 | dysfun | oh right |
| 03:41 | dstockton | its actually cljs |
| 03:42 | dysfun | you probably want a macro to make it tidy |
| 03:42 | dysfun | or put the component in a datastructure with meta information |
| 03:43 | dstockton | still not sure where i'd stick the metadata to make it more tidy, so that i could reference it later |
| 03:43 | dstockton | i could wrap them in another map i suppose |
| 03:43 | dysfun | a code example might help. http://refheap.com/ |
| 03:47 | dstockton | boils down to something like this https://www.refheap.com/98788 |
| 03:49 | dysfun | hrm, it looks alright |
| 03:49 | dysfun | i don't have an om project in a state i could test it, mind |
| 03:51 | dysfun | but i'm guessing you're adding tracking tags heh |
| 03:54 | dstockton | meta is just nil, i guess because widget is a completely different var to the original definition |
| 03:55 | dysfun | oh i see |
| 03:56 | dysfun | that's because the function 'component' has metadata, not the value you're checking |
| 03:56 | dysfun | however, you can use with-meta to wrap meta on the result |
| 03:56 | dysfun | however, i bet if you (meta #'component), you should see it |
| 03:59 | dstockton | probably dysfun, but i don't know the var's name inside some-fn |
| 03:59 | dstockton | it would be #'widget (wouldnt work) |
| 03:59 | dysfun | ,(meta (with-meta :foo {:bar :baz})) |
| 03:59 | clojurebot | #error{:cause "clojure.lang.Keyword cannot be cast to clojure.lang.IObj", :via [{:type java.lang.ClassCastException, :message "clojure.lang.Keyword cannot be cast to clojure.lang.IObj", :at [clojure.core$with_meta__4097 invoke "core.clj" 216]}], :trace [[clojure.core$with_meta__4097 invoke "core.clj" 216] [sandbox$eval25 invoke "NO_SOURCE_FILE" 0] [clojure.lang.Compiler eval "Compiler.java" 6784] ... |
| 04:00 | dysfun | or similar. you get the idea |
| 04:00 | dstockton | so wrap the defn in a with-meta? |
| 04:00 | dysfun | no, wrap the code inside the defn in with-meta |
| 04:00 | dstockton | aha |
| 04:01 | dysfun | although you may just want to create a custom record for it |
| 04:01 | dysfun | (that implements IRender) |
| 04:01 | dysfun | that way you can attach whatever information you like |
| 04:03 | dstockton | dysfun: great, that works |
| 04:03 | dysfun | thinking about it, that's how i'd play it |
| 04:03 | dstockton | feels kind of hacky but could clean it up with a custom record like u say |
| 04:04 | dstockton | so i end up having to call it like (meta (widget)) |
| 04:05 | dysfun | no |
| 04:05 | dysfun | you don't need the metadata now |
| 04:05 | dysfun | they'll just be fields in the record |
| 04:06 | dstockton | oh, i see what you mean |
| 04:06 | dysfun | (defrecord foo [name] om/IRender (render [_ |
| 04:06 | dysfun | ...) |
| 04:07 | dysfun | i haven't played enough with om to a get a feel for what the useful idioms are, but that seems like a generally useful pattern in this case |
| 04:07 | dstockton | usually the records are created on the fly with reify |
| 04:08 | dysfun | yes. there's no need to do it that way |
| 04:10 | dstockton | ok, thanks for the advice, think im on the right track now |
| 04:11 | dysfun | yw |
| 04:23 | noncom | i have just cloned my project from the repo, and here's what i am getting with leiningen: https://www.refheap.com/98791 |
| 04:23 | noncom | how can i fix this? |
| 04:26 | TEttinger | at java.io.WinNTFileSystem.canonicalize0 (WinNTFileSystem.java:-2 |
| 04:27 | TEttinger | that -2 is a little crazy |
| 04:28 | TEttinger | so it thinks you're in an unsafe to delete directory, apparently https://github.com/technomancy/leiningen/blob/master/src/leiningen/clean.clj#L69 |
| 04:32 | noncom | also, another symptom is that lein deps can't find clojars or maven repo and update the deps.. |
| 04:33 | noncom | neither UAC nor firewall are enabled on this machine.. hmm, strange thing |
| 04:37 | stain | noncom: http proxy settings? |
| 04:37 | stain | oh hang on.. on the file system! |
| 04:38 | noncom | stain: well, lein suggested that too, but no, no proxying here.. |
| 04:38 | stain | noncom: and you are not running two builds at the same time, right? |
| 04:38 | noncom | yeah, i have no builds running, since it cannot even fetch the deps |
| 04:38 | stain | how did you do the git clone? |
| 04:39 | stain | from another local repository, or from the network? |
| 04:39 | noncom | it was hg clone.. but i did this from eclipse + ccw, fetching from bitbucket.org |
| 04:39 | noncom | i did not have this problem before.. |
| 04:39 | stain | ok, I know this is silly.. but try shutting down Eclipse |
| 04:40 | stain | this is Windows - which has very eager file and directory locking |
| 04:40 | noncom | i shut it down, but it is still the same. also, eclipse was never an issue before.. |
| 04:41 | stain | https://github.com/stain/jdk8u/blob/master/src/windows/classes/java/io/WinNTFileSystem.java#L428 |
| 04:41 | noncom | heh.. idk what is going on.. i would suppose some problems in paths in project.clj, but the repo worked fine just yesterday on two different machines and there were no commits to it since then |
| 04:42 | stain | and https://github.com/stain/jdk8u/blob/master/src/windows/native/java/io/WinNTFileSystem_md.c#L243 |
| 04:43 | stain | have your project.clj got any hard-coded paths in it? |
| 04:44 | noncom | not really.. besides, it just wokred on two other machines just yeaterday.. |
| 04:46 | pkug | hi there, i just recently started diving into Clojure as a disappointed Python developer looking for some cleanliness and peace of mind ..:) currently i'm reading the highly regarded Joy of Clojure but it's keeping my pace and excitement kind of slow, it'd be nice to jump straight into program and algorithm composition patterns and some well commented real world examples to eventually start coding, i've found rosetta code a good resource so far but it lacks co |
| 04:47 | dysfun | that cut off at 'lacks co' |
| 04:47 | dysfun | anyway, TJOC is more a tour through the entire language. it's a very good piece to notch yourself up a level, but it's definitely not like e.g. 'dive into python' |
| 04:48 | dysfun | 4clojure is a good way to learn |
| 04:48 | pkug | oh sorry - but it lacks comments, what could you guys suggest in addition? |
| 04:48 | pkug | thanks |
| 04:49 | dysfun | i'd recommend picking a project and building it. we can point you in the right direction once you've decided |
| 04:50 | noncom | stain: ehh, well, problem is here anyway.. i have to leave now from this machine, so, probably this mystery will never be resolved.. although on my record it happens for the second time. |
| 04:51 | stain | pkug: Clojure in Action is a bit more like that - lots of simple piece meals that don't really connect. The second edition is in the MEAP programme, so you cean read it before its' finished: http://www.manning.com/rathore2/ (basically beta-testing the book) |
| 04:51 | TEttinger | $mail noncom it is possible windows or a firewall locked the files when you checked them out. I know downloading zips from github has them blocked by default, including all their contents, which prevents them from going out and making network calls |
| 04:51 | lazybot | Message saved. |
| 04:52 | dysfun | stain, pkug: i was disappointed by the first edition, fwiw |
| 04:52 | dysfun | i tried to learn clojure out of it |
| 04:53 | stain | dysfun: yeah, it didn't quite do it for me either.. I liked more Joy of Clojure - that is true to its title and is good to get you started.. although it's more like a "taster tour" |
| 04:53 | pkug | dysfun: ok so i'm currently doing a Coursera's course on discrete optimization and i'd like to tackle those problems with Clojure instead of Python for eg.. i doubt i'll be able to learn a new language and utilize optimization techniques so quick (it'd be pretty hardcore but i guess worth a try). So for instance it could be implementing a travelling salesman or graph coloring with constraint programming or dynamic programming algorithms. |
| 04:53 | stain | the O'Reilly one I haven't read |
| 04:53 | stain | http://www.clojurebook.com/ |
| 04:53 | stain | it's a bit old now |
| 04:54 | dysfun | pkug: okay. well most of that is data structure manipulation. which means list comprehensions and conditionals in python, yes? |
| 04:54 | TEttinger | clojure's definitely a good pick for graph-type algos |
| 04:54 | dysfun | in clojure, most everything boils down to mapping and reducing data structures |
| 04:55 | TEttinger | yep. map, reduce, some filter in there, and plenty of delicious anonymous fns |
| 04:55 | pkug | dysfun: correct, i could attempt to "translate" what i wrote in Python to Clojure but I feel there's supposed to be some "magic moment" when you can approach those problems in a different cleaner way rather than imperative Python:) |
| 04:55 | stain | and with the lazy sequences you can often do "the naive thing" and still run it quite efficiently |
| 04:56 | ane | i started learning clojure just by getting my hands dirty with a project |
| 04:56 | dysfun | pkug: well you find yourself not using mutation, that's a good start |
| 04:56 | stain | pkug: right, trying to do it imperatively in Clojure will not be so much fun.. as you will be fighting against the language |
| 04:56 | dysfun | anyway, ultimately everything boils down to composing a bunch of simple higher order functions |
| 04:56 | dysfun | anything involving data structures, anyway |
| 04:56 | stain | ane: me2, started with a mini-webserver for something trivial with a fair bit of data structure manipulation |
| 04:57 | dysfun | and then once you've written it, you can look at how to tidy it up |
| 04:57 | dysfun | and suddenly the code is half the size and you're like "wow, lisp is cool" |
| 04:57 | stain | and then you go a bit overkill for a few months |
| 04:57 | pkug | right and those examples in rosetta code are really tempting, for instance if you take a look at sudoku it's really short yet feels clean and nice (loc is probably not a good measure, i know) |
| 04:57 | stain | "I can generate a function that generates that metafunction!" |
| 04:58 | kungi | How would you convert a BufferedInputStream to a String? |
| 04:58 | kungi | Is there some magic helper function? |
| 04:58 | dysfun | you can read from the stream. eg. slurp |
| 04:58 | dysfun | though that might not take a stream, i don't remember |
| 04:58 | dysfun | ,(doc slurp) |
| 04:58 | clojurebot | "([f & opts]); Opens a reader on f and reads all its contents, returning a string. See clojure.java.io/reader for a complete list of supported arguments." |
| 04:59 | Empperi | slurp can eat a stream |
| 04:59 | stain | don't forget that character set.. |
| 04:59 | pkug | i think most of the solutions in J and Clojure there are the shortest ones, of course i find J really hard to read though |
| 05:00 | kungi | dysfun: \o/ thank you |
| 05:00 | dysfun | clojure tends to score quite well on code golf because the standard library is very pragmatic |
| 05:00 | TEttinger | J is unbelievably terse, but it's pretty much write-once, read-never |
| 05:00 | stain | :encoding "UTF-8" is probably what you need |
| 05:00 | Empperi | yeah, I suggest using that too |
| 05:01 | Empperi | :encoding that is |
| 05:02 | stain | (it will use UTF-8 by default anyway - but often it's good to be explicit in case you later find out it wasn't UTF-8) |
| 05:02 | stain | e.g. an InputStream from a network or file location |
| 05:02 | stain | and perhaps a bit of Windows |
| 05:02 | TEttinger | if you're looking for code golf, I'm pretty happy with some of the techniques used in this HP-Lovecraft-book-cult-style text generator |
| 05:02 | TEttinger | &(let[a #(apply str(flatten %))r repeatedly p partition N rand-nth n #(a(N(concat(repeat %"")(mapcat p[1 2 3]%&))))v #(n 0"aioeu""iaai")w(fn[](let[b(n 6"!.""""...")s[(n 0"STKNYPKLG""GlThShNyFt""ZvrCth")(r(N[1 2])#(do[(v)(n 9(map str"'-"(r 2 v)))(n 0(concat"lpstnkgx"[(N["h""gl""gr""nd"])(v)])"rlthggghtsltrkkhshng")]))]][b(if(seq b)[" "s][(n 3",")" "(.(a s)toLowerCase)])]))](re-find #"[A-Z].+"(a[(r 500 w)"."]))) |
| 05:02 | lazybot | ⇒ "Gliarlirk theng kindek... Thalalt! Zvrai-urk pakuth glail, nyia'ouai'igh... Glend ne-iak shiten! Kiaiegg pesh. Shagu'iash, nyaithogr sult! Thex... Yak gegil! Ku-axa'okh so-inguh! Soggias. Cthaie'iagg, thoth siagish, gliagh ftet, kiat! Ftu'akhung. Tha-ung! Pixelt fti... https://www.refheap.com/98793 |
| 05:03 | TEttinger | do not attempt to understand it |
| 05:03 | TEttinger | it was shrunk repeatedly to fit in one IRC message |
| 05:03 | TEttinger | it makes use of a ton of really neat clojure-only features though |
| 05:04 | TEttinger | it treats strings as sequences of characters so it can split them into single-char sequences, two-char sequences, and 3-char sequences |
| 05:04 | TEttinger | it makes use of map with two collections of different length, which terminates when it reaches the shorter length |
| 05:06 | stain | TEttinger: oh my, that made Klingon! |
| 05:06 | TEttinger | haha |
| 05:06 | TEttinger | I have a bunch of these generators |
| 05:07 | stain | you have just insulted my mother, I shall have to honour her and kill you |
| 05:07 | TEttinger | they're really fun to write, it's a real challenge to make them small enough to fit in ~400 chars |
| 05:08 | TEttinger | a much cleaner, longer version of a similar program that generates planet names and trims swears from the list: http://ideone.com/zwnFAL |
| 05:08 | pkug | TEttinger: that's quite hard to read for a newcomer:) is it common for people to rely on some sort of editors highlighting different logic parts of parentheses (if/then/else parts etc.) and current blocks being edited ? |
| 05:09 | TEttinger | absolutely. it's very difficult to write clojure without paren matching at least when you highlight a paren |
| 05:09 | TEttinger | which thankfully everything a step past notepad can do |
| 05:09 | dysfun | also rainbow parens |
| 05:10 | TEttinger | if you're used to IDEs, Cursive not only is a nice environment for writing Clojure, it provides one of the few really high-quality debuggers for clojure |
| 05:10 | TEttinger | Cursive is an IntelliJ IDEA plugin or something like that, not sure of the exact term |
| 05:10 | dysfun | https://github.com/jjl/elisp/blob/master/cust/jproject-cust.el the top of this is how i've set up emacs for clojure. or at least the last version that's on github |
| 05:11 | TEttinger | actually even lein repl provides paren matching, since version 1.0 I think |
| 05:11 | TEttinger | also tab completion |
| 05:11 | dysfun | both have been in there a while |
| 05:12 | pkug | ok, and what about vim? i see internet generally recommends vim-fireplace it has repl integrated, should come with paren matching too then |
| 05:12 | dysfun | dunno. assuming people do packages like emacs, you probably need rainbow-parens separately |
| 05:12 | stain | pkug: yeah, I am happy enough with parens-matching using % in gvim (it swaps to the opposite side) - but can't stand myself rainbow parentheses |
| 05:12 | ane | vim isn't as smart about lisps as other editors |
| 05:12 | oddcully | pkug: fireplace works like a charm for my beginner needs |
| 05:14 | ane | cider and clj-refactor make emacs a really nice clojure environment |
| 05:16 | the_frey | yeah I still use other editors work work in ruby || some_lang but really look forward to working with clj/emacs when I have clojure to do |
| 05:16 | pkug | stain: yup there's an extended matchit plugin.. i guess right now it's been integrated into vim by default, it makes it easy to set up custom tag matching as well using same "%" |
| 05:17 | ane | plus you can get vim inside emacs anyway :P |
| 05:19 | stain | ane: nooooooooo! |
| 05:21 | oddcully | ane: does it really run an instance or does ist just "emulate" (which usually takes about 2s to see that it does not work at all *coughintellijcough*) |
| 05:23 | clyfe | help https://gist.github.com/clyfe/1ffe4a8857d40f00e789 |
| 05:23 | stain | Atom with vim and clojure mode is also kind-of OK |
| 05:50 | ane | oddcully: it does not run an instance, it provides a vimlike modal interface to edition. it's called evil-mode |
| 05:52 | ane | oddcully: and it is about ten thousand times better than the intellij emulation |
| 05:56 | oddcully | ane: (* 0 10000) ;P |
| 05:58 | ane | heh |
| 06:03 | dysfun | just found ^:unsynchronized-mutable. is that documented anywhere? |
| 06:06 | mpenet | dysfun: in deftype probably |
| 06:07 | mpenet | ,(doc deftype) |
| 06:07 | clojurebot | "([name [& fields] & opts+specs]); (deftype name [fields*] options* specs*) Currently there are no options. Each spec consists of a protocol or interface name followed by zero or more method bodies: protocol-or-interface-or-Object (methodName [args*] body)* Dynamically generates compiled bytecode for class with the given name, in a package with the same name as the current namespace, the given fie... |
| 06:07 | mpenet | well :] |
| 06:08 | dysfun | heh |
| 06:09 | mpenet | it's jvm specific btw, cljs has :mutable I think |
| 07:54 | m1dnight_ | guys, for some dark reason leiningen takes ages to compile. Instead of like half a minute it takes about 1-2 minutes. |
| 07:54 | m1dnight_ | Any way to debug this? |
| 07:54 | m1dnight_ | it's very small project with maybe 5 files. |
| 07:55 | m1dnight_ | or could it be due to dependencies? |
| 07:56 | TEttinger | m1dnight_, have you tried https://github.com/technomancy/grenchman |
| 07:56 | hyPiRion | m1dnight_: `lein version` runs fine? |
| 07:57 | m1dnight_ | ill try soon, code is still compiling :/ |
| 07:58 | m1dnight_ | hyPiRion: that works fine, yes |
| 07:58 | m1dnight_ | Leiningen 2.5.1 on Java 1.7.0_75 OpenJDK 64-Bit Server VM |
| 07:58 | borkdude | is is possible in clojure to indent long string literals nicely like in other languages, like Scala? |
| 07:59 | hyPiRion | m1dnight_: and if you do `lein compile` now, how long does it take? Still as long? |
| 07:59 | hyPiRion | It might be that you had to AOT compile the dependencies too |
| 07:59 | m1dnight_ | strange, that completes rather quick |
| 08:00 | m1dnight_ | weird, now a simple lein run executes perfectly |
| 08:00 | hyPiRion | hm |
| 08:01 | m1dnight_ | lein clean && lein run seems to run fine now |
| 08:01 | m1dnight_ | strang |
| 08:01 | m1dnight_ | lets blame cosmic noise |
| 08:01 | hyPiRion | yeah, dang those cosmic rays |
| 08:02 | borkdude | lein was probably submitting privacy sensitive usage statistics |
| 08:02 | m1dnight_ | :D |
| 08:03 | TEttinger | borkdude, since s-expressions don't have a concept of indentation, I'm not so sure that's a good idea |
| 08:08 | dstockton | borkdude: maybe just break it up with str over many lines? |
| 08:24 | spinningarrow | has anyone used the rainbow_parentheses plugin for vim (https://github.com/kien/rainbow_parentheses.vim)? I'm trying to enable it only for clojure files (instead of all files), but I can't figure out how. |
| 08:27 | spinningarrow | anyone? |
| 08:27 | clojurebot | Just a heads up, you're more likely to get some help if you ask the question you really want the answer to, instead of "does anyone ..." |
| 08:29 | TEttinger | spinningarrow, uh it's pretty early in most of the US, Vim came up a little while ago so probably someone can answer (dysfun?) |
| 08:30 | whodidthis | https://github.com/amdt/vim-niji this should work just by installing |
| 08:31 | spinningarrow | TEttinger: makes sense - thanks! |
| 08:31 | spinningarrow | whodidthis: checking it out now |
| 08:32 | oddcully | spinningarrow: i have not used it. but puttin the toggle into a ~/.vim/ftplugin/clojure.vim might work? |
| 08:32 | TEttinger | (inc whodidthis) |
| 08:32 | lazybot | ⇒ 1 |
| 08:38 | profil | spinningarrow: you can put it into an augroup with autocmd, thats how I do it |
| 08:38 | profil | spinningarrow: https://github.com/profil/dotvim/blob/master/vimrc#L81 |
| 08:38 | spinningarrow | oddcully: that didn't work for some reason |
| 08:40 | whodidthis | spinningarrow: add "filetype plugin on |
| 08:40 | whodidthis | to .vimrc |
| 08:40 | borkdude | dstockton that's a good one |
| 08:40 | spinningarrow | profil: that worked like a charm |
| 08:40 | spinningarrow | thanks! |
| 08:43 | profil | np :) |
| 08:43 | whodidthis | man, clj-refactor seems amazeing, i wish i had an actual com puter to use emacs on |
| 08:46 | profil | I am writing a program where I am keeping some state in an atom, is it possible to listen for changes on this atom? |
| 08:46 | Glenjamin | (doc add-watch) |
| 08:46 | clojurebot | "([reference key fn]); Adds a watch function to an agent/atom/var/ref reference. The watch fn must be a fn of 4 args: a key, the reference, its old-state, its new-state. Whenever the reference's state might have been changed, any registered watches will have their functions called. The watch fn will be called synchronously, on the agent's thread if an agent, before any pending sends if agent or ref. Note that an atom's or ref's state |
| 08:47 | profil | Glenjamin: ahh, nice thanks |
| 08:49 | profil | is this the preferred way to listen for stateful events? or is there some other more clojure-like to do it? I am already using core.async to handle websockets and tcp connections |
| 08:49 | spinningarrow | whodidthis: I ended up going with vim-niji (no setup required!) cheers :D |
| 08:55 | Larva_ | Will Clojure be compatible with PAIP book http://norvig.com/paip.html ? |
| 09:00 | dnolen | Larva_: PAIP is written on Common Lisp, so not compatible. But translation to Clojure should be relatively straightforward. |
| 09:00 | dnolen | Larva_: but that assumes you're willing to learn enough Common Lisp & Clojure to do that |
| 09:01 | Larva_ | dnolen : so it is possible after all?! |
| 09:02 | dnolen | Larva_: I don't see why not |
| 09:02 | Larva_ | dnolen : oh very well, Ta! |
| 09:09 | noncom | what is clojure's common way to have some shared data memory among many namespaces? sure, i can make one with an atom and then require it from everywhere, but is this the way? |
| 09:09 | noncom | maybe there is a library for that? |
| 09:10 | dnolen | noncom: you probably want to use something like Stuart Sierra's component |
| 09:11 | noncom | dnolen: cool, from reading the intro i think this is it |
| 09:25 | pkug | Anybody read Paradigms of AI Programming by P. Norvig? would it still be relevant in learning Clojure? I just came across that it's available in my local lib |
| 09:27 | arrdem | pkug: Not directly, Clojure and Common Lisp are quite different in some ways, but there exist a couple projects which have translated all the examples to Clojure if you wanted to try and read along that way. |
| 10:20 | justin_smith | /win 22 |
| 10:20 | justin_smith | oops |
| 10:20 | tcrayford____ | don't use win32 kids, it kills |
| 10:21 | gfredericks | justin_smith: better change your passwords |
| 10:21 | gfredericks | ,(def password " /win 22") |
| 10:21 | clojurebot | #'sandbox/password |
| 10:21 | justin_smith | haha |
| 10:22 | justin_smith | tcrayford____: but win 22, that would have rocked, if intel actually came through with the 22 bit processor it was designed for |
| 10:26 | oddcully | opposite of a catch-22? |
| 10:40 | cnb_ | I'm trying to merge 2 vectors but always the resulting vector is only 1 element longer than the original. I'm doing (merge v (vector (take 250 (repeat "")))); v has 217 elements, after the merge the resulting vector only has 218 elements, what is wrong ? |
| 10:40 | gfredericks | cnb_: try into instead |
| 10:40 | gfredericks | merge is for maps |
| 10:40 | hyPiRion | gfredericks is correct. |
| 10:41 | gfredericks | hyPiRion: it's not a fact until you teach it to clojurebot |
| 10:41 | justin_smith | cnb_: merge would replace item 0 to 249 from v with "" |
| 10:41 | justin_smith | ,(merge [:a :b :c] [0 1 2 3 4 5 6]) |
| 10:41 | clojurebot | [:a :b :c [0 1 2 3 4 ...]] |
| 10:41 | justin_smith | err |
| 10:41 | justin_smith | never mind! |
| 10:42 | justin_smith | anyway, it's still wrong |
| 10:42 | gfredericks | kind of disappointing that it does anything at all :/ |
| 10:42 | hyPiRion | ,(merge nil []) ;; hurray |
| 10:42 | clojurebot | #error{:cause "Vector arg to map conj must be a pair", :via [{:type java.lang.IllegalArgumentException, :message "Vector arg to map conj must be a pair", :at [clojure.lang.APersistentMap cons "APersistentMap.java" 35]}], :trace [[clojure.lang.APersistentMap cons "APersistentMap.java" 35] [clojure.lang.RT conj "RT.java" 610] [clojure.core$conj__4067 invoke "core.clj" 85] [clojure.core$merge$fn__459... |
| 10:43 | noncom | ,(conj {} [:a :b :c 1 2]) |
| 10:43 | clojurebot | #error{:cause "Vector arg to map conj must be a pair", :via [{:type java.lang.IllegalArgumentException, :message "Vector arg to map conj must be a pair", :at [clojure.lang.APersistentMap cons "APersistentMap.java" 35]}], :trace [[clojure.lang.APersistentMap cons "APersistentMap.java" 35] [clojure.lang.RT conj "RT.java" 610] [clojure.core$conj__4067 invoke "core.clj" 85] [sandbox$eval73 invoke "NO_... |
| 10:43 | hyPiRion | oh right |
| 10:43 | hyPiRion | ,(merge nil [:a :b]) |
| 10:43 | clojurebot | {:a :b} |
| 10:43 | hyPiRion | of course |
| 10:44 | noncom | ,(merge '() [2 2]) |
| 10:44 | clojurebot | ([2 2]) |
| 10:44 | noncom | ,(merge '() {}) |
| 10:44 | clojurebot | ({}) |
| 10:44 | cnb_ | gfredericks using into gives the same result |
| 10:46 | justin_smith | ,(into [:a :b :c] [0 1 2 3 4 5 6]) |
| 10:46 | clojurebot | [:a :b :c 0 1 ...] |
| 10:46 | justin_smith | cnb_: it really shouldn't |
| 11:00 | justin_smith | woah, TIL for the IBM 1401 computer, there was an extra rental fee to access specific hardware instructions |
| 11:00 | justin_smith | I'm glad that hasn't come back |
| 11:00 | gfredericks | IBM 1401 Pro |
| 11:01 | justin_smith | freemium CPU |
| 11:01 | justin_smith | "sorry, your computer is too slow to run this app. But for a small monthly fee you could get SMID instructions." |
| 11:02 | justin_smith | SIMD I mean |
| 11:02 | justin_smith | "single multiple instruction data" would sure be useful |
| 11:04 | justin_smith | "The bit test instruction cost only $20 a month" http://www.righto.com/2015/03/12-minute-mandelbrot-fractals-on-50.html |
| 11:06 | noncom | justin_smith: probably these devices were technically difficult and that's why instructions did cost more money... it looks like an instruction was more like a plugin-module (from the pictures) |
| 11:07 | justin_smith | noncom: yeah, you actually got an extra card that plugged into the machine and implemented the instruction |
| 11:07 | xemdetia | justin_smith, this is still common even today. Lots of IBM processors are feature restricted depending on what you want to do |
| 11:07 | justin_smith | xemdetia: fascinating, I didn't realize |
| 11:07 | xemdetia | it lets customers cut costs if they don't want to use it |
| 11:08 | justin_smith | oh, the 1401 also had hardware level support for pounds / shillings / pence conversions |
| 11:08 | noncom | also, i remember that not so old story about ati radeon somewhat around the 9000 module, where you could get a more powerful videocard (next grade in fact) by just melting down some component on the circuit board |
| 11:08 | xemdetia | I believe there was a hardware xml parser that they had in one chipset but I forget the name of it. |
| 11:11 | noncom | also, we're coming back to modularization: https://en.wikipedia.org/wiki/Project_Ara and https://phonebloks.com/en |
| 11:11 | xemdetia | ah thats right, datapower |
| 11:12 | xemdetia | it wasn't in a chipset after all, my bad |
| 11:12 | justin_smith | noncom: do you think that those will really fly as cell phones? |
| 11:12 | justin_smith | xemdetia: it was believable. I mean we have hardware level codecs for mp3 / mp4 |
| 11:13 | justin_smith | and hardware level network routing |
| 11:13 | xemdetia | well I just went to a talk once from one of the people in the early networking hardware days and he said the next company was a part of was hardware/ASIC XML parsers |
| 11:13 | noncom | justin_smith: idk.. serious people are behind this.. and all this is backed by these popular trends to provide cheap hardware to poor countries and to improve the ecological sustainability |
| 11:13 | xemdetia | I just thought it got dropped into the power arch as a coprocessor I did not realize it was a standalone |
| 11:17 | noncom | justin_smith: and, btw, they're having a food tuck designed specifically to sell the phones :D |
| 11:17 | justin_smith | haha, of course |
| 11:18 | justin_smith | throw in bicycles somehow, and you may even sell two of them here in Portland |
| 11:18 | noncom | yeah :) |
| 11:25 | gfredericks | bicycles stapled to phones |
| 11:27 | justin_smith | gfredericks: noncom: see what you do is you take two unicycles and you add grommets so that they both attach to a cellphone et voila! bicycle |
| 11:28 | noncom | phonecycle |
| 11:28 | noncom | google phonecycle to be precise |
| 11:28 | justin_smith | that's too believable |
| 11:28 | noncom | i just want to be able to run clojure on it |
| 11:29 | noncom | so that i can program while biking |
| 11:29 | noncom | for long distances |
| 11:39 | noncom | ,(ns-map) |
| 11:39 | clojurebot | #error{:cause "Wrong number of args (0) passed to: core/ns-map", :via [{:type clojure.lang.ArityException, :message "Wrong number of args (0) passed to: core/ns-map", :at [clojure.lang.AFn throwArity "AFn.java" 429]}], :trace [[clojure.lang.AFn throwArity "AFn.java" 429] [clojure.lang.AFn invoke "AFn.java" 28] [sandbox$eval180 invoke "NO_SOURCE_FILE" -1] [clojure.lang.Compiler eval "Compiler.java"... |
| 11:40 | noncom | ,*ns* |
| 11:40 | clojurebot | #object[clojure.lang.Namespace "sandbox"] |
| 11:40 | noncom | ,(ns-map *ns*) |
| 11:40 | clojurebot | {primitives-classnames #'clojure.core/primitives-classnames, +' #'clojure.core/+', Enum java.lang.Enum, decimal? #'clojure.core/decimal?, restart-agent #'clojure.core/restart-agent, ...} |
| 11:40 | noncom | ,(ns-refers *ns*) |
| 11:40 | clojurebot | {primitives-classnames #'clojure.core/primitives-classnames, +' #'clojure.core/+', decimal? #'clojure.core/decimal?, restart-agent #'clojure.core/restart-agent, sort-by #'clojure.core/sort-by, ...} |
| 11:40 | noncom | ,(ns-aliases *ns*) |
| 11:40 | clojurebot | {} |
| 11:40 | noncom | ,(count (ns-refers *ns*)) |
| 11:40 | clojurebot | 629 |
| 11:40 | noncom | ,(count (ns-map *ns*)) |
| 11:40 | clojurebot | 726 |
| 11:41 | justin_smith | ,(require '[clojure.string :as str]) |
| 11:41 | clojurebot | nil |
| 11:41 | noncom | ooooooooops! sorry |
| 11:41 | justin_smith | ,(ns-aliases *ns*) |
| 11:41 | clojurebot | {str #object[clojure.lang.Namespace "clojure.string"]} |
| 11:41 | noncom | i thought i am in a private chat with clojure bot :D |
| 11:41 | justin_smith | haha |
| 11:41 | justin_smith | at least you didn't do anything embarrassing |
| 11:41 | noncom | :) |
| 11:42 | noncom | thank you, yes :) |
| 11:44 | noncom | justin_smith: can i make clojurebot to print on several lines? |
| 11:44 | noncom | ,(mapv #(println "whoa! " %) [1000 3000 6000]) |
| 11:44 | clojurebot | whoa! 1000\nwhoa! 3000\nwhoa! 6000\n[nil nil nil] |
| 11:44 | justin_smith | noncom: nope, neither of the bots can do that |
| 11:45 | noncom | i guess it uses conch which just returns the str of the output streams.. |
| 11:46 | noncom | and threads/futures are not allowed to space the execution in time.. |
| 11:46 | programisto | i don't use a ton of java or clojure, so i'm unsure where to start....i'd like to slowly append to a string over several iterations and then finally return a string or write to a file, is there a preferred way to do that? |
| 11:47 | programisto | i know java has a number of buffer classes |
| 11:47 | noncom | programisto: ummm either just add to the string or use java StringBuffer |
| 11:48 | noncom | the second variant is preferable is more efficient, although requries more characters of code |
| 11:48 | programisto | ok |
| 11:48 | justin_smith | programisto: iterations of what? |
| 11:48 | programisto | walking a tree, appending to the string based upon nodes |
| 11:48 | justin_smith | a single loop? successive calls to a function? |
| 11:49 | justin_smith | sorry, I hit return just after I saw your answer |
| 11:49 | nullptr | clojure.string/join https://github.com/clojure/clojure/blob/d7175e84e27816ee227220023a5411386d6aa32e/src/clj/clojure/string.clj#L178 |
| 11:50 | myguidingstar | hi all, what are the equivalent of those in Clojurescript? clojure.lang.IPersistentList clojure.lang.ISeq clojure.lang.IMapEntry and clojure.lang.IPersistentCollection |
| 11:50 | programisto | io just realizEd atoms can hold strings |
| 11:51 | programisto | pretty simple, then |
| 11:51 | programisto | thanks all |
| 11:52 | justin_smith | programisto: but you don't need an atom for this |
| 11:52 | nullptr | in cljs you can use goog.string.StringBuffer |
| 11:54 | programisto | noncom: okay, so it lools like the "proper" and easy solution is to just use a stringbuffer |
| 11:54 | programisto | well, maybe not, but that's what i'm going with |
| 11:54 | programisto | thansk :) |
| 11:57 | justin_smith | StringBuilder maybe? |
| 11:58 | programisto | justin_smith: you are right, didn't realize they were same api |
| 11:59 | justin_smith | programisto: is this clj or cljs? |
| 11:59 | programisto | justin_smith: regular clj |
| 12:00 | justin_smith | yeah, StringBuilder would be the way to do it then |
| 12:00 | programisto | awesome, i appreciate you taking the time to help so much |
| 12:14 | acron^ | What would be the best way to implement something like a routing macro, in terms of updating some global lookup ? |
| 12:14 | noncom | acron^: a little vague query.. could you add more detail? |
| 12:15 | acron^ | Yeah sure, I just want to create a routing table like for any normal web service (add-route "/foo", (fn [..] ...)) |
| 12:16 | acron^ | Lets say I have a (def routes []) hanging around |
| 12:16 | acron^ | What's the best way to handle this inside my add-route macro? |
| 12:16 | acron^ | AFAIK, I can't "alter" 'routes' because it's immutable |
| 12:17 | justin_smith | acron^: this really depends on what routing lib you are using. |
| 12:17 | acron^ | I'm not using one |
| 12:17 | acron^ | this is about how I would create one |
| 12:17 | justin_smith | then it depends on how you implement your routing |
| 12:17 | justin_smith | I would forget the "macro" part for now. Implement the functionality. Macros are for syntax, not functionality. |
| 12:18 | acron^ | Ok |
| 12:18 | acron^ | Message comes in, I parse the route |
| 12:18 | justin_smith | the annoying thing about using a global for routing, is that it means an end user can't have subsites that each do their own routing in one app |
| 12:18 | acron^ | I want to pass it to a dedicated function |
| 12:18 | justin_smith | sure |
| 12:19 | acron^ | Without a switch, obviously |
| 12:19 | justin_smith | obviously? there are a lot of ways to do routing. A trie for example. |
| 12:19 | acron^ | So it's just a string compare lets say, 1 to 1 |
| 12:20 | acron^ | "foo" => foo-func, "bar" => some-other-func |
| 12:20 | acron^ | My routes are trivially always defined as a single string |
| 12:24 | acron^ | Is the answer not to use state at all and just pass around the routing table? |
| 12:25 | justin_smith | acron^: the more typical thing is to construct the routing function, then wrap that with your middleware, and hand that to the server process as the handler |
| 12:25 | justin_smith | acron^: one thing that is useful is if you have a pure data representation of the routes, that can be converted into a routing function |
| 12:25 | acron^ | My problem is just an idiomatic one I think |
| 12:25 | justin_smith | then if you want to add or modify routes, you modify the data structure, then you regenerate the routing function |
| 12:26 | acron^ | Yeah, okay |
| 12:26 | justin_smith | so it's like a compiler - it takes a structure of routes and functions to call for those routes, and compile that into a function that takes a request and calls the endpoint |
| 12:27 | justin_smith | which means you stay flexible (it can be edited and regenerated) while also staying simple (you don't have to worry about modifying a running function) |
| 12:49 | m1dnight_ | Hi guys. Could somebody help me with figuring out the equivalent of (this.isInterrupted()) in clojure? |
| 12:49 | m1dnight_ | I tried the thread-stopper as an alternative, but it's not found in my repl |
| 12:51 | m1dnight_ | aha, found it! |
| 12:51 | m1dnight_ | (Thread/interrupted) |
| 12:51 | m1dnight_ | problem solved :> |
| 12:54 | justin_smith | isInterrupted surely? |
| 12:54 | m1dnight_ | nope, interrupted |
| 12:54 | justin_smith | ,(Thread/interrupted) |
| 12:54 | m1dnight_ | I thought so at first too, but it's interrupted |
| 12:54 | clojurebot | false |
| 12:54 | justin_smith | ahh |
| 12:54 | m1dnight_ | ,(Thread/isInterrupted) |
| 12:54 | clojurebot | #error{:cause "isInterrupted", :via [{:type clojure.lang.Compiler$CompilerException, :message "java.lang.NoSuchFieldException: isInterrupted, compiling:(NO_SOURCE_PATH:0:0)", :at [clojure.lang.Compiler analyzeSeq "Compiler.java" 6732]} {:type java.lang.NoSuchFieldException, :message "isInterrupted", :at [java.lang.Class getField "Class.java" 1584]}], :trace [[java.lang.Class getField "Class.java" ... |
| 12:55 | justin_smith | ,(.isInterrupted (Thread/currentThread)) |
| 12:55 | clojurebot | false |
| 12:55 | m1dnight_ | oh, you have currentThread |
| 12:55 | justin_smith | that's the more verbose alternative ^ |
| 12:55 | m1dnight_ | that wsa another solution |
| 12:55 | justin_smith | yeah |
| 12:55 | m1dnight_ | I was looking for how to get a reference to this, but couldnt find it |
| 12:55 | justin_smith | is that a static method or a field? |
| 12:55 | m1dnight_ | found Thread/interrupted in a book |
| 12:55 | m1dnight_ | isInterrupted is a field iirc |
| 12:55 | justin_smith | ,Thread/interrupted |
| 12:55 | clojurebot | #error{:cause "Unable to find static field: interrupted in class java.lang.Thread", :via [{:type clojure.lang.Compiler$CompilerException, :message "java.lang.RuntimeException: Unable to find static field: interrupted in class java.lang.Thread, compiling:(NO_SOURCE_PATH:0:0)", :at [clojure.lang.Compiler analyze "Compiler.java" 6535]} {:type java.lang.RuntimeException, :message "Unable to find stati... |
| 12:55 | justin_smith | not a field |
| 13:01 | gfredericks | ,(Thread/interrupted) |
| 13:01 | clojurebot | false |
| 13:01 | gfredericks | it's a static method |
| 13:27 | ToxicFrog | So, a friend of mine just ran into an interesting issue with the clojure compiler |
| 13:28 | ToxicFrog | He calls into a Java library that includes a static initializer that instantiates a class that spawns a thread that does some stuff in the background |
| 13:28 | justin_smith | ToxicFrog: there is something in 1.7 if this is the issue I am thinking of |
| 13:28 | ToxicFrog | This happens when he compiles the code, since the compiler loads the class file to check static method resolution (at least, I think this is what happens) |
| 13:29 | ToxicFrog | So at, say, lein uberjar time, he gets log messages from this library starting up, and then it never exits because the library's background thread is waiting for a shutdown message that never comes. |
| 13:29 | justin_smith | ToxicFrog: yeah, that's the issue |
| 13:29 | ToxicFrog | This is fixed in 1.7? |
| 13:31 | justin_smith | ToxicFrog: yeah, there are changes to address this behavior (switching .forName to .forNameNonLoading in relevant places) |
| 13:31 | ToxicFrog | justin_smith: awesome! Do you know what I should search for if I'm looking for bug tracker/changelog entries related to this? |
| 13:31 | justin_smith | ToxicFrog: I am looking for that right now |
| 13:32 | ToxicFrog | Thankyou :) |
| 13:32 | justin_smith | ToxicFrog: http://dev.clojure.org/jira/browse/CLJ-1315 |
| 13:33 | justin_smith | ToxicFrog: shown as closed and fixed in 1.7 |
| 13:33 | ToxicFrog | Thanks. |
| 14:03 | broma0 | Anyone use Riak with clojure? Experiences? I'm thinking of using it in a project |
| 14:22 | justin_smith | so how long until maven can use project.clj directly? http://www.infoq.com/news/2015/03/maven-polyglot?utm_source=reddit&utm_medium=link&utm_campaign=maven%20polyglot |
| 14:26 | atyz | So what happens when you do something like (map (partial some-function some-argument) some-collection). Does it create that partial function on every element? |
| 14:27 | justin_smith | atyz: no, the function is only created once |
| 14:28 | atyz | justin_smith: Thank you. Does it incur more overhead than (map #(some-function some-argument %) some-collection)? |
| 14:29 | justin_smith | atyz: #() creates something that runs faster, but it also generates a new class |
| 14:29 | justin_smith | partial creates something slightly slower (because it is always varargs) but doesn't create a new class |
| 14:29 | Bronsa | well faster for >3 elements :) |
| 14:29 | Bronsa | justin_smith: it's unrolled |
| 14:29 | atyz | so in some instances its better to use one or the other, but mostly its negligable? |
| 14:29 | justin_smith | Bronsa: partial is? |
| 14:29 | justin_smith | OK |
| 14:30 | atyz | Thank you Bronsa justin_smith |
| 14:30 | turbofail | eh? `partial' itself is unrolled, but doesn't the function that partial returns use varargs every time? |
| 14:31 | Bronsa | no |
| 14:31 | Bronsa | that's unrolled too |
| 14:31 | turbofail | hm, perhaps i'm looking at an older version then |
| 14:31 | Bronsa | well, partial actually isn't vararg at all |
| 14:32 | Bronsa | ,(partial + 1 2 3 4 5) |
| 14:32 | clojurebot | #object[clojure.core$partial$fn__4484 "clojure.core$partial$fn__4484@21e2f47b"] |
| 14:32 | Bronsa | nevermind I'm blind |
| 14:33 | hiredman | #ugg |
| 14:33 | turbofail | ah yeah later versions of partial do in fact return multi-arity functions |
| 14:34 | Bronsa | ah yeah, looks like it's a 1.7 enhancement, thought it had always been the case |
| 14:34 | Bronsa | http://dev.clojure.org/jira/browse/CLJ-1430 |
| 14:35 | justin_smith | that makes me feel a little better about being ignorant of that |
| 14:39 | numberten | anyone know why test.check documentation requires [clojure.test.check :as tc] when it isn't used? |
| 14:39 | numberten | i've also found that removing it breaks the tests.. so was kinda curious why it appears to be necessary |
| 14:40 | justin_smith | my first suspicion is ill behaved macros |
| 14:41 | reiddraper | numberten: which tests? |
| 14:41 | numberten | tests that I wrote using test.check |
| 14:42 | numberten | i get a ClassNotFoundException when i remove that requirement |
| 14:42 | numberten | i think it's probably macros, i'll take a look at the functions I call |
| 14:43 | justin_smith | numberten: so do you import some class that test.check generates? because yeah, removing a require will make it so the class doesn't get generated |
| 14:43 | numberten | https://github.com/clojure/test.check/blob/master/src/main/clojure/clojure/test/check/clojure_test.clj#L33 |
| 14:43 | numberten | I think that's it? |
| 14:44 | Bronsa | https://github.com/clojure/test.check/blob/master/src/main/clojure/clojure/test/check/clojure_test.clj#L57 |
| 14:44 | justin_smith | numberten: it generates a call to assert-check, which uses ct/is |
| 14:45 | Bronsa | this might why it doesn't work if test.check isn't loaded then |
| 14:45 | justin_smith | oh, that would do it to, yeah |
| 14:46 | justin_smith | it's odd that it is spelling out the namespace though, inside a ` block |
| 14:46 | amalloy | justin_smith: it doesn't require test.check |
| 14:46 | amalloy | so ` would qualify it incorrectly |
| 14:47 | amalloy | what's odd to me is that it doesn't require test.check |
| 14:47 | amalloy | but i see, it does the require at runtime |
| 14:47 | justin_smith | oh wait, yeah, that is weird |
| 14:47 | justin_smith | I had misread the clojure.test requirement above, oops |
| 14:54 | BinaryResult | Hi all, DiscoMelee.com is hiring clojure devs. http://www.reddit.com/r/Clojure/comments/301coc/disco_melee_is_hiring_clojure_developers/ |
| 14:57 | gfredericks | amalloy: it's a cyclic dependency problem |
| 14:57 | gfredericks | there's a comment in the file about it |
| 14:59 | gfredericks | numberten: so you're saying if you're just using clojure.test.check.clojure-test, your tests break when you don't require clojure.test.check? |
| 14:59 | gfredericks | this sounds plausible just from looking at the code; it's surprising I haven't heard of this before |
| 14:59 | amalloy | gfredericks: i see, thanks |
| 15:00 | gfredericks | the cyclic dependency thing was just considered an aesthetic problem till now, but since it seems to be reaching into userland I'd call it a bug worth fixing |
| 15:00 | dysfun | is there anything for screenscraping that sort of works like a template language? build a template and reverse engineer the data out of it? |
| 15:01 | justin_smith | dysfun: enlive is good for both scraping and generating html |
| 15:01 | justin_smith | dunno about general screen scraping though |
| 15:01 | dysfun | ta, i'll have a look |
| 15:01 | reiddraper | gfredericks: agree its a bug, if that's the case |
| 15:02 | gfredericks | reiddraper: I'm gonna upsert a ticket |
| 15:02 | dysfun | justin_smith: it just occurred to me that the two operations are pretty similar |
| 15:02 | reiddraper | gfredericks: thanks |
| 15:03 | justin_smith | dysfun: yeah, I have had great luck getting content via enlive, and it also does templating / programmatic transforms |
| 15:03 | gfredericks | reiddraper: any objections to fixing by adding more options to quick-check for reporting? |
| 15:03 | dysfun | and yet all the screenscraping libraries i've used either don't parse properly or expect you to pick out a tree via selectors |
| 15:03 | gfredericks | rather than quickcheck calling the .clojure-test functions directly |
| 15:03 | justin_smith | dysfun: enlive even has a thing where you can give it an html file to create a templating data structure out of |
| 15:04 | dysfun | that sounds really very shiny indeed |
| 15:04 | reiddraper | gfredericks: no objection |
| 15:04 | dysfun | (inc cgrand) |
| 15:04 | lazybot | ⇒ 1 |
| 15:06 | mavbozo | justin_smith: what enlive parser do you use most for screenscraping? tagsoup or jsoup? |
| 15:06 | gfredericks | looks like TCHECK-33 to me |
| 15:06 | gfredericks | I'll work on that later today |
| 15:06 | justin_smith | mavbozo: I just let it use its default |
| 15:06 | justin_smith | I do nothing super fancy |
| 15:06 | gfredericks | numberten: ^ |
| 15:07 | numberten | hm? |
| 15:07 | numberten | ah cool |
| 15:47 | pandeiro | can ragtime be used to migrate multiple different databases with one single migrations directory, or should there be a single migrations set per database? |
| 15:54 | catern | oh god why is using clojure so painful |
| 15:54 | catern | my .lein/profiles.clj looks like: |
| 15:55 | mavbozo | pandeiro: I use different directory for each database |
| 15:55 | catern | {:user {:plugins [[cider/cider-nrepl "0.9.0-SNAPSHOT"]] |
| 15:55 | catern | :dependencies [[org.clojure/tools.nrepl "0.2.7"]]}} |
| 15:55 | catern | and yet when I run lein repl |
| 15:55 | catern | I get |
| 15:55 | pandeiro | mavbozo: thanks; do you include the creation of database/role in the migrations? |
| 15:55 | pandeiro | catern: put tools.nrepl in :dev dependencies |
| 15:56 | catern | http://sprunge.us/JcbZ |
| 15:56 | catern | why |
| 15:56 | catern | why why why |
| 15:56 | mavbozo | pandeiro: no, there is a init script I put outside the migrations dir |
| 15:56 | catern | (why regarding my nrepl output) |
| 15:57 | pandeiro | catern: dunno, you're worried about the indentation there? |
| 15:57 | pandeiro | or the fact it's using 0.2.6 instead of 0.2.7? |
| 15:57 | mavbozo | pandeiro: it helps if i want to rebase. |
| 15:57 | catern | pandeiro: the second one |
| 15:57 | pandeiro | mavbozo: thanks a lot |
| 15:57 | catern | pandeiro: likewise when I use cider-jack-in it uses 0.2.6 for some reason |
| 15:57 | pandeiro | catern: i guess :dev gets merged in 'on top of' (my technical term) the regular project deps |
| 15:58 | pandeiro | catern: same issue |
| 15:58 | amalloy | lein probably inserts its own nrepl version into your project |
| 15:58 | amalloy | or something like that |
| 15:58 | catern | I'm not even in a project right now |
| 15:58 | gfredericks | lein is supposed to check for existing one though |
| 15:58 | pandeiro | what amalloy said |
| 15:58 | catern | I'm just running lein repl in a random directory |
| 15:58 | gfredericks | I've been using a profile like that for a while and I thought it was working |
| 15:58 | gfredericks | catern: what happens if you run it in an actual project? |
| 15:58 | gfredericks | I think lein-without-a-project can have weird degradations like this |
| 15:59 | catern | :( |
| 15:59 | catern | now it uses 0.2.7 |
| 15:59 | catern | but this is dumb |
| 15:59 | catern | I just have a single .clj file that I want to do use with CIDER |
| 15:59 | catern | for a few calculations |
| 15:59 | catern | gfredericks: er, ^ |
| 16:00 | catern | It used 0.2.7 when I ran it in a project |
| 16:00 | gfredericks | hyPiRion might know how to wrangle lein-without-a-project |
| 16:01 | catern | why is this complicated? why is this different from normal lein usage? why doesn't it refuse to run if it is obviously broken? |
| 16:02 | gfredericks | catern: digging into the leiningen code to try to solve the problem would be an instructive way to get answers to those questions |
| 16:04 | catern | :( |
| 16:05 | catern | can I just like, delete 0.2.7 |
| 16:05 | catern | er, 0.2.6 |
| 16:05 | catern | from somewhere |
| 16:05 | catern | to force it to use 0.2.7 |
| 16:05 | catern | except I already did this, deleting it from .m2 |
| 16:05 | catern | and it had no effect |
| 16:05 | gfredericks | well I should hope not |
| 16:06 | gfredericks | it'd be bad if the dependencies you got were sensitive to what was in your cache |
| 16:06 | catern | but 0.2.6 doesn't appear to actually exist anywhere |
| 16:06 | catern | and it isn't downloading it again |
| 16:06 | gfredericks | it's hard-coded into lein |
| 16:06 | catern | D: |
| 16:07 | gfredericks | you're saying it doesn't get downloaded into .m2 again? |
| 16:07 | catern | correct |
| 16:07 | gfredericks | but it runs with 0.2.6 anyhow? |
| 16:07 | catern | yes |
| 16:08 | catern | or at least claims to |
| 16:09 | gfredericks | https://github.com/technomancy/leiningen/blob/master/leiningen-core/src/leiningen/core/project.clj#L484 |
| 16:09 | gfredericks | is where it is hard-coded |
| 16:09 | gfredericks | but anyhow the part about it not coming back to .m2 is a lot harder to believe |
| 16:09 | gfredericks | gonna try it myself |
| 16:10 | catern | specifically I deleted /home/catern/.m2/repository/org/clojure/tools.nrepl/0.2.6 |
| 16:11 | catern | and it hasn't come back |
| 16:11 | gfredericks | yep mine redownloaded |
| 16:11 | gfredericks | that's what I deleted too |
| 16:12 | gfredericks | so that's super weird but maybe not your original problem |
| 16:12 | kaplan | What dies reify dio? |
| 16:12 | kaplan | *do |
| 16:13 | gfredericks | creates an anonymous type that implements some interfaces and/or protocols |
| 16:14 | amalloy | gfredericks: an instance of an anonymous type |
| 16:14 | gfredericks | depends on how you're thinking about it |
| 16:14 | gfredericks | at compile time it creates a type :P |
| 16:15 | kaplan | Can anyone walk me through the example code here? https://github.com/omcljs/om |
| 16:16 | patrickgombert | kaplan: what in particular? it might be best to start with https://github.com/omcljs/om/wiki/Conceptual-overview |
| 16:17 | catern | so I have this code: http://ix.io/h3J |
| 16:17 | catern | does it have any obvious performance problems or infinite loops? |
| 16:17 | catern | (sim) is taking a while to terminate... |
| 16:18 | catern | (sometimes) |
| 16:18 | catern | (sometimes it finishes quite quickly) |
| 16:18 | amalloy | catern: that looks like it should take a long time. getting down to 0 will take a long time with those betting odds |
| 16:18 | catern | amalloy: only 100 bets or so... |
| 16:19 | catern | or 1000 |
| 16:19 | catern | still |
| 16:19 | kaplan | ok patrickgombert , thanks |
| 16:19 | catern | 1000 is not a lot |
| 16:19 | catern | a 1000 invocations of a trivial function... come on clojure, don't tell me you're that slow! |
| 16:21 | amalloy | catern: on average you lose, what, 1/37th of $15? 0.5ish? so the average number of bets is indeed not very many, like 600 or so, but you can easily get lucky and go a lot longer |
| 16:25 | amalloy | catern: i think it actually takes quite a bit longer than that |
| 16:25 | amalloy | i just tried starting with $90 instead of $300, and the first four calls to (count (sim)) returned: (542 26 1190) |
| 16:26 | amalloy | so the mean is low but the variance is very high |
| 16:28 | amalloy | anyway, tldr your problem is with math, not with clojure |
| 16:30 | catern | amalloy: uhhhhhh |
| 16:31 | catern | oh! |
| 16:31 | catern | whoops! |
| 16:31 | catern | I think I have the conditional the wrong way around :) |
| 16:32 | catern | thanks amalloy |
| 16:32 | catern | incidentally |
| 16:32 | catern | I'm kind of curious |
| 16:33 | catern | what other languages have standard functions like "iterate" or "take-while"? |
| 16:33 | amalloy | haskell. probably python in its iter-whatever package |
| 16:33 | raek | Haskell, Scala, O'Caml? |
| 16:33 | sdegutis | Oh hi raek |
| 16:34 | raek | sdegutis: hi. |
| 16:34 | sdegutis | catern: my favorite of these three are so far is Haskell fwiw |
| 16:34 | catern | oh |
| 16:34 | catern | huh |
| 16:34 | catern | okay |
| 16:35 | catern | neat |
| 16:37 | raek | and all those languages borrowed their standard libraries from ML... :-) |
| 16:37 | catern | another question, is there some function that's equivalent to what I'm doing in: (map #(do % (sim)) (range 10)) |
| 16:38 | catern | or just a better way to do it? |
| 16:41 | aperiodic | (take 10 (repeatedly sim)) |
| 16:41 | catern | aperiodic: beautiful |
| 16:41 | aperiodic | though that may not be exactly equivalent due to lazy seq chunking |
| 16:43 | raek | (dotimes [_ 10] (sim)) |
| 16:43 | aaelony | I like the idea of yesql, but I need it to output the final query string to make sure it is parameterized correctly and also defer execution. Does anyone know if this is possible? |
| 16:43 | raek | catern: ^ |
| 16:44 | catern | raek: ah, hm |
| 16:44 | raek | I assume sim is run for its side-effects. as aperiodic hinted, you will get unpredictable behavior if you mix side-effects and lazy sequences |
| 16:44 | amalloy | raek: catern is trying to get the actual results from sim |
| 16:44 | catern | isn't there something like "tabulate" |
| 16:44 | raek | oh, right. |
| 16:44 | catern | raek: no, sim is pure |
| 16:45 | aperiodic | it's not pure |
| 16:45 | catern | well |
| 16:45 | catern | modulo grabbing random numbers :) |
| 16:46 | aperiodic | the take & repeatedly version just may end up doing extra work that's never used |
| 16:46 | catern | so, is there not something like (tabulate f n) which generates a sequence of length n, running f on the indices? |
| 16:46 | catern | (you'd just do that with map I assume?) |
| 16:47 | aperiodic | map-indexed |
| 16:48 | aaelony | ok nevermind, I'll just slurp and replace to fit my use case... |
| 16:49 | aperiodic | catern: not exactly what you want. seems like tabulate is just (map f (range n)) |
| 16:50 | catern | aperiodic: yes |
| 16:50 | catern | that's why I say, just use map |
| 16:51 | aperiodic | yup |
| 16:55 | catern | okay |
| 16:55 | catern | I have another elegance question |
| 16:56 | catern | (def sims (take numsims (repeatedly sim))) |
| 16:56 | catern | (def num_temporarily_rich (count (filter pos? (map (fn [sim] (count (filter #(> % 1000) sim))) sims)))) |
| 16:56 | catern | ;; this finds the number of simulations where at some point the balance is over 1000 |
| 16:56 | catern | could I make this nicer? |
| 16:57 | catern | (it's already so much nicer than in an imperative language, lol) |
| 16:57 | bensu | catern: you could use ->> |
| 16:58 | amalloy | catern: (repeatedly num-sims sim) |
| 16:58 | catern | amalloy: :D |
| 17:00 | amalloy | also, checking whether the count of a coll is positive is really gross. just check whether it has at least one element, with seq |
| 17:01 | catern | amalloy: hm? how? |
| 17:01 | catern | oh |
| 17:01 | catern | filter seq? |
| 17:01 | catern | wow, that's hacky :D |
| 17:01 | amalloy | "hacky" |
| 17:01 | catern | couldn't I just use identity rather than seq? |
| 17:01 | bensu | catern: or remove empty? |
| 17:02 | Glenjamin | (doc keep) |
| 17:02 | clojurebot | "([f] [f coll]); Returns a lazy sequence of the non-nil results of (f item). Note, this means false return values will be included. f must be free of side-effects. Returns a transducer when no collection is provided." |
| 17:02 | Glenjamin | hrm, is there a filter-by in core? |
| 17:03 | Glenjamin | i guess that's just done with (for) |
| 17:03 | catern | okay, it now looks like: |
| 17:03 | catern | (def num_temporarily_rich (->> sims (map (fn [sim] (filter #(> % 1000) sim))) (remove empty) count)) |
| 17:03 | catern | ; |
| 17:03 | Glenjamin | (for [s sims |
| 17:03 | catern | (yuck, for) |
| 17:04 | catern | is there a way to clean up that (map (fn [sim] ...? |
| 17:04 | amalloy | uhhhhhhhhhhhhh, (remove empty xs) should be a no-op |
| 17:04 | amalloy | or rather, it should produce () every time |
| 17:04 | Glenjamin | wait, sim is a number? |
| 17:04 | catern | Glenjamin: sim is a seq of numbers |
| 17:05 | Glenjamin | so it's just (->> sims (filter #(> % 100)) count) then? |
| 17:05 | Glenjamin | oh right, sorry |
| 17:05 | Glenjamin | sims is a seq of sim, and sim is a seq of numbers |
| 17:05 | catern | amalloy: ah, true, replacing that with (filter seq) like you said) |
| 17:06 | bensu | catern: I meant empty? not empty. |
| 17:06 | catern | now replacing that* |
| 17:06 | catern | bensu: oh, derp |
| 17:07 | catern | hmm |
| 17:07 | catern | battle it out |
| 17:07 | catern | which is better, (filter seq) or (remove empty?) :D |
| 17:07 | catern | I can tell from the docstring for empty? that this is a point of debate |
| 17:07 | bensu | catern: I'm not in for a battle! I just like it when my filter predicate clearly returns a bool |
| 17:08 | catern | bensu: I tend to agree :) |
| 17:08 | bensu | catern: without in mind you could also say (filter seq?) |
| 17:08 | bensu | catern: *with that in mind |
| 17:08 | amalloy | bensu: that is a really bad plan |
| 17:09 | bensu | amalloy: why? |
| 17:09 | amalloy | seq? is very different from seq |
| 17:09 | amalloy | you can't use it to test whether a collection is empty, which is what catern is trying tod |
| 17:10 | bensu | amalloy: ahh yes, just found this: ;; (seq x) is the recommended idiom for testing if a collection is not empty |
| 17:11 | bensu | amalloy catern: my 0.02 are then (remove empty?) |
| 17:14 | crazydiamond | Hi. Is there function to make alphabetical sorting of vector of strings by some custom alphabet? |
| 17:15 | kwladyka | hi, i am reading a book about Clojure and read some coursers in the Internet. But i choose bad book, because it is describing functions in really dry way. I need do some coursers which learn me how to thing, when use lists, when vectors, how to solve real problems. For now there is so many possibility for me in Clojure, i don't know how to do things in this language. |
| 17:15 | kwladyka | Can you recommend me some coursers which learn me how to think in Clojure and how to solve problems? |
| 17:15 | kwladyka | Not describe functions |
| 17:16 | Bronsa | crazydiamond: look at sort-by |
| 17:17 | crazydiamond | Bronsa, I'm trying to use it, but I rather need correct version of keyfn |
| 17:17 | {blake} | kwladyka: I can't really recommend the stuff I read for that. I've mostly found it more useful to do things in Clojure, then go back to the various books/docs. |
| 17:18 | {blake} | kwladyka: However, I haven't tried tbaldridge's videos yet, and they may be the ticket. |
| 17:19 | Glenjamin | ,(->> sims (filter (partial some #(> % 1000))) count) ; catern - how about this |
| 17:19 | clojurebot | 2 |
| 17:19 | mavbozo | kwladyka: the closest book I could find is How to Design Program book htdp.org |
| 17:19 | mavbozo | kwladyka: it uses racket lang which is quite similar to clojure, esp the immutability |
| 17:20 | mavbozo | kwladyka: there's a mooc that uses that book too https://www.coursera.org/course/programdesign |
| 17:40 | kwladyka | thx for info :) |
| 18:01 | crazydiamond | Hi. In Datomic, can I sort using custom key-function? |
| 18:10 | kludgecode_ | Basic question: I have a bunch of maps. I want to dump them into a data structure sorted data structure with heap semantics. I could not find a heap implementation for Clojure. Suggestions? |
| 18:12 | justin_smith | kludgecode: like a sorted-set or sorted-map or something? |
| 18:13 | justin_smith | kludgecode: actually, can you describe what you mean by "heap semantics"? do you just mean associative lookup? |
| 18:13 | kludgecode | justin_smith: I don't need map or set semantics. |
| 18:15 | turbofail | there's always java.util.PriorityQueue |
| 18:15 | kludgecode | justin_smith: By "heap semantics" I mean :1: data structure maintains sort order on addition of new items. :2: "popping" or "first"ing produces the first value in sorted order. |
| 18:17 | kludgecode | turbofail: does that put me into the world of mutation and should I really go there if it does? |
| 18:17 | turbofail | it's very much in the world of mutation |
| 18:18 | turbofail | whether you should go there depends on how you're going to use it |
| 18:19 | kludgecode | turbofail: I am very new, so forgive me. Can I just throw ordinary Clojure maps into it without great risk of obscure Java errors? |
| 18:19 | turbofail | yes, there'll be no problems there |
| 18:20 | turbofail | the only problems you'll get will be the usual set of mutable data structure caveats |
| 18:21 | kludgecode | turbofail: Can you point me to some example code, so that I have something to guide me through the interop ceremony? I haven't done any yet and was hoping to avoid it? |
| 18:21 | kludgecode | turbofail: the scope should probably be ok for mutation in this application. |
| 18:22 | gfredericks | kludgecode: I think clojure's sorted-set is all you want |
| 18:22 | gfredericks | or sorted-set-by, depending |
| 18:22 | justin_smith | gfredericks: he said he didn't want set semantics |
| 18:23 | gfredericks | or didn't "need" |
| 18:23 | turbofail | kludgecode: (let [q (java.util.PriorityQueue. 10 compare)] (doseq [i (repeatedly 10 #(rand-int 100))] (.add q i)) q) |
| 18:23 | turbofail | that's about all you need |
| 18:23 | gfredericks | throw some random IDs on them if you worry about duplicates |
| 18:24 | turbofail | er, missing a dot in there somewhere |
| 18:24 | turbofail | (let [q (java.util.PriorityQueue. 10 compare)] (doseq [i (range 100)] (.add q i))) |
| 18:24 | justin_smith | (inc gfredericks) |
| 18:24 | lazybot | ⇒ 126 |
| 18:24 | justin_smith | that's a great idea actually |
| 18:24 | turbofail | but yes in general i'd agree that a sorted set would work fine |
| 18:24 | kludgecode | gfredricks: How will `sorted-set` determine that two maps are identical? Will all fields need the same values? |
| 18:25 | justin_smith | kludgecode: yes, that is how equality is done for clojure data structures |
| 18:25 | justin_smith | kludgecode: which is why adding a random id to each element before insertion would fix the de-duping if you don't what it |
| 18:25 | gfredericks | ,(def my-heap (atom (sorted-set-by :priority))) |
| 18:25 | clojurebot | #error{:cause "clojure.lang.Keyword cannot be cast to java.util.Comparator", :via [{:type clojure.lang.Compiler$CompilerException, :message "java.lang.ClassCastException: clojure.lang.Keyword cannot be cast to java.util.Comparator, compiling:(NO_SOURCE_FILE:0:0)", :at [clojure.lang.Compiler$InvokeExpr eval "Compiler.java" 3622]} {:type java.lang.ClassCastException, :message "clojure.lang.Keyword c... |
| 18:25 | gfredericks | damn comparators |
| 18:25 | hiredman | you could also roll your own heap |
| 18:25 | gfredericks | like a boss |
| 18:25 | hiredman | http://typeocaml.com/2015/03/12/heap-leftist-tree/ |
| 18:26 | kludgecode | justin_smith: that's what I thought, but I hate to assume anything. |
| 18:26 | kludgecode | hiredman: I think you have mistaken me for someone else. |
| 18:27 | kludgecode | unless you're just being theoretical... |
| 18:27 | turbofail | eh. it's not that hard to implement |
| 18:27 | hiredman | no, I mean, it is a nice write up of a straight forward to implement persistent heap with examples in a straight forward functional language |
| 18:28 | gfredericks | ,(def my-heap (atom (sorted-set-by #(compare (:priority %1) (:priority %2))))) |
| 18:28 | clojurebot | #'sandbox/my-heap |
| 18:28 | gfredericks | ,(swap! my-heap conj {:data 12 :priority 3}) |
| 18:28 | clojurebot | #{{:data 12, :priority 3}} |
| 18:28 | gfredericks | ,(swap! my-heap conj {:data "eight" :priority 8}) |
| 18:28 | clojurebot | #{{:data 12, :priority 3} {:data "eight", :priority 8}} |
| 18:29 | gfredericks | ,(swap! my-heap conj {:data "taco" :priority 1}) |
| 18:29 | clojurebot | #{{:data "taco", :priority 1} {:data 12, :priority 3} {:data "eight", :priority 8}} |
| 18:29 | gfredericks | ,(first @my-heap) |
| 18:29 | clojurebot | {:data "taco", :priority 1} |
| 18:30 | kludgecode | gfredricks: Thanks. Using `atom` means that I only have one heap to worry about, right? |
| 18:30 | kludgecode | Yes, I am that new |
| 18:30 | kludgecode | Versus passing a new value recursively. |
| 18:31 | justin_smith | kludgecode: you should check out some of the official clojure docs http://clojure.org/documentation |
| 18:31 | justin_smith | for this specific question http://clojure.org/atoms |
| 18:32 | gfredericks | kludgecode: probably don't use an atom, I was just doing that to have some state in the replbot |
| 18:32 | justin_smith | kludgecode: passing a new value recursively will also end up using structural sharing as applicable (won't copy the whole data structure to do one add or remove typically) |
| 18:32 | kludgecode | justin_smith: RTFM'ing is how I got into this mess. I have a vague idea understanding of what they do. |
| 18:32 | gfredericks | kludgecode: atoms and sorted sets are orthogonal features; one is the data structure, the other is state management |
| 18:34 | justin_smith | kludgecode: in this specific case it answers your specific question in the first sentence of the page, and has a better intro than anyone here could give. |
| 18:35 | justin_smith | kludgecode: to be clear, I am not saying "read the docs instead of asking questions here", but sometimes a link to a doc gives a better answer |
| 18:35 | kludgecode | gfredricks: That's what I thought. The `heap`/`sorted-set` is managing my state. The analogy is prioritzing continuations in the language of the data. |
| 18:35 | justin_smith | kludgecode: no, a sorted-set is stateless in clojure, so an atom manages the state (or the updated binding via recursion etc.) |
| 18:36 | kludgecode | justin_smith: I understand. I was just trying to make sure I was on the right track when I saw `atom` in the example code. It surprised me. That's all. Thanks. |
| 18:36 | gfredericks | ,(def my-number (atom 42)) |
| 18:36 | clojurebot | #'sandbox/my-number |
| 18:36 | kludgecode | gfredricks: I understand. Thanks. |
| 18:36 | gfredericks | ,(swap! my-number * 12) |
| 18:36 | clojurebot | 504 |
| 18:36 | justin_smith | you could say the sorted set "is" your current state, and the atom manages changes in state (by replacing it with another sorted set) |
| 18:38 | kludgecode | justin_smith: So then I can just refer to the atom instead of building the set up manually each time around? |
| 18:39 | justin_smith | right, though an alternative is if you have some recursive function and you pass an updated version each time |
| 18:39 | justin_smith | typical fp techniques you know |
| 18:39 | gfredericks | atoms are a sort of functional impurity; we try to avoid them when feasible |
| 18:40 | kludgecode | gfredricks: that's why I've deprioritized learning them in detail. |
| 18:40 | gfredericks | they're handy for quick&dirty things |
| 18:42 | kludgecode | Thanks for all the help. I think I have enough to push the rock a bit further up the hill. |
| 18:50 | gfredericks | speaking of quick&dirty I think deffing something in a function is occasionally the easiest way to do something |
| 18:51 | justin_smith | gfredericks: or a top level let block with defs inside it |
| 18:51 | justin_smith | no, actually that is never convenient |
| 18:52 | gfredericks | I don't mean that I keep the code that way |
| 18:53 | justin_smith | gfredericks: but for fixing cyclic weirdness in namespaces then, that sort of thing? |
| 18:53 | gfredericks | no just for stashing an arg to a function so I can poke it at the repl |
| 18:53 | gfredericks | I throw (def foo foo) somewhere in there |
| 18:54 | gfredericks | and then run the code |
| 18:54 | gfredericks | and boom I have a global handle to it |
| 18:54 | gfredericks | you tell me a faster way of doing that and I'll repent |
| 18:54 | justin_smith | gfredericks: ahh, my version of that is (def debug (atom nil)) and then inside the function (swap! debug foo) |
| 18:54 | turbofail | yeah i usually use an atom for that |
| 18:54 | gfredericks | sounds slower to me :) |
| 18:55 | justin_smith | gfredericks: bonus, with the atom version, you can make it a vector, and conj values on - peek it to get the most recent, but you can also do things with the values it has had over time |
| 18:55 | gfredericks | oh totes |
| 18:55 | justin_smith | gfredericks: slower in dev time? it takes a few seconds maybe |
| 18:55 | gfredericks | yours is two steps |
| 18:55 | justin_smith | right, right |
| 18:56 | justin_smith | it also doesn't make me die of embarassment when coworkers see it |
| 18:56 | gfredericks | I only do it in private |
| 18:56 | jonathanj | if i have a map like {:key "the key" :value "the value"}, is there a concise way to turn that into {"the key" "the value"}? |
| 18:57 | gfredericks | (let [{:keys [key value]} m] {key value}) |
| 18:57 | amalloy | (map m [:key :value]) |
| 18:57 | justin_smith | ,(conj {} ((juxt [:key :value]) {:key "the key" :value "the value"})) |
| 18:57 | clojurebot | #error{:cause "Key must be integer", :via [{:type java.lang.IllegalArgumentException, :message "Key must be integer", :at [clojure.lang.APersistentVector invoke "APersistentVector.java" 284]}], :trace [[clojure.lang.APersistentVector invoke "APersistentVector.java" 284] [clojure.core$juxt$fn__4459 invoke "core.clj" 2454] [sandbox$eval25 invoke "NO_SOURCE_FILE" 0] [clojure.lang.Compiler eval "Compi... |
| 18:58 | justin_smith | err |
| 18:58 | justin_smith | ,(conj {} ((juxt :key :value) {:key "the key" :value "the value"})) |
| 18:58 | clojurebot | {"the key" "the value"} |
| 18:58 | amalloy | oh, you want it to be a map too. so i guess (apply hash-map (map m [:key :value])) |
| 18:58 | jonathanj | what is allowed to be a key of a map? |
| 18:58 | amalloy | anything |
| 18:58 | justin_smith | jonathanj: things |
| 18:59 | jonathanj | byte[]? |
| 18:59 | turbofail | preferably immutable things |
| 18:59 | turbofail | but they don't have to be |
| 18:59 | amalloy | if you do it with mutable things, or things with bad hashcodes, you will probably be sad, but it is allowed |
| 18:59 | justin_smith | anything but a primitive, and yeah, better if it is immutable |
| 19:02 | jonathanj | hmm |
| 19:02 | jonathanj | so i actually have a list of maps with that structure |
| 19:03 | jonathanj | [{:key "a" :value "1"} {:key "b" :value "2"}] => {"a" "1" "b" "2"} |
| 19:03 | justin_smith | ,(apply conj {} (map (juxt :key :value) [{:key "the key" :value "the value"} {:key :a :value :b}])) |
| 19:03 | clojurebot | {"the key" "the value", :a :b} |
| 19:04 | jonathanj | hmm |
| 19:04 | justin_smith | better ##(into {} (map (juxt :key :value) [{:key "the key" :value "the value"} {:key :a :value :b}])) |
| 19:04 | lazybot | ⇒ {"the key" "the value", :a :b} |
| 19:07 | jonathanj | ah yes, i was wondering how to get rid of `apply conj {}` |
| 19:07 | jonathanj | thanks |
| 19:07 | turbofail | using a byte array as a hash key is probably a bad idea actually |
| 19:07 | justin_smith | because of the mutation thing, right? |
| 19:07 | hiredman | byte arrays have identity equality and hash codes |
| 19:07 | turbofail | the mutation thing, and the hash code is identity based |
| 19:08 | hiredman | http://docs.oracle.com/javase/6/docs/api/java/nio/ByteBuffer.html#equals%28java.lang.Object%29 |
| 19:08 | turbofail | ~[(.hashCode (.getBytes "foo")) (.hashCode (.getBytes "foo"))] |
| 19:08 | clojurebot | Cool story bro. |
| 19:08 | justin_smith | ,[(.hashCode (.getBytes "foo")) (.hashCode (.getBytes "foo"))] |
| 19:08 | clojurebot | [867692635 1896153315] |
| 19:09 | amalloy | ,(into {} (for [x ["test" "test"]] [(.getBytes x) x])) |
| 19:09 | clojurebot | {#object["[B" "[B@6dbbc7b6"] "test", #object["[B" "[B@4334b602"] "test"} |
| 19:09 | hiredman | uggh |
| 19:09 | hiredman | #array |
| 19:09 | TEttinger | ugggggggh reiterated |
| 19:09 | TEttinger | is there a reader literal for arrays? |
| 19:10 | turbofail | hm, that'd be a nice touch |
| 19:10 | turbofail | #u8[10 24 124 33] |
| 19:11 | justin_smith | what would u8 stand for there? |
| 19:11 | turbofail | i haven't had a whole lot of need for such a thing but i imagine someone else might |
| 19:11 | turbofail | well as this is the JVM it would stand for "uh... i wish this was unsigned" 8-bit |
| 19:12 | justin_smith | haha, I was gonna say |
| 19:13 | turbofail | but presumably the EDN reader handler could translate it into the appropriate equivalent signed numbers |
| 19:19 | gfredericks | my guess is that clojure wouldn't want to default to roundtrip serialization on objects where identity semantics are the normal approach |
| 19:19 | gfredericks | I suppose it could still try to print arrays with #array and just not have a default reader though |
| 19:22 | gfredericks | #byte 42 |
| 19:23 | turbofail | bah, i still haven't gotten a plane ticket and hotel room for clojure/west |
| 19:23 | gfredericks | do it right this second |
| 19:23 | gfredericks | drop everything |
| 19:24 | turbofail | i'm still considering taking amtrak to portland though |
| 19:25 | turbofail | i might be a little bit insane |
| 19:26 | gfredericks | I would do amtrak if I had time and money |
| 19:27 | TEttinger | the train is nicer than a plane, I gotta say |
| 19:27 | turbofail | i feel like a long time on a train with no internet access might be a good thing for me |
| 19:27 | TEttinger | trains can have internet these days |
| 19:28 | gfredericks | and then they don't |
| 19:29 | turbofail | hm. looks like the train in question does have internet access. oh well |
| 19:29 | turbofail | i've been told the route has amazing natural scenery |
| 19:30 | hyPiRion | Hm. What's unnatural scenery? |
| 19:30 | justin_smith | turbofail: the northern route? |
| 19:30 | TEttinger | like #clojure in your IRC client |
| 19:30 | justin_smith | hyPiRion: gary, indiana |
| 19:30 | TEttinger | which is what you might be staring at! |
| 19:30 | turbofail | unnatural scenery would be, say, the surface of trantor |
| 19:30 | raspasov | turbofail: I'm considering driving :) |
| 19:30 | turbofail | or the under-surface rather |
| 19:31 | TEttinger | turbofail, yeah the car ride around oregon area is so nice |
| 19:31 | TEttinger | I'm used to southern california being in constant drought, so seeing *green* |
| 19:31 | TEttinger | is nice |
| 19:31 | turbofail | justin_smith: i'm coming from california. the route would be the coast starlight train |
| 19:31 | justin_smith | oh, that's a nice one, sure |
| 19:32 | justin_smith | my trip will be like walking ten blocks to the light rail, then riding for ten minutes until we get downtown |
| 19:32 | raspasov | justin_smith: you live in Portland? |
| 19:33 | TEttinger | justin_smith IS portland |
| 19:33 | justin_smith | yeah |
| 19:41 | btking | hey all. new person to clojure here and i’m running into a roadblock. i am trying to define a var like `(def my-var ‘(1 2 3))` and then use it like so `(first my-far)`. I keep getting exceptions around unbound vars no matter what I try. I would love some help. |
| 19:42 | amalloy | well uh, my-var is different from my-far |
| 19:43 | amalloy | otherwise what you're doing is fine; if you spell things right and it's still broken, more details are needed |
| 19:44 | btking | lol yes i am spelling things right, other than right here now. So if I spell correctly in the above case, the exception is: IllegalArgumentException Don’t know how to create ISeq from: clojure.lnag.Var$Unbound |
| 19:45 | raspasov | btking: can you create a gist with your whole namespace? |
| 19:48 | justin_smith | ,(def a) |
| 19:48 | clojurebot | #'sandbox/a |
| 19:48 | justin_smith | ,(first a) |
| 19:48 | clojurebot | #error{:cause "Don't know how to create ISeq from: clojure.lang.Var$Unbound", :via [{:type java.lang.IllegalArgumentException, :message "Don't know how to create ISeq from: clojure.lang.Var$Unbound", :at [clojure.lang.RT seqFrom "RT.java" 506]}], :trace [[clojure.lang.RT seqFrom "RT.java" 506] [clojure.lang.RT seq "RT.java" 487] [clojure.lang.RT first "RT.java" 626] [clojure.core$first__4061 invok... |
| 19:48 | btking | sure i can. however, i just noticed when i am getting different results per machine. i am getting the error on ubuntu, and not on my osx machine. seems like i have some other issues to sort out. thanks for the time |
| 19:48 | justin_smith | btking: ^ most common cause of that error |
| 19:48 | justin_smith | btking: are you maybe calling def inside a function? |
| 19:50 | Wild_Cat | btking: I'm noticing the def line you pasted has a non-standard quote in it. Maybe that's the problem? |
| 19:51 | btking | that’s not the issue, i am on two machines now and typed the output from one to the other, some formatting thing occurred |
| 19:56 | TEttinger | ,(def my-var ‘(1 2 3)) |
| 19:56 | clojurebot | #error{:cause "Too many arguments to def", :via [{:type clojure.lang.Compiler$CompilerException, :message "java.lang.RuntimeException: Too many arguments to def, compiling:(NO_SOURCE_PATH:0:0)", :at [clojure.lang.Compiler analyzeSeq "Compiler.java" 6732]} {:type java.lang.RuntimeException, :message "Too many arguments to def", :at [clojure.lang.Util runtimeException "Util.java" 221]}], :trace [[cl... |
| 19:57 | TEttinger | that would be if that nonstandard quote got in there |
| 19:58 | btking | i’ve resolved the issue, i am using cider for repl/evaluation and the nrepl version was behind the package version |
| 19:58 | TEttinger | btking, can you get any value for my-var after defining it? like |
| 19:58 | TEttinger | ah ok |
| 19:58 | btking | thanks for all the ideas, of course there was no actual problem with the code |
| 19:58 | TEttinger | heh, of course |
| 19:58 | justin_smith | the def inside function one is fun |
| 19:59 | justin_smith | ,(defn not-called [] (def unbound 42)) |
| 19:59 | clojurebot | #'sandbox/not-called |
| 19:59 | justin_smith | ,undbound |
| 19:59 | clojurebot | #error{:cause "Unable to resolve symbol: undbound in this context", :via [{:type clojure.lang.Compiler$CompilerException, :message "java.lang.RuntimeException: Unable to resolve symbol: undbound in this context, compiling:(NO_SOURCE_PATH:0:0)", :at [clojure.lang.Compiler analyze "Compiler.java" 6535]} {:type java.lang.RuntimeException, :message "Unable to resolve symbol: undbound in this context",... |
| 19:59 | justin_smith | oops |
| 19:59 | justin_smith | ,unbound |
| 19:59 | clojurebot | #object[clojure.lang.Var$Unbound "Unbound: #'sandbox/unbound"] |
| 19:59 | justin_smith | the var is created at compilation time |
| 20:09 | kludgecode | ,my-heap |
| 20:09 | clojurebot | #error{:cause "Unable to resolve symbol: my-heap in this context", :via [{:type clojure.lang.Compiler$CompilerException, :message "java.lang.RuntimeException: Unable to resolve symbol: my-heap in this context, compiling:(NO_SOURCE_PATH:0:0)", :at [clojure.lang.Compiler analyze "Compiler.java" 6535]} {:type java.lang.RuntimeException, :message "Unable to resolve symbol: my-heap in this context", :a... |
| 20:11 | kludgecode | ,(def my-heap (atom (sorted-set-by #(compare (:p %1)(:p %2))))) |
| 20:11 | clojurebot | #'sandbox/my-heap |
| 20:12 | kludgecode | ,(swap! my-heap {:d 1 :p1}) |
| 20:12 | clojurebot | #<RuntimeException java.lang.RuntimeException: Map literal must contain an even number of forms> |
| 20:12 | justin_smith | kludgecode: swap! needs a function |
| 20:12 | kludgecode | ,(swap! conj my-heap {:d 1 :p 1}) |
| 20:12 | clojurebot | #error{:cause "clojure.core$conj__4067 cannot be cast to clojure.lang.IAtom", :via [{:type java.lang.ClassCastException, :message "clojure.core$conj__4067 cannot be cast to clojure.lang.IAtom", :at [clojure.core$swap_BANG_ invoke "core.clj" 2237]}], :trace [[clojure.core$swap_BANG_ invoke "core.clj" 2237] [sandbox$eval73 invoke "NO_SOURCE_FILE" -1] [clojure.lang.Compiler eval "Compiler.java" 6784]... |
| 20:13 | justin_smith | kludgecode: the function comes after the atom |
| 20:14 | justin_smith | ,(swap! my-heap conj {:d 1 :p 1}) |
| 20:14 | clojurebot | #{{:d 1, :p 1}} |
| 20:15 | kludgecode | Anyway, the point I was hoping to make is that `sorted-set-by` will only take one value of the comparison field for maps. That is if `my-heap` contains {:p 1 :d 2}, then {:p1 :d 3} cannot be added. |
| 20:16 | kludgecode | Looks like I need java.util.PriorityQueue, after all. |
| 20:16 | turbofail | it works fine if your comparison function factors in other bits |
| 20:18 | gfredericks | kludgecode: you can use a comparison of (juxt :p identity) |
| 20:18 | justin_smith | (inc gfredericks) |
| 20:18 | lazybot | ⇒ 127 |
| 20:18 | justin_smith | that's the ticket |
| 20:19 | justin_smith | nice, max value for a signed byte |
| 20:19 | amalloy | 4karma set gfredericks -128 |
| 20:19 | gfredericks | ,Byte/MAX_VALUE |
| 20:19 | clojurebot | 127 |
| 20:19 | gfredericks | (identity gfredericks) |
| 20:19 | lazybot | gfredericks has karma 127. |
| 20:19 | gfredericks | phew |
| 20:19 | justin_smith | haha |
| 20:20 | kludgecode | turbofail: So I could kludge my code around the set semantics? Why does that sound attractive? |
| 20:21 | justin_smith | kludgecode: if what gfredericks suggested (which implements what turbofail said) is too ugly, you could always implement your own heap |
| 20:21 | gfredericks | it's still easier than managing a mutable thing |
| 20:21 | gfredericks | kludgecode: this also might work: https://github.com/clojure/data.priority-map |
| 20:22 | gfredericks | looks like it handles duplicate priorities fine |
| 20:24 | kludgecode | I thought about it before. I don't know that I really want to manage identities in the form of keys just for the sake of managing them. Though it would be kind of kludgey. |
| 20:25 | kludgecode | At least the hurt with mutation is a known form of hurt. I suspect I'll invent enough new ones on my own. |
| 20:27 | gfredericks | so what's your application for this? |
| 20:32 | kludgecode | gfredricks: Right now I'm using Coursera's *Discreet Optimization* as a platform for learning more about Optimization and Clojure. Right now I'm writing a branch and bound solver for the knapsack problem where the state is tossed on a heap. The state is a map containing a knapsack and an estimate. The heap sorts by estimate. I was using sorted-set-by. It turns out I was losing states because... |
| 20:32 | kludgecode | ...estimates were staying the same. I didn't know this until this discussion, only that things weren't working. |
| 20:33 | kludgecode | since the application is single threaded, mutation isn't quite so bad. |
| 20:34 | justin_smith | kludgecode: #(compare ((juxt :p identity) %1) ((juxt :p identity) %2)) sorts properly, and eliminates the problem you site |
| 20:34 | justin_smith | *cite |
| 20:35 | justin_smith | But if a mutable never leaves scope, and never gets threaded, you can of course use it in pure code. |
| 20:37 | kludgecode | justin_smith: So #(compare ((juxt :estimate identity) %1)((juxt :estimate identity) %2)) would sort on :estimate ? |
| 20:38 | justin_smith | sort on :estimate, if :estimate matched, it would then sort on the whole map as a value |
| 20:40 | kludgecode | That makes sense. BTW, I just came across juxt last night in Joy of Clojure 2nd edition. Thanks. |
| 20:40 | justin_smith | ,(sorted-set-by #(compare ((juxt :estimate identity) %1) ((juxt :estimage identity) %2)) {:estimate 8 :val -1} {:estimate 1 :val 42} {:estimate 1 :val 100} {:estimate :2 :val 33}) |
| 20:40 | clojurebot | #{{:estimate 8, :val -1} {:estimate 1, :val 42} {:estimate 1, :val 100} {:estimate :2, :val 33}} |
| 20:40 | justin_smith | kludgecode: that's why I inc'd gfredericks, juxt is always great |
| 20:40 | justin_smith | (inc juxt) |
| 20:40 | lazybot | ⇒ 21 |
| 20:40 | amalloy | ~juxt |
| 20:40 | clojurebot | juxt is pretty metal |
| 20:41 | turbofail | certainly it should be the other way around, metal is pretty juxt |
| 20:41 | kludgecode | Back to bashing away. Thanks. |
| 20:42 | justin_smith | wait, in my example above, why is the one with :estimate 8 first? I must be using sorted-set-by wrong |
| 20:43 | justin_smith | ugh, "estimage" |
| 20:43 | justin_smith | ,(sorted-set-by #(compare ((juxt :estimate identity) %1) ((juxt :estimate identity) %2)) {:estimate 8 :val -1} {:estimate 1 :val 42} {:estimate 1 :val 100} {:estimate 2 :val 33}) |
| 20:43 | clojurebot | #error{:cause "clojure.lang.PersistentArrayMap cannot be cast to java.lang.Comparable", :via [{:type java.lang.ClassCastException, :message "clojure.lang.PersistentArrayMap cannot be cast to java.lang.Comparable", :at [clojure.lang.Util compare "Util.java" 153]}], :trace [[clojure.lang.Util compare "Util.java" 153] [clojure.lang.APersistentVector compareTo "APersistentVector.java" 424] [clojure.la... |
| 20:45 | justin_smith | ,(sorted-set-by #(compare ((juxt :estimate vec) %1) ((juxt :estimate vec) %2)) {:estimate 8 :val -1} {:estimate 1 :val 42} {:estimate 1 :val 100} {:estimate 2 :val 33}) |
| 20:45 | clojurebot | #{{:estimate 1, :val 42} {:estimate 1, :val 100} {:estimate 2, :val 33} {:estimate 8, :val -1}} |
| 20:45 | justin_smith | kludgecode: there was a tricky bug left, see this version ^ |
| 20:46 | justin_smith | tl/dr you can't compare hash-map (or even seq, my first fallback) but putting it in a vec solves it |
| 20:57 | lvh | I have a system that has a bunch of stuff running in parallel using pipeline-blocking. All of the concurrently running processes do some stuff to the world, and then occasionally subscribe to (the same) states of the world. Since pipeline-blocking takes a transducer, I didn't want to mess with core.async's mult + tap, and just wrote something that add-watch'es an atom. However; it doesn't work; it blocks indefinitely. https://github. |
| 20:57 | lvh | com/lvh/nordschleife/blob/master/src/nordschleife/affect.clj#L12-L63 |
| 20:59 | justin_smith | lvh: irc broke up that url |
| 20:59 | lvh | https://github.com/lvh/nordschleife/blob/master/src/nordschleife/affect.clj#L12-L63 |
| 21:00 | lvh | justin_smith: Sorry; looked good from my end :-) Did that work? |
| 21:01 | lvh | It's a little gross, but I couldn't come up with a significantly better way of doing it |
| 21:01 | justin_smith | yeah |
| 21:01 | Shayanjm | question - is this proper "clojuric form"? I thought the most elegant way to handle this is to do all of the math in a let statement, and just return in the next line: https://gist.github.com/shayanjm/451a3242685225aa934b |
| 21:01 | Shayanjm | but unsure if this is how another clojurist would handle it |
| 21:02 | lvh | Shayanjm: I'd definitely indent it more |
| 21:02 | amalloy | Shayanjm: the general approach is fine, but you could use some newlines in the expressions for lat2 and lon2 |
| 21:03 | justin_smith | Shayanjm: one thing to note is that I don't think clojure is smart enough to simplify your multiply calls eg (Math/cos lat1) - though hotspot might be |
| 21:03 | amalloy | indenting it more doesn't really make sense...? |
| 21:03 | justin_smith | s/multiply/multiple |
| 21:03 | Shayanjm | hmmk |
| 21:04 | Shayanjm | but past that the functional structure of it is ok? |
| 21:04 | amalloy | seems fine to me |
| 21:04 | Shayanjm | great, thanks for the feedback :) |
| 21:04 | justin_smith | yes, that's how any of us would break a computation into steps, yeah |
| 21:04 | amalloy | i would also consider defining aliases for the frequently-used functions in Math, so you don't have to keep typing/reading Math/whatever |
| 21:04 | Shayanjm | Yeah definitely, that was on my next to-do |
| 21:05 | Shayanjm | actually that brings me to my next question, does it make sense to add vars inside the let corresponding to frequently used vals? |
| 21:05 | Shayanjm | i.e: bind 'coslat1' to (math/cos lat1) |
| 21:05 | Shayanjm | and just use that in the next sets of computations? Or does it make no performance difference? |
| 21:06 | justin_smith | Shayanjm: I'm going to do a benchmark of (let [y (Math/sin x)] (+ y y)) vs. (+ (Math/sin x) (Math/sin x)) |
| 21:06 | justin_smith | because I honestly wonder if there is a perf difference there |
| 21:06 | Shayanjm | sweet :) |
| 21:08 | lvh | amalloy: Yes, I meant linebreaks in those exprs, and indent those, instead of being on the same line :) |
| 21:10 | Shayanjm | justin_smith: maybe a better test would be (let [a 1 y(Math/sin x)] (+ y y)) vs. (let [a 1] (+ (Math/sin x) (Math/sin x))) |
| 21:10 | Shayanjm | just in case there's any overhead in invoking a let |
| 21:10 | amalloy | there's not |
| 21:11 | Shayanjm | disregard me |
| 21:11 | justin_smith | Shayanjm: yeah, even with full hotspot optimization turned on, the version with the let binding is twice as fast |
| 21:11 | justin_smith | because it does half as many Math/sin calls |
| 21:11 | Shayanjm | well shit |
| 21:11 | justin_smith | just benchmarked it with criterium |
| 21:12 | Shayanjm | That actually surprises me |
| 21:12 | justin_smith | Shayanjm: yeah, when in doubt, you can usually assume that clojure's compiler did not optimize something :) |
| 21:12 | Shayanjm | Yeah noted |
| 21:13 | justin_smith | for reference, the actual criterium tests / results: https://www.refheap.com/98811 |
| 21:13 | kludgecode | justin_smith: Thanks. When I was out walking the dogs, I realized that I have what boils down to :id already -- the unique path through the tree of the search space. Though I'm not sure about sorting a vector of booleans? |
| 21:14 | lvh | Mostly because I spent a good while writing faster Chebyshev interpolated versions of a lot of those functions for a while :) |
| 21:14 | justin_smith | lvh: I think it comes down to a floating point sin instruction (not a cheap instruction) |
| 21:14 | justin_smith | and not super high quality in its output either |
| 21:15 | justin_smith | eg. for audio you want to do a proper calculation of the waveform and sample it from a table, rather than rely on the noisy output of the CPU instruction |
| 21:16 | justin_smith | kludgecode: OK - be sure to see my update, replace identity with vec |
| 21:16 | justin_smith | or use a guaranteed unique element from the input to replace vec |
| 21:16 | lvh | justin_smith: Yeah. One of the benefits of the chebyshev version was that it was significantly more accurate than the instruction. |
| 21:17 | justin_smith | lvh: I forget, does the Chebyshev way of calculating use stored intermediates or lookup tables? |
| 21:20 | justin_smith | lvh: did anyone address your deadlock issue? |
| 21:20 | lvh | justin_smith: you approximate a part of the function as the ratio of two polynomials |
| 21:20 | lvh | justin_smith: nope |
| 21:20 | lvh | justin_smith: the chebyshev part is "compute the polynomials" |
| 21:21 | lvh | well, I guess that's the horner part, with some extra smarts for certain value ranges |
| 21:22 | lvh | justin_smith: so, for very large inputs, fsin is pretty much totally wrong |
| 21:22 | lvh | justin_smith: which is unfortunate since it takes a double :) |
| 21:22 | kludgecode | justin_smith: now, after looking again and double clutching, I understand. My brain was still stuck back in identity gear. |
| 21:22 | amalloy | lvh: i can't really follow all of the stuff going on in that paste, but it looks like you might have multiple different processes adding watches to an atom with the same key? |
| 21:23 | amalloy | i would expect that to replace the watcher, so that only one process is actually notified when whatever happens |
| 21:23 | lvh | amalloy: Yes, but the problem persists when I build the pipeline with a parallelism of 1 |
| 21:24 | justin_smith | lvh: lines 42 through 46 |
| 21:24 | justin_smith | the second watch replaces the first |
| 21:25 | justin_smith | the first one will never get triggered, because the second one replaced it |
| 21:25 | justin_smith | so if you wait on prev, you will wait forever |
| 21:26 | justin_smith | in fact, every time you call (get-state) there, you are ensuring any values from previous calls to (get-state) will never unblock |
| 21:26 | justin_smith | since each one replaces the watcher, and ensures the chan can never be delivered to |
| 21:26 | lvh | justin_smith: I don't understand why with parallelism 1; won't get-state block until it's done, therefore preventing the second (get-state) from overriding the watcher?? |
| 21:26 | lazybot | lvh: What are you, crazy? Of course not! |
| 21:27 | amalloy | good work, lazy |
| 21:27 | justin_smith | lvh: you bind prev to (get-state), on the next line, you bind curr to (get-state), ensuring that prev's channel will never, ever be written to |
| 21:27 | amalloy | aw c'mon, who added another nick in here that starts with lazy. pls lazylambda, think of the tab-completion |
| 21:27 | justin_smith | haha |
| 21:27 | amalloy | lvh: replace line 29 with: k (gensym) |
| 21:28 | justin_smith | yeah, that may just be the fix |
| 21:28 | amalloy | is all that really needs to change to address what justin_smith and i are talking about. maybe there are more issues after that, but... |
| 21:29 | justin_smith | lvh: and I don't understand this code well enough to say this with 100% certainty, but when I see code this mind-pretzel-forming, I am inclined to believe there is some way to fold the code so my brain doesn't need to fold so much over it |
| 21:30 | lvh | justin_smith: sure, but I'm saying is once (get-state) is evaluated, prev's channel is already closed, right? get-state blocks until something happens to it, and let bindings are evaled sequentially |
| 21:30 | lvh | justin_smith: Yeah, I totally appreciate that it's gross. I can't think of a better way to do it, though. |
| 21:30 | justin_smith | lvh: why would prev's channel be closed? |
| 21:30 | justin_smith | it's sitting there waiting to be written to |
| 21:31 | justin_smith | (as in "c" as bound in block-until-updated) |
| 21:31 | amalloy | justin_smith: lvh is pointing out that block-until-updated blocks |
| 21:31 | lvh | err, not closed, but already written to, right? |
| 21:31 | lvh | maybe it should be closed, I'm not sure it matters |
| 21:31 | lvh | I could make it a promise-chan anyway, I know it'll only ever get one item on it |
| 21:31 | amalloy | so curr doesn't get defined until prev's watcher has already fired |
| 21:31 | lvh | amalloy: Yeah, that's what I'm saying :) |
| 21:31 | justin_smith | amalloy: ahh, right, - so it doesn't even return until the atom is changed... |
| 21:34 | lvh | OK, so let's talk about that code being totally gross |
| 21:35 | justin_smith | haha |
| 21:35 | lvh | maybe I'm missing some cool way of doing it |
| 21:35 | justin_smith | lvh: cool way, or a way of expressing it that would make it more clear to a reader what "it" is |
| 21:36 | lvh | justin_smith: I think the latter would count as cool, but given that *this* is what I have right now I'll settle for less |
| 21:36 | lvh | So, I have a system, and the system is supposed to have some properties that hold over time. Specifically, it's orchestrating creating and deleting some servers. Eventually, the system under test (not part of this code; this code treats it as a black box), makes there be the Appropriate amount of servers. |
| 21:36 | lvh | I have some pure functions that take a series of steps and figure out what that appropriate thing is. |
| 21:37 | lvh | So, basically: do some stuff, figure out if the black box did the right stuff. You do that by observing the total state of the world. All of these scenarios (generated sequences of events) observe the same state of the world, so I want to distribute it to all of the things executing scenarios. |
| 21:37 | lvh | Ideally, scenarios would be executed concurrently. |
| 21:38 | lvh | Does that help at all? |
| 21:38 | lvh | I guess my problem definition is pretty imperative :) |
| 21:40 | lvh | Part of the problem is that servers don't magically appear. They need to build; building takes time. That's what that :acquiesce method impl does. |
| 21:42 | lvh | I guess an alternative, but clearly not isomorphic, design would be to produce an ordered map of timestamps and things to do at that timestamp, and asynchronously both execute and collect all of that information, and then process it all the way at the end. |
| 21:43 | lvh | (Fortunately this only runs on one box, so I can get a monotonic & accurate clock if I really want) |
| 21:51 | justin_smith | it seems like the thing that would translate to core.async would be to have a function named after verifying each step, and then run those in series, followed by the verification logic? |
| 21:52 | lvh | justin_smith: so, there's a verification step, and there's some "do-a-thing" steps |
| 21:52 | lvh | justin_smith: I wanted them to be separate because I want to check if there's a difference between A-A-A and A-wait-A-wait-A-wait |
| 21:53 | lvh | (turns out, from manual testing, there probably is) |
| 21:53 | lvh | justin_smith: which is why there's the defmulti; the other reason there's a defmulti is that it makes the xform really easy, it's just map ;-) |
| 21:54 | lvh | justin_smith: Here's some of the less gross scenarios code: https://github.com/lvh/nordschleife/blob/master/src/nordschleife/scenarios.clj |
| 23:19 | justin_smith | I started a server on my vps on port 8000, I keep getting attempts to hit /manager/html from the same ip... |
| 23:22 | TEttinger | make that URL redirect to the wikileaks snowden stuff |
| 23:24 | justin_smith | ooo, that would be smart |