#clojure log - Jan 07 2017

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

0:28 sobel: tensorflow is pretty neat. i heard google's vector processors can run TF models 10x faster than the best GPUs, so running models on their cloud is pretty advantageous

2:16 domgetter: Is there a data structure in Clojure that I can push to both sides of?

2:24 hiredman: https://github.com/pjstadig/deque-clojure

2:43 TEttinger: ,(doto java.util.ArrayDeque. (.addFirst 6) (.addFirst 5) (.addLast 7)) ;; not necessarily a good option, but an option

2:43 clojurebot: #error {\n :cause "java.util.ArrayDeque."\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.ClassNotFoundException: java.util.ArrayDeque., compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyze "Compiler.java" 6719]}\n {:type java.lang.ClassNotFoundException\n :message "java.util.ArrayDeque."\n :at [java.net.URLClassLoader$1 run "URLClassLoader.j...

2:43 TEttinger: ,(doto (java.util.ArrayDeque.) (.addFirst 6) (.addFirst 5) (.addLast 7)) ;; not necessarily a good option, but an option

2:43 clojurebot: #object[java.util.ArrayDeque 0x6e40a8fb "[5, 6, 7]"]

2:47 domgetter: awesome, thank you

2:47 It's not for production, it's just for a proof-of-concept mandelbrot viewer

2:50 Any idea why (.repaint canvas) isn't repainting until a while loop is finished? The println's next to it are printing to the console, but the canvas isn't repainting

2:51 https://gist.github.com/domgetter/12415657b9acb2494fa7271860301a0d#file-core-clj-L187

2:57 nvm, apparently repaint doesn't guarantee a refresh.

3:58 amalloy: domgetter: don't tie up the event dispatch thread. nothing in the UI can change while you're handling an event

3:59 if you have expensive computations to do, you do it on a different thread

4:00 domgetter: amalloy the first version of the fractal viewer draws the whole thing as soon as possible. This version is me wanting to "see" the progress as chunks are finished recursively

4:01 amalloy: right. so you start a threat to compute a new chunk, and once you have a chunk ready you insert an event on the dispatch thread that renders it

4:01 domgetter: oh, you're saying I shouldn't be coupling computation to rendering

4:03 amalloy: indeed. rendering is time-sensitive

6:27 jonathanj: jeaye: that's sort of actively discouraged

6:27 https://www.youtube.com/watch?v=oyLBGkS5ICk if you want to know a bit about why

6:28 dysfun: technomancy: julia is a bit of a strange beast though. i was initially very in favour, but after a certain amount of use i realised it's got a while to go before it's useful

6:30 python is pretty much the language to learn about anything like machine learning these days. not so much useful material for other langs

6:59 domgetter: amalloy: It's already going quite a bit faster! https://i.gyazo.com/b62965215fbd81d9dedcf6bc4a3670d6.gif

8:38 dysfun: how do i compare the value of a var against a keyword in selmer?

8:41 oh, {% ifequal foo :bar %}

9:30 lasse_: Hey. I'm reading this tutorial about using clojure, postgresql, compojure to make a small blog.

9:30 https://devcenter.heroku.com/articles/clojure-web-application

9:31 My question is about keys and binds in general. The tutorial has a db-table "shouts" which they use in queries like so:

9:32 (defn all [] (into [] (sql/query spec ["select * from shouts order by id desc"])))

9:32 Which is straight-forward.

9:32 And inserting is handled like:

9:32 (defn create [shout] (sql/insert! spec :shouts [:body] [shout]))

9:33 I don't like how the name of the table is hardcoded in the query-string, so thought about using (str "select * from" table-name)

9:33 But how can I change the use of the key ":shouts" in the insert-function?

9:34 dysfun: add another parameter?

9:34 (defn create [shouts key] ...)

9:34 there is no mystical magical binding going on, they are just data passed as parameters

9:35 lasse_: Oh yeah. Thanks. How about defining a global (def table-name "shouts") and referring to that?

9:35 dysfun: the only bindings your example uses is the parameter 'shout' to the create function

9:35 we don't much like globals

9:36 i understand why you want to do this, but it's not a good idea

9:36 writing sql works great until you want to change the queries

9:37 i'd suggest using a library to generate the queries at this point to avoid getting it wrong

9:37 zilti: What is the boot equivalent of lein's :java-source-paths? I have a java file in my sources, but I can't access the class from Clojure whatsoever.

9:38 dysfun: zilti: the same as for your clojure sources

9:38 lasse_: Anything you can recommend? I'm not really a fan of ORMs because I've experienced problems with the queries that gets generated (fx for joins).

9:38 dysfun: working with java is a bit sensitive to ordering of things

9:38 zilti: dysfun: So, :source-paths? Because that way, it compiles on "boot javac", but I still can't access it

9:38 dysfun: it's not just putting (javac) before running your clojure tests

9:39 what cannot access it?

9:39 what is the process you are trying to make succeed?

9:39 zilti: I can't (:import namespace.MyJavaClass)

9:39 dysfun: lasse_: we don't do ORMs, we do query builders. korma is probably flexible enough for your needs

9:39 zilti: It says it cannot find that class.

9:40 dysfun: from where? the repl? a test?

9:40 zilti: A repl. Also, it's of course not possible to run the application via task since I can't import the class in build.boot either

9:41 dysfun: repl might be slightly more of a challenge, but tests should be easy enough

9:42 my test task just adds "test" to source-paths and runs (javac) before (test)

9:42 zilti: So basically, the class isn't going to change much, it's just a wrapper subclassing a java class and handing the class variables to a clojure fn.

9:42 As long as I can access it anytime I don't care if I have to manually recompile it on the rare occasion.

9:43 dysfun: okay, well try and get it going in your tests first

9:43 zilti: I don't even have tests yet though ^^ It's mainly to try out how I can get this to work

9:43 dysfun: if you can get that working, it might just be as simple as boot javac repl

9:55 vdmit11: Hey guys, since clojure.spec is buzzing around, I have a little question. I would like to define specs for protocol methods. That is, when I use `defprotocol`, I would like to define some specs for the methods of this protocol. And I would like these specs to be checked automatically in runtime. So whenever I call the method, I would like some validation to be performed in runtime. And I would not like to do the validation manually in every implementation

9:55 So I would like to have a modified `defprotocol` macro or something that will instrument all methods to perform checks whenever I call the method. Is this possible?

9:56 dysfun: you can't

9:56 two workarounds that i see:

9:56 justin_smith: protocol methods are 100% abstract

9:56 dysfun: 1. write functions that wrap the methods, doing the checks in those

9:56 2. use a multimethod, where you will be able to execute a spec check before it is run

9:58 vdmit11: Yeah, I noticed :pre/:post in multimethods, but I think that protocols are more handy for me. Because I have a lot of value objects (records) in may code, and it is super-handy to extend them with implementations of various protocols.

9:59 dysfun: sure, but it's easy with multimethods too

10:01 it also has the advantage that it's actually possible with multimethods ;)

10:01 vdmit11: Maybe this is just a personal preference. In my opinion protocols provide more "documentation" of what operations are available on some kind of objects, so they somehow cleaner. Multimethods are good when you have a huge number of implementations of the single method, while protocols look better when you have not just one, but a bunch of coupled methods, and not that many implementations of them.

10:02 dysfun: "it depends"

10:02 vdmit11: yeah

10:02 dysfun: in practice, i prefer multimethods and use protocols when i'm performance gaming

10:02 vdmit11: specs look very attractive as contracts

10:02 dysfun: indeed they are

10:03 vdmit11: so maybe I'll reconsider my approach

10:03 dysfun: if you are adamant on using protocols, i'd recommend doing what cljs does

10:03 for example deref calls -deref (which is a method of protocol IDeref)

10:04 vdmit11: yeah, this is the thing I wanted to point out about functions... if you define a wrapper function around the method, you have to prefix all these methods

10:05 looks a bit dirty

10:06 but maybe I could implement a custom defprotocol/extend macros that work in pair and hide away this name mangling

10:07 ok, thanks

10:07 dysfun: you might be overengineering it

10:07 and you risk obscuring a well known pattern

10:09 vdmit11: well, you see, I also would like to use specs together with deftype/defrecord to describe the data contained in my objects

10:09 so I anyways need some set of helper macros

10:10 maybe I can live with methods prefixed with the dash sign

10:11 but I think I'll stick with records and protocols and a bunch of helper macros

10:11 thanks for the discussion anyway

10:11 dysfun: cool

10:12 osfameron: protocols are oddly disappointing in several ways

10:12 but I do like the way that they "tag" the data

10:13 dysfun: i think they serve their purpose adequately

10:13 osfameron: sure

10:13 justin_smith: osfameron: what do you mean by tag the data?

10:13 dysfun: they are just post-extensible interfaces

10:13 osfameron: justin_smith: instead of being a map, it's a map with a type

10:14 justin_smith: osfameron: what 0 or more types

10:14 for a record, that is

10:14 a protocol is just one of those types

10:14 osfameron: sorry yes, I'm confusing protocol and record :-(

10:14 dysfun: a protocol does tag the type with something, but only (satisfies? proto-name thing) finds it of use

10:14 justin_smith: I've used records for debugging - so that I could identify who created a given item in the profiler

10:15 dysfun: just add a key?

10:15 osfameron: (I'm using them kinda in sync)

10:15 justin_smith: dysfun: the profiler doesn't show keys very readily

10:15 dysfun: i have really gone off records in the general case

10:15 justin_smith: but it does show the class quite readily

10:15 dysfun: ah

10:17 osfameron: I kinda want ADTs... I know there are extensions to get them, but there's no point working against the language, especially while you're learning

10:17 vdmit11: One more little question: is there some standard protocol or maybe an interface that I can use to implement math functions (like + and -) for my custom data types?

10:18 justin_smith: + and - are not abstract

10:18 intentionally, for performance

10:18 vdmit11: but the Java method dispatch is almost free, isn't it?

10:18 justin_smith: not cheap enough for the raw math

10:19 or so the implementors of clojure decided at least

10:20 osfameron: and there's no standard (with-abstract-maths) macro that rewrites e.g + into an abstract +' function? ;-P

10:20 vdmit11: ok, I expected that you have abstract versions by default, and provide some performance-oriented versions in addition (like the unchecked- functions are implemented)

10:24 dysfun: osfameron: i want ADTs too. but in clojure i settle for maps with a key

10:24 and i use spec to make sure they're valid

10:25 osfameron: and one day spec will have a tutorial I can understand, and I'll use it too

10:25 dysfun: anyone know how to make boot do things like "copy the build artifact into this directory, git commit and git push"?

10:44 Empperi: dysfun: can't remember how but yeah, that's possible

10:45 dysfun: well of course it is :)

10:45 as ever with boot, it's just more complex than it needs to be

10:59 osfameron: more complex because of its design?

10:59 dysfun: yes

10:59 osfameron: ah, so not just the lack of docs and supplied tasks

11:00 dysfun: anyway, you won't be surprised to hear i now have a shell script with a big case statement

11:00 osfameron: \o/

11:00 dysfun: because life's too fucking short

11:01 osfameron: the basic idea of middleware and pipelines sounds sensible enough... but the extent of my tweaking so far is to add `(test)` to the build task generated by boot-new...

11:01 dysfun: oh sure, i buy the theory

11:01 but build is where i want tooling to just work, and boot rarely does

11:01 osfameron: it it worth persevering with?

11:02 dysfun: consequently i copy and paste bits from files like it's 2005

11:02 osfameron: $boss pointed us at it because "it's more modern than leiningen"

11:02 dysfun: boot is more powerful than leiningen

11:02 osfameron: and I'm using it at home purely because might be useful for work

11:02 dysfun: while i don't *like* boot, i do grudgingly use it because it's powerful

11:02 i don't use leiningen at all for my own projects

11:03 made the switch a couple of years ago

11:04 osfameron: ah. interestingly, I got the feeling that people actually *liked* lein?

11:04 dysfun: oh yes, if it solves your problem, it's generally likeable

11:05 i think only a handful of people like boot, but god is it useful

11:05 osfameron: as the only thing I want it to do is run tests, build a jar, run a repl, and create a new project, boot handles all of those things (except the last one)

11:06 dysfun: you lack imagination so far

11:06 osfameron: (yes, I know about boot-new. I enjoy googling for it every time I need it ;-)

11:06 dysfun: that's trivially wrappable with a shell script though

11:07 you don't have to forget the old ways just because you use a lisp, you know

11:07 osfameron: sure. googling is also one of the old ways I guess

11:07 dysfun: definitely

11:07 osfameron: I'm sure one day I'll think of something else to do with a build system

11:07 dysfun: and i don't know how i'd program clojure if i weren't over 9000 in googling

11:10 TimMc: dysfun: When do you drop back to makefiles?

11:11 dysfun: when i want the built in mtime checks

11:11 but yes, that would be just as easy

11:58 justin_smith: why not just split calculating dependencies vs. build logic? almost makes sense

12:03 osfameron: damn all this thinking. I now have a better idea for a data structure having already written lots of code :-(

12:03 * osfameron tries to put genie back in bottle

12:09 dysfun: damnit, anyone good at css?

12:18 ragepandemic: Is there any guide explaining how to add a plain react library (E.g. for file uploads) to reagent?

12:33 dysfun: oh hey ragepandemic, i deployed my first rum app today

12:33 a few minutes ago, in fact

12:36 ragepandemic: dysfun, I tried rum last night and me and tolstoy had a long discussion about it

12:36 I couldn't get it to work with :did-mount, for some reason that behaviour was broken on my system

12:37 which is annoying because it seems like a great library

12:40 justin_smith: oh, they call it :did-mount instead of :component-did-mount ?

12:42 dysfun: yes, rum is very into short names

12:42 no argument from me

12:47 ragepandemic: so, the problem was that the :did-mount mixins return value was ignored. i thought it might be the CLJS version, but nah

12:55 anyway, here's the code https://www.refheap.com/124527 I thought you might know since you're a "rum guy"

12:59 congrats on your deploy by the way, can we see it?

13:15 jeaye: jonathanj: I've seen that talk and I don't think it applies.

13:15 I was worried that my question might be interpreted as such.

13:15 I'm not asking the common question of "How can I verify that my map _only_ has these keys?" I'm asking "How can I verify that my map has anything _but_ this key?"

13:16 That doesn't violate Rich's proposal, in the talk, the way I see it.

13:16 dysfun: ragepandemic: the rum bit is private, i'm afraid

13:17 i use rum quite simply i'm afraid, i'm not the best to help with all the lifecycle stuff

13:17 ragepandemic: ah, shame. so, any conclusions? rum vs reagent?

13:17 dysfun: well i never liked reagent at all, so yes

13:18 ragepandemic: how do you architect your frontend apps? redux/re-frame style?

13:18 dysfun: okay, 'at all' might be a little strong, i found it too limiting

13:18 i have a single source of truth atom and everything is just subatoms into it

13:19 everything is wrapped into reusable components and reused

13:19 i have things like a reorderable list that allows insertion of a new item at any point

13:20 ragepandemic: are subatoms conceptually similar to cursors?

13:21 dysfun: er they even call them cursors

13:21 * dysfun doesn't know why he called them subatoms

13:22 ragepandemic: and how do you modify the app state? with events?

13:22 dysfun: ragepandemic: okay, your bugs is that ::time is an atom

13:23 so mix in @ or rum/react as appropriate

13:23 ragepandemic: so I should be doing @(::time state)?

13:23 dysfun: (i think)

13:23 yes

13:24 ragepandemic: alright, let me try

13:24 dysfun: oh hang on

13:24 ragepandemic: nope, its a null value

13:24 dysfun: sorry, i thought you were using (rum/local

13:24 which well, i'm not sure why you're not

13:25 i hate frontend

13:25 ragepandemic: ok, i think I know why. on-js-reload wasn't called on init

13:26 or it was, but it wasn't called twice?

13:26 I mean, it only works when I call (on-js-reload) again

13:26 even though its already called once

13:27 so this fixes it https://www.refheap.com/124528

13:28 dysfun: that's a bit fugly

13:28 ragepandemic: yea, that's not a fix

13:29 it should work on first call, right?

13:29 The first time it just renders "The mount time is:" with no datetime

13:30 dysfun: well, if you made it a state atom that was reactive and updated it on mount, that would work better

13:30 ragepandemic: true, but I was following the readme

13:30 dysfun: the readme could be better

13:30 ragepandemic: https://github.com/tonsky/rum#writing-your-own-mixin

13:30 4th example down

13:31 its a bug though, right?

13:31 dysfun: no idea, far too tired to think properly

13:32 ragepandemic: eh, i'll continue using reagent for now

13:35 thanks for your help

13:37 dysfun: yw

14:13 jonathanj: jeaye: i think it's more or less the same thing, isn't it?

14:42 jeaye: jonathanj: Not at all. What Rich is speaking against is preventing the growth of code, and data, by limiting the shape of it to a specific key set. I'm talking about unrestricted growth of data, with the knowledge that a certain key will never be present.

14:43 I think they're fundamentally different. How else would you write the :ret spec for something like dissoc? It's the input map, guaranteed to not have the specified key; it can have anything else though.

15:35 TimMc: I should watch the spec keynote. The inability to forbid keys is one of the reasons I haven't bothered to pick up spec.

15:36 I want to protect against misspelling an optional key, basically.

15:42 vdmit11: well, a custom predicate function may be used to ensure that all keys belong to some pre-defined set of keys

15:43 so it is possible to forbid keys, but there is no first-citizen support for this

17:18 jeaye: TimMc: It's not an inability, as vdmit11 mentioned; it's quite simple, actually. There's just no built-in support for it.

17:19 (s/def ::without-foo #(not (contains? % :foo))) ; does the trick

17:22 dysfun: which doesn't fit the states use case (key misspellings)

17:26 jeaye: dysfun: As the one who originally brought up the use case, which was not anything to do with misspelling, it absolutely does fit it.

17:26 dysfun: sorry, i mean timmc's stated use case

17:27 i didn't read quite far back enough to see your use case

17:27 jeaye: Ah, right.

17:27 I was looking to spec a function similar to dissoc, where I just want to convey that the output map would be anything without a specific key.

17:28 dysfun: not a chance :)

17:28 not for the general case anyway

17:29 TEttinger: ,(let [ugly {Double/NaN :a (/ 0.0 0.0) :b}] ugly)

17:29 clojurebot: {NaN :a, NaN :b}

17:29 jeaye: dysfun: This isn't a general case.

17:29 TEttinger: ,(let [ugly {Double/NaN :a (/ 0.0 0.0) :b}] (dissoc ugly Double/NaN))

17:29 clojurebot: {NaN :a, NaN :b}

17:29 jeaye: dysfun: The spec I laid out above is exactly what matches my case.

17:29 dysfun: ah okay

17:29 in that case, great :)

17:29 jeaye: (defn clean-internal [data] (dissoc data ::internal)) ; basically

17:31 osfameron: what are the double-colon keywords used for?

17:32 jeaye: osfameron: They're fully-namespaced, which helps with cleanliness and prevents collisions.

17:33 ::foo may expand to :my.ns/foo if I'm in my.ns

17:33 It also works with required aliases, so I can (require '[foo.bar :as bar]) and then ::bar/spam to get :foo.bar/spam

17:34 osfameron: ah

17:35 I've not seen a need to namespace keywords *yet*, will try to remember that for when I do :D

17:35 dysfun: well if you're using spec, you will

17:35 oddly enough the reader got some namespaced keyword related adjustments in in the 1.9 series

17:37 osfameron: yeah, I've seen :: in the spec docs, but as those make my eyes glaze over, I hadn't figured out what they were for ;-)

17:37 jeaye: osfameron: Outside of spec, they're good to describing ownership of data. With normal keywords, anything goes, but dependencies are much more explicit with namesapced keywords.

17:38 dysfun: note that i still haven't fully drunk the namespaced keywords koolaid

17:38 i am much more inclined to use :req-un than :req

17:39 osfameron: right, after I've done my lambdalounge talk in a few weeks, I'll give spec another go

17:40 I got really grumpy about the docs being full of meaningless waffle and not enough examples

17:40 dysfun: oh, will you be boring people about haskell?

17:40 osfameron: I suspect that will get better when spec gets stable?

17:40 nope, clojure examples. data structures for text editors

17:40 dysfun: "docs will get better when clojure gets more stable"

17:40 * dysfun isn't holding his breath

17:41 osfameron: this is the talk synopsis: https://github.com/RickMoynihan/lambdalounge-website/pull/1

17:41 heh, no. which is why I might as well try to stop being grumpy and see if I can figure anything out despite the docs...

17:41 but I have enough on my plate for a few weeks

17:41 dysfun: well, i did a launch today

17:42 osfameron: woo

17:42 dysfun: and fuck, the prod build is insanely faster than the dev one

17:42 osfameron: yay

17:42 dysfun: i have now filled my frontend hump and wish to not do any frontend for the rest of the year

17:57 jeaye: In two current ~2K line projects, I'm using namespaced keywords everywhere in one and nowhere in the other. When comparing, I very much prefer the former.

17:58 dysfun: interesting

17:58 i'm only using namespaces for specs, and keys in spec maps i'm stripping the namespace with :req-un

18:06 machinewar: any core function that does opposite of ffirst, looking for something like (comp last last)

18:06 I really want to get the value in a 1 element map

18:07 (llast {:name "foo"})

18:11 WhiskyRyan: How can I create an empty collection of type x, where x is a var containing a collection of an unknown type?

18:11 justin_smith: machinewar: I would use (comp val first) - at least that makes it clear you are getting something out of a hash entry

18:11 ridcully_: WhiskyRyan: empty

18:12 machinewar: true

18:12 thanks that makes sense

18:13 WhiskyRyan: ridcully: That was easy... ha. Thanks!

18:13 ridcully_: That was easy... ha. Thanks!

20:06 TimMc: ,{(rand) :a (rand) :b} ^_^

20:06 clojurebot: #<IllegalArgumentException java.lang.IllegalArgumentException: Duplicate key: (rand)>

20:10 scriptor: ,(defn f [x] (rand))

20:10 clojurebot: #error {\n :cause "SANBOX DENIED"\n :via\n [{:type java.lang.Exception\n :message "SANBOX DENIED"\n :at [clojure.core$eval29$fn__30$fn__43 invoke "NO_SOURCE_FILE" -1]}]\n :trace\n [[clojure.core$eval29$fn__30$fn__43 invoke "NO_SOURCE_FILE" -1]\n [clojure.core$eval29$fn__30 invoke "NO_SOURCE_FILE" 0]\n [clojure.core$eval29 invokeStatic "NO_SOURCE_FILE" 0]\n [clojure.core$eval29 invoke "NO_SO...

20:10 scriptor: {(rand 2) :a (rand 4) :b}

20:10 ,{(rand 2) :a (rand 4) :b}

20:10 clojurebot: {1.8215813500926088 :a, 3.8151065102200437 :b}

20:11 TimMc: ,{(identity (rand)) :a (rand) :b} Or just this.

20:11 clojurebot: {0.7840885619436757 :a, 0.5429409650182597 :b}

20:11 justin_smith: ,{(rand 1N) :a (rand 1) :a}

20:11 clojurebot: #<IllegalArgumentException java.lang.IllegalArgumentException: Duplicate key: (rand 1N)>

20:11 justin_smith: woah!

20:11 TimMc: ,(= 1 1N)

20:11 clojurebot: true

20:12 justin_smith: ,(type 1N)

20:12 clojurebot: clojure.lang.BigInt

20:12 justin_smith: it mist just check equality of keys at read time

20:13 scriptor: looks like it

20:13 ,(hash-map (rand) 1 (rand) 2)

20:13 clojurebot: {0.17756123528665302 2, 0.26561328496261327 1}

20:36 WhiskyRyan: Is there a function to do: "hello" -> ("h" "e" "l" "l" "o") ?

20:37 ridcully_: ,#:foo{(rand) :a (rand) :b}

20:37 clojurebot: {0.7513892950513176 :b}

20:37 ridcully_: ,(seq "hello")

20:37 clojurebot: (\h \e \l \l \o)

20:37 justin_smith: ,(map str "hello")

20:37 clojurebot: ("h" "e" "l" "l" "o")

20:37 ridcully_: oh you want strings

20:38 WhiskyRyan: there we go... map str... thanks

Logging service provided by n01se.net