2015-06-04
| 00:23 | Seylerius | There a good clojurish way to spawn virtual machines to accomplish a specific task? |
| 00:26 | TEttinger | hey Seylerius, did you get the sudoku solver GUI working? |
| 00:26 | Seylerius | TEttinger: Been busy with errands all damn day, so no, unfortunately. |
| 00:26 | Seylerius | Planning on taking another whack at it tomorrow. |
| 00:26 | TEttinger | cool |
| 00:27 | Seylerius | Oh, btw, why is your clone always hanging in here? |
| 00:27 | Seylerius | TEttinger: It kinda throws off tab-completion on your nick. |
| 00:28 | TEttinger | TEttinger2? logger bot, I run an irc bot on an old laptop and I keep an irc client open as well so I can check if it's working |
| 00:28 | TEttinger | err |
| 00:28 | TEttinger | TEttinger2 is not actually a bot, it's the client |
| 00:28 | heurist | Seylerius: just set your irc client to complete based on last spoken instead of alpha. |
| 00:29 | TEttinger | or shortest first |
| 00:29 | TEttinger | but TEttinger leaves, TEttinger2 does not |
| 00:29 | TEttinger | ok, time to get this cluajure obscene hybrid working |
| 00:29 | Seylerius | TEttinger, heurist: The problem isn't that, the problem is that it just provides the common prefix, which leaves me retyping the ": " every time. |
| 00:30 | TEttinger | ahhhhh |
| 00:30 | Seylerius | TEttinger: Cluajure? Sounds like an abomination. |
| 00:30 | Seylerius | (In other words, I'm being lazy) |
| 00:31 | Seylerius | I'm heading out to town. See y'all later, maybe tomorrow. |
| 00:31 | Seylerius | heurist: It's ERC, so I just have to configure it a little differently. |
| 00:31 | Seylerius | Again, I've been lazy. |
| 02:44 | dfletcher | added my first code sample to clojuredocs.org today :) http://clojuredocs.org/clojure.core/condp#example-556fc440e4b03e2132e7d185 |
| 02:47 | dfletcher | also heh I never really noticed by my github qrcode thingy looks like a space invader. |
| 02:47 | dfletcher | *but my |
| 02:49 | dfletcher | condp makes all the other solutions to fizzbuzz look like a big joke heh. |
| 02:50 | amalloy | dfletcher: not really. it's much nicer with a loop over the divisor list |
| 02:50 | dfletcher | example? |
| 02:52 | amalloy | ,(let [divisors [[15 "fizzbuzz"] [3 "fizz"] [5 "buzz"]]] (defn fizzbuzz [n] (-> (first (for [[r s] divisors :when (zero? (mod n r))] s)) (or (str n))))) |
| 02:52 | clojurebot | #'sandbox/fizzbuzz |
| 02:52 | amalloy | ,(dorun (map (comp prn fizzbuzz) (range 1 30))) |
| 02:52 | clojurebot | "1"\n"2"\n"fizz"\n"4"\n"buzz"\n"fizz"\n"7"\n"8"\n"fizz"\n"buzz"\n"11"\n"fizz"\n"13"\n"14"\n"fizzbuzz"\n"16"\n"17"\n"fizz"\n"19"\n"buzz"\n"fizz"\n"22"\n"23"\n"fizz"\n"buzz"\n"26"\n"fizz"\n"28"\n"29"\n |
| 02:53 | amalloy | ,(clojure.string/join " " (map fizzbuzz (range 1 31))) |
| 02:53 | clojurebot | "1 2 fizz 4 buzz fizz 7 8 fizz buzz 11 fizz 13 14 fizzbuzz 16 17 fizz 19 buzz fizz 22 23 fizz buzz 26 fizz 28 29 fizzbuzz" |
| 02:55 | J_A_Work | personally, my favorite FB is with javascript, because switch case can fall through, so you can write it with only the conditionals on mod 3 and 5 |
| 02:56 | amalloy | the nice thing is that now the divisors are just data, a list you could replace without having to re-define fizzbuzz if you wanted different numbers, and the various bookkeeping is separate from the specific rules |
| 02:57 | dfletcher | yeah I like it. also heh thanks for zero? updated my sample |
| 02:59 | lumafi | how about fizzbuzz without any conditionals? |
| 02:59 | lumafi | ,(def fizzbuzz (letfn [(fb [s k coll] (mapcat (fn [x] (cons s (rest x))) (partition k coll)))] (->> (range) (fb "fizz" 3) (fb "buzz" 5) (fb "fizzbuzz" 15)))) |
| 02:59 | clojurebot | #'sandbox/fizzbuzz |
| 03:00 | lumafi | ,(clojure.string/join " " (take 30 fizzbuzz)) |
| 03:00 | clojurebot | "fizzbuzz 1 2 fizz 4 buzz fizz 7 8 fizz buzz 11 fizz 13 14 fizzbuzz 16 17 fizz 19 buzz fizz 22 23 fizz buzz 26 fizz 28 29" |
| 03:00 | dfletcher | actually I retract my earlier statment and ammend it. *clojure* makes other solutions to fizzbuzz look like a joke hehe |
| 03:01 | amalloy | that's a cute one, lumafi |
| 03:02 | dfletcher | zero is a weird case it matches all |
| 03:04 | dfletcher | when i tried it as an infinite seq ended up using (rest range) to start with since 0 doesn't make tons of sense |
| 03:04 | dfletcher | *to start with 1 |
| 03:07 | dfletcher | man. i understood amalloy's one pretty quick. this one is making me look up thinigs and I still have no idea whats going on heh. |
| 03:08 | amalloy | dfletcher: do you want a hint or to figure it out yourself? |
| 03:08 | dfletcher | i like a puzzle i'll ask if I want help hehe |
| 03:10 | dfletcher | thanks for asking though rather than just answering it. just feeling chatty this eve :) |
| 03:12 | mmeix | Beginner's question: I have [ {:a 1} {:a 2} {:a 3} {:b 5} {:b 6} {:c 99} ] and I want to get [ {:a [1 2 3] {:b [5 6]} {:c [99]} ] - what would be the fn to use with merge-with in this case? |
| 03:12 | mmeix | (obviously conj and concat etc wouldn't work) |
| 03:13 | TEttinger | (doc merge-with) ; let's see... |
| 03:13 | clojurebot | "([f & maps]); Returns a map that consists of the rest of the maps conj-ed onto the first. If a key occurs in more than one map, the mapping(s) from the latter (left-to-right) will be combined with the mapping in the result by calling (f val-in-result val-in-latter)." |
| 03:13 | amalloy | mmeix: in fact concat does work (though i recommend into instead), as long as you pre-process the sequence ahead of time |
| 03:14 | mmeix | ah, ok |
| 03:14 | amalloy | try something like this: (apply merge-with into (for [m [{:a 1} ...]] ...)) |
| 03:15 | mmeix | ok, wrapping my brain around this - thanks! |
| 03:29 | benhuda | hello |
| 03:30 | benhuda | do you think it is wise to name an open source library "kevlar" given that Kevlar is registered trademark? |
| 03:31 | amalloy | well on the one hand you would be safeish on trademark infringement, since there is no danger of someone confusing your clojure library for actual physical kevlar. on the other hand there's nothing stopping them from suing you anyway |
| 03:31 | benhuda | yes i just bumped into some lawsuit for kevlarftp (OSS) which was named to kftp after lawsuit threats |
| 03:33 | benhuda | i'll just call it 'armor' then :) |
| 03:35 | dfletcher | oh oh I get it! partition is breaking it into sets of 3,5,15. then replace the first element of each partitioned bit with the string. then cons to stitch it all back together. genius! thanks for that lumafi |
| 03:36 | TEttinger | kavler |
| 03:36 | TEttinger | cavalier |
| 03:39 | dfletcher | err, mapcat to stitch it back together, cons is doing the string replacement thingy. ok after midnight i'm a pumpkin now. night peeps. |
| 03:44 | TEttinger | &(let [r (range 100) matching (fn [n s] (map #(if (zero? (mod % n)) s "") r) fizz (matching 3 "fizz") buzz (matching 5 "buzz") fizzbuzz (map str fizz buzz)] (map #(if (empty? %1) %2 %1) fizzbuzz r)) |
| 03:44 | lazybot | java.lang.RuntimeException: Unmatched delimiter: ] |
| 03:44 | TEttinger | aww |
| 03:45 | TEttinger | &(let [r (range 100) matching (fn [n s] (map #(if (zero? (mod % n)) s "") r)) fizz (matching 3 "fizz") buzz (matching 5 "buzz") fizzbuzz (map str fizz buzz)] (map #(if (empty? %1) %2 %1) fizzbuzz r)) |
| 03:45 | lazybot | ⇒ ("fizzbuzz" 1 2 "fizz" 4 "buzz" "fizz" 7 8 "fizz" "buzz" 11 "fizz" 13 14 "fizzbuzz" 16 17 "fizz" 19 "buzz" "fizz" 22 23 "fizz" "buzz" 26 "fizz" 28 29 "fizzbuzz" 31 32 "fizz" 34 "buzz" "fizz" 37 38 "fizz" "buzz" 41 "fizz" 43 44 "fizzbuzz" 46 47 "fizz" 49 "buzz" "fizz... https://www.refheap.com/102078 |
| 03:45 | TEttinger | it's always nice to write fizzbuzz |
| 03:46 | TEttinger | different ways every time |
| 03:51 | H4ns | how can i, in cider, achieve that a macro expansion (C-c C-m) is not elided using #? |
| 03:51 | H4ns | C-c M-m that is |
| 05:28 | kungi | I updated compojure from 1.2.0 to 1.3.4 and the order of the keys/vals in (:roles (friend/current-authentication)) reversed? |
| 05:29 | kungi | O.o |
| 05:30 | Empperi | kungi: you cannot rely on map value ordering |
| 05:30 | Empperi | not unless you are using a sorted map |
| 05:30 | Empperi | https://clojuredocs.org/clojure.core/sorted-map |
| 05:31 | TEttinger | or an ordered map, which doesn't come with clojure and is in flatland |
| 05:31 | kungi | Empperi: not the ordering of the map. The keys and values reversed |
| 05:31 | kungi | Keys are now values and the other way around |
| 05:31 | TEttinger | hm |
| 05:31 | Empperi | well that sounds strange |
| 05:32 | TEttinger | that would break all sorts of things if there were duplicate values before: ##(hash-map :a 1 :b 1) |
| 05:32 | lazybot | ⇒ {:b 1, :a 1} |
| 05:32 | TEttinger | totally fine, but |
| 05:32 | TEttinger | ##(hash-map 1 :a 1 :b) |
| 05:32 | lazybot | ⇒ {1 :b} |
| 05:32 | TEttinger | ,{1 :a 1 :b} |
| 05:32 | clojurebot | #<IllegalArgumentException java.lang.IllegalArgumentException: Duplicate key: 1> |
| 05:33 | TEttinger | the function hash-map is more lenient than the literal |
| 05:38 | kungi | ... I think it's my fault because of my get-roles-for-user function ... |
| 05:40 | ionthas_ | What is the neatest way to define default values for a function? Right now I'm using arity and I call the function with the default parameter value. |
| 05:41 | Empperi | that is pretty much the neatest way except if you pass in a map and want to provide default values for keys |
| 05:41 | Empperi | ,((fn [{:keys [foo bar] :or {foo 1 bar 2}}] [foo bar]) {:foo 15}) |
| 05:41 | clojurebot | [15 2] |
| 05:42 | Empperi | in that case it's better to use that part of destructuring syntax |
| 05:42 | Empperi | as one might expect, works everywhere where destructuring works |
| 05:43 | ionthas_ | Thanks Empperi :) |
| 05:43 | Empperi | np |
| 05:45 | danielcompton | @cfleming: you around? |
| 05:48 | kungi | Found it! |
| 05:52 | mmeix | amalloy recommended "into" instead of "concat" for use in merge-with - what are the advantages of into vs. concat? |
| 05:52 | mmeix | (besides looking neat) |
| 05:52 | justin_smith | mmeix: hash-maps are strict, concat is lazy |
| 05:53 | justin_smith | it's usually a bad idea to mix strict and lazy unless you have a specific reason to |
| 05:53 | mmeix | I see |
| 05:53 | justin_smith | see also stuartsierra's blog post on concat |
| 05:54 | justin_smith | http://stuartsierra.com/2015/04/26/clojure-donts-concat |
| 05:54 | mmeix | If I'm foreseeing, that I will consume the whole data, lazyness buys me nothing inthis case - right? |
| 05:54 | justin_smith | right |
| 05:54 | mmeix | ah - thanks for the article! |
| 05:54 | justin_smith | unless the data is too large to be in memory all at once |
| 05:55 | justin_smith | mmeix: it's a good blog to follow for clojure |
| 05:55 | mmeix | my data is mostly around 5-20 elements |
| 05:55 | justin_smith | yeah, staying strict will keep it simpler than |
| 05:55 | justin_smith | *then |
| 05:55 | mmeix | great advice, as ever :-) |
| 06:00 | kungi | Empperi: you where right. I depended on the order of entries in a map. It was a bit hidden in the code |
| 06:01 | cfleming | danielcompton: Yep, what's up? |
| 06:02 | kungi | Is there a standardlibrary function to (select-vals {:a 1 :b 2 :c 3} [:a :c]) -> [1 3] |
| 06:07 | mmeix | I have a second question, loosely related: for my current project (music typesetting with svg in clojurescript) I built a couple of basic functions, and a bigger one, which uses them to build a combined graphical group (a chord, consisting of several noteheads, accidentals, stem flags/beam, dots etc.) with many calculations in it, depending on each other; this makes sense as a semantic unit and building block for the next higher |
| 06:07 | mmeix | level. Now for spacing several of these units in a row (staff) I need to ask the group about its dimensions, which would have to be calculated out of the elements in it - this begins to sound like an object with a function "return-size" or something like that in it. What would be a proper Clojure solution to expose this to the next higher function? |
| 06:12 | mmeix | , (map {:a 1 :b 2 :c 3} [:a :c]) |
| 06:12 | clojurebot | (1 3) |
| 06:12 | mmeix | (for kungi) |
| 06:12 | justin_smith | alternately ##((juxt :a :c) {:a 1 :b 2 :c 3}) |
| 06:12 | lazybot | ⇒ [1 3] |
| 06:13 | TEttinger | juxt! |
| 06:13 | TEttinger | juxtin_smith |
| 06:13 | kungi | mmeix: justin_smith thank you :-) |
| 06:13 | TEttinger | (inc mmeix) |
| 06:13 | lazybot | ⇒ 1 |
| 06:13 | TEttinger | (inc justin_smith) |
| 06:13 | lazybot | ⇒ 258 |
| 06:13 | mmeix | my first inc :-) |
| 06:13 | justin_smith | TEttinger: eventually I will have to implement juxt-in |
| 06:13 | TEttinger | this-juxt-in |
| 06:14 | justin_smith | that's the version for protocols, of course |
| 06:14 | ddellacosta | omg |
| 06:14 | ddellacosta | you guys are such dorks |
| 06:15 | justin_smith | mmeix: are the graphical elements nested like a tree? if so you may want to do a tree walk and either a thing knows its width, or can find out the width from its children, recursively |
| 06:16 | mmeix | they are not nested, but dependent on each other via some rules for placement |
| 06:16 | justin_smith | mmeix: oh, then that sounds like a reduce |
| 06:17 | justin_smith | each one figures out what its right edge in, based on the prior state, and passes that forward |
| 06:17 | justin_smith | s/in/is |
| 06:17 | mmeix | aha ... have to ponder this for a while ... |
| 06:19 | mmeix | that means, my group has to collect these measurements inside in a neatly accessible way, and expose it as an additional return value, in a map or something like this) |
| 06:21 | mmeix | and since I'll need the dimensions anyway, the "object" should calculate it alongside all the placement and return it with them - is this right thinking? |
| 06:21 | justin_smith | I think so |
| 06:21 | mmeix | ok - thanks! |
| 06:24 | mmeix | does anyone have a good source for algorithms for overlap detection of shapes (consisting of horizontal/vertical straight lines only)? |
| 06:25 | mmeix | (expressed in x/y coords, of course) |
| 06:26 | TEttinger | if the line is vertical, check if its x is between the end and start of any horizontal lines, and if its x is identical with any other vertical lines |
| 06:26 | TEttinger | if the line is horizontal, check if its y is between the end and start of any vertical lines, and if its y is identical with any other horizontal lines |
| 06:27 | mmeix | and do this for any combination ...? |
| 06:27 | mmeix | I see |
| 06:27 | TEttinger | I mean that's super naive, but each check should be very fast |
| 06:27 | TEttinger | you can end early if you're doing a reduce, see ##(doc reduced) |
| 06:27 | lazybot | ⇒ "([x]); Wraps x in a way such that a reduce will terminate with the value x" |
| 06:28 | TEttinger | so if you know you overlap, you don't need to keep checking |
| 06:28 | mmeix | I didn't know about early ending in reduce |
| 06:28 | mmeix | more to learn |
| 06:28 | mmeix | thanks again |
| 06:30 | justin_smith | yeah, it's easy to get it mixed up, because we have something called "for", but reduce really ends up being the idiomatic replacement of for in other languages in most cases |
| 06:31 | mmeix | I get the notion, that for is seldomly the best solution in Clojure |
| 06:31 | mmeix | using map and reduce instead |
| 06:31 | justin_smith | it's useful, but I think people get misled by the name about what it would be good for |
| 06:32 | TEttinger | for is often a good solution, but it's "for" generating sequences that you usually want to end up changing with map, reduce, filter, etc. |
| 06:33 | mmeix | I see - "reduced" is my finding of the day ... |
| 06:33 | mmeix | (inc TEttinger) |
| 06:33 | lazybot | ⇒ 57 |
| 06:34 | mmeix | (inc justin_smith) |
| 06:34 | lazybot | ⇒ 259 |
| 06:35 | TEttinger | gotta inc justin |
| 06:36 | mmeix | which I did :-) |
| 06:36 | TEttinger | yeah, but it's basically becoming a rule now that technomancy isn't showing up here |
| 06:36 | TEttinger | (identity technomancy) |
| 06:36 | lazybot | technomancy has karma 163. |
| 06:36 | TEttinger | wow |
| 06:36 | TEttinger | he used to be King Karma |
| 06:37 | justin_smith | (identity amalloy) |
| 06:37 | lazybot | amalloy has karma 276. |
| 06:37 | TEttinger | I guess he's still garnering good karma, just uh not bot karma |
| 06:38 | mmeix | last question: |
| 06:39 | mmeix | ,(let [m [1 4 2 7 8 5] ] ((juxt min max) m) |
| 06:39 | clojurebot | #<RuntimeException java.lang.RuntimeException: EOF while reading> |
| 06:39 | mmeix | umpf |
| 06:39 | mmeix | ;(let [m [1 4 2 7 8 5] ] ((juxt min max) m)) |
| 06:39 | justin_smith | so close! |
| 06:40 | mmeix | ,(let [m [1 4 2 7 8 5] ] (apply (juxt min max) m)) |
| 06:40 | clojurebot | [1 8] |
| 06:40 | mmeix | vs. |
| 06:43 | mmeix | ,(let [m [1 4 2 7 8 5]] ((juxt first last) (sort m))) |
| 06:43 | clojurebot | [1 8] |
| 06:43 | mmeix | has one of these an advantage? |
| 06:44 | TEttinger | yeah |
| 06:44 | mmeix | (if this would be needed a lot of times) |
| 06:44 | TEttinger | ,(let [m ["the" "quick" "brown" "fox"]] ((juxt first last) (sort m))) |
| 06:44 | clojurebot | ["brown" "the"] |
| 06:44 | TEttinger | min and max are number only |
| 06:44 | mmeix | ah! |
| 06:45 | mmeix | didn't think of that |
| 06:45 | TEttinger | so sort will have better behavior if you need to change it to another comparable type |
| 06:45 | mmeix | in my case I have only numbers |
| 06:45 | justin_smith | we have max-key and min-key |
| 06:45 | justin_smith | (doc max-key) |
| 06:45 | clojurebot | "([k x] [k x y] [k x y & more]); Returns the x for which (k x), a number, is greatest." |
| 06:46 | tvanhens | I'm having some difficulty wrapping my head around how protocols work in the repl. I have a dsl ns that has various records that implement the same protocol in a protocols ns. Then I have another ns called api that checks to see if the records passed into a function satisfy the protocol in the protocols ns but all the inputs are returning false even though when I call type on the inputs they are returning the proper record type which does implement the |
| 06:46 | tvanhens | protocol I am checking for. If I manually evaluate the nses in a different order (dsl first then protocols then api) it works as expected. |
| 06:46 | justin_smith | ,(let [m ["the" "quick" "brown" "fox"]] ((juxt (partial apply max-key count) (partial min-key count)) m)) |
| 06:46 | clojurebot | ["brown" ["the" "quick" "brown" "fox"]] |
| 06:46 | justin_smith | oops |
| 06:47 | justin_smith | ,(let [m ["the" "quick" "brown" "fox"]] ((juxt (partial apply max-key count) (partial apply min-key count)) m)) |
| 06:47 | clojurebot | ["brown" "fox"] |
| 06:47 | mmeix | great stuff! |
| 06:51 | j-pb | ,(let [m ["the" "quick" "brown" "fox"]] (apply (juxt (partial max-key count) (partial min-key count)) m)) |
| 06:51 | clojurebot | ["brown" "fox"] |
| 06:52 | mmeix | juxt as the ultimative extractor |
| 06:53 | mmeix | (learning Clojure is really fun) |
| 06:53 | tvanhens | it appears that for some reason the namespaces are loading in a weird order and the only way I can get around the behavior is to manually evaluate my namespaces in the right order. Whats weirder is that the problem does not occur when I run my program with lein run or run the tests with lein tests |
| 06:54 | tvanhens | it appears that the strange protocol behavior only occurs when I am in the repl |
| 06:54 | TEttinger | what's amazing is that the code in there is practically all function calls with names, and almost all of those are defined in clojure. nothing like in java or C or C++ with for(int i = 0; i < 10; i++) |
| 06:54 | justin_smith | tvanhens: sounds like you are not requiring something you should be? |
| 06:54 | j-pb | ,(let [m ["the" "quick" "brown" "fox"]] (apply (partial (juxt max-key min-key) count) m)) |
| 06:54 | clojurebot | ["brown" "fox"] |
| 06:55 | j-pb | this also works, but at this point my brain stops properly comprehending whu |
| 06:55 | justin_smith | j-pb: ahh, much better |
| 06:55 | justin_smith | heh |
| 06:55 | tvanhens | I think that might be the case justin_smith hard to track it down when the tests are passing |
| 06:55 | justin_smith | tvanhens: it's true I am hard to track down when the tests are passing |
| 06:56 | justin_smith | (I know that's not what you meant) |
| 06:56 | tvanhens | haha :) |
| 06:56 | TEttinger | (inc j-pb) |
| 06:56 | lazybot | ⇒ 1 |
| 06:56 | TEttinger | that's a nice golf solution, j-pb |
| 06:57 | j-pb | TEttinger: got to think about it some more to make sure it's correct though ;) |
| 06:57 | tvanhens | yeah its funky cause the system will start with lein run with no problems. What might cause there to be a discrepency between the two? Its almost as if the repl is using a different protocol even though its the same definition |
| 06:57 | j-pb | because right now, the transformation seems correct, but not really intuitive :D |
| 06:57 | justin_smith | tvanhens: with the repl are you using the same top level namespace that lein run is? |
| 06:57 | mmeix | a bit of brain twister, yes |
| 06:57 | hyPiRion | psst |
| 06:57 | hyPiRion | ,(let [m ["the" "quick" "brown" "fox"]] (apply (juxt max-key min-key) count m)) |
| 06:57 | clojurebot | ["brown" "fox"] |
| 06:58 | hyPiRion | no need for partial there |
| 06:58 | mmeix | wow |
| 06:58 | tvanhens | no. I will try doing that with repl options |
| 06:59 | tvanhens | actually scratch that... it is loading into the same top level namespace |
| 06:59 | justin_smith | another possibility is any classpath differences between your profiles |
| 07:03 | tvanhens | interesting ok so if I restart my repl and then try to eval the user ns or the core test ns I get an error that the records do not satisfy the protocol. However, if I reset my system with stuart sierra (wich uses refresh for ns-es) I can eval either of those two ns-es fine |
| 07:04 | TEttinger | I have a feeling you mean one of stuart sierra's libraries, not the person who often is in here |
| 07:04 | justin_smith | tvanhens: are things being required in the wrong order? |
| 07:05 | justin_smith | TEttinger: he has stuartsierra in another room, when he gets the signal he reloads all the namespaces |
| 07:05 | j-pb | hyPiRion: haha very nice, actually using the apply that way make it quite abit more intuitive :D |
| 07:05 | j-pb | (inc hyPiRion) |
| 07:05 | lazybot | ⇒ 75 |
| 07:05 | tvanhens | haha if only |
| 07:06 | mmeix | [light bulb] re: juxt "The returned fn takes a variable number of args" - that made my day |
| 07:06 | justin_smith | TEttinger: tvanhens also this reminds me I need to make the tests pass on my port of component to cljc so I can share it (it totally works in my dev code so far, using it for a while now) |
| 07:06 | mmeix | thanks guys! |
| 07:06 | tvanhens | yeah it looks like they are getting required in the wrong order but only in development. The only difference in the classpath is adding a user and a utils ns when in dev... must be related to those |
| 07:06 | j-pb | mmeix: yeah, but actually this is what makes them a tad slower :D compared to #(foo %) |
| 07:07 | j-pb | not significantly though |
| 07:07 | j-pb | speaking of which, am I the only one really missing a #` reader macro? that would combine #() and `[] ? |
| 07:07 | tvanhens | justin_smith: that would be great |
| 07:07 | mmeix | so readabilty/understandability wins in this case :D |
| 07:09 | TEttinger | j-pb, so it is anonymous fn syntax that produces a quoted list? |
| 07:09 | TEttinger | err, syntax-quoted |
| 07:10 | j-pb | TEttinger: yeah exactly, the ` syntax quote already produces a set of function call to build the described structures, but you can't use it in a #() form because of the immediate function call |
| 07:10 | TEttinger | ,`'#(+ % %) |
| 07:10 | clojurebot | (quote (fn* [p1__25__26__auto__] (clojure.core/+ p1__25__26__auto__ p1__25__26__auto__))) |
| 07:11 | TEttinger | ,`~'#(+ % %) |
| 07:11 | clojurebot | (fn* [p1__51#] (+ p1__51# p1__51#)) |
| 07:11 | TEttinger | wheeeeeee |
| 07:11 | TEttinger | ,(`~'#(+ % %) 2) |
| 07:11 | clojurebot | #error {\n :cause "clojure.lang.PersistentList cannot be cast to clojure.lang.IFn"\n :via\n [{:type java.lang.ClassCastException\n :message "clojure.lang.PersistentList cannot be cast to clojure.lang.IFn"\n :at [sandbox$eval77 invoke "NO_SOURCE_FILE" 0]}]\n :trace\n [[sandbox$eval77 invoke "NO_SOURCE_FILE" 0]\n [clojure.lang.Compiler eval "Compiler.java" 6792]\n [clojure.lang.Compiler eval "... |
| 07:11 | TEttinger | wowza |
| 07:11 | justin_smith | ,`~`~`~`~'#(constantly nil) |
| 07:11 | clojurebot | (fn* [] (constantly nil)) |
| 07:12 | justin_smith | ,`~`~`~`~`~`~`~`~`~`~`~`~`~'#(constantly nil) |
| 07:12 | clojurebot | (fn* [] (constantly nil)) |
| 07:13 | tvanhens | oy this is annoying. Ok so test-refresh works (which is using the dev profile) lein run works (which is using prod). Starting the repl goes ok. But if I try and run the tests in the test ns without restarting the system... it won't work. Or if I try evaling the user ns. Any other ideas? I guess its pretty simple to workaround but not understanding whats going on is eating at me |
| 07:13 | TEttinger | ,(defmacro whee [anon] `~anon) |
| 07:13 | clojurebot | #'sandbox/whee |
| 07:13 | TEttinger | ,(whee #(+ % %)) |
| 07:13 | clojurebot | #object[sandbox$eval177$fn__178 0x4ae63a85 "sandbox$eval177$fn__178@4ae63a85"] |
| 07:14 | TEttinger | ,((whee #(+ % %)) 2) |
| 07:14 | clojurebot | 4 |
| 07:14 | TEttinger | woo |
| 07:14 | j-pb | hrhr |
| 07:16 | j-pb | but yeah, I find myself quite often in a situation where I would like to map over some data and transform each element to some datasructure, a #` would tremendously help with that |
| 07:17 | justin_smith | j-pb: I still don't see where syntax quote helps build data structures |
| 07:18 | j-pb | justin_smith: when you deal with xml/html trees, variants or maps representing some kind of record it's really usefull |
| 07:19 | j-pb | justin_smith: mostly because of its splicing capabilities |
| 07:19 | j-pb | justin_smith: ~@x is the inverse operation for & x |
| 07:21 | gfredericks | I always thought list* was |
| 07:21 | j-pb | TEttinger: ah sorry I think I missunderstood you, it would be a syntax for producing a function that takes args and returns a datastructure with the arguments embedded at some places |
| 07:22 | crocket | (slurp cat) |
| 07:22 | j-pb | ,(macroexpand '`[:foo %1 %2]) |
| 07:22 | clojurebot | (clojure.core/apply clojure.core/vector (clojure.core/seq (clojure.core/concat (clojure.core/list :foo) (clojure.core/list (quote sandbox/%1)) (clojure.core/list (quote sandbox/%2))))) |
| 07:22 | j-pb | ,(macroexpand '#(`[:foo %1 %2])) |
| 07:22 | clojurebot | (fn* [p1__49# p2__50#] ((clojure.core/apply clojure.core/vector (clojure.core/seq (clojure.core/concat (clojure.core/list :foo) (clojure.core/list (quote p1__49__51__auto__)) (clojure.core/list (quote p2__50__52__auto__))))))) |
| 07:23 | j-pb | while #`[:foo %1 %2] would return basicall y #(clojure.core/apply clojure.core/vector (clojure.core/seq ... |
| 07:24 | mmeix | ( followup question: would something like "(apply (juxt max-key min-key) count ...)" a use case for a transducer? ) |
| 07:25 | mmeix | (potentially a silly question, I fear ...) |
| 07:25 | j-pb | gfredericks: yeah kinda, but that is what syntax quote will just generate, right? manually building the function calls to generate the datastructures is a lot less obvious than syntax quote |
| 07:26 | j-pb | mmeix: could you explain further? |
| 07:26 | gfredericks | j-pb: yeah if it does what you need I guess you may as well use it |
| 07:26 | mmeix | I'm not sure .... sorry .... does (apply (juxt max-key min-key) count m) generate intermediate lists, internally? |
| 07:27 | j-pb | mmeix: no |
| 07:27 | mmeix | ah, ok, then the question was silly :D |
| 07:29 | mmeix | (partial (apply (juxt max-key min-key) count)) could make sense, OTH, maybe ... |
| 07:29 | j-pb | mmeix: well the strings will be cast to a sequence, for count probably, and the apply might turn the input vector to a seq as well |
| 07:29 | j-pb | would have to be (partial apply (juxt max-key min-key) count) |
| 07:29 | mmeix | ok |
| 07:29 | mmeix | ja |
| 07:31 | mmeix | (inc j-pb) |
| 07:31 | lazybot | ⇒ 2 |
| 07:53 | zamaterian | ikitommi_, should I try to implement a pull request for isssue #121 - that moves the validation into a couple of middleware, as described in my comments ? |
| 08:17 | crocket | Ruby map's rehash method terrifies me. |
| 08:17 | crocket | It leads to all sorts of bugs. |
| 08:17 | crocket | Mutation is bad. |
| 08:19 | TEttinger | crocket, if rehash terrifies you, you should see another ruby method, vomit-spiders |
| 08:19 | tdammers | is that like Haskell's hypothetical unsafeLaunchMissiles? |
| 08:19 | TEttinger | hehe |
| 08:21 | TEttinger | vomit-spiders is an interesting function in ruby's standard lib. they don't know when the commit was, but it was before 1970 so the exact time is hard to guess. the comments are in aramaic though. |
| 08:23 | TEttinger | the author's name also appears to be permanently lost, since anyone who claims to have decrypted the thousands-of-characters-sequence speaks in tongues for a while then never speaks again. |
| 08:23 | TEttinger | which is something of a liability to a large software team |
| 08:25 | TEttinger | but it hasn't been removed from the standard lib because Matz has implied that to do so would be very bad if "the stars are not yet right, and the sleeping multitudes have not yet awoken from their dreaming complacency and seen the fire and heard The Screams." |
| 08:25 | crocket | What is vomit-spiders? |
| 08:26 | TEttinger | $google creepypasta |
| 08:26 | lazybot | [Creepypasta] http://www.creepypasta.com/ |
| 08:26 | tbaldridge | ~guards |
| 08:26 | clojurebot | SEIZE HIM! |
| 08:26 | tbaldridge | crocket: do no speak of this again |
| 08:26 | crocket | tbaldridge, this? |
| 08:27 | crocket | I need a clarification of what 'this' refers to. |
| 08:28 | TEttinger | humor |
| 08:30 | crocket | Clojure's data abstractions are as soothing as my aftershave. |
| 08:37 | crocket | Heisenbugs... |
| 08:46 | crocket | In the land of ruby and java, you'll see heisenbugs... |
| 08:54 | crocket | ,(map inc [1 2 3]) |
| 08:54 | clojurebot | (2 3 4) |
| 08:54 | crocket | ,(doc join) |
| 08:54 | clojurebot | Gabh mo leithscéal? |
| 08:56 | crocket | (clojure.string/join ["s" "e" "x"]) |
| 08:56 | crocket | ,(clojure.string/join ["s" "e" "x"]) |
| 08:56 | clojurebot | "sex" |
| 09:19 | crocket | How would you allocate memory on JVM? |
| 09:19 | crocket | Without aggressive GC, I'm not comfortable. |
| 09:28 | profil | why is there no multiple bind version of if-let? sorta like how some-> works |
| 09:31 | crocket | profil, Did you ever need a multiple bind version of if-let? |
| 09:36 | profil | yes, I find it ugly to nest multiple if-lets |
| 09:36 | H4ns | i've also wanted that in the past. |
| 09:36 | hyPiRion | Nesting if-lets won't give the same functionality as having a multiple-bind if-let |
| 09:36 | crocket | profil, Why don't you make one? |
| 09:36 | profil | hyPiRion: what do you mean? some-> threads sequentially when the result is not nil |
| 09:36 | H4ns | just because you can add general language-level to clojure does not necessarily mean that it is a good idea to do so. |
| 09:36 | Empperi | hmm, that sounds more like what "some-let" should be, not multiple binding version of if-let |
| 09:36 | profil | I think scheme has what I want, called and-let |
| 09:36 | Empperi | "bind these expressions into let constants as long as the previous binding ended up into something else than nil, then execute the body with those constants available" |
| 09:36 | Empperi | if I got it right |
| 09:36 | crocket | You should be able to write cond-let. |
| 09:36 | crocket | cond is what you want. |
| 09:36 | profil | Empperi: yes, by using something like (and ~@binds) |
| 09:36 | Empperi | pretty easy to do with some macro magic |
| 09:37 | hyPiRion | profil: (if-let [a b] (if-let [b c] foo bar) baz) is different from (if-let [a b c d] foo baz) |
| 09:37 | profil | crocket: no, I dont care about which one failed |
| 09:37 | profil | hyPiRion: there is no (if-let [a b c d] foo baz) ... |
| 09:37 | chouser | actually, that's interesting. cond-let and and-let both sound plausible but would have different semantics. |
| 09:38 | crocket | profil, What do you want to do? |
| 09:38 | chouser | s/actually,// |
| 09:38 | hyPiRion | profil: the point is, even if there were, multiple-binding if-let wouldn't be the same as nested if-lets |
| 09:38 | Empperi | definitely, but I can see the use case for what I just described above |
| 09:39 | hyPiRion | yeah, sure thing |
| 09:42 | crocket | profil, Can you give us a paste of a minimal nested if-let form? |
| 09:42 | crocket | I may be able to simplify your code. |
| 09:57 | crocket | If you don't care about which one failed, you should nest an if form inside a let form. |
| 09:57 | crocket | This is simpler. |
| 09:58 | H4ns | crocket: it is also not the same thing |
| 09:59 | H4ns | crocket: because when if-let allowed multiple bindings, i would expect it to not evaluate bindings further down as soon as an initialization form returned a false value |
| 09:59 | hyPiRion | (let [a b c (and a d) e (and c f)] (if f foo bar)) |
| 10:00 | crocket | We need to see an actual problem case. |
| 10:00 | H4ns | beautiful |
| 10:00 | chouser | sounds like nested when-let to me |
| 10:00 | hyPiRion | if is probably better to use than and actually. |
| 10:00 | hyPiRion | gives same result, but might be easier to read? idk |
| 10:01 | chouser | ah, you want one else for any falsey. hm. |
| 10:02 | profil | I was thinking of something like "(defmacro and-let [bindings then else] (let [tests (take-nth 2 (rest bindings))] `(if (and ~@tests) (let ~bindings ~then) ~else)))" |
| 10:02 | chouser | yeah, and you want 'if' instead of 'and' |
| 10:02 | Bronsa | if-lets |
| 10:02 | H4ns | profil: nice |
| 10:03 | crocket | https://gist.github.com/pingles/5150585 |
| 10:03 | chouser | profil: good sketch, clarifies things. But runs expressions twice. |
| 10:03 | profil | yeah, I havent tested it |
| 10:04 | crocket | profil, ^^ |
| 10:06 | chouser | very interesting attempts. Even the last one in the comments there copies the else clause multiple times in the expansion, though only runs it once. |
| 10:06 | crocket | Why doesn't clojure already provide a proper let binding for if-let? |
| 10:08 | crocket | I mean multiple local bindings should be available in if-let. |
| 10:09 | hyPiRion | crocket: I believe it's because it's not evident what the evaluation rules would be. Given (if-let [a b c d] foo bar), should c be evaluated if a is falsey? If so, then it's "inconsistent" with all the other binding forms out there. |
| 10:09 | hyPiRion | Er, I meant the opposite |
| 10:10 | crocket | "consistent" |
| 10:10 | hyPiRion | I meant: If c is not evaluated if a is falsey, then it would be inconsistent with the other binding forms |
| 10:11 | chouser | (if (when-let [a b] (when-let [c d] (when-let [e f] ~then))) ~else) |
| 10:11 | chouser | is that it? |
| 10:12 | crocket | That is ugly |
| 10:12 | crocket | difficult to read |
| 10:13 | chouser | Well, I appreciate the input. I was asking if the semantics match what is desired. |
| 10:13 | crocket | chouser, That's what I had in mind. |
| 10:14 | H4ns | chouser: if then returned falsey, else would be evaluated and returned. that's not right. |
| 10:14 | chouser | H4ns: ah, great catch. |
| 10:17 | chouser | ok, so hyPiRion's solution, but with 'if' instead of 'and' looks best so far |
| 10:19 | crocket | nested if-let sounds nasty. |
| 10:19 | H4ns | crocket: if it is only in macroexpansion, what would be wrong with it? |
| 10:19 | crocket | Is this a deal breaker? |
| 10:20 | crocket | H4ns, Can you show me the macro? |
| 10:21 | hyPiRion | crocket: https://gist.github.com/pingles/5150585#comment-981238, was it not? |
| 10:21 | H4ns | crocket: i have not written it because in my opinion, it is not right to add semantics to the language at that level. i do think, though, that it would be the easiest path towards a correct solution. i understand the argument that it would be inconsistent with other clojure binding forms if if-let did not always bind all variables, so i'm okay with not having it. |
| 10:22 | tbaldridge | you aren't really adding semantics, it's adding syntactic sugar. |
| 10:22 | H4ns | tbaldridge: same thing to me. |
| 10:23 | tbaldridge | I'm just saying, don't be afraid to use the features of LISP. They're there for a reason, and used correctly they can offer great power. |
| 10:23 | H4ns | tbaldridge: that kind of stuff always reminds me of "#define BEGIN {" back in the day |
| 10:24 | crocket | That duplicates else multiple times. |
| 10:24 | H4ns | tbaldridge: well yeah right. and in the end, i always prefer conventional code to sugar-coated |
| 10:24 | tbaldridge | suit yourself, but remember, when is a macro implemented in user code (not in the compiler), same with if-let, if-some, and, or, etc. |
| 10:25 | tbaldridge | The compiler only implements about 12 special forms, everything else is syntactic sugar. |
| 10:26 | H4ns | tbaldridge: that is just implementation detail. i don't care about the implementation. all i want is that if i see a common control flow or branching form, i can look into the language manual to see how it works. |
| 10:27 | crocket | I think I'll get back to it later when it becomes a problem. |
| 10:27 | tbaldridge | but that's what (doc 'foo) and (source 'foo) are for. |
| 10:28 | tbaldridge | I mean, if you don't want to use macros, that's fine, but just realize you'll be coding lisp with one hand tied behind your back. |
| 10:28 | H4ns | tbaldridge: i'm using macros all day long, just not to add syntactic sugar for basic language features that i thing should be "better". |
| 10:29 | H4ns | tbaldridge: i think you can stop trying to evangelize me. :) |
| 10:29 | chouser | this channel has a bad influence on my responsible use of time :-P |
| 10:31 | chouser | destructuring forms cause a bit of a problem with hyPiRion's formulation |
| 10:33 | hyPiRion | Oh, I've never thought about destructuring binds in if-lets :o |
| 10:34 | hyPiRion | ,[(if-let [[a b] [nil nil]] 10) (if-let [[a b] nil] 20)] |
| 10:34 | clojurebot | [10 nil] |
| 10:34 | hyPiRion | Hrm, I'm not sure what I expected for the first one. |
| 10:35 | chouser | well, that's how it's always been. I take advantage of that at times |
| 10:35 | chouser | else is only for the *expr* being falsey. Nothing to do with the bound locals. |
| 10:35 | hyPiRion | right |
| 10:36 | chouser | but for multiple-binding-if-let, you can't feed nil to users destructuring forms without risking an exception |
| 10:36 | chouser | ...an exception that they may have been trying to guard against by using if-let :-P |
| 10:37 | chouser | But you can't wait and do the destructuring just before the ~then because of course they may be using the bound locals along the way |
| 10:38 | hyPiRion | I guess (let [g1# b, a g1#, g2# (if g1# d), c g2#] (if g2# then else)) would work |
| 10:38 | hyPiRion | but that looks convoluted |
| 10:38 | chouser | no, that's what I'm saying won't work |
| 10:39 | chouser | if b is nil, c will be fed a nil. |
| 10:39 | chouser | If c is a destructuring form that blows up on nil, you'll get an exception instead of the else |
| 10:40 | hyPiRion | ooh |
| 10:40 | chouser | er, there are destructuring forms that blow up on nil, right? |
| 10:41 | chouser | maybe not. There are destructing forms that blow up, but maybe none with nil. |
| 10:41 | hyPiRion | I think you can if you expect the form to be of some shape |
| 10:42 | hyPiRion | ,(let [{foo :foo bar :bar :or {bar (+ foo 10)}} nil] bar) |
| 10:42 | clojurebot | #error {\n :cause nil\n :via\n [{:type java.lang.NullPointerException\n :message nil\n :at [clojure.lang.Numbers ops "Numbers.java" 1013]}]\n :trace\n [[clojure.lang.Numbers ops "Numbers.java" 1013]\n [clojure.lang.Numbers add "Numbers.java" 128]\n [clojure.lang.Numbers add "Numbers.java" 3644]\n [sandbox$eval54 invoke "NO_SOURCE_FILE" 0]\n [clojure.lang.Compiler eval "Compiler.java" 6792]... |
| 10:42 | hyPiRion | ,(let [{foo :foo bar :bar :or {bar (+ foo 10)}} {:foo 10}] bar) |
| 10:42 | clojurebot | 20 |
| 10:42 | chouser | ah, :or ... excellent |
| 10:43 | hyPiRion | Heh, macros are hard to get right. |
| 10:43 | chouser | trying to expand the else clause exactly once makes this quite tricky |
| 10:44 | chouser | you could wrap it in a function, I suppose. But that loses its tail position in the containing form. sheesh |
| 10:46 | chouser | Maybe mutating a local flag is the best way. Huh. |
| 10:57 | phillord | I'm just trying nightcode out and it seems to be sending my system load through the roof...anyone else had the same experience |
| 11:01 | gfredericks | I wrote a basic test.check property testing carmine message queues and immediately ran into a connection pooling quasi-bug https://github.com/ptaoussanis/carmine/issues/135 |
| 11:01 | gfredericks | (inc test.check) |
| 11:01 | lazybot | ⇒ 1 |
| 12:07 | mikerod | I'm struggling to remember what puredanger blog is now |
| 12:07 | mikerod | something like "inside a clj developer" - my google searching is failing |
| 12:10 | mikerod | http://insideclojure.org/ |
| 12:10 | mikerod | got it |
| 12:15 | CookedGryphon | Hey, I want to download zip files in my application from multiple end points, with associated names and version numbers... this sounds a lot like artifact dependency management. Does anyone know if there's a light weight artifact download/cache management client library that I could bundle with my app? |
| 12:18 | dfletcher | https://github.com/cemerick/pomegranate CookedGryphon maybe? |
| 12:18 | dfletcher | morning all |
| 12:19 | alexyakushev | Does anyone have suggestions how to use gen-class in tests? |
| 12:20 | tbaldridge | I don't know that you can, gen-class requires AOT compilation, don't think that works with most test suites |
| 12:23 | alexyakushev | tbaldridge: That's what I thought. I'm trying to run compile step before testing now, let's see if it works |
| 12:24 | mikerod | Does anyone know of a good post anywhere that compares operations on Clojure transients to some mutable Java types - like Arraylist and then even primitive arrays? |
| 12:24 | mikerod | I was doing some microbenches locally with criterium and not getting the expected results (transients were faster) |
| 12:24 | mikerod | just doing something basic like, conj'ing up a vector |
| 12:25 | mikerod | with longs |
| 12:25 | tbaldridge | what java collection were you using/ |
| 12:25 | tbaldridge | ? |
| 12:25 | tbaldridge | nvm, just read what you said |
| 12:25 | mikerod | I tried PersistentVector vs transient PersistentVector vs ArrayList vs Primitive array |
| 12:25 | mikerod | I'm thinking I'm just writing something stupid, but I was hoping to find some solid resource online |
| 12:25 | mikerod | where someone already gives a good rundown |
| 12:25 | tbaldridge | some code would be good |
| 12:26 | mikerod | I'll get some up shortly to demo |
| 12:26 | tbaldridge | It could just come down to default sizes of things in Java. transient vectors allocate data in chunks of 32. So it might be possible that ArrayList is using something different |
| 12:28 | tbaldridge | Also, array lists must copy all contents every time they resize, while vectors allocate in chunks and don't copy old chunks when creating new. ] |
| 12:28 | tbaldridge | So there's a lot of things here that could cause what you're seeing |
| 12:48 | franklnrs | when using reagent, is it idiomatic to keep the complete app state in a single atom and have event handlers do deeply nested update-ins? |
| 12:50 | dnolen | franklnrs: you should probably direct your question to #clojurescript |
| 12:51 | franklnrs | ah yes, will do |
| 12:51 | dnolen | franklnrs: Reagent supports both dividing up your state into multiple ratoms and an Om style single atom + cursors. |
| 12:51 | justin_smith | franklnrs: I don't think you would need "nested update-ins" - one update-in with a deep nesting of keys maybe... |
| 12:52 | justin_smith | unless I misunderstand you here |
| 12:52 | franklnrs | and things won't be rerendered multiple times when they depend on multiple ratoms? |
| 12:53 | franklnrs | justin_smith, you're right, update-in with deep nesting of keys |
| 13:10 | mikerod | tbaldridge: thanks for the input |
| 13:10 | mikerod | sorry, I had to step away a few. I have https://www.refheap.com/102091 |
| 13:10 | mikerod | there is a good chance I just did something wrong in the loop-recur examples, but I don't see where the issue would be |
| 13:11 | mikerod | I was also surprised peek-pop traversal of the vector wasn't as fast as first-next - but not completely relevant |
| 13:12 | tbaldridge | mikerod: they're slow because you're using first/next to access the vector |
| 13:13 | tbaldridge | your first two examples are using the .reduce method on the input vector, this will always be much faster, as it doesn't allocate lazy-seq cells. |
| 13:14 | tbaldridge | mikerod: your first two examples eventually call this method: https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/PersistentVector.java#L328 |
| 13:14 | tbaldridge | that'll be much faster than first & next |
| 13:15 | tbaldridge | So I'd recommend refactoring the ArrayList example to use reduce. Keep the array list in the accumulator, and call .add on it with each item given to you. |
| 13:19 | dysfun | when i deploy an uberjar to my server and java -jar, i get an error saying my core class cannot be found. i've just looked inside the jar and there are AOT versions and the clojure source as well. the named main class is correct. any ideas? |
| 13:20 | dysfun | it's built with leiningen |
| 13:21 | hiredman | dysfun: is the main class specified in the manifest? |
| 13:23 | dysfun | yes, Main-Class is correct in the manifest |
| 13:24 | hiredman | and what happens if you run java -cp your.jar your.main.Class |
| 13:25 | dysfun | "Could not find the main class: my.app. Program will exit" |
| 13:25 | hiredman | how sure are you that the class exists in the jar? |
| 13:26 | dysfun | zip -Tv | grep -v warning | less |
| 13:26 | dysfun | er + the jar filename |
| 13:26 | hiredman | (zgrep) |
| 13:26 | dysfun | ooh, handy |
| 13:26 | hiredman | first thing to do is to blow away target or classes for lein to make sure nothing stale is in there |
| 13:27 | dysfun | there isn't anything stale because i don't have leiningen on the target machine |
| 13:27 | hiredman | dysfun: on the build machine |
| 13:28 | dysfun | okay, it'll take a minute to build and push |
| 13:28 | hiredman | the class reported in the "could not find the main class" error exactly matches your main class? |
| 13:28 | dysfun | okay, now i get "Warning: The Main-Class specified does not exist within the jar. It may not be executable as expected. A gen-class directive may be missing in the namespace which contains the main method. |
| 13:29 | hiredman | there you go |
| 13:30 | dysfun | right, so i've got :main ^:skip-aot my.app and :profiles {:uberjar {:aot []}} |
| 13:31 | dysfun | if i don't disable aot, i get build errors |
| 13:31 | dysfun | i think it's to do with running clojure-1.7.0-beta3 |
| 13:31 | justin_smith | dysfun: my usual approach is to either use clojure.core as my main (supplying my ns as an arg) or make a very tiny namespace that implements the right magic for jsvc, and use require at runtime, plus resolve, to invoke my stuff dynamically after loading |
| 13:31 | hiredman | well, like, fix your build |
| 13:32 | dysfun | hrm, i could require at runtime, that could work |
| 13:32 | justin_smith | that avoids the issues that come with aot |
| 13:32 | hiredman | your build just sounds broken, I would wipe as much as possible from your project.clj and get it working from a clean slate |
| 13:32 | dysfun | while fixing it all would be lovely, i've already spent ages fiddling with toolchain |
| 13:33 | dysfun | i suppose i probably don't need clojure 1.7 any more now i stopped using the latest clojurescript |
| 13:37 | mikerod | tbaldridge: I thought so, but I'm not exaclty sure what my alternatives are |
| 13:38 | mikerod | tbaldridge: oh ok |
| 13:38 | mikerod | I didn't see your second post |
| 13:38 | mikerod | I was skeptical of the first/next stuff |
| 13:41 | mikerod | tbaldridge: I also tried iterating over an ArrayList.get() instead of a PersistentVector |
| 13:41 | mikerod | It still looked like transients win |
| 13:42 | tbaldridge | mikerod: the accessing is muddling your results I think. Perhaps just rewrite them all to use a loop with a counter instead of (vec (range ...)) |
| 13:42 | mikerod | https://www.refheap.com/102093 |
| 13:43 | mikerod | tbaldridge: good point |
| 13:43 | tbaldridge | Then you're not "complecting" the testing of access with creation. |
| 13:43 | mikerod | I figured thesse were just sloppy comparisons |
| 13:43 | mikerod | threw it together quick to try to gauge when it really matters if you are using a mutable Java collection vs transient vs persistent immutable |
| 13:44 | mikerod | Then I started searching around online and didn't find anything too illuminating out there |
| 13:44 | dysfun | justin_smith: brilliant, i used a dynamic require and it works great. thanks! |
| 13:44 | mikerod | beyond transients outperforming their persistent counterparts - but I wanted to also try again Java mutation |
| 13:44 | mikerod | Java-style* |
| 13:47 | tbaldridge | mikerod: dnolen has done some tests showing that transients outperform arrays on JS platforms, but no I haven't seen similar benchmarks on the JVM |
| 13:48 | tbaldridge | perhaps that's just because collections are much more tunable on the JVM. |
| 13:48 | dnolen | tbaldridge: well JS arrays are really analagous ArrayList not fixed dimension arrays |
| 13:49 | dnolen | so it's not surprising that transients wins, they don't have to resize as much |
| 13:50 | mikerod | dnolen: I have some experiments against Java primitive arrays too |
| 13:50 | tbaldridge | right, but on the JVM "faster" would probably depend on your needs and what JVM collections you used |
| 13:50 | mikerod | I still keep "winning" with transients |
| 13:50 | mikerod | seems a bit impossible to me |
| 13:50 | mikerod | so I figure I have something wrong still |
| 13:51 | mikerod | I've also tried starting the ArrayList at the correct, final size. speeds it up slightly, but transient still wins |
| 13:51 | mikerod | tbaldridge: https://www.refheap.com/102094 |
| 13:51 | mikerod | I think I'm keeping the pattern of access consistent here |
| 13:55 | tbaldridge | some things are different however. The latter one is doing boxed math on the i value |
| 14:28 | Bruce_Wayne | I am having trouble implementing re-com in one of my re-frame projects. Does anyone have re-com working? |
| 14:34 | Bruce_Wayne | looking to integrate this library: |
| 14:34 | Bruce_Wayne | https://github.com/Day8/re-com |
| 14:35 | dnolen | Bruce_Wayne: question more likely to be answered in #clojurescript |
| 14:35 | Bruce_Wayne | thank you! |
| 15:06 | whodidthis | emacs prelude seems cool but does anyone know where to start if im still not getting pairing ) added when typing (, my modes are(?) Clojure Projectile Pre |
| 15:07 | justin_smith | whodidthis: paredit is the mode that does that, also things like prelude are best to ditch as early as you can |
| 15:08 | justin_smith | because emacs has standard ways to manage libraries and installation, and using some hacked-up preset setup makes actually managing your own install harder, not easier, in the long run |
| 15:10 | pbx | justin_smith, i'm glad to hear you say that because i've had a hard time reconciling such setups with my regular but non-leet use of emacs. |
| 15:11 | luxbock | I started out using emacs-starter-kit, then I moved only the things I was actually using to my own setup, but now I eventually switched over to using Spacemacs, which is even more monolithic than Prelude is |
| 15:11 | stuartsierra | Most pre-built Emacs set-ups I've seen give you too many new things to learn at once. |
| 15:11 | luxbock | and I'm a pretty big fan of it |
| 15:11 | brainproxy | justin_smith: I have had nothing but success with prelude over several years and zero friction working with the standard mechanisms for libs and installations |
| 15:11 | luxbock | stuff breaks sometimes when I upgrade to the newest develop branch, but overall I really like having actively thought out and developed power user UI |
| 15:11 | tbaldridge | emacs-starter-kit was rather recently removed. It's now just a list of packages with instructions on how to do it yourself. Big fan of that now |
| 15:11 | brainproxy | prelude, ultra highly recommended in my book, but i realize opinions vary on this subject |
| 15:12 | stuartsierra | tbaldridge: glad to hear it |
| 15:12 | tbaldridge | They did a good job of walking through what each package does, and why you may or may not need it. |
| 15:13 | brainproxy | btw, I merge my fork with prelude's master branch almost every day (i.e. if there are changes) and in the several years I've been using it, only twice has that resulted in a problem requiring me to git reset |
| 15:13 | brainproxy | which is a testament to bbatsov's care in making sure that prelude is rock-solid |
| 15:13 | luxbock | the difference between now and when I was using the starter-kit before is that now that I've mostly wrapped my head around Emacs and can code in elisp then I can usually figure out pretty fast what broke and how when I upgrade |
| 15:15 | brainproxy | also, check out smartparens, an alternative to paredit, actively maintained |
| 15:15 | whodidthis | maybe ill do starter-kit instead, seems like a good idea |
| 15:16 | brainproxy | whodidthis: going back to your original question, it may be that smartparents isn't enabled |
| 15:16 | brainproxy | which is what prelude favors over paredit |
| 15:17 | brainproxy | did you copy the prelude-modules.el file from prelude/sample into ~/.emacs.d and uncomment the line for 'prelude-clojure? |
| 15:25 | whodidthis | sounds pretty crucial actually heh, thanks |
| 15:25 | brainproxy | sure thing |
| 15:25 | whodidthis | ill try prelude again after testing this starter-kit |
| 15:25 | brainproxy | sure |
| 15:35 | justin_smith | one of the complexities introduced by prelude is instead of emacs help, you now need prelude help |
| 15:37 | brainproxy | could be; I first started with it and Emacs in late 2011, when prelude was just getting its start as well; the newbie experience w/ prelude in 2015 may be different than mine, i will admit that :-) |
| 15:37 | brainproxy | I mainly remember spending time with plain old emacs help and fumbling around looking at prelude source ot understand what was giong on |
| 15:37 | brainproxy | *to |
| 15:45 | sdegutis | i too do not use prelude |
| 15:46 | sdegutis | i tried to make that rhyme but i didnt have the time |
| 15:51 | brainproxy | i guess my "bigger picture" view would be that a framework or starter kit that tends to hinder one's understanding and personal development of the Emacs environment is ultimately unhelpful; that hasn't been my experience with prelude, but it could affect others that way, i guess; i haven't worked with other kits, so can't really comment on them |
| 15:52 | sdegutis | bbl deadline |
| 15:54 | brainproxy | a general recommendation would be to study the source of one's kit of choice and understand what it's doing for you; then, move away from it or morph it into an environment that truly serves your needs |
| 16:30 | mikerod | is there any sane way to search through google groups along with sort topics by time etc? I search for these topics online and don't get much help. I feel I'm always struggling to try and use google groups to look through the clj stuff and find what I want. |
| 16:30 | mikerod | am I just crazy? |
| 16:31 | hiredman | nope, google groups kind of suck |
| 16:43 | aaelony | hiredman: agree |
| 16:47 | mikerod | hiredman: good to know |
| 16:59 | mikerod | http://dev.clojure.org/jira/browse/CLJ-1224 was bumped from major to critical recently |
| 16:59 | mikerod | I was hoping that also meant, bumped to 1.7 release instead :P |
| 16:59 | mikerod | but I think I'm too hopefully |
| 17:00 | mikerod | however, critical does sound like a "big deal" |
| 17:03 | xemdetia | does jira have blocker like bugzilla |
| 17:03 | xemdetia | or does critical already mean escalated to the mooooon |
| 17:12 | fredfe | Will slamhound remove unused (:require)'d items? |
| 17:15 | mikerod | fredfe: I doubt it |
| 17:15 | mikerod | that's a hard problem too |
| 17:15 | mikerod | unused requires sounds very difficult to determine to me |
| 17:15 | mikerod | which does bother me about Clojure semantics with loading |
| 17:15 | fredfe | Funny, I'd think discovering missing items would be a bigger accomplishment lol |
| 17:15 | mikerod | :require can cause a namespace to be loaded and compiled for the first time. This processing can have arbitrary environmental side-effects |
| 17:16 | mikerod | 1) define global vars 2) define protocols 3) extend protocols to types 4) create new Classes dynamically etc |
| 17:17 | arohner | mikerod: 5) run arbitrary clojure expressions at top-level |
| 17:17 | mikerod | So my point is, how do you know what an "unused" require is? If it was transitively already loaded by another namespace, that may be ok, but then you're relying on implicit dependencies of your own dependencies, which is a bad practice. |
| 17:18 | mikerod | arohner: yeah, I was enumerating common ones. yes, it can certainly just do anything in the world of side effects. |
| 17:18 | mikerod | this makes :require management tough from my experience |
| 17:18 | fredfe | Makes sense |
| 17:18 | mikerod | in larger libraries |
| 17:18 | mikerod | I often review people's code and see that they do not specify :require's that they should |
| 17:19 | mikerod | because it just happens to transitively be compiled for them |
| 17:19 | hiredman | :( |
| 17:19 | hiredman | people are terrible |
| 17:19 | mikerod | Which is unreliable because it can change out from underneath and break your stuff. Typical transitive dependency issues like from Maven. |
| 17:19 | arohner | mikerod: I have a habit of only using aliased namespaces, to prevent that |
| 17:20 | mikerod | arohner: yes, I like aliasing a LOT |
| 17:20 | arohner | (:require [foo.bar :as bar]), then only ever use bar/ |
| 17:20 | mikerod | I get scared when people use fully-qualified symbols - which obviously should be rare |
| 17:20 | mikerod | but also, if you depend on some protocol extensions from another namespace. that can get messy. |
| 17:21 | mikerod | I'm not saying all of this is "best practice" or anything though. I just see it come up often enough. |
| 17:21 | mikerod | or you make some defrecords somewhere else |
| 17:21 | mikerod | then people do an :import [my.other.ns RecType] |
| 17:21 | mikerod | but they don't do a :require on [my.other.ns] |
| 17:21 | jarjar_prime | hello :) |
| 17:22 | mikerod | hello world! |
| 17:22 | jarjar_prime | is there a way to set lein deploy to use uberjar instead of the smaller one? |
| 17:24 | hiredman | you don't want that |
| 17:25 | jarjar_prime | hiredman: I'm using that to drop into artifactory (maven) and then pull that into a dockerfile |
| 17:29 | fredfe | Has anyone used Jenkins with clojure? Is this how it works: Job #1 Pull project from remote git and run tests (lein test--how to capture test results?) ---> Job #2 Run `lein ring uberjar` and Publish over SSH. But what is used to keep some jar versions in case I need to perform an arbitrary number of rollbacks? |
| 17:31 | hiredman | fredfe: jenkins can archive builds |
| 17:31 | hiredman | fredfe: at work we just have jenkins capture the stdout of test runs and of course the pass/fail of the lein test run |
| 17:32 | hiredman | we publish built artifacts to s3 |
| 17:32 | hiredman | the path on s3 as the version, so we have builds are archived on jenkins, but also on s3 |
| 18:11 | andyf | fredfe: mikerod: Eastwood linter can determine when :use or :require'd namespace is not used within a namespace, modulo some bugs where it might not report correctly. |
| 18:11 | andyf | lein eastwood "{:add-linters [:unused-namespaces]}" https://github.com/jonase/eastwood#unused-namespaces |
| 18:14 | mikerod | andyf: how can it know that you aren't relying on the :require for load-compile side-effects? |
| 18:14 | mikerod | I know that eastwood is powerful in terms of detecting symbol references |
| 18:14 | mikerod | given that (I believe) it uses tools.analyzer to get the AST "big picture" |
| 18:16 | andyf | mikerod: I'm not sure what kind of examples you have in mind, but it does some magic, and not other magic :) |
| 18:16 | andyf | basically if you :require or :use a namespace, but do not reference any Vars def'd in that namespace, you get a warning that the namespace is unused. |
| 18:16 | andyf | It can be fooled, I am sure. |
| 18:18 | mikerod | andyf: having a :require to get the side effect of extend-protocol, extend-type, extend, etc |
| 18:18 | mikerod | that's the most obvious one |
| 18:18 | mikerod | I'm guessing that is bad practice, but it has came up quite a bit from what I've seen. |
| 18:19 | mikerod | And as long as it can detect references to deftype'ed classes, that would eliminate my biggest other concern. |
| 18:20 | mikerod | But don't get me wrong, I think eastwood is a great project. I was just more ranting over how :require can be tied to side-effects and makes it tricky. |
| 18:21 | mikerod | I see a lot of people coming from Java that think of it as like :import - but it is a lot different to that. It potentially does a lot of things, import is just sugar |
| 18:24 | arohner | crazy idea of the day, I don't suppose it's possible to pass data from one nrepl to another? |
| 18:25 | andyf | Clojure is surprisingly mutable in terms of definitions of things and loading code, and I agree that makes some things tricky. |
| 18:25 | mikerod | arohner: if it is in a "pure" data form you should be able to copy/paste? |
| 18:25 | arohner | mikerod: yeah, but I'm thinking of a lot of data |
| 18:25 | mikerod | andyf: yes, that is the part I'm not a huge fan of... Perhaps it is inevitable though. |
| 18:25 | mikerod | arohner: pr it to a file |
| 18:25 | mikerod | read it from the file from the other process |
| 18:26 | andyf | If you treat Eastwood as "sometimes finds bugs I didn't find using other methods, but sometimes doesn't, and sometimes gives false warnings", i.e. like every other lint tool I've seen, then it might help you. |
| 18:26 | mikerod | edn, if you don't trust it. |
| 18:26 | mikerod | andyf: I think that is a good way to put it. And I think eastwood can reveal a ton of things that are very helpful. |
| 18:27 | mikerod | On the topic of mutable environmental stuff, it looked like https://github.com/mikera/kiss |
| 18:27 | mikerod | Tried to address this with "Immutable environments " I was very interested to see where that was going |
| 18:28 | mikerod | "immutable all the things" |
| 18:31 | andyf | mikerod: You can ask mikera to see if anyone has enhanced it since his proposal, but I think the status is something like "you can patch your own local copies of Clojure all you like, subject to the license". Core team probably doesn't consider it anywhere near high priority for including in the standard distribution. |
| 18:35 | Drick | http://i.imgur.com/cbOGiI8.jpg |
| 18:39 | m1dnight_ | Is there any way to make this fail: (if-let [{a :a} {:b 1}] (println "foo") (println "bar")) |
| 18:39 | m1dnight_ | Id hate to write an if test and only destructure in a nested let |
| 18:39 | m1dnight_ | (in the acutal use case {:b 1} would be a call to a function) |
| 18:40 | m1dnight_ | oh no nvm i was confused for a sec, carry on |
| 18:48 | mikerod | andyf: yes, I figured. I was just intrigued by the concept. |
| 18:54 | reilly3000 | anybody know of updates to arcadia since clojure/west? |
| 19:00 | Drick | {`} |
| 19:36 | jjttjj | i have a list of heavily nested maps containing things of many types. im trying to end up with a human readable list of every type that appears in the thing. I've been trying to use postwalk to just amass keep conjing an atom but think i might be on the wrong track... is there a way to only deal with leaf nodes? |
| 19:39 | hiredman | ,(doc tree-seq) |
| 19:40 | clojurebot | "([branch? children root]); Returns a lazy sequence of the nodes in a tree, via a depth-first walk. branch? must be a fn of one arg that returns true if passed a node that can have children (but may not). children must be a fn of one arg that returns a sequence of the children. Will only be called on nodes for which branch? returns true. Root is the root node of the tree." |
| 19:40 | jjttjj | hiredman: perfect, thanks! |
| 20:10 | crocket | http://dpaste.com/3KYMW8W |
| 20:11 | crocket | How do I consolidate "else2" and "else1" on http://dpaste.com/3KYMW8W ? |
| 20:12 | crocket | I want "else1" to be evaluated and returned if the innermost if-let form's binding evaluates to false. |
| 20:12 | crocket | Does anyone have any idea? |
| 20:13 | justin_smith | (let [a "3" b "4"] (if (and a b) "then" "else1") |
| 20:13 | justin_smith | if "4" should not be evaluated if "3" was nil, then that can be handled also |
| 20:14 | justin_smith | (let [a "3" b (when a "4")] (if b "then" "else1") |
| 20:14 | justin_smith | if a is nil, b will be nil, guaranteed |
| 20:14 | crocket | justin_smith, People are not going to write that by hand. |
| 20:15 | justin_smith | I write code like that by hand |
| 20:15 | crocket | ouch |
| 20:15 | justin_smith | you can use cond |
| 20:15 | crocket | There is no cond-let. |
| 20:16 | justin_smith | sure, the let thing is a convenience, and it's not available for multiple bindings in any useful way |
| 20:16 | crocket | I'm looking for something like (if-let [[result1 result2] (map-all not-nil? ["1" nil])] (+ result1 result2)) |
| 20:17 | justin_smith | doesn't work though |
| 20:17 | justin_smith | it isn't there |
| 20:17 | crocket | What isn't? |
| 20:17 | justin_smith | that version of if-let does not do what you want |
| 20:17 | justin_smith | *that usage |
| 20:17 | justin_smith | destructuring + if-let = bugs |
| 20:17 | amalloy | welllll |
| 20:17 | crocket | That's just a wtf. |
| 20:18 | justin_smith | ,(if-let [[a b] [nil nil]] "OK") |
| 20:18 | clojurebot | "OK" |
| 20:18 | justin_smith | crocket: that's just how it works |
| 20:18 | amalloy | it's a bit more nuanced than that, as i'm sure justin_smith knows. you can destructure with if-let as long as you know what is going on |
| 20:18 | crocket | ,(if-let [[a b] nil] "ok" "no") |
| 20:18 | clojurebot | "no" |
| 20:18 | justin_smith | amalloy: right, but what I am saying is that the semantics he wants do not exist in the core language |
| 20:19 | amalloy | justin_smith: i'm just taking issue with "destructuring + if-let = bugs" |
| 20:19 | crocket | justin_smith, ^^ |
| 20:19 | justin_smith | sure, yeah, that was overstating it |
| 20:19 | amalloy | everything else you're saying i've only glanced at but is probably spot-on |
| 20:19 | crocket | ,(if-let [[a b] nil] "ok" "no") |
| 20:19 | clojurebot | "no" |
| 20:19 | justin_smith | yes, I saw that the first time |
| 20:19 | justin_smith | but that doesn't do what you want |
| 20:20 | crocket | A hypothetical function map-all should return nil if any element evaluates to nil. |
| 20:20 | justin_smith | ,(if-let [[a b] ()] "OK") |
| 20:20 | clojurebot | "OK" |
| 20:20 | justin_smith | so even if you remove nil, it still doesn't do what you want |
| 20:20 | justin_smith | OK |
| 20:22 | crocket | (if-let [[a b] (reduce (fn [vec el] blahblah....) (map identity ["1" nil]))] "ok" "no") |
| 20:22 | crocket | Ok, this is becoming complex... |
| 20:22 | crocket | I need to write a macro. |
| 20:22 | justin_smith | crocket: to me that is much more complex than using when / and |
| 20:24 | crocket | Without (when-let), you have to evaluate something again and bind it to a local binding. |
| 20:24 | crocket | Thus, it leads to double evaluation. |
| 20:24 | justin_smith | crocket: not in the version I proposed |
| 20:24 | crocket | justin_smith, Show me your code |
| 20:24 | justin_smith | (let [a (f) b (and a (g))] (if b (h)) |
| 20:24 | justin_smith | no double eval |
| 20:25 | crocket | justin_smith, What if you have to do that for 7 bindings? |
| 20:25 | justin_smith | and (g) is not invoked if (f) was nil |
| 20:25 | crocket | What if you have to do that for 7-8 bindings repeatedly? |
| 20:25 | justin_smith | crocket: then a macro that checks the prior at each step |
| 20:25 | amalloy | crocket: if you need to bind 7 separate things to distinct local variables your function is probably a bit lacking in purpose anyway |
| 20:26 | crocket | amalloy, 'probably' is not enough. |
| 20:26 | amalloy | crocket: the language provides you with the tools to do whatever wacky things you want. there's no "not enough" you can say about the core language, unless it makes something important impossible |
| 20:27 | crocket | I meant 'probably' didn't convince me. |
| 20:27 | justin_smith | ,(let [vaues [a b nil]] (if-not (some nil? values) "OK")) ; something like this? |
| 20:27 | clojurebot | #error {\n :cause "Unable to resolve symbol: a in this context"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.RuntimeException: Unable to resolve symbol: a in this context, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyze "Compiler.java" 6543]}\n {:type java.lang.RuntimeException\n :message "Unable to resolve symbol: a in this context"\n ... |
| 20:27 | justin_smith | ,(let [vaues [:a :b nil]] (if-not (some nil? values) "OK")) ; something like this, I meant |
| 20:27 | clojurebot | #error {\n :cause "Unable to resolve symbol: values in this context"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.RuntimeException: Unable to resolve symbol: values in this context, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyze "Compiler.java" 6543]}\n {:type java.lang.RuntimeException\n :message "Unable to resolve symbol: values in t... |
| 20:28 | justin_smith | ,(let [values [:a :b nil]] (if-not (some nil? values) "OK")) ; should have tested it first |
| 20:28 | clojurebot | nil |
| 20:30 | crocket | ,(if-let [will-you-dance-with-me nil] "ok" nil) |
| 20:30 | clojurebot | nil |
| 20:30 | crocket | ,(doc if-not) |
| 20:30 | clojurebot | "([test then] [test then else]); Evaluates test. If logical false, evaluates and returns then expr, otherwise else expr, if supplied, else nil." |
| 20:31 | crocket | justin_smith, That ends up evaluating every binding. |
| 20:31 | crocket | I wonder if a lazy sequence could be used for preventing evaluation. |
| 20:32 | justin_smith | as long as you watch out for chunking |
| 20:32 | crocket | ouch |
| 20:32 | crocket | chunks of 32 items |
| 20:32 | justin_smith | but, eg lists are not chunked |
| 20:32 | justin_smith | so you could use a list of functions |
| 20:32 | justin_smith | but a reduce might make more sense unless you have another reason to want laziness |
| 20:33 | justin_smith | with a reduced case if any return nil |
| 20:34 | justin_smith | (reduce (fn [results f] (if-let [r (f)] (conj results r) (reduced nil))) [] [f g h ...]) |
| 20:34 | crocket | justin_smith, That's very hard to read. |
| 20:34 | crocket | Can you use dpaste.com ? |
| 20:34 | justin_smith | one moment |
| 20:35 | justin_smith | https://www.refheap.com/102103 |
| 20:37 | crocket | I never knew about reduced. |
| 20:37 | justin_smith | it makes reduce at least twice as useful I think |
| 20:38 | crocket | Does reduced terminate reduce right away? |
| 20:38 | justin_smith | yes |
| 20:38 | crocket | Or, does reduce consume a sequence until the end? |
| 20:38 | justin_smith | ,(reduce (fn [a n] (if (> n 10) a (+ n a)) 0 (range)) |
| 20:38 | clojurebot | #<RuntimeException java.lang.RuntimeException: EOF while reading> |
| 20:39 | crocket | ,(doc range) |
| 20:39 | clojurebot | "([] [end] [start end] [start end step]); Returns a lazy seq of nums from start (inclusive) to end (exclusive), by step, where start defaults to 0, step to 1, and end to infinity. When step is equal to 0, returns an infinite sequence of start. When start is equal to end, returns empty list." |
| 20:40 | crocket | ,(take 10 (range)) |
| 20:40 | clojurebot | (0 1 2 3 4 ...) |
| 20:40 | justin_smith | ,(reduce (fn [a n] (if (> n 10) (reduced a) (+ n a))) 0 (range)) |
| 20:40 | clojurebot | 55 |
| 20:40 | justin_smith | range returns an indefinite sequence - so (range) won't return for a while if eagerly consumed |
| 20:40 | crocket | How does clojure catch that? |
| 20:40 | justin_smith | catch which? |
| 20:41 | crocket | How does clojure catch an infinite evaluation? |
| 20:41 | justin_smith | it generally just lets it happen, but clojurebot has print-level and print-length set up to avoid indefinite printing, which with something lazy, prevents indefinite forcing |
| 20:42 | justin_smith | ,(reduce + (range)) |
| 20:42 | clojurebot | eval service is offline |
| 20:42 | justin_smith | that's because it timed out, of course |
| 20:43 | crocket | I wish clojure caught infinite loops. |
| 21:06 | wei | interesting puzzle for you all: I want to walk a nested vector and build up an array of indices. e.g. (indices [1 [1 [1 1]]]) => [[0] [1 0] [1 1 0] [1 1 1]] |
| 21:07 | gfredericks | ,(defn indices [v] (map-indexed (fn [i x] (if (vector? x) (map #(cons i (indices %)) x) (list i))) v)) |
| 21:07 | clojurebot | #'sandbox/indices |
| 21:07 | gfredericks | ,(indices [1 [1 [1 1]]]) |
| 21:07 | clojurebot | #<IllegalArgumentException java.lang.IllegalArgumentException: Don't know how to create ISeq from: java.lang.Long> |
| 21:08 | gfredericks | ,(defn indices [v] (map-indexed (fn [i x] (if (vector? x) (map #(cons i %) (indices x)) (list i))) v)) |
| 21:08 | clojurebot | #'sandbox/indices |
| 21:08 | gfredericks | ,(indices [1 [1 [1 1]]]) |
| 21:08 | clojurebot | ((0) ((1 0) (1 (1 0) (1 1)))) |
| 21:08 | gfredericks | ,(defn indices [v] (apply concat (map-indexed (fn [i x] (if (vector? x) (map #(cons i %) (indices x)) (list i))) v))) |
| 21:08 | clojurebot | #'sandbox/indices |
| 21:08 | gfredericks | ,(indices [1 [1 [1 1]]]) |
| 21:08 | clojurebot | #<IllegalArgumentException java.lang.IllegalArgumentException: Don't know how to create ISeq from: java.lang.Long> |
| 21:08 | gfredericks | poopsiedoodle |
| 21:09 | gfredericks | ,(defn indices [v] (apply concat (map-indexed (fn [i x] (if (vector? x) (map #(cons i %) (indices x)) [[i]])) v))) |
| 21:09 | clojurebot | #'sandbox/indices |
| 21:09 | gfredericks | poopsiedoodle |
| 21:09 | gfredericks | whoops false poopsiedoodle, meant to scrollback farther |
| 21:09 | gfredericks | ,(indices [1 [1 [1 1]]]) |
| 21:09 | clojurebot | ([0] (1 0) (1 1 0) (1 1 1)) |
| 21:10 | gfredericks | phew okay there we go |
| 21:10 | gfredericks | wei: ^ |
| 21:12 | wei | nice!! |
| 21:13 | wei | (inc gfredericks) |
| 21:13 | lazybot | ⇒ 139 |
| 21:14 | gfredericks | hoo ray a prime |
| 21:16 | wei | wish there was a mapv-indexed |
| 21:31 | crocket | http://dpaste.com/36F19FE generates an error. |
| 21:31 | crocket | How can I fix it? |
| 21:50 | crocket | How do I make a macro call itself safely? |
| 21:57 | crocket | I created the first working prototype of if-let-all. http://dpaste.com/0S2VYM5 |
| 21:57 | crocket | Yay |
| 22:00 | crocket | Can anyone evaluate if-let-all? |
| 22:02 | gfredericks | crocket: I found a bug |
| 22:02 | crocket | What is it? |
| 22:02 | gfredericks | (if-let-all [x (seq ())] :true-case :false-case) |
| 22:02 | crocket | Why is it a bug? |
| 22:02 | gfredericks | ,(if-let [x (seq ())] :true-case :false-case) |
| 22:03 | clojurebot | :false-case |
| 22:03 | crocket | oops |
| 22:03 | gfredericks | this is a common macro pitfall |
| 22:03 | gfredericks | you're preforming your logic on the forms at compile-time |
| 22:04 | gfredericks | (coll-or-nil only runs once when you're compiling the macro call) |
| 22:07 | crocket | hmm... |
| 22:07 | crocket | I think coll-or-nil should evaluate... |
| 22:08 | crocket | gfredericks, How about http://dpaste.com/3B45AFB ? |
| 22:08 | crocket | (eval f) fixes the bug. |
| 22:08 | gfredericks | and that's the next pitfall :) |
| 22:08 | crocket | What is it? |
| 22:08 | gfredericks | using eval to fix the first pitfall |
| 22:08 | gfredericks | here's the next bug |
| 22:09 | gfredericks | (let [a ()] (if-let-all [x (seq a)] :true-case :false-case)) |
| 22:09 | crocket | ,(let [a ()] (if-let [x (seq a)] :true-case :false-case)) |
| 22:09 | clojurebot | :false-case |
| 22:10 | hasket | What are people's opinion on haskell vs clojure for web dev |
| 22:10 | hasket | (backend) |
| 22:10 | crocket | gfredericks, Do you know a solution? |
| 22:10 | crocket | hasket, Why don't you try them? |
| 22:11 | crocket | For web development, both languages are far superior to ruby, java, and python. |
| 22:11 | gfredericks | crocket: you need to be doing the logic at runtime, not compile time; to do that you need to emit code that does the logic |
| 22:11 | gfredericks | crocket: I'd play with macroexpand-1 |
| 22:11 | gfredericks | that might give more insight into where things aren't working |
| 22:12 | hasket | I know Haskell quite well. I'm just curious as to what clojure has to offer (I know it's an amazing language and I've played around with it a bit, but not extensively). |
| 22:12 | crocket | macroexpand-1 doesn't help me with (let [a ()] (if-let-all [x (seq a)] :true-case :false-case)) |
| 22:12 | crocket | hasket, One word, ClojureScript. |
| 22:12 | crocket | Clojure & ClojureScript |
| 22:12 | gfredericks | crocket: you can macroexpand just the if-let-all part |
| 22:13 | hasket | crocket, yeah I've tried GHCJS and it's a pain in the butt to install and keep track of dependencies |
| 22:13 | hasket | lein seems to work much better than cabal |
| 22:14 | hasket | But I'm in love with Haskell's type system is the issue. Does clojure provide any kind of type safety? Or some assurance of safety? |
| 22:14 | crocket | hasket, You can use PureScript. |
| 22:14 | crocket | hasket, clojure has different ways of ensuring interface integrity than haskell.... |
| 22:15 | skeuomorf | hasket: https://github.com/clojure/core.typed |
| 22:15 | crocket | That being said, haskell is better at checking compile time errors. |
| 22:16 | hasket | crocket, yeah that's what it seems like, but I'm fascinated by the language also. I love functional programming. One of my favorite things about haskell is that you can write out the types, then if you don't know the type of something should be in your code, you can leave a hole and haskell will figure out relevant types in scope and tell you what type the hole has. What drew you to clojure? I love the talk "simple made easy" which brought me |
| 22:16 | hasket | here :) |
| 22:17 | crocket | hasket, It's simple. |
| 22:17 | crocket | It's concise. |
| 22:18 | hasket | Cool, I'm gonna learn it. I love learning new languages anyways so it's not even necessarily about trying to do anything with it rather than the beauty of the language itself (at least for me). Clojure looks like an elegant language |
| 22:19 | hasket | And compiling with ghc and cabal in haskell can be a pain in the butt |
| 22:22 | crocket | gfredericks, How do you make if-let-all work? |
| 22:22 | crocket | It seems I can't evaluate values in if-let-all. |
| 22:23 | crocket | Because values are defined outside the scope. |
| 22:23 | gfredericks | crocket: your macro shouldn't be evaluating them |
| 22:23 | gfredericks | macros are about rewriting the code |
| 22:23 | crocket | gfredericks, Does it mean I have to duplicate the else clause as many times as bindings? |
| 22:23 | gfredericks | no |
| 22:23 | crocket | The use of (if-let) leads to multiple instances of the same else clause. |
| 22:24 | gfredericks | but you have coll-or-nil |
| 22:24 | gfredericks | so you can write this with only one if-let |
| 22:24 | crocket | ???? |
| 22:25 | crocket | gfredericks, I thought about nesting if-let. |
| 22:25 | crocket | If you nest if-let forms, you'll get multiple else clauses. |
| 22:26 | gfredericks | (if-let [[a b c] (coll-or-nill [x y z])] true-case false-case) |
| 22:26 | gfredericks | ^ you want to write it that way, right? |
| 22:26 | crocket | Yes, I did |
| 22:26 | gfredericks | so your macro needs to emit code that looks like that |
| 22:26 | gfredericks | the macro does *not* need to call coll-or-nil itself |
| 22:26 | crocket | ok |
| 22:27 | gfredericks | in your original code it does, because of the unquoting |
| 22:27 | gfredericks | ~(coll-or-nil values) |
| 22:27 | clojurebot | I don't understand. |
| 22:27 | crocket | good |
| 22:27 | crocket | gfredericks, Does it mean I have to expose coll-or-nil? |
| 22:27 | gfredericks | you mean make it not-private? |
| 22:27 | crocket | Yes |
| 22:28 | crocket | I wanted to make it private. |
| 22:28 | crocket | with defn- |
| 22:28 | gfredericks | you cannot do that easily |
| 22:28 | crocket | I should probably inline coll-or-nil in if-let-all. |
| 22:29 | gfredericks | btw if you're going to be using this for serious stuff you might want to think about the fact that your current approach doesn't short-circuit -- it will evaluate all of the "values" no matter which ones are nil |
| 22:29 | gfredericks | you also can't use previous values in the later expressions |
| 22:33 | gfredericks | crocket: http://www.infoq.com/presentations/macros-clojure-west-2013 |
| 22:37 | crocket | gfredericks, Does anyone have a better version of if-let-all? |
| 22:39 | gfredericks | prismatic/plumbing and flatland/useful are a couple places to check |
| 22:39 | gfredericks | I don't often find myself wanting it so I'm not sure |
| 22:42 | gfredericks | if I had to write it I'd probably use a function or a sentinel to avoid the repeated else clause problem |
| 22:42 | tstout | What are the scope rules of a namespace? For example, can a single file define multiple namespaces? Can multiple files contribute to the same namespace? |
| 22:42 | gfredericks | (and so still use nested if-lets) |
| 22:42 | gfredericks | tstout: there aren't rules about that, only conventions |
| 22:42 | gfredericks | tstout: one-to-one is the convention, and there are probably a lot of tools that assume it |
| 23:03 | crocket | By the way, when-let doesn't have else clause problem. |
| 23:07 | gfredericks | when-let doesn't have an else at all |
| 23:08 | figoe | Something weird |
| 23:08 | figoe | user=> (into {} (list (vector :a 3))) => {:a 3} |
| 23:08 | figoe | user=> (into {} (list (list :a 3))) => ClassCastException clojure.lang.Keyword cannot be cast to java.util.Map$Entry clojure.lang.ATransientMap.conj (ATransientMap.java:44) |
| 23:09 | figoe | Any ideas? :) |
| 23:09 | gfredericks | figoe: it's a little weird but that's how it works |
| 23:10 | gfredericks | pairs for maps have to be vectors |
| 23:10 | figoe | Yes, just got bitten by ... heh |
| 23:10 | figoe | Guess I gotta do a walk to convert the nested structure to vector or some way |
| 23:11 | crocket | gfredericks, When do you use if you want something like if-let-all? |
| 23:14 | crocket | When -> What |
| 23:16 | gfredericks | crocket: I think I rarely need more than two clauses and so I just tolerate a bit of repetition |
| 23:16 | mbuf | in the "Language of the System" talk, it was mentioned that Clojure has the notion of system namespace. Are there any examples to illustrate this? |
| 23:17 | andyf | tstout: I'm a little late in answering, but Clojure's require and use determine the source file name to read based upon the namespace name, and check that the namespace has been defined after loading the file. You could define additional namespaces in that same file with other namespace names, but you could not require or use those namespaces successfully from that file. |
| 23:17 | gfredericks | mbuf: I can't remember him saying that nor can guess what it means; any further context? |
| 23:17 | mbuf | gfredericks, like the use of namespaces in datomic with zookeeper and riak |
| 23:18 | gfredericks | mbuf: still nothing, sorry :/ |
| 23:18 | crocket | I guess people haven't needed to use a lot of bindings in if-let. |
| 23:18 | gfredericks | crocket: I'll write one up in a minute |
| 23:19 | andyf | crocket: A multiple-binding if-let has been asked about multiple times over the last few years on the Clojure Google group. Different people have written different variants of it as macros. |
| 23:22 | ToBeReplaced | seems like too much control-flow to put into the language itself... i think i like that you need to define your own so that you have to decide the semantics you want |
| 23:23 | ToBeReplaced | and the "if all of these bindings are non-nil then do this else that" version is very easy to write and a good exercise if you haven't written a binding macro before |
| 23:23 | mbuf | gfredericks, https://www.youtube.com/watch?v=ROor6_NGIWU 36:00 - 37:30 |
| 23:26 | gfredericks | mbuf: I'm can't listen to noise atm, sorry |
| 23:27 | mbuf | gfredericks, okay |
| 23:27 | cfleming | gfredericks: I'm going to tell Rich you said that |
| 23:28 | gfredericks | cfleming: no no! don't tell him! oh god |
| 23:28 | gfredericks | I didn't mean that kind of noise |
| 23:28 | gfredericks | oh no |
| 23:28 | cfleming | That was an even better reaction than I was hoping for |
| 23:29 | gfredericks | now he's never going to accept my patch for CLJ-1237 |
| 23:30 | cfleming | That does look like it would have been difficult to debug |
| 23:30 | gfredericks | and then it happened to my teammate a year later! |
| 23:41 | gfredericks | crocket: give this a try https://www.refheap.com/102107 |
| 23:42 | crocket | Jesus |
| 23:45 | crocket | gfredericks, Is it better to call recur instead of self in self? |
| 23:45 | gfredericks | crocket: it's impossible |
| 23:45 | gfredericks | it's not a tail call |
| 23:45 | crocket | impossible? |
| 23:46 | gfredericks | if you try it you'll get a compile error |
| 23:46 | crocket | I don't know what self does. |
| 23:46 | gfredericks | that's just a name I gave the function |
| 23:47 | gfredericks | or you mean what that function does |
| 23:47 | gfredericks | it sets up (if-let [a x] (if-let [b y] (if-let [c z] [a b c]))) |
| 23:47 | gfredericks | which gives you short-circuiting and visibility of previous results |
| 23:48 | crocket | What is short-circuiting? |
| 23:49 | gfredericks | if x is falsy it won't evaluate y or z |
| 23:53 | crocket | gfredericks, (if-let-all [a 2 b 2] "ok" no") is translated to something like (let [temp [a b]] (if temp (let [[a b] temp] "ok") "no")) |
| 23:54 | gfredericks | crocket: that approach doesn't give you short-circuiting |
| 23:54 | crocket | Whut |
| 23:54 | crocket | gfredericks, I used https://www.refheap.com/102107 |
| 23:58 | gfredericks | when I expand it I get (if-let [[a b] (if-let [a 2] (if-let [b 2] [a b]))] "ok" "no") |
| 23:58 | gfredericks | which is short-circuiting |
| 23:59 | gfredericks | you can try (if-let-all [a (do (println "a") nil) b (do (println "b") 2)] "ok" "no") to test out short-circuiting properties |