#clojure log - Sep 11 2014

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

0:01 wildnux: is this the idiomatic way of applying a function to every elements in a nested list?

0:01 (map #(apply * %) [[1 2 3] [4 5 6]])

0:01 this works, are there any other better way to achieve this?

0:01 justin_smith: ,(map * [1 2 3] [4 5 6])

0:01 clojurebot: (4 10 18)

0:02 justin_smith: ,(apply map * [[1 2 3] [4 5 6]])

0:02 clojurebot: (4 10 18)

0:03 justin_smith: or wait - you want (* 1 2 3) and (* 4 5 6)

0:03 wildnux: justin_smith: I want function to apply to each each element of the outer list (apply funtion to nested list)

0:03 justin_smith: so that it should give (6 120)

0:03 justin_smith: right, so #(apply * %) is the best option

0:03 wildnux: ok

0:03 ,(map #(apply * %) [[1 2 3] [4 5 6]])

0:03 clojurebot: (6 120)

0:04 justin_smith: though #(reduce * %) would also give the right answer

0:05 wildnux: now, if i wanted to get the max of the resulting elements i could do

0:05 ,(max (map #(apply * %) [[1 2 3] [4 5 6]])

0:05 clojurebot: #<RuntimeException java.lang.RuntimeException: EOF while reading>

0:05 wildnux: ,(max (map #(apply * %) [[1 2 3] [4 5 6]]))

0:05 clojurebot: (6 120)

0:05 justin_smith: I think you want apply max

0:05 wildnux: ,(reduce max (map #(apply * %) [[1 2 3] [4 5 6]]))

0:05 clojurebot: 120

0:05 justin_smith: yeah, apply max and reduce max would both work

0:06 wildnux: i could do that, now, my question is how do i get that list [4 5 6] because of which 120 (max) was returned

0:06 justin_smith: ,(apply max (map #(apply * %) [[1 2 3] [4 5 6]]))

0:06 clojurebot: 120

0:06 wildnux: is there a way to get that list which has max product?

0:06 justin_smith: max-key

0:07 ,(max-key #(apply * %) [1 2 3] [4 5 6])

0:07 clojurebot: [4 5 6]

0:07 justin_smith: and again, if the args are all in one list, you can use apply, of course

0:08 ,(apply max-key #(apply * %) [[1 2 3] [4 5 6]])

0:08 clojurebot: [4 5 6]

0:08 justin_smith: clojure is magical

0:08 wildnux: justin_smith: awesome :)

0:08 this is sooo cool

0:09 justin_smith: extending this, is there a funtion which takes any function instead of 'max' in max-key?

0:09 justin_smith: (first (sort-by f l))

0:09 l being a sequence

0:10 wildnux: aah ok

0:11 justin_smith: and f should give the most qualified item the lowest score

0:11 otherwise you have to walk the whole sequence at the end

0:11 you could also optimize that with a reduce

0:11 (in order not to build a collection you don't really need)

0:14 ,(reduce (fn [[score mx] e] (let [s2 (count e)] (if (> s2 score) [s2 e] [score mx]))) [0 nil] ["hello" "this" "is" "sort by count"])

0:14 clojurebot: [13 "sort by count"]

0:15 justin_smith: appropriate if you don't want to call your f more than once per item, and don't want to build the whole ordered collection

2:01 dorkmafia: i copied my directory over to another computer then tried to run lein repl on it and now i'm getting this error: Exception in thread "main" java.lang.UnsupportedClassVersionError: org/jivesoftware/smack/Roster : Unsupported major.minor version 51.0

2:01 amalloy: dorkmafia: your version of java is too old

2:01 dorkmafia: oh yes

2:01 amalloy: i forget what 51 means, but i think it means you need 7 and have 6-

2:01 dorkmafia: thank u

2:01 yup

2:02 makes sense i forgot about that

2:03 do i need the jre and jdk? or just the jdk?

2:04 beamso: jdk

2:07 dorkmafia: so I'm wrapping this xmpp lib and a lot of things require me to pass the connection to my functions I get the connection when the user logs in is a way for me to store in a def?

2:08 there*

2:09 beamso: you could store the connection in an atom

2:14 dorkmafia: oh cool how would i do that? :B

2:15 beamso: something like (def conn (atom <however you established your connection>))

2:15 http://clojure.org/atoms

2:18 dorkmafia: ok cool thanks i'll check it out

2:28 yedi_: i'm making a metronome webapp, so timing is hugely important. it seems that there is some lag when using timeout. e.g: https://gist.github.com/yedi/1abcdf0d8675fd532eca

2:29 there seems to 2-3 milliseconds of lag when using timeout (it jumps up to about 6-7 ms of lag in my actual application)

2:29 is there anyway to nullify or account for this lag? or is there a better way to handle timing in clojurescript?

2:30 beamso: javascript isn't threaded

2:30 yedi_: right

2:31 beamso: i think even if it was threaded you would see the timeout being longer than the exact 1000 that you're looking for

2:31 yedi_: know of a better way?

2:33 i guess i could try to test / calculate the lag and then adjust the timing based off of that. but it seems like that could get messy / won't be perfect either

2:39 beamso: i found this : http://www.sitepoint.com/creating-accurate-timers-in-javascript/

2:40 basically they are running a shorter timeout and adjusting by the difference in intended and actual timeout they encounter

2:47 piranha: beamso: in reality you don't even need to adjust anything, just check what time is it now. Plus it may be worth it having a setTimeout instead of setInterval so you can try to ask for a shorter delay if you need that

2:47 on the other hand, you can just have very short (1-5ms) interval and not worry about it, I guess

2:47 but that still could backfire if the system is a bit overloaded :(

2:47 beamso: okay

2:48 piranha: ah, that's what they are doing (adjusting the timer) - didn't read till the end

2:49 beamso: plus I see you're using async channels, and I think it could a bit of it's own overhead

2:49 maybe it's worth to to stick with primitives in your case...

2:49 beamso: i should be using async channels, but i need to learn about them.

2:49 it was yedi_'s gist

2:50 piranha: beamso: I need to drink coffee before I look into a clojure channel, I'm sorry :)

2:50 yedi_: ^

2:51 beamso: not a problem.

2:51 * beamso has only had 3 coffees so far

2:52 yedi_: ah thanks guys

2:52 i'll try using primitives before just going with the 'figure out the time difference and change timeout accordingly approach)

2:52 though i just love using core.async for everything

2:52 makes me feel nice n fuzzy inside

2:53 piranha: it does :)

2:53 but in this case you want to get least amount of layers between a cpu and your code, and you've got js already :)

2:54 no need to add core.async on top for it to be not exactly real time :)

4:36 magopian: can someone please point me at some docs on the "volatile!" function? can't find any :/

4:55 maxthoursie: magopian: https://github.com/clojure/clojure/blob/42f68bc7688db3a24565dfcdc1cba92dd8a99159/src/clj/clojure/core.clj#L2390

4:55 it's not exactly verbose though :)

4:56 magopian: ah :)

4:56 so what's a volatile? :)

4:56 maxthoursie: * volatiles - there are a new set of functions (volatile!, vswap!, vreset!, volatile?) to create and use volatile "boxes" to hold state in stateful transducers. Volatiles are faster than atoms but give up atomicity guarantees so should only be used with thread isolation.

4:57 (from changes.md)

4:57 magopian: ok, so it's linked with transducers, that's why i see those come up from time to time (i'm trying to get my head around transducers, but still having issues atm)

4:58 maxthoursie: if I understand correctly it's just a wrapper around javas volatile

4:58 they were added as they were beneficial for the implementation of transducers

4:59 magopian: ok ;)

4:59 thanks a lot for the answe r;)

4:59 maxthoursie: np

5:36 CookedGryphon: How would I write a core async buffering strategy which does a distinct-by :id just for things in the buffer but keeping order

5:36 so I have a number of overlapping events, each of which have an id

5:37 and for each event i might receive an undetermined number of updates

5:37 I want to apply backpressure, but only keeping the latest event for each ID, as each event also contains all the historical data (persistent data structures rule)

5:38 for extra credit, some way of controlling whether the order is maintained as first-id-in, or latest-id-updated

5:39 any ideas? My best so far was to create a chan per ID with a sliding buffer 1 and then merge them all, but keeping track of all that when the event ids are unlimited and constantly increasing is tricky

5:45 gws: CookedGryphon: you could write your own buffer that implemented your strategy (maybe using a set for testing membership?) - see this for inspiration https://github.com/clojure/core.async/blob/master/src/main/clojure/clojure/core/async/impl/buffers.clj

5:49 CookedGryphon: gws: that looks like exactly what I need, thanks a lot!

5:51 lvh: I have a list of different arguments; I want to check if (apply f args) is equal to the same constant for each of them

5:52 can I coerce core.test's "are" macro into doing that?

5:57 gws: ,(apply = 42 (map (partial apply +) [[21 21] [21 21]]))

5:57 clojurebot: true

5:57 gws: ,(apply = 42 (map (partial apply +) [[21 21] [21 22]]))

5:57 clojurebot: false

5:58 gws: lvh: would that do what you want?

5:58 lvh: gws: hm, maybe yes

5:58 I didn't realize apply had an & colls part in the signature

6:01 err, or more accurately that = was variadic I guess

6:02 gws: yep! and > and < and so on

6:02 ,(> 5 4 3 2 1)

6:02 clojurebot: true

6:03 gws: ,(> 5 4 3 2 2)

6:03 clojurebot: false

6:03 gws: ,(>= 5 4 3 2 2)

6:03 clojurebot: true

6:04 lvh: ack, this unfortunately doesn't help me because these are byte arrays

6:05 (so = doesn't work :()

6:06 I guess what I really want is (apply are ...), except of course that doesn't really work (I think) because are's a macro?

6:08 every? true? it is

6:26 piranha: anybody using prismatic.schema here? I'm not sure what's the best way to express "for some values of :filter, :user_id should be specified" in {:filter (s/enum ...), :user_id s/Int}

6:29 sm0ke: piranha: look at s/pred

6:29 you can define a function there

6:30 piranha: sm0ke: but pred only gets it's own value to check, right? in this case how do I express "true if other value is something"?

6:31 ah, it could be much more complex than that

6:31 it's just pred is greatly simplified

6:31 ok, I'll try to look into that

6:32 I actually made it work through s/either, but then error reporting becomes really obscure :\

7:13 babygau: https://www.refheap.com/ce7f89cbca4992e046c8dc50c

8:11 rurumate: Hello #clojure, I want to find all (nonempty) subsequences of given sequence a. So for example, (sublists [1 2 3]) should evaluate to '((1) (2) (3) (1 2) (1 3) (2 3) (1 2 3)). I know (comp set #(map sort %) powerset) can do it, but it seems wasteful to calculate the full powerset and then throw away all the lists that are just permutations of the same sorted list.

8:17 clgv: rurumate: then just write a recursive function that directly computes the set of all unordered combinations

8:18 rurumate: I dont know how your powerset function is implemented, but you can probably steal the general idea from it

8:35 jkj: http://stackoverflow.com/questions/22959804/inserting-postgresql-arrays-with-clojure/25786990#25786990

8:49 Kamuela: Is clojure relational/logic programming?

8:49 clgv: Kamuela: no, not the core language itself. but there is a library called core.logic that allows logic programming under clojure

8:51 Kamuela: clgv, That seems to be what I'm using with this tutorial

8:56 clgv: Kamuela: ok, so you are actually learning two things at once

8:57 Kamuela: clgv, the tutorial purports itself as an introduction to logical programming

8:57 clgv: Kamuela: yeah thats ok when they use core.logic

8:57 Kamuela: Clojure itself is mostly functional programming, though there are imperative constructs for side-effects as well

9:05 rurumate: list powerset, seems workey: https://www.refheap.com/90094

9:06 clgv: rurumate: recursive concat may blow your stack for large `xs`

9:08 rurumate: ah and non-tail recursion as well

9:13 Kamuela: clgv, what do you think of core.logic for AI?

9:17 clgv: Kamuela: I did not use core.logic, yet

9:18 Kamuela: I only read about it

9:18 rurumate: clgv: yes it would be nicer with lazy seq

9:19 clgv: what exactly do you mean "recursive concat"?

9:20 clgv: rurumate: when you wrap concats in each other

9:21 rurumate: hmm yes seems like that's the case there

9:27 lvh: reiddraper: Hi! I'm playing with test.check for the first time. Thanks for building it.

9:28 reiddraper: I was wondering if there's a better way to get length-n byte arrays rather than (gen/fmap byte-array (gen/vector gen/byte n))

9:28 Doesn't seem like I can use "bytes" for it. Also, if that would be a good thing to contribute to test.check :)

9:32 clgv: lvh: what is the problem with that? the possible overhead due to vector construction?

9:33 lvh: clgv: no, no problem with that, except that there's already a gen/bytes that *almost* does what I want

9:33 clgv: and gen/vector, a pretty close cousin, can be parametrized by length

9:34 clgv: lvh: but it's exactly the same structure

9:35 lvh: clgv: Yes, I created that thing by copying bytes' implementation

9:35 clgv: I'm trying to figure out if there are clever ways to constrain the generator's output

9:35 clgv: lvh: I think you could externally control its size

9:35 lvh: reading some of the code it looks like maybe there's something like that

9:35 by clever I mean "not generating a bunch of arrays and throwing away the ones that aren'te xactly 16 bytes long)

9:36 clgv: lvh: the probably that arity impl needs to be added^^

9:37 lvh: clgv: that's what I would guess but unfrtunately right now bytes isn't even supposed to be called, it's just a constant

9:39 clgv: lvh: thats no problem. it can be easily converted to a function with both arities

9:40 lvh: clgv: wtihout breaking backwards compatibility? really?

9:40 clgv: you teach it to be a regular value and then override its IFn behavior or something?

9:40 AeroNotix: I want to run a jetty/ring handler on port 0 (random port) how would I then retrieve the port number it is using? This is for tests.

9:41 clgv: lvh: well, were is written that you are not allowed to break backwards compatibility for improvements? imho you only need to communicate that there are breaking changes

9:41 lvh: clgv: oh, okay; yeah, sure -- I guess that's an implicit question for reiddraper :)

9:42 mikerod: If we have something like: (LocalDate. 1) called, which constructor does Clojure call? LocalDate(Object) or LocalDate(long)

9:42 I know clj numeric literals are boxed Long by default

9:43 but does the Compiler automatically cast it as primitive to call the LocalDate(long) in case like this? Perhaps this is a dumb question, but I'm a bit unclear how this part works.

9:52 clgv: mikerod: set warn-on-reflection on true and see what it tells you

10:10 mikerod: clgv: I have that set and it doesn't say anything

10:12 lvh: is https://github.com/paraseba/lein-reload still the thing I use if I want my tests to be constantly run?

10:13 pjstadig: lvh: https://github.com/jakemcc/lein-test-refresh is actively maintained

10:15 lvh: pjstadig: thanks!

10:15 clgv: mikerod: I'd vote for LocalDate(long) when you pass the primitive long - you can check via a decompiler.

10:16 mikerod: clgv: Do you mean when I specifically "ask" for a primitive though? Yes, I think I'll go to the decompiler for this one.

10:17 bbloom: Bronsa: did you ever get around to looking in to jvm mechanisms for chaperons etc?

10:26 clgv: bbloom: what is a chaperon?

10:27 bbloom: clgv: racket stuff for meta-object protocol voodoo for checking contracts and other things dynamically via object proxies

10:27 clgv: bbloom: uh ok.

10:28 bbloom: clgv: http://docs.racket-lang.org/reference/chaperones.html

10:33 ToxicFrog: So, with core.typed, I'm having two weird issues. I haven't added any type annotations yet, just enabled checking for a few namespaces in preparation.

10:33 The first issue is that ns spellcast.core has (require '[taoensso.timbre :as log]) and then calls some things as log/foo ..., and this produces a 'no such namespace: log' message.

10:34 I also get a 'not checking spellcast.game: tagged :collect-only' -- but there's no such tag.

10:36 jlongster: what is the use case for the transformation function in `transduce` taking in the final result of the transformation? https://github.com/clojure/clojure/blob/master/src/clj/clojure/core.clj#L6521

10:37 dnolen_: jlongster: it's the completion step

10:37 tbaldridge: jlongster: consider starting with (transient x) and ending with (persistent! x)

10:38 dnolen_: jlongster: you imagine also imagine reducing over a resource like a file and closing it in the completion step

10:38 jlongster: dnolen_: tbaldridge: huh, interesting. thanks. I can see that

10:38 bounb: anyone got a copy of rhickey's chunked sequences talk?

10:39 ToxicFrog: Hmm. refer :all and (use) are just scope hacks, right? They don't actually change the contents of the current namespace?

10:44 llasram: ToxicFrog: The opposite actually. All `refer`ing (include `:all`) modifies the `refer'ing namespace to map the name symbols to the target vars

10:45 ToxicFrog: llasram: huh. So if ns A refers, say, clojure.core.typed/ann, and ns B requires A, B can then call A/ann?

10:51 llasram: ToxicFrog: I believe that is actually the case, yes

10:51 CookedGryphon: only if they fully qualify it though

10:52 llasram: Most tooling (and stdlib functions?) ignores vars which don't belong to the namespace refering them, but the namespace itself refers to the var

10:55 Oh, nevermind -- I'm confused. Half of what I said is true, but namespaces differentiate between "interning" and "refering"

10:55 Well, kind of.

10:56 No, they don't. Ok, so you can't say A/ann, but only because there's a check on lookup of `ann` in `A` to verify that the namespace of the var found for `ann` is the same namespace

10:58 https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Namespace.java#L195-L200

10:59 But the actual mechanics of what is stored in the namespace are identical for vars which "belong" to the namespace vs referred from others

11:00 justin_smith: llasram: woah, a validating sanity check, in Clojure? astounding news

11:00 I kid because I love

11:01 ToxicFrog: llasram: aah. Honestly that kind of seems like the worst of both worlds~

11:10 mikerod: Does anyone know where the notation used in the Java specs is defined? Such as what <: means?

11:10 I don't see it anywhere, it just starts being used...

11:10 or <<

11:10 I think I have a guess what they are meaning, but it'd be nice to have clarification

11:11 clgv: mikerod: reserved names or something like that?

11:12 justin_smith: mikerod: is it documented somewhere around here? http://docs.oracle.com/javase/8/docs/api/

11:12 clgv: mikerod: http://docstore.mik.ua/orelly/java-ent/jnut/ch02_05.htm

11:14 justin_smith: mikerod: do you have a link to a page using this notation you are unsure of?

11:33 mikerod: clgv: justin_smith ok to clarify, I'm not referring to Java language syntax

11:34 I'm referring to notation used to describe the Java specs

11:34 justin_smith: example: http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-

11:35 Notation like "Ai << Fi (1 ≤ i ≤ n) "

11:35 what is "<<"

11:35 Or "Ai <: Si "

11:35 What is "<:"

11:35 I do not see a page in the specs that introduce what these notations mean.

11:35 So apparently they have some more global meaning, but I don't know where that is defined.

11:36 justin_smith: ≤ is the mathematical less than or equal to

11:36 mikerod: Even better: " Ul <: Bl[R1=U1,...,Rp=Up]" I'm not 100% sure I know what the square brackets are here "[" "]"

11:36 justin_smith: is that what you mean by <:

11:36 maybe it displays differently in my browser

11:36 oh never mind, now I see it

11:37 mikerod: Yeah it is a less-than and a colon

11:37 I don't think I have a browser issue, it seems like it intended to mean something

11:37 justin_smith: yeah, I found it

11:37 mikerod: it is about being a subtype of another type I'm sure

11:37 justin_smith: I just asked a mathematician friend, on the off chance he would recognize it from somewhere...

11:37 mikerod: but I see nothing specific about this notation and it used throughout the specs

11:38 and google searching for this notation is not so good :P

11:38 justin_smith: right

11:39 I bet it means something like inherits from / subtyping

11:39 mikerod: yeah, I'd like to know the difference between "<:" and "<<"

11:39 justin_smith: or derives

11:39 mikerod: and some specifics on this bracketed "Bl[R1=U1 <etc>]" notation

11:40 I just think it is frustrating and would have expected it to be defined somewhere :P

11:40 justin_smith: mikerod: click the footnotes!

11:40 there are hypertext footnotes on the rules that explain the notation

11:40 mikerod: There was even http://docs.oracle.com/javase/specs/jls/se7/html/jls-1.html#jls-1.3 but no good

11:40 oh

11:41 justin_smith: "U << V indicates that type U is convertible to type V by method invocation conversion"

11:41 mikerod: I don't see what to click on

11:41 justin_smith: ". We write T <: S to indicate that that the subtype relation holds between types T and S."

11:41 there are footnote links near each item

11:42 mikerod: ah

11:42 http://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.10

11:42 like that

11:42 justin_smith: mikerod: also, you can control-f here https://en.wikipedia.org/wiki/List_of_mathematical_symbols for things like <:

11:42 mikerod: justin_smith: awesome

11:42 justin_smith: though that does not have <<

11:42 mikerod: problem solved hah

11:43 justin_smith: oh it has ≪ instead - thanks unicode!

11:43 mikerod: ,(inc justin_smith)

11:43 clojurebot: #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: justin_smith in this context, compiling:(NO_SOURCE_PATH:0:0)>

11:43 justin_smith: you may not want the , there :)

11:43 mikerod: (inc justin_smith)

11:44 lazybot: ⇒ 76

11:44 mikerod: oh, I didn't realize taht's how that one worked haha

11:44 justin_smith: it's a pseudo-clojure bot command

11:44 mikerod: I see

11:46 Well now the Java specs are much more fun to read.

11:46 justin_smith: as in "not 100% bewildering"?

12:44 izirku: hi all! is there a predicate to check if something is an atom

12:45 justin_smith: atom?

12:45 oh, I thought that existed, I guess not!

12:45 llasram: ,(instance? clojure.lang.Atom (atom 0))

12:45 clojurebot: true

12:45 justin_smith: there you go

12:46 izirku: aha! you just saved my life!

12:46 TimMc: phew

12:46 I'm glad you didn't die.

12:47 izirku: coming from CL, it's still a bit foreign, but I'm adjusting. Thank you all once again!

12:48 justin_smith: izirku: nb this is not "atom" in the sense cl calls something atomic

12:48 izirku: but I assume you allready knew that

12:49 izirku: justin_smith: yes, I know, I just needed a check if I needej to (deref place) in my macro if it's an atom :)

12:49 llasram: Scary

12:49 tadni_`: On a related note, what does Clojure call small the equivialant of a stereoptypical "Lisp Atom"?

12:50 noonian: it would be nice if there was an atomic? fn, but it doesnt come up as much since clojure collections are immutable whereas it mattered more in cl and scheme since they were mutable

12:50 technomancy: tadni_`: I think "atom" means different things in lisp depending on how far back you go

12:50 it used to be a synonym for symbol iirc? erlang uses that terminology.

12:51 but I think the term you're looking for is scalar

12:51 noonian: i like the little schemers definition

12:51 technomancy: (meaning not compound)

12:51 noonian: yeah

12:51 justin_smith: technomancy: so numbers and other primitives were not atomic?

12:51 tadni_: technomancy: I've always known it as a term for things that are indivisible.

12:52 Numbers, strings, some single charecters like "*".

12:53 justin_smith: but numbers and strings are divisible into bits and chars...

12:53 bbloom: atomic or scalar is a matter of perspective :-)

12:53 tadni_: justin_smith: Well yeah, not my metrics though really.

12:54 Kinda just what lisps, or at least Emacs Lisp intro quantifies.

12:54 technomancy: justin_smith: depends how far back you go iirc

12:55 dagda1_: what does this type of expression mean (into {} *1)

12:56 it is in the docs for map http://clojuredocs.org/clojure_core/1.2.0/clojure.core/map

12:57 hiredman: *1 is bound to the result of the last expression in the repl

12:57 technomancy: justin_smith: this seems to consider numbers and atoms distinct: http://www.softwarepreservation.org/projects/LISP/book/Weismann_LISP1.5_Primer_1967.pdf

12:57 TimMc: izirku: You can also check if something is an IDeref

12:58 izirku: Why does your macro care if something is an atom?

12:58 izirku: TimMc: IDeref?

12:58 justin_smith: dagda1_: look at (doc into)

12:59 *1 means "the last result evaluated in the repl session"

12:59 dagda1_: justin_smith: k

13:00 izirku: TimMc: it's a PeopleSoft specific DSL wrapper on top of Korma. When I have an WHERE setid IN (...) ..

13:00 TimMc: &(map (partial instance? clojure.lang.IDeref) [(atom 0) (future 5) (promise) (var +) (delay 4) :abc])

13:00 lazybot: java.lang.SecurityException: You tripped the alarm! future-call is bad!

13:00 TimMc: ,(map (partial instance? clojure.lang.IDeref) [(atom 0) (future 5) (promise) (var +) (delay 4) :abc])

13:00 clojurebot: #<SecurityException java.lang.SecurityException: no threads please>

13:00 TimMc: anyway

13:00 noonian: yeah, *1 only means something in the repl, its not normal clojure magic syntax

13:00 ,(+ 2 4)

13:00 clojurebot: 6

13:00 noonian: ,*1

13:00 clojurebot: #<Unbound Unbound: #'clojure.core/*1>

13:00 justin_smith: noonian: *1 does not work with clojurebot, each command is a new repl

13:00 izirku: TimMc: my values for IN are stored in an atom, I'm had to make sure I do deref it

13:00 noonian: i see

13:01 &(+ 1 1)

13:01 lazybot: ⇒ 2

13:01 noonian: &*1

13:01 lazybot: ⇒ #<Unbound Unbound: #'clojure.core/*1>

13:01 justin_smith: so "the last value returned by the repl" is unbound

13:01 noonian: shrug

13:01 justin_smith: yeah, it's inconvenient

13:01 ,(do 1 *1)

13:01 clojurebot: #<Unbound Unbound: #'clojure.core/*1>

13:01 izirku: TimMc: it works now. Thanks for the IDeref explanation, will come in handy!

13:01 TimMc: izirku: Oh, this is for the code the macro emits, not the macro's own processing.

13:03 izirku: TimMc: yes, you are right on target :)

13:07 yedi: is there a built-in data structure for / what's the best way to create a sliding queue with a size limit. (where new elements pop off old ones when the limit has been reached)

13:08 could just create a function for appending to a list, that also pops out the other end but I was wondering if there was a more elegant way

13:13 justin_smith: yedi: so a dequeue?

13:13 yedi: lemme google

13:13 justin_smith: https://github.com/pjstadig/deque-clojure

13:13 a deque is a queue that supports efficient addition or removal from either end

13:14 hiredman: there is no built in immutable sliding queue, there is a queue, and building a sliding queue from that can be as simple as checking the size and poping when you add an item if the "size" would overflow your bounds

13:15 noonian: core async channels can use sliding buffers, i'm not sure what your use case is but that might be more appropriate if you're comfortable with core async

13:15 bbloom: core async's buffers are mutable

13:15 hiredman: right

13:15 not values

13:19 noonian: yep, but yedi didn't say anything about what he wanted it for

13:19 yedi: i need to record a bunch of things in real time, but I only will ever care about the last 10 things recorded

13:20 hiredman: well, he asked about built in data structures, and those are all values

13:20 yedi: ty hiredman, that's what i'll go with most likely

13:22 justin_smith: I keep forgetting about clojure.lang.PersistentQueue - it would be nice to have a literal syntax for it

13:22 maybe #[]

13:22 seems a natural fit

13:23 technomancy: $google clojure queuefish

13:23 lazybot: [fogus: So long, and thanks for all the :-)-] http://blog.fogus.me/2012/07/27/so-long-and-thanks-for-all-the-queue-fish/

13:23 hiredman: queue fish!

13:25 justin_smith: https://groups.google.com/forum/#!topic/clojure-dev/GQqus5Wycno a convo about queue-fish

13:27 stuartsierra: http://dev.clojure.org/jira/browse/CLJ-1078 and http://dev.clojure.org/jira/browse/CLJ-976

13:31 justin_smith: I think queues are good enough for something like #[] instead of #queue []

13:35 bbloom: justin_smith: i've needed an immutable queue a handful of times at most, and not once did i ever need a non-empty literal queue

13:35 justin_smith: seems pointless to dedicate syntax to that

13:38 technomancy: #q/ueue [] ; <- technically namespaced

13:39 hiredman: #q/u

13:39 bbloom: it would be nice to at least have a function that returns an empty one

13:41 bbloom: hiredman: yup

13:42 hiredman: (by which I mean, that is a good point about the non-empty бизнес

13:42 )

13:49 dorkmafia: (defn foo [bar] ... ) (defn foo [baz] ... ) is this allowed in clojure two methods with the same name but different inputs?

13:49 jcsims: no - there's no way for the runtime to differentiate between them

13:50 dbasch: dorkmafia: if you want polymorphism, take a look at multimethods

13:51 dorkmafia: cool is there a way to talk to python from clojure? (I should probably google it)

13:53 justin_smith: dorkmafia: what are your constraints? can you talk to it via the network? can it be the version of python that runs in the jvm?

13:54 dorkmafia: which version of python runs in the jvm? 2.7?

13:54 justin_smith: http://www.jython.org/

13:54 dorkmafia: they will both run on the same box

13:55 justin_smith: yeah, looks like they have a 2.7

13:55 dorkmafia: cool beans

13:55 justin_smith: well, with the jvm version it would be in the same process, and won't be able to use C bindings (with all the advantages and disadvantages that these imply)

13:56 (or maybe some C bindings, but it would be via jni or something similar)

13:56 *could be in the same process

13:56 I just picked that as an example as that is the tightest you could bind the two that I know of

13:56 while talking on a socket is a very loose binding between the two

13:57 dorkmafia: well i was just going to try and get skype4py working since the skype4java that I tried before had issues

13:58 technomancy: dorkmafia: hylang.org might be better for that

13:58 I have had luck in the past communicating with skype over dbus

13:58 fsvo "luck"

13:59 dorkmafia: heh

13:59 technomancy: as much as anyone with the misfortune of having to use skype for nontrivial things can be said to have luck, I mean

14:06 stw: I'm using a future to run a third party java library with a timeout, when it times out because the 3rd party library fails the memory and cpu usage remain, what is the best way to isolate this third party call in clojure or to kill it off if it times out? I've looked everywhere, tried future-cancel to no avail

14:07 justin_smith: stw: what about putting the in its own vm, and shutting that process down as needed?

14:08 stw: I was thinking about that, wasn't sure if there was a more idiomatic solution

14:08 in another language I would certainly fork a process for it

14:08 vanila: hi

14:09 SegFaultAX: Unfortunately that's a /really/ heavyweight solution.

14:09 vanila: I've been looking at nanopass frameworkf for making compilers

14:09 just wondering if anyone knows other modern compiler building tools?

14:09 stw: SegFaultAX: yes, any other ideas?

14:10 SegFaultAX: stw: Is the library still maintained? Is it open source?

14:12 stw: SegFaultAX: open source yes, maintained, doesn't look like it - contacted the author a while back to see if he was interested in making changes for me, but he wrote back that he's moved on

14:12 SegFaultAX: I'm wondering if it's practical to patch the library to make it behave better or even support timeouts natively for whatever it's doing.

14:12 stw: Well if its OSS, you could just fork it and make the changes yourself. Is that a reasonable solution?

14:12 stw: Yes, that's a good thought, I may need to wrap the 3rd party method call

14:13 SegFaultAX: Out of curiosity, what library is it?

14:13 stw: SegFaultAX: yes, thats a good idea and I've already made some customizations to it, it's daisydiff https://code.google.com/p/daisydiff/

14:14 SegFaultAX: Whoa, that's pretty cool.

14:14 dorkmafia: technomancy: yah skype is horrid

14:14 stw: SegFaultAX: works well most of the time, gets hung up on some inputs

14:15 technomancy: dorkmafia: at my last job it was used for multi-user chat ಠ_ಠ

14:15 like, text chat

14:15 dorkmafia: yes thats what we use it for toO!

14:15 cause who cares about security!

14:16 technomancy: my condolances

14:16 https://github.com/dakrone/skyyy this is a thing

14:16 SegFaultAX: stw: Neat, what kinds of edge cases have you found?

14:17 technomancy: You still at Heroku?

14:18 stw: SegFaultAX: in the limited time I've been using it, tables don't work out so well, adds a lot of new lines, but for the most part pretty good

14:18 technomancy: SegFaultAX: yeap

14:18 SegFaultAX: stw: Does it do some kind of semantic evaluation of the DOM?

14:18 technomancy: It's all IRC there, yea?

14:18 stw: SegFaultAX: we pre-process the html before processing with this

14:19 technomancy: SegFaultAX: sadly no; we are on hipchat. but it can be bridged to IRC without too much fuss.

14:19 bbloom: technomancy: what, no chatter? ;-)

14:19 SegFaultAX: We also use HipChat. The most recent UI update is just all kinds of terrible. :(

14:19 technomancy: bbloom: haha, we are lucky enough to be fairly insulated from that

14:20 SegFaultAX: I wouldn't know; I use bitlbee =)

14:20 SegFaultAX: can't recommend it strongly enough http://www.phase2technology.com/blog/using-hipchat-through-an-irc-client-with-bitlbee/

14:21 SegFaultAX: technomancy: Awesome, thanks!

14:22 catern: technomancy: that's very neat

14:22 technomancy: it gets the job done

14:22 stw: SegFaultAX: somewhat, it parses the dom and compares inline nodes from what I've looked at

14:22 catern: technomancy: i mean the skyyy thing

14:23 technomancy: oh... well, same =)

14:23 catern: fills me with internal conflict though, because it would allow nice command line usage of Skype

14:23 and... I don't know how to do command line usage of XMPP/Jingle, which I prefer

14:23 SegFaultAX: stw: Seems like a cool project!

14:24 ToxicFrog: How does lein handle it when you require two libs that each require a different version of a third library?

14:24 technomancy: catern: bitlbee is nice for that

14:24 catern: technomancy: I mean the video chat part

14:24 technomancy: oh gotcha

14:24 catern: I have just discovered http://talky.io which works reasonably well for small conversations

14:25 all webrtc'd up

14:25 catern: meh

14:25 i'm willing to inconvenience people by forcing them to make XMPP accounts :)

14:25 technomancy: ToxicFrog: whichever one is highest up the dependency graph wins

14:25 catern: depends how badly you want to talk to them I guess

14:26 ToxicFrog: technomancy: aaaaaaaaaaaaaaa

14:26 catern: yeah, if I don't force them to make XMPP accounts I just use Google Hangouts or Skype

14:27 technomancy: catern: talky.io is nice because you can just hand out a short URL, no need for any account setup

14:27 justin_smith: how hard would it be to make the repl show a stack trace of the running thread when you use an interrupt to stop an evaluation in the repl?

14:27 AeroNotix: after running a midje test in a cider session I get a: IllegalArgumentException Wrong number of args passed to keyword: :irrelevant-return-value clojure.lang.Keyword.throwArity (Keyword.java:92)

14:27 technomancy: Hangout invitations still confuse the heck out of me and I use them almost every day

14:27 justin_smith: AeroNotix: use (pst) to see a fuller stack trace

14:28 see where you are calling :errelevant-return-value with 0, or more than two, args

14:28 AeroNotix: justin_smith: it's in midje code...

14:28 justin_smith: (of course :irrelevant-return-value likely came back from some function you called)

14:28 ToxicFrog: Hmm. Ok, I thought that core.typed and clj-http wanting different versions of tool.reader was causing the crashes, but apparently not.

14:29 justin_smith: My point is, see where it intersects with your code. My guess would be you are executing something it hands back to you. Or midge is fucked and you should use clojure.test.

14:29 AeroNotix: justin_smith: now I get it -- the midje syntax is a bit non-lispy

14:30 ToxicFrog: Argh. I just want to use core.typed, but I don't even know where to start figuring out what it's conflicting with.

14:32 justin_smith: AeroNotix: midje is "lispy" in the bizarro sense that rubyists call things lispy

14:32 AeroNotix: justin_smith: :)

14:34 bbloom: lispiness aside, midje is just plain harder to use than assertions

14:34 technomancy: "lispy" -> offers you enough power to do really crazy things

14:34 bbloom: hell, clojure.test is harder to use than regular assertions

14:34 noonian: i never understood ruby people calling ruby a lisp

14:34 AeroNotix: bbloom: I've started using midje, seems to integrate with CIDER/Emacs better

14:35 bbloom: AeroNotix: i find that non-trivial classes of assertions require me to look at the (poor) docs with 100% frequency

14:35 justin_smith: AeroNotix: core.test integrates with clojure better - the tests are functions, you call them and they tell you if they failed

14:35 dbasch: noonian: for the same reason people prepend "smart" to any product name

14:36 justin_smith: it's the same way Avril Lavine identifies as punk - it makes her and her fans feel cool, and the punks are all like "wat"

14:36 AeroNotix: Smart Water

14:37 justin_smith: I actually really like dumb products - I love having a phone that doesn't know what a cloud is, or how to upload my shit to one.

14:37 technomancy: I'm getting close to having a smarter keyboard than phone.

14:38 probably just need to drop my nokia on concrete a few times

14:38 justin_smith: heh - I'm just waiting until the atreus app store comes out

14:38 technomancy: (just finished my ARM port last night)

14:38 justin_smith: very nice

14:39 like - make dvorjack available as a free download, but with no shift key - then allow shift as an "in app purchase" on a per-keypress basis

14:39 then rake in the dough

14:39 * technomancy takes notes

14:42 catern: whaat

14:42 ctrl-m is enter and ctrl-i is tab

14:42 technomancy: mind_blown.gif

14:42 catern: i already knew ctrl-[ is escape

14:42 where can I find more of these

14:43 helpful things

14:43 justin_smith: catern: and ctrl-j is return (distinct from enter)

14:43 ToxicFrog: catern: man ascii

14:43 catern: ToxicFrog: huh?

14:43 justin_smith: and control-space is the null byte

14:43 ToxicFrog: catern: the capital letters on the right correspond to the control codes on the left when ctrl is pressed

14:43 justin_smith: catern: there is a unix command called "man"

14:43 catern: the man page for ascii has a bunch of nice info

14:44 catern: justin_smith: yeah, but I don't see any of these ctrl-[ ctrl-m ctrl-i things in it

14:44 ToxicFrog: 14:43 < ToxicFrog> catern: the capital letters on the right correspond to the control codes on the left when ctrl is pressed

14:44 catern: ah

14:45 ToxicFrog: catern: e.g. 015 13 0D CR '\r' (carriage ret) 115 77 4D M <-- ctrl-M corresponds to CR, carriage return

14:45 catern: mind blown

14:46 technomancy: yeah, control codes are sent just by flipping a bit on regular ascii codes

14:46 justin_smith: catern: for example, I am sure you already knew Ctrl-D was EOT

14:46 * ToxicFrog returns to stabbing core.typed over and over and over again

14:47 catern: justin_smith: everything begins to make sense

14:47 ToxicFrog: justin_smith: to be fair it could plausibly also have been ETX or EM

14:48 justin_smith: fair enough

14:48 catern: do ctrl-c or or ctrl-\ fit in this at all?

14:48 dbasch: catern: back in the day computers only had the ascii charset. My TI99 used the values > 127 for graphics (e.g. horizontal line, vertical line, angles)

14:48 catern: given that they send signals

14:49 cbp: ctr-c is etx

14:49 catern: yes

14:49 etx doesn't seem very sigint-ish

14:49 dbasch: catern: that depends on the shell

14:49 justin_smith: catern: your terminal translates the keycode into a signal to the currently running process

14:49 cbp: also known as 'break'

14:50 catern: dbasch: justin_smith: is it the shell or the terminal?

14:50 ToxicFrog: Yeah, I think it's just ctrl-C for Cancel

14:50 justin_smith: catern: the terminal - the keycodes work even when you exec (which makes the shell exit)

14:50 and it works even if the shell is not running when the keycode is sent

14:50 catern: justin_smith: so wait, emacs understands C-c keybindings by *running a signal handler*?

14:50 dbasch: catern: the terminal driver

14:51 justin_smith: the terminal runs the signal handler

14:51 err

14:51 n/m

14:51 yeah, it uses a singal handler I think :)

14:51 in the console

14:51 catern: weird

14:51 it works, though

14:51 justin_smith: it works :)

14:52 technomancy: reading about terminals is like reading about mime encoding

14:52 it simply increases your wonderment and awe at the fact that anything ever works

14:53 bbloom: frickin' terminals...

14:55 justin_smith: "fucking terminals, how do they work? I don't want to talk to a computer scientist, motherfuckers lying, making me pissed"

14:56 johnwalker: technomancy: what did core.typed do to you ? :(

14:56 woops, wrong completion

14:56 ToxicFrog: what did core.typed do to you ?

14:59 catern: wait so

14:59 why do both Ctrl-m and Ctrl-M send CR?

15:00 ToxicFrog: johnwalker: when I lein typed check, it does this: https://gist.github.com/anonymous/c37a772c1c470b7b1812

15:00 bbloom: ,(- (int \A) (int \a))

15:00 clojurebot: -32

15:00 ToxicFrog: At first I thought this was because clj-http and core.typed wanted different versions of tools.reader, but if I drop the clj-http dependency or force them both to use the same version it still happens.

15:00 bbloom: ,(- (int \a) (int \A)) ; heh, positive

15:00 clojurebot: 32

15:01 justin_smith: catern: the control bit and the shift bit interact oddly - I forget the details

15:01 catern: aaaieeeeeeeee

15:01 justin_smith: catern: there is no such thing as C-m - it becomes C-M

15:01 catern: AIEEEEEEEEE

15:01 johnwalker: ToxicFrog: the easiest way to check is to move the core.typed dependency before anything else in your :dependencies

15:01 bbloom: ,(char 45)

15:01 clojurebot: \-

15:01 amalloy: justin_smith: is it perhaps as simple as, when there's a control bit set, everything but the bottom five bits are masked off?

15:01 bbloom: *shrug*

15:01 technomancy: dang, catern's been gazing into the abyss again

15:01 ToxicFrog: catern: historically, ctrl zeroes the two high bits, which includes the bit that shift sets

15:02 justin_smith: amalloy: hrm - I dunno, that sounds plausible?

15:02 johnwalker: whether there's some sort of dependencies collision. i don't have a clue why thats happening though

15:02 amalloy: sounds like basically what ToxicFrog is saying, and i imagine he knows better than i do

15:02 ToxicFrog: johnwalker: it already is.

15:02 johnwalker: and lein deps :tree is clean.

15:02 catern: technomancy: i've learned things mere mortals are not meant to know, delved to abstraction levels that hide ancient horrors, and it has driven me mad

15:02 ToxicFrog: (since removing clj-http, that is)

15:03 amalloy: speaking of ascii control codes, a while ago i started typing C-j instead of RET while editing source buffers. it's easier, really - i don't have to reach over with a pinky

15:03 catern: okay, got any reading on this subject? there's that one really long article about terminals I've seen in passing, but I haven't read it or bookmarked it..

15:03 amalloy: plus then in the repl you can use C-j to insert a newline, and RET to send a finished expression

15:03 technomancy: amalloy: it also should auto-indent out of the box

15:04 whereas you have to configure RET to do newline-and-indent

15:04 amalloy: technomancy: i'm on such an old version of clojure-mode that RET still does, i think

15:04 maybe i upgraded and then reconfigured it to the old behavior

15:04 technomancy: amalloy: yeah, someone complained about that (rightly, I think) and now it works the same as everyone else

15:04 amalloy: yeah, i agree it was right to make that change

15:04 technomancy: I haven't really got in the habit of preferring C-j, maybe one of these days

15:05 I only got using C-i because I was able to remove the TAB keycap from my ergodox

15:06 ToxicFrog: johnwalker: yeah, that's the thing, I was thinking "ok, dependencies collision, I'll just remove deps until it goes away and then figure out how to fix things", but I pared it down to just clojure and core.typed and it still happened. But I know that core.typed 0.2.68 and clojure 1.6.0 are compatible because I'm using them in another project without crashing.

15:13 johnwalker: blew away ./target and it started working. I guess it wasn't rebuilding something it should have been?

15:14 johnwalker: ToxicFrog: wow that is bizarre

15:14 amalloy: AOT compilation. not even once

15:14 ToxicFrog: I'm not even using AOT for anything but uberjar.

15:15 johnwalker: i'm glad you fixed the issue though

15:17 ToxicFrog: Now, my types are all completely hosed after a year of updates without bothering to typecheck anything, but I know how to fix that~

15:19 johnwalker: grep -v ann ?

15:25 ToxicFrog: Ok, new core.typed question!

15:26 I have a function that's basically (defn register-foo! [& xs] (def foo (into foo xs)))

15:26 I gave it signature [Any * -> Nothing]

15:27 But apparently it actually has signature [Any * -> (Var (Vec Any) (Vec Any))]

15:27 Which kind of makes sense if I read (Var old-type new-type) as being the type of def

15:27 Except Var doesn't exist in core.typed, so I can't use it as part of the signature!

15:31 amalloy: justin_smith: i just saw your comments on http://stackoverflow.com/questions/25793668/why-is-my-clojure-code-running-so-slowly. it's funny, i didn't actually intend for the powers-of-two sequence to be especially inefficient as part of the problem; i didn't really imagine anyone realizing a finite-but-too-large piece of it

15:31 justin_smith: heh, here i thought it was an excellent design choice in constructing the puzzle :)

15:31 ToxicFrog: Hmm, ok, it actually wants either (Var1 T) or (Var2 Tw Tr) even though the error message reports it on Var

15:32 amalloy: sometimes i did create intentionally-large inputs so that you'd have to think about performance, but most of the time i just wanted any correct solution to work

15:33 it's an interesting problem. looking back at it now i'm not even sure if the solution i wrote years ago is actually efficient or not: https://www.refheap.com/90119

15:34 it seems inefficient because it goes over every seq but the first multiple times, but...can you do better? i don't know that you can

15:37 justin_smith: amalloy: https://www.refheap.com/90120 mine, does a bunch of sorting, so is likely slower

15:37 amalloy: certainly my in-lists? is a bad reimplementation of every?

15:37 ToxicFrog: Seriously tempted to just :refer :all when I use core.typed now, remembering which things need t/ and which don't is a pain

15:38 amalloy: justin_smith: well, there are certainly inputs for which yours is faster

15:39 well, maybe not. i dunno. performance is hard

15:39 justin_smith: benching them now

15:40 use criterium, it's a library, it's a space heater, it solves random clojure trivia

15:43 amalloy: justin_smith: i was going to suggest using test.check to generate evil input sequences, but...since it just has to be N sorted collections, there's really nothing exciting it could do

15:45 justin_smith: as long as the solution is smart enough not to be over eager in reading any inputs

15:45 and that final test is good on that count

15:46 https://www.refheap.com/90122 looks like mine was significantly faster (> ms µs ns)

15:47 I dunno - is it worth benchmarking again predefining the functions?

15:47 may as well

15:48 amalloy: justin_smith: don't predefine them, just let them outside: (letfn [...] (bench ...))

15:48 but no, i don't think it matters at all

15:52 justin_smith: you can improve yours quite a bit, actually, by not sorting and by possibly advancing multiple inputs at once: https://www.refheap.com/0142f12d90d7cef1ac56a0222

15:53 dbasch: justin_smith: here's mine fwiw https://www.refheap.com/90124

15:54 which has obvious improvements

15:54 amalloy: dbasch: ah, using max is cute, although you can use drop-while instead of next, as in my recent suggestion

15:54 dorkmafia: how do you create a new instance of a java class from clojure? (ClassName. (arg1) (arg2)) ?

15:54 dbasch: (I mean can be improved obviously)

15:54 amalloy: and, just for style points: (let [[mi ma] (apply (juxt min max) ...)] ...)

15:54 justin_smith: dbasch: interesting

15:54 dbasch: amalloy: that's what I meant, I look at it now and I could have done it less redundantly

15:55 tadni_: So, I'm glad to see that "Clojure From The Ground Up" should be more or less done by Janurary.

15:55 dbasch: juxt wasn't on my radar at that point

15:55 amalloy: yeah, (apply (juxt min max) ...) is a trick that still confuses me

15:55 like, i know it works, but my head hurts if i think it through

15:57 i love that these 4clojure problems are still interesting years later, knowing much more about the language

15:57 justin_smith: yeah, it's pretty cool

15:59 amalloy: dbasch: I wouldn't have guessed so, but mine is still fastest - though dbasch's version is close https://www.refheap.com/90125

16:00 amalloy: justin_smith: it'll depend on the inputs for sure

16:00 justin_smith: yeah, just using the "tricky" input

16:00 dbash's would excell with a longer input list

16:00 amalloy: and either yours or dbasch's would be improved by using drop-while instead of rest

16:00 justin_smith: true that

16:02 Bronsa: bbloom: re: hours ago -- no I haven't :)

16:02 also I just learned that src/foo/bar/baz/ is the same as src/foo.bar.baz for the jvm. I'm kinda tempted to mkdir clojure.tools.analyzer

16:02 bbloom: Bronsa: heh, just for less work when cd-ing?

16:02 justin_smith: oh, wow, that's a weird thing

16:03 Bronsa: bbloom: I have to tab like 6 times to find the first clj file on my tools.* libraries

16:03 technomancy: I wonder if that's imlementation-specific

16:03 bbloom: Bronsa: i was super excited when github released the deep-jump links thingt

16:04 Bronsa: bbloom: me too!

16:04 technomancy: I remember reading some crazy thing about how dashes in class names are actually supported by openjdk, just not the JVM spec

16:04 Bronsa: bbloom: my actual comment on #clojure-offtopic "the first github UI change I approve"

16:04 joobus: how do I call Integer/parseInt from my code? I can call from the repl, but in my code I get a compile error.

16:04 justin_smith: bbloom: Bronsa: maybe we need deep-jump-find-file

16:04 Bronsa: technomancy: dunno, I actually saw this on the openjdk source tree

16:05 amalloy: justin_smith: ido-mode has a setting for that somewhere

16:05 technomancy: Bronsa: the five users of Clojure on IBM's JDK will yell at you

16:05 justin_smith: joobus: are you using it as if it were a first class function? it isn't one

16:06 joobus: justin_smith: I guess I am. (map Integer/parseInt blah)

16:06 justin_smith: #(Integer/parseInt %) is one

16:06 joobus: ok

16:06 justin_smith: joobus: this is all because clojure functions are objects, not methods on some object

16:06 joobus: I guess that makes sense. i searched and found parseInt is a static method of java.lang.Integer

16:07 just didn't know how to handle that

16:07 thanks justin

16:07 * tadni_ is already a bit disenfranchised by "Clojure from the Ground Up."

16:07 technomancy: I don't really get why Clojure doesn't auto-memfn or its static equivalent

16:07 justin_smith: yeah, the idea is that an arg to a clojure function can be an object or primitive, but it can't be a method, they are not first class

16:08 technomancy: are there ambiguous contexts in which it can't be determined?

16:08 justin_smith: technomancy: it would be another bit of magic, I support being skeptical of magic

16:09 Bronsa: technomancy: that would almost always require runtime reflection

16:09 technomancy: justin_smith: I don't see how it's magic. how else would you interpret (map .toString objs)?

16:09 Bronsa: technomancy: compare Object foo(Object); Object foo(Object, Object);

16:10 how could you statically determine which one you're using when compiling (map Class/foo ..) ?

16:10 bbloom: (doc memfn)

16:10 clojurebot: "([name & args]); Expands into code that creates a fn that expects to be passed an object and any args and calls the named instance method on the object passing the args. Use when you want to treat a Java method as a first-class fn. name may be type-hinted with the method receiver's type in order to avoid reflective calls."

16:10 bbloom: note that you have to provide type hints

16:10 technomancy: Bronsa: I don't mind runtime reflection

16:11 bbloom: technomancy: the problem isn't that it requires reflection, it's that the reflection doesn't occur until later

16:11 Bronsa: technomancy: I do

16:11 bbloom: i guess that the compiler would warn on reflection when auto-memfn-ing

16:11 Bronsa: bbloom: I don't understand the distinction you're trying to make

16:12 technomancy: there's lots of stuff like that in clojure already; it seems like the line is drawn at a somewhat arbitrary spot

16:12 bbloom: Bronsa: sorry, i didn't fully think that thougth out. i guess that's also true of fn too

16:12 ignore me :-P

16:13 Bronsa: technomancy: for instance-methods it wouldn't even be a matter of only "it would require reflection" -- you wouldn't even know what arities are available

16:14 tadni_: justin_smith: Yeah, Clojure from the Ground up -- the more I looked into it, appears to be more an introduction to the lang more-so a general compsci introduction.

16:14 technomancy: yet memfn exists

16:14 Bronsa: what would it do? turn .foo into (fn ([x] (.foo x)) ([x y] (. x y)) ..)?

16:14 technomancy: you have to provide the argc to memfn, that's the point

16:14 joobus: w00t! I've solved 4 project euler problems in clojure. I'm feeling slightly less noobish...

16:14 amalloy: technomancy: well, memfn is for a specific, single arity

16:15 AeroNotix: I'm seeing a http-kit/get call being blocked (where it should always return a promise). Any ideas why that would be?

16:15 amalloy: you can expand into a million different arities, as Bronsa points out, but it's not super-clean

16:15 technomancy: Bronsa: you actually don't?

16:16 justin_smith: tadni_: did you mean disillusioned? or does it disenfranchise you from some right you would otherwise have?

16:16 joobus: justin_smith: lol

16:16 justin_smith: "this tutorial is opressing me"

16:16 johnny_mck: Greetings! I haz questions if anyone cares to answer some? (mostly about programming in a functional style...)

16:16 dorkmafia: is this the correct syntax for creating a java class from clojure and passing constructor args (ClassName. (arg1) (arg2)) ?

16:16 amalloy: technomancy: yes you do. (memfn add) only accepts exactly one argument; (memfn add x) accepts exactly two...

16:17 tadni_: justin_smith: Well, if I were to follow the thinking in the "who is this guide for" and I was non-cis, or non-white and was using another guide ... then maybe. :^P

16:17 technomancy: huh... I've never used the second arity of memfn

16:17 tadni_: I'm saying, it's not really a general compsci text as much as a general introduction to clojure.

16:17 Bronsa: technomancy: you've only used on no-arg methods then :)

16:17 justin_smith: tadni_: true

16:18 johnny_mck: we grant permission to ask questions freely

16:18 joobus: johnny_mck: you should just ask and see if someone responds. that's what the pro noobs like myself do.

16:18 amalloy: justin_smith: unless it's about the new iphone

16:18 justin_smith: heh

16:18 yeah, maybe I should have qualified that

16:24 TEttinger: dorkmafia: ##(java.util.HashMap. 64)

16:24 lazybot: ⇒ #<HashMap {}>

16:24 TEttinger: dorkmafia: ##(java.util.HashMap. (64))

16:24 lazybot: java.lang.ClassCastException: java.lang.Long cannot be cast to clojure.lang.IFn

16:25 TEttinger: 64 is a constructor arg to that java class that is the initial capacity, IIRC

16:26 justin_smith: there's that javascript compiler that removes lines of code until everything compiles, we should do something similar with clojure, and removing parens

16:27 TEttinger: I think there could be some ambiguity.

16:27 ,(map identity [+ 1 2 3])

16:27 clojurebot: (#<core$_PLUS_ clojure.core$_PLUS_@15773de> 1 2 3)

16:27 AeroNotix: I'm seeing a http-kit/get call being blocked (where it should always return a promise). Any ideas why that would be?

16:27 TEttinger: ,(map identity [(+ 1 2 3)])

16:27 clojurebot: (6)

16:28 amalloy: justin_smith: the readme for wtfjs is sublime

16:29 justin_smith: indeed

16:50 defn: dnolen_: Whaddya know about probabilistic programming? I want to dig in and am curious if you have suggestions on papers, resources, etc.

16:50 dnolen_: defn: not much I just surveyed some literature at one point, Church is a good jumping off point

16:51 defn: http://projects.csail.mit.edu/church/wiki/Church

16:51 defn: dnolen_: Some fascinating stuff.

16:52 Yeah I found the church lang. So many recent papers and research topics involved that I'm feeling overwhelmed.

16:52 Probmods.org was a good intro, but I need to see more in practice. Anyway, thanks again.

16:53 Oh, and mcmc has been done in clojure. If you're interested dnolen_

16:53 https://github.com/farr/mcmc-clojure

16:53 dnolen_: defn: interesting though old and not maintained

16:54 defn: Yeah :/. Looks like I need to take a page out of the dnolen book and write clojure.core.prob

16:57 bbloom: defn: go for it!

16:58 jdkealy: Hello, I have been trying to use the AMI startup script for Dynamo DB and AWS. I have gotten the startup script to launch a new instance, but it stops and restarts itself with the following error: ./startup.sh: line 26: kill: (1768) - No such process, /dev/fd/11: line 1: /sbin/plymouthd: No such file or directory ... has anyone here encountered anything like this before ?

16:58 arrdem: defn: there's an implementation of distributions kicking around somewhere from contrib that may be interesting material as well although that's more probability modeling than a probabalistic structure

16:58 defn: jdkealy: I believe there is a #datomic channel

16:58 jdkealy: sorry about that! I thought i was in #datomic :/

16:58 defn: Np

16:59 arrdem: I'll have a look. I think I know the one you're referring to. Been a long while since I went through contrib

16:59 Thanks!

17:00 arrdem: defn: there's an old implementation of a distribution monad. It doesn't make a whole lot of sense as a monad, but the distribution structure has served me well in a tabletop game project.

17:08 dbasch: arrdem: wow, it hasn't been touched for 5 years https://github.com/richhickey/clojure-contrib/tree/master/src/main/clojure/clojure/contrib/probabilities

17:08 arrdem: dbasch: yep

17:08 dbasch: oh do you still have that clojure vs clojurescript link?

17:09 dbasch: arrdem: this? https://github.com/clojure/clojurescript/wiki/Differences-from-Clojure

17:10 arrdem: dbasch: I found that... I seem to recall you mentioning some post about expressions that didn't behave the same.

17:13 dbasch: trying to find it

17:14 sdegutis: Quick, what's a good name for an app that does your chores for you?

17:14 andyf_: sdegutis: littleBrother ?

17:15 dbasch: sdegutis: siri :P

17:15 sdegutis: Something that won't invoke trademark infringement? :P

17:15 justin_smith: sdegutis: apprentice

17:15 it even has app in the name

17:17 sdegutis: Thanks everyone!

17:17 noonian: man, i'm going to be pondering that all day now

17:21 sdegutis: Oh maybe old maid? Or steward?

17:21 s/old//

17:23 noonian: i was thinking robo-maid or something

17:23 or no-chore no-more-chore

17:23 sdegutis: :D

17:23 Certainly not Golem.

17:24 technomancy: yeah, you wouldn't want folks thinking it was written in google go

17:24 sdegutis: Or that it's from LotR.

17:24 AeroNotix: I'm seeing a http-kit/get call being blocked (where it should always return a promise). Any ideas why that would be?

17:24 justin_smith: GoLem: a generator of high concept sci fi, written in google go

17:25 sdegutis: technomancy: I wrote an 80-line script in Go the other day, which downloaded some .tar.gz archives from the net, extracted them in-memory, and output contents of files matching a pattern.

17:25 cbp: sounds like a clojure 5 liner

17:25 sdegutis: technomancy: A few hours later, I replaced it with a 4-line Bash script.

17:25 technomancy: nice

17:25 sdegutis: I have never found a good use for Go that I haven't rewritten in something better.

17:26 ieure: Go is great if you enjoy writing "if (err != nil)" every other line.

17:26 sdegutis: :)

17:27 ieure: As someone who needs to write extremely correct software, Go sends me screaming.

17:27 technomancy: hey, when I was in school, you didn't have to get 100% on every test

17:27 even if you got just like 90% it was no big deal

17:28 mdrogalis: Gonna put that on my resume. "I write sorta good code. Good enough anyways"

17:28 ieure: Hah.

17:28 mdrogalis: ieure: What industry do you work in?

17:28 sdegutis: <3

17:28 ieure: mdrogalis, Banking.

17:28 sdegutis: I was gonna guess "financial"

17:28 mdrogalis: Unit testing on your own bank account. Don't mess up too much, now.

17:28 AeroNotix: ieure: so what language do you use then?

17:29 justin_smith: mdrogalis: nah, you just add a test fixture that resets the balance :P

17:29 ieure: AeroNotix, Depends. We're a JVM shop, but write Java, Scala, Clojure, and JRuby.

17:29 sdegutis: <3 Java

17:29 ieure: Depending on what the thing is.

17:29 AeroNotix: ieure: and you think you can write more correct programs in Java than in Go?

17:29 sdegutis: Such nice. So language.

17:29 TEttinger: JRuby seems like the thing to not use for correctness

17:29 AeroNotix: sdegutis: are you kidding?

17:30 sdegutis: Who doesn't love Java?

17:30 (Besides hipsters.)

17:30 mdrogalis: justin_smith: "Gave myself some padding by adding a few zeros this week."

17:30 ieure: AeroNotix, I believe it is easier to write correct programs in Java than Go.

17:30 technomancy: Java: at least it has exceptions

17:30 AeroNotix: ieure: could it be that you're just more familiar with it?

17:30 ieure: AeroNotix, No.

17:30 AeroNotix: oh ok. Case closed.

17:30 mdrogalis: Hahah.

17:31 sdegutis: At the end of the day, there's nothing really wrong with Java, it's perfectly suitable for writing any kind of serious app in. Clojure is just the icing on the cake.

17:31 TEttinger: sdegutis, designed for average coders, by average coders?

17:31 Oak, anyway

17:31 AeroNotix: sdegutis: that's not a very nuanced opinion.

17:32 arrdem: TEttinger: read the CVs of the Java language committee and lets hear you say that again

17:32 TEttinger: I was kidding

17:32 sdegutis: AeroNotix: uhh

17:32 TEttinger: uhh

17:32 mdrogalis: Not sure how you can appreciate Clojure without realizing what's wrong with Java. D:

17:32 TEttinger: I know they got some very experienced devs on that team

17:33 and it is interesting how Java got by with less serious design flaws at an early stage than most other large languages

17:33 TimMc: Pity about the type system, though.

17:33 TEttinger: they had to do a big rewrite for generics, and they still aren't great

17:33 sdegutis: mdrogalis: There are quirks in every language, and that's kind of why I have a job actually, because writing software is kind of hard.

17:33 ieure: Java Generics are really terrible.

17:33 Is typed Clojure usable yet?

17:34 It seems very promising.

17:34 sdegutis: I could try and write Haskell all day but the tools I use now work fine.

17:34 TEttinger: I have wondered the same, ieure. it seems to be, though I haven't tried it.

17:35 ieure: I've been appreciating static typechecking more since I started writing systems that have to correctly deal with millions of dollars of other peoples' money.

17:35 TEttinger: the main thing I use clojure for right now is one-liners of very dense code.

17:35 ##(clojure.string/join" "(repeatedly 2000(fn [](apply str(concat[(rand-nth ["rh""s""z""t""k""ch""n""th""m""p""b""l""g""phth"])](take(+ 2(* 2(rand-int 2)))(interleave(repeatedly #(rand-nth ["a""a""o""e""i""o""au""oi""ou""eo"]))(repeatedly #(rand-nth ["s""p""t""ch""n""m""b""g""st""rst""rt""sp""rk""f""x""sh""ng"]))))[(rand-nth ["os""is""us""um""eum""ium""iam""us""um""es""anes""eros""or""ophon""on""otron"])])))))

17:35 lazybot: ⇒ "rhauchaumor peobus rhamor pourkoistum teongeochium phthongoushor theonarstis zeofor phthaungeorstotron girtoirtanes pospeoshiam chepum toumon loitocheros zixophon lamon sabousotron gespium toxortis soirtenor laspum chomum paurteopis zeofepus moigum thortousheum togo... https://www.refheap.com/90131

17:35 justin_smith: ieure: there is also prismatic/schema

17:35 sdegutis: In fact, I'm betting on the fact that people are overly picky about languages, and I'm embedding 4 different scripting languages into my upcoming commercial app.

17:36 dbasch: TEttinger: future you would like to have a word with present you

17:36 sdegutis: They can choose between Ruby, Java, Python, or Lua.

17:36 ieure: justin_smith, Looks interesting.

17:36 arrdem: dbasch: lol

17:36 sdegutis: er, JavaScript

17:36 TEttinger: dbasch: the reduced need for spaces helps with these one-liners fitting in 400 or so characters

17:37 amalloy: and imagine the savings on commas

17:38 dbasch: amalloy: I like my machine code to have more ones than zeros because it saves ink when printing them out in binary

17:40 TEttinger: I'm currently almost exclusively writing C# for a rapidly-expanding-in-code-size renderer for voxel models. I'm hoping to use the rendered stuff from clojure using play-clj when I get closer to done.

17:43 dbasch: arrdem: I found this in my browser history, it only goes back 90 days https://gist.github.com/alandipert/2346460

17:44 arrdem: dbasch: thanks for looking

17:51 sdegutis: lol, Proletarian

17:59 TEttinger: ,(filter #".*foo.*" ["foobar" "goobar" "foobaz"])

17:59 clojurebot: #<ClassCastException java.lang.ClassCastException: java.util.regex.Pattern cannot be cast to clojure.lang.IFn>

17:59 TEttinger: hm, I guess it doesn't work in vanilla clojure without further black magick

18:00 llasram: TEttinger: yeah -- in JVM Clojure there's no way to turn existing classes (like regular expressions) into IFns

18:00 technomancy: you could define a clojure.lang.Regex

18:01 TEttinger: you could add a reader literal to create your own REFn

18:01 technomancy: since no one has ever used #"" regexes for interop ever

18:01 * llasram suspects sarcasm, but isn't certain

18:01 TEttinger: it could also be a subclass of the java regexp

18:02 technomancy: llasram: no seriously

18:02 I would be mildly surprised if anyone on this channel has ever done it

18:02 Bronsa: TEttinger except Pattern is final :)

18:02 TEttinger: wat

18:02 Bronsa: http://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html

18:03 TEttinger: then you could have another class that has a Pattern as a member and itself implements IFn

18:03 technomancy: TEttinger: I would vote for that =)

18:04 Bronsa: TEttinger you couldn't use that for interop then

18:04 noonian: why do you need it to work with just a literal?

18:04 llasram: If classes aren't explicitly designed to be extensible, best to make them final. Keeps things all neat and tidy.

18:04 Prevents the proletariat from getting uppity etc

18:04 TEttinger: right, but you could get the Pattern out of it once and use that for interop

18:04 I dunno

18:05 Bronsa: TEttinger but there'd be no way to always known statically when you're passing a MyPattern instead of a proper Pattern to "unbox" it

18:06 TEttinger: I guess. the best solution would be to not interop, I suppose

18:06 Bronsa: you'd need to add instance checks + "unbox" paths everywhere you call a method taking a Pattern

18:06 which might not be too bad actually

18:06 technomancy: noonian: filtering on a regex is many orders of magnitude more useful than interopping a regex, so it's unfortunate that the latter is convenient and the former is not

18:09 Bronsa: I might actually attempt a patch for that one of the next days

18:10 it might break code that explicitely tests for j.u.regex.Pattern though

18:12 dorkmafia: http://paste.debian.net/120473/ why does line 17 throw a java.lang.NullPointerException the first time i call it but after that it's fine?

18:14 noonian: ,(filter (partial re-find #".*foo.*") ["foobar" "goobar" "foobaz"])

18:14 clojurebot: ("foobar" "foobaz")

18:14 noonian: i'm happy enough with that though

18:16 dbasch: noonian: I'd probably want re-matches behavior rather than re-find

18:18 noonian: dbasch: it wouldn't matter for filtering though right? both would return a truthy value if there are any matches or nil otherwise if i'm not mistaken

18:18 dbasch: noonian: it depends on the regexp

18:19 noonian: dbasch: ah, good call

18:19 ,(filter (partial re-matches #".*foo") ["foobarfoobar" "goobar" "foobaz"])

18:19 clojurebot: ()

18:19 noonian: (filter (partial re-find #".*foo") ["foobarfoobar" "goobar" "foobaz"])

18:19 ,(filter (partial re-find #".*foo") ["foobarfoobar" "goobar" "foobaz"])

18:19 clojurebot: ("foobarfoobar" "foobaz")

18:22 dorkmafia: is there something wrong I'm doing with the chaining of functions?

18:24 dbasch: dorkmafia: what parameters are you calling that with? What's the exception?

18:26 dorkmafia: dbasch: http://paste.debian.net/120474/

18:29 dbasch: I don't see any calls there, just definitions

18:30 dorkmafia: it's in the handler

18:32 noonian: so where do you create the handler? it looks like all those functions get it passed in

18:32 dorkmafia: http://paste.debian.net/120475/

18:33 hmm

18:33 maybe it's passing nil as the from-user?

18:34 noonian: yeah maybe, you might get a message where the body isn't blank but there is no :from-name

18:35 i'd definitely print the message for now so you know what it's getting

18:38 dorkmafia: hmm

18:38 k

18:41 nope the from-user is correct

18:42 it doesn't print out twice which is strange

18:55 noonian: i think it has to do with the roster not being defined

18:57 (defn roster [conn] (when conn (.getRoster conn) )) am i using when correctly here?

18:59 dbasch: dorkmafia: it depends on what you want. If conn is falsey that will evaluate to nil.

19:02 dorkmafia: hm i dunno

19:03 noonian: dorkmafia: i'd change it to an if for now and print something if the conn is nil

19:03 its nice to have more information during dev/debugging

19:06 dorkmafia: (.getEntry (roster conn) uname) )

19:06 could it be due to taht?

19:06 i'm going to try and use a local variable for the roster there

19:07 technomancy: IMO you should check for nils as early as possible and error out

19:07 letting them leak through any old place in your program makes for bugs that are tedious to track down

19:08 dorkmafia: all of the inputs are fine

19:13 is it possible I need to set java types for the return types of some of these methods?

19:14 amalloy: dorkmafia: no

19:15 tuft: technomancy: they can work like a poor man's maybe monad, which is nice

19:16 technomancy: monads without a type checker... poor man indeed =)

19:23 dbasch: dorkmafia: I still don't know how you're starting the whole thing. I assume you call starter-bot, but what is smack/start-bot?

19:23 amalloy: sounds like bot abuse to me

19:24 dbasch: amalloy: you just reminded me of a Futurama episode

19:26 dorkmafia: dbasch: there is another class i missed lol sorry

19:27 http://paste.debian.net/120478/

19:36 dbasch: dorkmafia: that code is pretty convoluted, where does it come from?

19:36 dorkmafia: yah that's why i'm trying to make it better it's from xmpp-clj

19:36 on github

19:46 dbasch: should i just start over? lol

19:48 adereth: I wish I had done the Heroku Clojure walkthrough sooner. That was really easy.

19:48 Made a toy: http://templar-clj.herokuapp.com/

19:48 http://templar-clj.herokuapp.com/?url=http%3A%2F%2Ftemplar-clj.herokuapp.com%2F

19:55 justin_smith: adereth: is it giving a templated version of the page provided?

19:55 locks: cute

19:56 justin_smith: An error occurred in the application and your page could not be served. Please try again in a few moments. If you are the application owner, check your logs for details.

19:58 adereth: Yes

19:58 In Enlive, Hiccup, and Hickory style

19:58 Oh noes. Still?

21:12 yedi: jsut to confirm, clojure lists have 0(1) prepending and appending correct?

21:12 bbloom: yedi: prepending only

21:13 yedi: oh... that's unfortunate. is there a data structure that also keeps a pointer to the end of the lis tas well

21:13 bbloom: yedi: concat constructs a lazy sequence in O(1) time

21:13 yedi: vectors have fast push/pop from the tail and can be converted in to a seq in O(1) time

21:14 if you genuinely need push/pop from both sides, there are contrib libs for finger trees and rrb vectors

21:14 justin_smith: yedi: there is a lib with a persistent deque (which does fast prepand and append)

21:14 bbloom: but it's pretty rare that you actually need that

21:14 yedi: justin_smith: ah i think that was the library you linked me to before

21:14 justin_smith: yedi: probably

21:14 yedi: bbloom: well i'm creating a queue that needs to be able to append on one side and pop from the other

21:15 justin_smith: but you wanted a queue actually, right? and there is a built in Persistentqueue if you want fast front insertion and fast tail removal

21:15 bbloom: ,clojure.lang.PersistentQueue/EMPTY

21:15 clojurebot: #<PersistentQueue clojure.lang.PersistentQueue@1>

21:15 yedi: this is on clojurescript btw

21:15 TimMc: "by the way"

21:15 yedi: >_<

21:15 bbloom: yedi: i think cljs has persistent queue also...

21:15 yedi: sweet, ill go check

21:17 TimMc: I'd be curious to hear what you find.

21:17 bbloom: it's there

21:18 yedi: yep

21:48 zeebrah: adereth: is there a link to the walk through?

21:52 truebuddi: any tips or good reading links about how an experienced OO dev can think of modeling data in a functional world?

21:53 rubygeek: maybe this? https://leanpub.com/fp-oo

21:53 matthoffman: truebuddi: I quite liked that one

21:54 justin_smith: truebuddi: many of Rich Hickey's video talks are about contrasting Clojure style functional programming to Java style OO

21:55 truebuddi: I did a lot of reading .. practiced almost everything from iloveponies.github.com; watched quite a few talks from rich hickey .. recently started looking at joy of clojure .. i get the language but am having trouble getting something real done in clojure ...

21:56 justin_smith: truebuddi: what real things have you tried to do?

21:57 truebuddi: justin_smith: well i wanted to build a small web app .. for fun kind ..but have some starting trouble ...

21:58 justin_smith: what were your roadblocks?

21:58 matthoffman: it can be tough to stare at a blank page and think of how to model the world functionally when you're used to OO; i found it easier to try adding a feature to an existing project.

21:58 'cause then i had to walk through existing code and figure out how they modelled things

21:59 jasonjck_: following SICP in clojure is a good way to learn

22:00 jasonjckn: i think there's a whole clojure book on webapps

22:00 it's not joy of clojure

22:00 justin_smith: truebuddi: anyway, if you have specific questions, feel free, all of my largest clojure projects have been either web apps or my work on a web app framework, and I know a number of other folks here do clojure web apps too

22:00 truebuddi: @justin ... for eg, i want to build a "trip journal" where you have a "group of people". each person can comment on a trip...trip cannot be deleted by anyone else other than that person who created it ... things like that ...

22:01 bja: where has prismatic/schema been all of my life?

22:02 justin_smith: truebuddi: on a data modeling level, a database is by definition not functional (unless you use something like datomic that has an immutible history, but frankly I think that is often overkill) - functional programming can use persistence and mutation judiciously, just as OO can use immutible data or static methods

22:02 bja: I know, right?

22:03 truebuddi: the key, for me, is to have a clear mental model of where and why the mutation / persistence occur (they often go hand in hand), and how they integrate with the purely functional ecosystem that is the rest of my code

22:03 bja: built a coercer to handle configs pulled in via environ/zookeeper

22:03 my life is now simple

22:04 justin_smith: bja: as long as you don't expect to be able to use watches, or treat it like a db, zookeeper is awesome

22:05 truebuddi: justin_smith: initially i am not even worried about persistence ... for the most part I am only concerned about how you would you model something? say I want anemic object Person .. with a name, profile picture, some description ... you make the person a map or a record or what...thats the kind of stuff that isn't clear to me yet

22:05 justin_smith: truebuddi: to be more concrete, I will usually associate a request with gathering db data coming in, and then writing db data on the way out again

22:06 truebuddi: use a map until maps are a bottleneck

22:06 truebuddi: use assertions or prismatic/schema to make sure the data has the shape you expect

22:06 bja: justin_smith: what's wrong with using watches?

22:06 justin_smith: bja: they are flawed inside zookeeper

22:07 bja: oh, I mean avout - the clj zookeeper binding that acts like an atom

22:07 it makes zookeeper extremely easy to use, but the watches are not worth it (and don't use it for large data sizes)

22:07 bja: I've been using watches for settings updates

22:08 but have not been using about

22:08 justin_smith: bja: I specifically meant watches on avout/atom objects

22:08 bja: ah, ok

22:08 justin_smith: bja: http://avout.io/ check out the example code - they do make it very similar to clojure.core atoms

22:09 (and refs also, but there is less reason to use those)

22:09 bja: oh, I saw that on /r/clojure I think

22:10 justin_smith: but I am sure zookeeper is awesome on its own too (and in some ways simpler when it doesn't try to pretend to be a standard clojure reference type)

22:10 bja: yeah. We're just using it to distribute settings

22:11 justin_smith: right, that is what I did too, but being able to look at the settings like atoms was a bonus

22:11 bja: having a config schema makes it easy to know that a bad settings push won't blow up my production systems

22:14 justin_smith: truebuddi: another revelation for me was focusing less on creating structures that emulate the real world and more on creating stateless transformations that can be composed to create the process I need

22:15 truebuddi: if my map needs a new key in it, or the list needs to become a vector, this is a simple change if I wrote my code well - the interesting part isn't getting the data model perfect up front, its being able to quickly iterate the data transformations until I have the program I need

22:17 truebuddi: justin_smith: so you suggest I start with something basic ... just model as much data as I could with what I know ... maps...lists ... vectors..sets and then refactor later?

22:17 justin_smith: truebuddi: yeah, that is how clojure programs typically evolve

22:17 and all the operations on maps are supported on records

22:17 so if you need something more specific later, you can upgrade easily

22:18 truebuddi: justin_smith: now that makes me worry next about ownership ... usually in OO you can have a repository which owns a list of people .. so in a fp world who owns say a list of my persons? another structure eventually in a global context?

22:19 justin_smith: truebuddi: maybe you've seen that Alan Perlis quote? It is better to have 100 functions operate on one data structure than 10 functions on 10 data structures."

22:19 truebuddi: when you have ubiquitous immutibility, ownership becomes less important - when you need mutation, keep it near the owner, and export something immutible at the earliest practical moment

22:19 truebuddi: justin_smith: I didn't know it was from Alan Perlis but heard of that quote when doing some reading about Clojure and Rich Hickey quoted it somewhere i guess ..

22:21 ToxicFrog: How do I express "this function does not return" in a core.typed annotation?

22:22 justin_smith: truebuddi: so, since you need a mutible storage of user data (assuming that is what "people" are for here), I would make a people ns, keep all implementation details internal to that ns, and clearly delineate the functions comprising the API, which returns immutible people for queries, or takes update maps and manages state based on those updates

22:23 TimMc: ToxicFrog: Declare it to yield _|_, obviously. :-P

22:23 truebuddi: justin_smith: so use ns to organize functionality .. hmmm

22:24 justin_smith: truebuddi: yeah, for me an ns represents some group of related abilities provided to other code

22:24 TimMc: ToxicFrog: (No, I don't actually know if core.typed supports bottom.)

22:25 truebuddi: justin_smith: what do you think of https://leanpub.com/fp-oo that was suggested earlier to me ..

22:25 justin_smith: ⏟⏟ <- a much more shapely bottom, thanks to unicode

22:25 ToxicFrog: TimMc: it describes "Nothing" as "the bottom type"

22:25 justin_smith: truebuddi: I have not read it

22:25 TimMc: justin_smith: Oh, Unicode and its shapely bottoms...

22:26 truebuddi: justin_smith: been a few years since I did web dev ... anyway do you have a suggestion for a small but practical web app that I can study preferably one in clojure/cljs

22:26 TimMc: ToxicFrog: But then the docs say "Nothing is the bottom type that inhabits no types except itself." which I think disagrees with (say) the Haskell notion of bottom.

22:26 _|_ is supposed to inhabit *all* types, right?

22:27 truebuddi: justin_smith: I played around with compojure, http-kit .. so i am not too concerned about the technology but am more interested in how things like sessions, cookies, web sockets are mixed with business end of things in clojure

22:28 justin_smith: truebuddi: https://github.com/prismofeverything/schmetterling is by a friend of mine (I contributed extensively to the design, but less to the actual code) - sadly I can't think of a really good web service in clojure for reading off the top of my head (all my good ones are closed source client work)

22:28 TimMc: stupid sexy unicode

22:31 TimMc: justin_smith: http://www.boardsandrec.com/showthread.php?t=82114

22:31 "unicode butt" is now in my google search history, forever

22:32 justin_smith: lol

22:34 and all along, I was looking for: ⊥ "UP TACK"

22:34 why the hell is it called up tack? who knows

22:35 * TimMc fils an angry letter with the Unicode Consortium

22:35 TimMc: *files, also

22:35 teslanick: Looks like a tack sitting on its head, pointing up?

22:35 justin_smith: right, but I have never heard it called that name in a mathematical context, though it is categorized as a mathematical symbol

22:36 TIL http://en.wikipedia.org/wiki/Up_tack

22:36 "falsum"

22:37 also, (⊥) has an antonym, (⊤) and both look kind of butt-like when parenthesized

22:38 teslanick: Indeed. It's like the two great taxinomies of highly convex rear-ends.

22:38 I think Sir Mix-A-Lot wrote a ballad to the union of both taxonomies.

22:39 justin_smith: (inc teslanick)

22:39 lazybot: ⇒ 2

22:39 teslanick: \o/ I will treasure this.

22:44 ToxicFrog: Man, apply+core.typed is my worst enemy

22:44 Target: (IFn [java.lang.String Any * -> java.lang.String])

22:44 Arguments: (clojure.lang.PersistentList String)

22:45 Those look type-compatible to me!

22:45 justin_smith: ToxicFrog: is apply worse than other higher order constructs?

22:45 ToxicFrog: justin_smith: well, it's the only one giving me grief

22:46 justin_smith: one of these days I will take the core.typed plunge - I think I'll try using prismatic/schema more extensively first though

22:46 ToxicFrog: An earlier issue with it was entirely my fault -- (apply f x ys) matches the type [X Y * -> ...], not [X (Vec Y) -> ...]

22:46 But here it looks like it should be type-compatible; the PersistentList String expands to String String String... when applied, so it should match the signature [String Any * -> ...]

22:48 I also get this new and exciting error:

22:48 Type Error (bltool/data/default.clj:26:1) Internal Error (bltool/data/default.clj:26:1) Unreachable method: Local inferred to be bottom when applying multimethod filter

22:50 ambrosebs: ToxicFrog: that will fail for an empty list

22:51 truebuddi: +cnt

22:51 ToxicFrog: ambrosebs: in this case, the list is generated by macro expansion and is known at compile time to be nonempty.

22:51 (and I don't control the macro, it's slingshot's throw+)

22:52 ambrosebs: ToxicFrog: very likely throw+ will need a typed variant.

22:52 for any complicated macro it's usually the case

22:52 ToxicFrog: As in, write my own type-annotated replacement for it?

22:52 ambrosebs: yes

22:52 ToxicFrog: D:

22:52 ambrosebs: like clojure.core.typed/for is for clojure.core/for

22:53 ToxicFrog: I don't suppose there's some way I can tell it to just not check anything inside a throw+ block

22:53 (also, any idea on the internal error?)

22:54 ambrosebs: ToxicFrog: hmm I'd need to see the defmulti/defmethod

22:55 ToxicFrog: core.typed just macroexpands out everything blindly and checks it

22:55 the solution is another macro unfortunately

22:59 ToxicFrog: ambrosebs: they're pretty simple: https://gist.github.com/ToxicFrog/73e20b453e4b578ab590

22:59 And it's only the second one that it generates that error on, which is especially weird.

23:00 ambrosebs: ToxicFrog: the return type should not be Nothing

23:00 Nothing means an error

23:00 of write-games

23:01 ToxicFrog: What should it be, then? nil?

23:01 Also, that passes type checking, it's read-games that it objects to.

23:01 ambrosebs: oh right I see

23:02 ToxicFrog: so it's saying that read-games with dispatch value "nil" is unreachable based on the type of the multimethod

23:03 perhaps the first argument of read-games should be (U nil String)

23:04 note that core.typed shouldn't really be complaining this loudly

23:04 it should just ignore the method and move on

23:04 but I decided to be noisy at least while core.typed's implementation is relatively young

23:04 ToxicFrog: Yep, if I changed it to (U nil String) it stops complaining about that one and starts complaining about the fourth one.

23:05 ambrosebs: right same issue I guess

23:05 ToxicFrog: Yeah.

23:05 ambrosebs: nothing to do with the Nothing return type

23:05 ToxicFrog: Either can be nil for "argument not specified"

23:05 And now all four of them are complaining about "bad arguments to apply" from throw+'s use of format, which is more in line with what I'd expect.

23:07 For now I think I'll just mark that ns :collect-only, I really only care about it for checking the other defmethods associated with it.

23:07 ambrosebs: good idea

23:10 ToxicFrog: ...hmm. How do I mark it :collect-only? I can't find docs for this, and I thought it was just (ns bltool.data.default ^:collect-only ...) but that doesn't appear to do anything.

23:11 Oh, I see. It's either (ns foo {:core.typed {:collect-only true}} ...), or (ns ^{:core.typed ...} foo ...)

23:38 * ToxicFrog bonks his head against the keyboard a few times and goes to sleep. Maybe this will make more sense in the morning.

Logging service provided by n01se.net