#clojure log - Mar 23 2015

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

0:02 ben_vulpes: ahahaha

0:02 i very definitely wired a figwheel server into the reloaded/component/system flow.

0:02 yussss.

1:46 Seylerius: How d'you recurse an anonymous function?

1:47 TEttinger: Seylerius: give it a name. ##((fn rec [n] (if (> n 5) n (rec (inc n)))) 0)

1:47 lazybot: ⇒ 6

1:48 Seylerius: Why the ##?

1:48 TEttinger: fn allows names for this exact purpose

1:48 just telling lazybot to eval

1:48 Seylerius: Shiny

1:48 TEttinger: ((fn rec [n] (if (> n 5) n (rec (inc n)))) 0)

1:48 is the actual snippet

1:50 Seylerius: Awesome, thanks.

1:51 Wow, my internet really slows down in the rain...

1:52 TEttinger: satellite internet?

1:52 or cellular of some kind?

1:52 Seylerius: Wireless. 802.11n over TDMA, essentially, broadcast from a tower at the head of the lake.

1:53 TEttinger: how far does this reach? wow

1: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:56 lazybot: ⇒ #<sandbox6330$eval45317$flatify__45318 sandbox6330$eval45317$flatify__45318@271546bb>

1:56 Seylerius: Wait...

1:56 Forgot to make it do something.

1:56 ##((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])

1:56 lazybot: ⇒ (4 1 2 3)

1:56 Seylerius: Hrm.

1:57 Ahah.

1:58 ##((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])

1:58 lazybot: ⇒ (1 2 3 4)

1:58 Seylerius: ^_^

1:59 TEttinger: Seylerius, is this for 4clojure?

1:59 ~flatten

1:59 Seylerius: It is.

1: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.

1:59 Seylerius: Flatten is in fact the task.

1:59 TEttinger: that's a good solution though

2:00 Seylerius: Thanks.

2: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)]))))))

2:01 clojurebot: #'sandbox/flatify

2:02 TEttinger: ,(flatify [:a :b {:a 0 :b #{1 2 3}}])

2:02 clojurebot: (:a :b :a 0 :b ...)

2:02 TEttinger: ,(flatify [:a { :b #{1 2 3}}])

2:02 clojurebot: (:a :b 1 3 2)

2:02 TEttinger: nice!

2:03 Seylerius: I'm a little prone to over-engineering things, but I prefer the fully generalized solution where possible.

2:04 amalloy: Seylerius: flatten is a lot easier to implement with mapcat than with loop/recur

2:04 Seylerius: amalloy: I'll take a look at mapcat.

2:04 Hmm... Interesting.

2:05 amalloy: ,((fn flatify [x] (if (coll? x) (mapcat flatify x) [x])) '[1 2 [3 [4] 5] [6 (7)]])

2:05 clojurebot: (1 2 3 4 5 ...)

2:05 Seylerius: Nice.

2:17 ##((fn [string] (apply str (re-seq #"[A-Z]" string))) "HeLlO, WoRlD!")

2:17 lazybot: ⇒ "HLOWRD"

2: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?

2:34 amalloy: Seylerius: close enough. lazybot also evals lines starting with &, and allows ##'(expressions) to appear mid-sentence

2:34 lazybot: ⇒ (expressions)

2:34 Seylerius: Neat.

2:34 And lazybot discards, while clojurebot doesn't?

2:35 amalloy: well, "discards". lazybot doesn't allow definitions

2:36 clojurebot evals more or less anything, and throws away the whole VM every 15 minutes or so

2:37 Seylerius: Gotcha. Shiny.

2:38 What about the ,(inc amalloy) stuff? That get discarded?

2:38 Or is that maintained separately?

2:38 amalloy: Seylerius: it's a separate thing. not really clojure at all, just a regex that matches something like (inc|dec username)

2:39 Seylerius: Right.

2:39 amalloy: (inc Seylerius)

2:39 lazybot: ⇒ 1

2:39 Seylerius: (inc amalloy)

2:39 lazybot: ⇒ 240

2:39 Seylerius: For answering all these damn questions.

2:51 vas: can i upsert enumerated types in datomic?

3:36 dstockton: how would i get the metadata for a var defined in another namespace?

3:39 dysfun: dstockton: (meta #'namespace/var)

3:39 dstockton: dysfun: so i'd have to know the symbol of the var in that namespace

3:40 its actually a fn argument, so in my current namespace has a completely different var

3:40 dysfun: if you don't manually attach metadata, it's attached to a symbol

3:40 er to a var, sorry

3:40 not to a value

3:40 dstockton: yeah, i guess i'll have to rethink what im doing then

3: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

3:41 dstockton: im building some widgets, wanted to add configuration data to the component fns

3:41 dysfun: yes, perhaps start by explaining what you're trying to do :)

3:41 dstockton: like {::required true}

3:41 dysfun: widgets could be any number of things. could you be a little more specific?

3:41 dstockton: om component fns

3:41 dysfun: oh right

3:41 dstockton: its actually cljs

3:42 dysfun: you probably want a macro to make it tidy

3:42 or put the component in a datastructure with meta information

3:43 dstockton: still not sure where i'd stick the metadata to make it more tidy, so that i could reference it later

3:43 i could wrap them in another map i suppose

3:43 dysfun: a code example might help. http://refheap.com/

3:47 dstockton: boils down to something like this https://www.refheap.com/98788

3:49 dysfun: hrm, it looks alright

3:49 i don't have an om project in a state i could test it, mind

3:51 but i'm guessing you're adding tracking tags heh

3:54 dstockton: meta is just nil, i guess because widget is a completely different var to the original definition

3:55 dysfun: oh i see

3:56 that's because the function 'component' has metadata, not the value you're checking

3:56 however, you can use with-meta to wrap meta on the result

3:56 however, i bet if you (meta #'component), you should see it

3:59 dstockton: probably dysfun, but i don't know the var's name inside some-fn

3:59 it would be #'widget (wouldnt work)

3:59 dysfun: ,(meta (with-meta :foo {:bar :baz}))

3: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] ...

4:00 dysfun: or similar. you get the idea

4:00 dstockton: so wrap the defn in a with-meta?

4:00 dysfun: no, wrap the code inside the defn in with-meta

4:00 dstockton: aha

4:01 dysfun: although you may just want to create a custom record for it

4:01 (that implements IRender)

4:01 that way you can attach whatever information you like

4:03 dstockton: dysfun: great, that works

4:03 dysfun: thinking about it, that's how i'd play it

4:03 dstockton: feels kind of hacky but could clean it up with a custom record like u say

4:04 so i end up having to call it like (meta (widget))

4:05 dysfun: no

4:05 you don't need the metadata now

4:05 they'll just be fields in the record

4:06 dstockton: oh, i see what you mean

4:06 dysfun: (defrecord foo [name] om/IRender (render [_

4:06 ...)

4:07 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

4:07 dstockton: usually the records are created on the fly with reify

4:08 dysfun: yes. there's no need to do it that way

4:10 dstockton: ok, thanks for the advice, think im on the right track now

4:11 dysfun: yw

4: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

4:23 how can i fix this?

4:26 TEttinger: at java.io.WinNTFileSystem.canonicalize0 (WinNTFileSystem.java:-2

4:27 that -2 is a little crazy

4:28 so it thinks you're in an unsafe to delete directory, apparently https://github.com/technomancy/leiningen/blob/master/src/leiningen/clean.clj#L69

4:32 noncom: also, another symptom is that lein deps can't find clojars or maven repo and update the deps..

4:33 neither UAC nor firewall are enabled on this machine.. hmm, strange thing

4:37 stain: noncom: http proxy settings?

4:37 oh hang on.. on the file system!

4:38 noncom: stain: well, lein suggested that too, but no, no proxying here..

4:38 stain: noncom: and you are not running two builds at the same time, right?

4:38 noncom: yeah, i have no builds running, since it cannot even fetch the deps

4:38 stain: how did you do the git clone?

4:39 from another local repository, or from the network?

4:39 noncom: it was hg clone.. but i did this from eclipse + ccw, fetching from bitbucket.org

4:39 i did not have this problem before..

4:39 stain: ok, I know this is silly.. but try shutting down Eclipse

4:40 this is Windows - which has very eager file and directory locking

4:40 noncom: i shut it down, but it is still the same. also, eclipse was never an issue before..

4:41 stain: https://github.com/stain/jdk8u/blob/master/src/windows/classes/java/io/WinNTFileSystem.java#L428

4: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

4:42 stain: and https://github.com/stain/jdk8u/blob/master/src/windows/native/java/io/WinNTFileSystem_md.c#L243

4:43 have your project.clj got any hard-coded paths in it?

4:44 noncom: not really.. besides, it just wokred on two other machines just yeaterday..

4: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

4:47 dysfun: that cut off at 'lacks co'

4:47 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'

4:48 4clojure is a good way to learn

4:48 pkug: oh sorry - but it lacks comments, what could you guys suggest in addition?

4:48 thanks

4:49 dysfun: i'd recommend picking a project and building it. we can point you in the right direction once you've decided

4: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.

4: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)

4: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

4:51 lazybot: Message saved.

4:52 dysfun: stain, pkug: i was disappointed by the first edition, fwiw

4:52 i tried to learn clojure out of it

4: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"

4: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.

4:53 stain: the O'Reilly one I haven't read

4:53 http://www.clojurebook.com/

4:53 it's a bit old now

4:54 dysfun: pkug: okay. well most of that is data structure manipulation. which means list comprehensions and conditionals in python, yes?

4:54 TEttinger: clojure's definitely a good pick for graph-type algos

4:54 dysfun: in clojure, most everything boils down to mapping and reducing data structures

4:55 TEttinger: yep. map, reduce, some filter in there, and plenty of delicious anonymous fns

4: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:)

4:55 stain: and with the lazy sequences you can often do "the naive thing" and still run it quite efficiently

4:56 ane: i started learning clojure just by getting my hands dirty with a project

4:56 dysfun: pkug: well you find yourself not using mutation, that's a good start

4: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

4:56 dysfun: anyway, ultimately everything boils down to composing a bunch of simple higher order functions

4:56 anything involving data structures, anyway

4:56 stain: ane: me2, started with a mini-webserver for something trivial with a fair bit of data structure manipulation

4:57 dysfun: and then once you've written it, you can look at how to tidy it up

4:57 and suddenly the code is half the size and you're like "wow, lisp is cool"

4:57 stain: and then you go a bit overkill for a few months

4: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)

4:57 stain: "I can generate a function that generates that metafunction!"

4:58 kungi: How would you convert a BufferedInputStream to a String?

4:58 Is there some magic helper function?

4:58 dysfun: you can read from the stream. eg. slurp

4:58 though that might not take a stream, i don't remember

4:58 ,(doc slurp)

4: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."

4:59 Empperi: slurp can eat a stream

4:59 stain: don't forget that character set..

4: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

5:00 kungi: dysfun: \o/ thank you

5:00 dysfun: clojure tends to score quite well on code golf because the standard library is very pragmatic

5:00 TEttinger: J is unbelievably terse, but it's pretty much write-once, read-never

5:00 stain: :encoding "UTF-8" is probably what you need

5:00 Empperi: yeah, I suggest using that too

5:01 :encoding that is

5: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)

5:02 e.g. an InputStream from a network or file location

5:02 and perhaps a bit of Windows

5: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

5:02 &(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)"."])))

5: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

5:03 TEttinger: do not attempt to understand it

5:03 it was shrunk repeatedly to fit in one IRC message

5:03 it makes use of a ton of really neat clojure-only features though

5:04 it treats strings as sequences of characters so it can split them into single-char sequences, two-char sequences, and 3-char sequences

5:04 it makes use of map with two collections of different length, which terminates when it reaches the shorter length

5:06 stain: TEttinger: oh my, that made Klingon!

5:06 TEttinger: haha

5:06 I have a bunch of these generators

5:07 stain: you have just insulted my mother, I shall have to honour her and kill you

5:07 TEttinger: they're really fun to write, it's a real challenge to make them small enough to fit in ~400 chars

5:08 a much cleaner, longer version of a similar program that generates planet names and trims swears from the list: http://ideone.com/zwnFAL

5: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 ?

5:09 TEttinger: absolutely. it's very difficult to write clojure without paren matching at least when you highlight a paren

5:09 which thankfully everything a step past notepad can do

5:09 dysfun: also rainbow parens

5: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

5:10 Cursive is an IntelliJ IDEA plugin or something like that, not sure of the exact term

5: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

5:11 TEttinger: actually even lein repl provides paren matching, since version 1.0 I think

5:11 also tab completion

5:11 dysfun: both have been in there a while

5: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

5:12 dysfun: dunno. assuming people do packages like emacs, you probably need rainbow-parens separately

5: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

5:12 ane: vim isn't as smart about lisps as other editors

5:12 oddcully: pkug: fireplace works like a charm for my beginner needs

5:14 ane: cider and clj-refactor make emacs a really nice clojure environment

5: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

5: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 "%"

5:17 ane: plus you can get vim inside emacs anyway :P

5:19 stain: ane: nooooooooo!

5: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*)

5:23 clyfe: help https://gist.github.com/clyfe/1ffe4a8857d40f00e789

5:23 stain: Atom with vim and clojure mode is also kind-of OK

5:50 ane: oddcully: it does not run an instance, it provides a vimlike modal interface to edition. it's called evil-mode

5:52 oddcully: and it is about ten thousand times better than the intellij emulation

5:56 oddcully: ane: (* 0 10000) ;P

5:58 ane: heh

6:03 dysfun: just found ^:unsynchronized-mutable. is that documented anywhere?

6:06 mpenet: dysfun: in deftype probably

6:07 ,(doc deftype)

6: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...

6:07 mpenet: well :]

6:08 dysfun: heh

6:09 mpenet: it's jvm specific btw, cljs has :mutable I think

7:54 m1dnight_: guys, for some dark reason leiningen takes ages to compile. Instead of like half a minute it takes about 1-2 minutes.

7:54 Any way to debug this?

7:54 it's very small project with maybe 5 files.

7:55 or could it be due to dependencies?

7:56 TEttinger: m1dnight_, have you tried https://github.com/technomancy/grenchman

7:56 hyPiRion: m1dnight_: `lein version` runs fine?

7:57 m1dnight_: ill try soon, code is still compiling :/

7:58 hyPiRion: that works fine, yes

7:58 Leiningen 2.5.1 on Java 1.7.0_75 OpenJDK 64-Bit Server VM

7:58 borkdude: is is possible in clojure to indent long string literals nicely like in other languages, like Scala?

7:59 hyPiRion: m1dnight_: and if you do `lein compile` now, how long does it take? Still as long?

7:59 It might be that you had to AOT compile the dependencies too

7:59 m1dnight_: strange, that completes rather quick

8:00 weird, now a simple lein run executes perfectly

8:00 hyPiRion: hm

8:01 m1dnight_: lein clean && lein run seems to run fine now

8:01 strang

8:01 lets blame cosmic noise

8:01 hyPiRion: yeah, dang those cosmic rays

8:02 borkdude: lein was probably submitting privacy sensitive usage statistics

8:02 m1dnight_: :D

8:03 TEttinger: borkdude, since s-expressions don't have a concept of indentation, I'm not so sure that's a good idea

8:08 dstockton: borkdude: maybe just break it up with str over many lines?

8: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.

8:27 anyone?

8: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 ..."

8: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?)

8:30 whodidthis: https://github.com/amdt/vim-niji this should work just by installing

8:31 spinningarrow: TEttinger: makes sense - thanks!

8:31 whodidthis: checking it out now

8:32 oddcully: spinningarrow: i have not used it. but puttin the toggle into a ~/.vim/ftplugin/clojure.vim might work?

8:32 TEttinger: (inc whodidthis)

8:32 lazybot: ⇒ 1

8:38 profil: spinningarrow: you can put it into an augroup with autocmd, thats how I do it

8:38 spinningarrow: https://github.com/profil/dotvim/blob/master/vimrc#L81

8:38 spinningarrow: oddcully: that didn't work for some reason

8:40 whodidthis: spinningarrow: add "filetype plugin on

8:40 to .vimrc

8:40 borkdude: dstockton that's a good one

8:40 spinningarrow: profil: that worked like a charm

8:40 thanks!

8:43 profil: np :)

8:43 whodidthis: man, clj-refactor seems amazeing, i wish i had an actual com puter to use emacs on

8: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?

8:46 Glenjamin: (doc add-watch)

8: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

8:47 profil: Glenjamin: ahh, nice thanks

8:49 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

8:49 spinningarrow: whodidthis: I ended up going with vim-niji (no setup required!) cheers :D

8:55 Larva_: Will Clojure be compatible with PAIP book http://norvig.com/paip.html ?

9:00 dnolen: Larva_: PAIP is written on Common Lisp, so not compatible. But translation to Clojure should be relatively straightforward.

9:00 Larva_: but that assumes you're willing to learn enough Common Lisp & Clojure to do that

9:01 Larva_: dnolen : so it is possible after all?!

9:02 dnolen: Larva_: I don't see why not

9:02 Larva_: dnolen : oh very well, Ta!

9: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?

9:09 maybe there is a library for that?

9:10 dnolen: noncom: you probably want to use something like Stuart Sierra's component

9:11 noncom: dnolen: cool, from reading the intro i think this is it

9: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

9: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 oops

10:20 tcrayford____: don't use win32 kids, it kills

10:21 gfredericks: justin_smith: better change your passwords

10:21 ,(def password " /win 22")

10:21 clojurebot: #'sandbox/password

10:21 justin_smith: haha

10:22 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 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 ,(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 never mind!

10:42 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 ,(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 woah, TIL for the IBM 1401 computer, there was an extra rental fee to access specific hardware instructions

11:00 I'm glad that hasn't come back

11:00 gfredericks: IBM 1401 Pro

11:01 justin_smith: freemium CPU

11:01 "sorry, your computer is too slow to run this app. But for a small monthly fee you could get SMID instructions."

11:02 SIMD I mean

11:02 "single multiple instruction data" would sure be useful

11:04 "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 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 xemdetia: it was believable. I mean we have hardware level codecs for mp3 / mp4

11:13 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 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 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 so that i can program while biking

11:29 for long distances

11:39 ,(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 at least you didn't do anything embarrassing

11:41 noncom: :)

11:42 thank you, yes :)

11:44 justin_smith: can i make clojurebot to print on several lines?

11:44 ,(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 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 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 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 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 pretty simple, then

11:51 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 well, maybe not, but that's what i'm going with

11:54 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 Lets say I have a (def routes []) hanging around

12:16 What's the best way to handle this inside my add-route macro?

12:16 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 this is about how I would create one

12:17 justin_smith: then it depends on how you implement your routing

12:17 I would forget the "macro" part for now. Implement the functionality. Macros are for syntax, not functionality.

12:18 acron^: Ok

12:18 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 "foo" => foo-func, "bar" => some-other-func

12:20 My routes are trivially always defined as a single string

12:24 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 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 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 I tried the thread-stopper as an alternative, but it's not found in my repl

12:51 aha, found it!

12:51 (Thread/interrupted)

12:51 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 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 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 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 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 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 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 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 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 ,(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 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 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 i get a ClassNotFoundException when i remove that requirement

14:42 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 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 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 so ` would qualify it incorrectly

14:47 what's odd to me is that it doesn't require test.check

14:47 but i see, it does the require at runtime

14:47 justin_smith: oh wait, yeah, that is weird

14:47 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 there's a comment in the file about it

14:59 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 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 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 I'll work on that later today

15:06 justin_smith: mavbozo: I just let it use its default

15:06 I do nothing super fancy

15:06 gfredericks: numberten: ^

15:07 numberten: hm?

15:07 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 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 :dependencies [[org.clojure/tools.nrepl "0.2.7"]]}}

15:55 and yet when I run lein repl

15:55 I get

15:55 pandeiro: mavbozo: thanks; do you include the creation of database/role in the migrations?

15:55 catern: put tools.nrepl in :dev dependencies

15:56 catern: http://sprunge.us/JcbZ

15:56 why

15:56 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 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 catern: same issue

15:58 amalloy: lein probably inserts its own nrepl version into your project

15:58 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 catern: what happens if you run it in an actual project?

15:58 I think lein-without-a-project can have weird degradations like this

15:59 catern: :(

15:59 now it uses 0.2.7

15:59 but this is dumb

15:59 I just have a single .clj file that I want to do use with CIDER

15:59 for a few calculations

15:59 gfredericks: er, ^

16:00 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 can I just like, delete 0.2.7

16:05 er, 0.2.6

16:05 from somewhere

16:05 to force it to use 0.2.7

16:05 except I already did this, deleting it from .m2

16:05 and it had no effect

16:05 gfredericks: well I should hope not

16:06 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 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 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 is where it is hard-coded

16:09 but anyhow the part about it not coming back to .m2 is a lot harder to believe

16:09 gonna try it myself

16:10 catern: specifically I deleted /home/catern/.m2/repository/org/clojure/tools.nrepl/0.2.6

16:11 and it hasn't come back

16:11 gfredericks: yep mine redownloaded

16:11 that's what I deleted too

16:12 so that's super weird but maybe not your original problem

16:12 kaplan: What dies reify dio?

16:12 *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 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 does it have any obvious performance problems or infinite loops?

16:17 (sim) is taking a while to terminate...

16:18 (sometimes)

16:18 (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 or 1000

16:19 still

16:19 kaplan: ok patrickgombert , thanks

16:19 catern: 1000 is not a lot

16:19 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 catern: i think it actually takes quite a bit longer than that

16:25 i just tried starting with $90 instead of $300, and the first four calls to (count (sim)) returned: (542 26 1190)

16:26 so the mean is low but the variance is very high

16:28 anyway, tldr your problem is with math, not with clojure

16:30 catern: amalloy: uhhhhhh

16:31 oh!

16:31 whoops!

16:31 I think I have the conditional the wrong way around :)

16:32 thanks amalloy

16:32 incidentally

16:32 I'm kind of curious

16:33 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 huh

16:34 okay

16:35 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 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 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 (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 that's why I say, just use map

16:51 aperiodic: yup

16:55 catern: okay

16:55 I have another elegance question

16:56 (def sims (take numsims (repeatedly sim)))

16:56 (def num_temporarily_rich (count (filter pos? (map (fn [sim] (count (filter #(> % 1000) sim))) sims))))

16:56 ;; this finds the number of simulations where at some point the balance is over 1000

16:56 could I make this nicer?

16:57 (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 oh

17:01 filter seq?

17:01 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 i guess that's just done with (for)

17:03 catern: okay, it now looks like:

17:03 (def num_temporarily_rich (->> sims (map (fn [sim] (filter #(> % 1000) sim))) (remove empty) count))

17:03 ;

17:03 Glenjamin: (for [s sims

17:03 catern: (yuck, for)

17:04 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 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 oh right, sorry

17:05 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 bensu: oh, derp

17:07 hmm

17:07 battle it out

17:07 which is better, (filter seq) or (remove empty?) :D

17:07 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 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 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 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 Can you recommend me some coursers which learn me how to think in Clojure and how to solve problems?

17:15 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 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 kwladyka: it uses racket lang which is quite similar to clojure, esp the immutability

17:20 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 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 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 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 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 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 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 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 (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 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 hiredman: I think you have mistaken me for someone else.

18:27 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 Yes, I am that new

18:30 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 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 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 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 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 I throw (def foo foo) somewhere in there

18:54 and then run the code

18:54 and boom I have a global handle to it

18:54 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 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 ,(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 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 so i actually have a list of maps with that structure

19:03 [{: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 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 #array

19:09 TEttinger: ugggggggh reiterated

19:09 is there a reader literal for arrays?

19:10 turbofail: hm, that'd be a nice touch

19:10 #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 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 I suppose it could still try to print arrays with #array and just not have a default reader though

19:22 #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 drop everything

19:24 turbofail: i'm still considering taking amtrak to portland though

19:25 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 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 I'm used to southern california being in constant drought, so seeing *green*

19:31 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 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 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 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 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 ,(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 ,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 ,(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 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 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 kludgecode: this also might work: https://github.com/clojure/data.priority-map

20:22 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 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 ...estimates were staying the same. I didn't know this until this discussion, only that things weren't working.

20:33 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 *cite

20:35 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 (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 ugh, "estimage"

20:43 ,(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 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 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 justin_smith: Sorry; looked good from my end :-) Did that work?

21:01 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 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 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 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 i.e: bind 'coslat1' to (math/cos lat1)

21:05 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 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 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 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:13 * lvh wonders how Math/sin actually works

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 and not super high quality in its output either

21:15 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 kludgecode: OK - be sure to see my update, replace identity with vec

21:16 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 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 justin_smith: nope

21:20 justin_smith: the chebyshev part is "compute the polynomials"

21:21 well, I guess that's the horner part, with some extra smarts for certain value ranges

21:22 justin_smith: so, for very large inputs, fsin is pretty much totally wrong

21:22 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 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 the second watch replaces the first

21:25 the first one will never get triggered, because the second one replaced it

21:25 so if you wait on prev, you will wait forever

21:26 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 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 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 it's sitting there waiting to be written to

21:31 (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 maybe it should be closed, I'm not sure it matters

21:31 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 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 I have some pure functions that take a series of steps and figure out what that appropriate thing is.

21:37 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 Ideally, scenarios would be executed concurrently.

21:38 Does that help at all?

21:38 I guess my problem definition is pretty imperative :)

21:40 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 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 (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 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 (turns out, from manual testing, there probably is)

21:53 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 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

Logging service provided by n01se.net