#clojure log - Nov 08 2014

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

0:15 rritoch: I'd love to switch to Mac but they're so overpriced, Lenovo Flex 2 (15-Inch) $700, Mac (15-inch) $2000, does Tin Cook really think we're that stupid?

0:16 justin_smith: there's offices full of people with office supplied macbooks saying yes

0:17 rritoch: I've noticed, many of my clients use Mac, I just don't get it

0:18 My server with 4 Teraflops of computing power via 2 Radeon 280X's cost me less than that Macbook

0:22 It was the first time I've seriously looked at Mac's in 25 years, not because Mac has improved, but because Microsoft has devolved.

0:26 catern: switch to Linux

0:26 holy crap freenode spammers everywhere

0:26 kickban kirloo, is spammer

0:29 rritoch: Well, I am running Ubuntu (rooted) on my server, but Linux still requires a lot of complex maintenance and configuration to set it up properly.

0:30 catern: that's not true

0:30 also what

0:30 Ubuntu (rooted), as in you have root?

0:30 on a server you administrate, it would be highly unusual if you did not

0:30 (have root)

0:30 justin_smith: if it was complex, would we really be using it on servers?

0:32 rritoch: justin_smith: Once it's configured it's stable for the most part, but getting the AMD drivers and OpenCL to work properly is a nightmare

0:32 justin_smith: rritoch: I bought this box with linux pre-installed. Compared to installing windows or mac from scratch it was a breeze to set up (but let's compare apples to apples - pre-installed to pre-installed, install from scratch to install from scratch)

0:32 rritoch: It still isn't working properly

0:32 I can't get any video-out on the second video card

0:33 justin_smith: rritoch: as soon as I first powered up this machine I had full accelerated video

0:33 just like with a mac or windows box, the factory set it up for me

0:33 comapre apples to apples

0:33 rritoch: I can run dual screen on the one card, but if I connect screens to the second card they don't display anything

0:33 justin_smith: rritoch: I am using three screens right now, I can potentially use up to five, it just works

0:34 rritoch: From separate AMD cards?

0:34 justin_smith: one card

0:34 like I said, it was pre-configured by the folks who built my laptop

0:34 rritoch: multi-monitor works fine from my first video card, I just can't get any output on the second video card

0:34 justin_smith: just as your windows box was pre-configured by the folks who built your machine

0:35 rritoch: At least not from Linux, I have a dual-boot to windows and both cards function properly from windows

0:35 justin_smith: and who configured that? I expect it worked when you first bought the machine.

0:36 rritoch: It is a problem with the AMD catalyst driver, but I"m not sure what

0:36 I configured it myself, it only came with Windows.

0:37 catern: rritoch: yes, but someone configured the Windows for you

0:37 rritoch: No, I just installed the Catalyst driver and it worked out of the box

0:39 catern: yes

0:39 that's what we're saying

0:39 anyway

0:40 rritoch: It worked on windows out of the box

0:40 It doesn't work on Ubuntu out of the box

0:40 that is what I"m saying

0:41 catern: yes, that's because someone already (mostly) configured it for you on Windows

0:41 anyway

0:41 rritoch: Windows doesn't have any effect on linux in a dual-boot situation

0:41 catern: yes, justin_smith was just being competitive

0:42 justin_smith: catern: I just think it is unfair that people compare the experience installing an OS from scratch, to the experience with an OS that was pre-installed and pre-configured

0:42 catern: you seemed to be bashing Linux and praising Windows, so he was pointing out the seeming superiority of Windows in this regard is just a result of your laptop coming preinstalled and preconfigured with Windows

0:42 justin_smith: i agree

0:43 justin_smith: "I tried to build a mercedes from parts, but just driving my kia is easier"

0:43 (an exageration, of course0

0:44 rritoch: justin_smith: I've installed windows from scratch literally hundreds of times, and linux from scratch dozens of times, windows is always easier to install.

0:44 I suppose if you have garbage generic hardware linux is easy to use, but if you have good/modern hardware, linux is a nightmare.

0:45 catern: see justin_smith that's why you don't jump so far ahead in the conversation

0:45 rritoch: I have a 5th gen motherboard and 2X GPU's, so the setup was far from simple.

0:45 justin_smith: rritoch: I have a laptop with a top of the line video card that supports four simulaneous external displays, 32 gigs of ram installed, and 8 cores. The machine is over a year old but it is not trash.

0:46 rritoch: I can't compare any of this to Mac, as I said I haven't used an apple product in over 25 years, unless you count virtual machines, but I just used a prepared VM drive for that so I really don't know what the install is really like.

0:46 catern: well, anyway, on Windows you *STILL* have to look around for drivers, which is ridiculous, so Linux is superior there at least. you do have an unconventional setup so some configuration is to be expected

0:48 justin_smith: this is all pretty off topic, I'm sorry I went off like that.

0:48 rritoch: Well, clojure needs an OS, and needs a good one

0:49 I wish oracle would bring back sparc, I bet clojure would run like a sportscar on a sparc server.

0:51 I've been toying with the idea of a clojure OS, but I think that would be a brutal nightmare.

0:51 razum2um: is there any best practice to override map->MyRecord with a function with preconditions? or do I need to stick with another fn name?

0:51 justin_smith: razum2um: why override? just write your own and use it

0:52 don't steal the name, I think that would inevitably lead to confusion

0:52 razum2um: justin_smith: but ideally not about to override it, just add precondition

0:53 ok, is there any semantic under fn* names, would it be ok for such cases?

0:54 justin_smith: razum2um: just write a function that validates the arguments and constructs the structure

0:56 razum2um: justin_smith: ok, but I think it good if such cases have traditionaly approved names, e.g. map->Record* means it behaves just like map->Record but may check args and fill in defaults

0:56 i think convention over configuration is always good

0:56 justin_smith: there is no such tradition that I know of

0:57 adding a * at the end typically means "don't use this one"

0:57 see fn*, let*

0:57 razum2um: perhaps adding a bang will be good such in rails it means that fn may raise an exception

0:58 but agian, I think absence of convention is very bad for understanding other's people code

0:58 justin_smith: razum2um: in clojure a bangh usually means that a function is not safe in a transaction, or it does some extreme mutation

0:59 razum2um: justin_smith: yeah, naming and cache invalidation are hard :)

0:59 justin_smith: ,(clojure.string/join \space (filter (comp #(.endsWith % "!") name) (keys (ns-publics 'clojure.core))))

0:59 clojurebot: "vswap! vreset! set-error-mode! set-agent-send-executor! disj! conj! pop! compare-and-set! reset-meta! set-error-handler! set-agent-send-off-executor! dissoc! assoc! reset! alter-meta! persistent! run! set-validator! swap! volatile! io!"

1:00 razum2um: yes, they deal with mutation

1:01 e.g. will you recognize map->>Record without looking into source of fn?

1:03 justin_smith: I would expect construct-Record or make-Record to do something that map->Record does not

1:09 razum2um: justin_smith: ok, but how you think, is there any sense to turn it and perhaps some other similar cases into a survey? just not to invent convention, but collaborately define it

1:16 rritoch: Does clojure provide any means of namespace inheritance? I'm thinking of changing the MVC framework I'm using to be more pure clojure (without the gen-class) but I'd like common functions available, like view-ns/render which can be overridden but have a default functionality "imported".

1:17 My issue is that use/require doesn't actually "import" the functions into the current namespace, it just makes them available for use

1:26 akhudek: rritoch: you can refer either some of the symbols or all of the symbols when you require

1:26 razum2um: rritoch: I suggest to wirite a macro generating defn's which call original fn

1:26 akhudek: rritoch: or do you mean you want a copy essentially?

1:27 rritoch: Yes, I want a local copy, or better yet, reference

1:27 Probably similar to what akhudek suggested

1:27 But some means of bringing in all of the symbols

1:28 akhudek: e.g. you if you import into foo into namespace b, you want to be able to call it as b.foo

1:29 I think there was a thread on the clojure list about that

1:29 don’t remember any good solutions sadly

1:30 rritoch: Something like (map #(def (second %1)) (ns-publics 'some-other-ns))

1:31 But of course it would need to be much cleaner than that, I suppose a macro could be used

1:32 godd2: I have (map #(vector %1 %2) (range 10) (range 10)) but I want to pass that second (range 10) -as the collection itself- to the anonymous function. Is there a way to stop map from sending the individual elements?

1:33 rritoch: I guess ... (map #(def (first %1) (second %1)) (ns-publics 'some-other-ns)) is closer though I don't think that would work... A macro may

1:37 ,(map #(vector %1 %2) (range 10) (take 5 (repeatedly #(range 10))))

1:37 clojurebot: ([0 (0 1 2 3 4 ...)] [1 (0 1 2 3 4 ...)] [2 (0 1 2 3 4 ...)] [3 (0 1 2 3 4 ...)] [4 (0 1 2 3 4 ...)])

1:37 rritoch: godd2: Is that ok with you?

1:37 err

1:37 ,(map #(vector %1 %2) (range 10) (take 10 (repeatedly #(range 10))))

1:37 clojurebot: ([0 (0 1 2 3 4 ...)] [1 (0 1 2 3 4 ...)] [2 (0 1 2 3 4 ...)] [3 (0 1 2 3 4 ...)] [4 (0 1 2 3 4 ...)] ...)

1:37 TEttinger: tbaldridge: nice work with https://github.com/pixie-lang/pixie

1:41 godd2: yes! thank you rritoch

1:42 TEttinger: ,(map (partial vector (range 10)) (range 10))

1:42 clojurebot: ([(0 1 2 3 4 ...) 0] [(0 1 2 3 4 ...) 1] [(0 1 2 3 4 ...) 2] [(0 1 2 3 4 ...) 3] [(0 1 2 3 4 ...) 4] ...)

1:42 TEttinger: that does put it in reverse order though

1:43 godd2: TEttinger that will nicely produce the list rritoch made, but I wanted to pass the collection to the anon function so I could do more work on it

1:43 TEttinger: ah, ok

1:43 you can have it as a variable, or other bound name

1:45 ,(let [roll (fn [] (repeatedly 5 #(rand-int 100)))] (map (partial vector (roll)) (range 10))

1:45 clojurebot: #<RuntimeException java.lang.RuntimeException: EOF while reading>

1:45 TEttinger: ,(let [roll (fn [] (repeatedly 5 #(rand-int 100)))] (map (partial vector (roll)) (range 10)))

1:45 clojurebot: ([(53 29 24 43 64) 0] [(53 29 24 43 64) 1] [(53 29 24 43 64) 2] [(53 29 24 43 64) 3] [(53 29 24 43 64) 4] ...)

1:45 TEttinger: weird

1:46 ,(let [roll (fn [] (repeatedly 5 #(rand-int 100)))] (map #(vector % (roll)) (range 10)))

1:46 clojurebot: ([0 (51 59 8 71 10)] [1 (45 46 53 29 55)] [2 (60 10 97 46 57)] [3 (67 78 25 26 55)] [4 (80 40 53 14 9)] ...)

1:48 godd2: awww I cant do repeated #() ??

1:48 lazybot: godd2: Uh, no. Why would you even ask?

1:48 rritoch: ? It's repeatedly

1:49 godd2: sorry, nested

1:49 I can't do nested #()

1:50 rritoch: No but #() is just a reader macro, you can resort to an anony function via (fn [...] ....)

1:51 godd2: ah okay awesome

1:51 yay it worked! (map #(map (fn [x y] (vector x y)) %2 (repeat %1)) (range 10) (repeatedly #(range 10)))

1:51 I hope that's not an entirely stupid way of making a list of vector pairs of the cartesian product of (range 10) with itself

1:54 TEttinger: kinda

1:55 ,(map #(map vector %2 (repeat %1)) (range 10) (repeatedly #(range 10)))

1:55 clojurebot: (([0 0] [1 0] [2 0] [3 0] [4 0] ...) ([0 1] [1 1] [2 1] [3 1] [4 1] ...) ([0 2] [1 2] [2 2] [3 2] [4 2] ...) ([0 3] [1 3] [2 3] [3 3] [4 3] ...) ([0 4] [1 4] [2 4] [3 4] [4 4] ...) ...)

1:56 godd2: I added (apply concat ...) to get rid of the list of lists

1:56 TEttinger: remember, fns are first-class in clojure, so (fn [x y] (vector x y)) is almost the same as vector

1:57 godd2: TEttinger but then I couldn't rely on map passing the elements of the colls from %2 and (repeat %1)

1:58 are you saying I could just pass (vector)

1:58 TEttinger: no

1:58 the function vector

1:58 like in the example I just posted

1:58 godd2: ahh okay I was making it more complicated than I needed to

1:59 ,(apply concat (map #(map vector (repeat %1) %2) (range 10) (repeatedly #(range 10))))

1:59 clojurebot: ([0 0] [0 1] [0 2] [0 3] [0 4] ...)

1:59 TEttinger: vector, instead of an anon fn calling vector, should be ever so slightly faster, and simpler to write

1:59 dbasch: &(for [x (range 10) y (range 10)] [x y])

1:59 lazybot: ⇒ ([0 0] [0 1] [0 2] [0 3] [0 4] [0 5] [0 6] [0 7] [0 8] [0 9] [1 0] [1 1] [1 2] [1 3] [1 4] [1 5] [1 6] [1 7] [1 8] [1 9] [2 0] [2 1] [2 2] [2 3] [2 4] [2 5] [2 6] [2 7] [2 8] [2 9] [3 0] [3 1] [3 2] [3 3] [3 4] [3 5] [3 6] [3 7] [3 8] [3 9] [4 0] [4 1] [4 2] [4 3] [4... https://www.refheap.com/92893

1:59 TEttinger: and yeah, for is good for this :P

1:59 dbasch: ^ godd2 is that what you want?

2:00 godd2: dbasch that is precisely what I wanted. Ill go look at the docs for for now, thank you!

2:04 rritoch: ,(map-indexed (fn [x y] (map (partial #(vec (list %1 %2)) x) (range 10))) (range 10)

2:04 clojurebot: #<RuntimeException java.lang.RuntimeException: EOF while reading>

2:05 rritoch: ,(map-indexed (fn [x y] (map (partial #(vec (list %1 %2)) x) (range 10))) (range 10))

2:05 clojurebot: (([0 0] [0 1] [0 2] [0 3] [0 4] ...) ([1 0] [1 1] [1 2] [1 3] [1 4] ...) ([2 0] [2 1] [2 2] [2 3] [2 4] ...) ([3 0] [3 1] [3 2] [3 3] [3 4] ...) ([4 0] [4 1] [4 2] [4 3] [4 4] ...) ...)

2:06 rritoch: ,(map-indexed (fn [x y] (map (partial #(vec (list %1 %2)) x) (range 2))) (range 3))

2:06 clojurebot: (([0 0] [0 1]) ([1 0] [1 1]) ([2 0] [2 1]))

2:20 godd2: Here is the completed problem. Feel free to offer any criticism of the code, including format. https://gist.github.com/nicklink483/a7ad9968a9a58c7ebf0a

2:26 arrdem: Okay. Someone convince me to learn a structural editing mode for emacs

2:29 nonuby: is there a nil loving nth? rather than IOOB exceptipn

2:30 ah nevermind 3rd arg is default not found, fits

2:33 rritoch: ,(map #(seq (zipmap (range 10) (take 10 (repeatedly (partial identity %))))) (range 10))

2:33 clojurebot: (([0 0] [7 0] [1 0] [4 0] [6 0] ...) ([0 1] [7 1] [1 1] [4 1] [6 1] ...) ([0 2] [7 2] [1 2] [4 2] [6 2] ...) ([0 3] [7 3] [1 3] [4 3] [6 3] ...) ([0 4] [7 4] [1 4] [4 4] [6 4] ...) ...)

2:36 rritoch: Any ideas why that isn't sorted?

2:38 ,(map #(sort (zipmap (range 10) (take 10 (repeatedly (partial identity %))))) (range 10))

2:38 clojurebot: (([0 0] [1 0] [2 0] [3 0] [4 0] ...) ([0 1] [1 1] [2 1] [3 1] [4 1] ...) ([0 2] [1 2] [2 2] [3 2] [4 2] ...) ([0 3] [1 3] [2 3] [3 3] [4 3] ...) ([0 4] [1 4] [2 4] [3 4] [4 4] ...) ...)

2:40 TEttinger: (doc zipmap)

2:40 clojurebot: "([keys vals]); Returns a map with the keys mapped to the corresponding vals."

2:40 TEttinger: maps aren't sorted

2:42 ,(map #(interleave (range 10) (repeat 10 %)) (range 10))

2:42 clojurebot: ((0 0 1 0 2 ...) (0 1 1 1 2 ...) (0 2 1 2 2 ...) (0 3 1 3 2 ...) (0 4 1 4 2 ...) ...)

2:42 TEttinger: ,(map #(map vector (range 10) (repeat 10 %)) (range 10))

2:42 clojurebot: (([0 0] [1 0] [2 0] [3 0] [4 0] ...) ([0 1] [1 1] [2 1] [3 1] [4 1] ...) ([0 2] [1 2] [2 2] [3 2] [4 2] ...) ([0 3] [1 3] [2 3] [3 3] [4 3] ...) ([0 4] [1 4] [2 4] [3 4] [4 4] ...) ...)

2:43 TEttinger: that closer to what you're after, rritoch?

2:43 rritoch: I see, I just assumed they maintained the order items were added to them. Scary how many bugs may be floating around because of that mistake.

2:43 TEttinger: maps are never sorted by default, you can use the collections in a lib called "ordered" if you want the behavior you describe

2:44 rritoch: I actually don't have use with this code, I was just playing with the different ways of creating a matrix of positional vectors

2:44 godd2: in (reduce conj () "hello") is the 'magic' that reduce is treating "hello" like a sequence of characters?

2:44 TEttinger: there is the sorted-map , and you can also do sorted-map-by

2:44 yes

2:45 strings can be treated as seqs by most core clojure fns

2:45 they aren't actually seqs but they can be used as such

2:46 ,(reduce str "hello " "world")

2:46 clojurebot: "hello world"

2:46 TEttinger: ##(reductions str "hello " "world") ;; let's see how this works

2:46 lazybot: ⇒ ("hello " "hello w" "hello wo" "hello wor" "hello worl" "hello world")

2:49 godd2: okay cool

2:50 TEttinger: godd2, you'll probably enjoy learning about destructuring, if you haven't already

2:50 it's one of the cooler features clojure has in regards to cleaning up code

2:51 godd2: I have learned about destructuring. I haven't tried it out with all the different types and such, but I do know how to, say, pass a vector as if its elements were the parameters

2:52 I come from a Ruby background, and destructuring seemed similar to passing arrays to methods and having individual params take on the elements themselves by default

2:54 But I'm trying to learn Clojure without trying to do things the Ruby way

2:58 TEttinger: it does seem like a lot of people come to clojure from the ruby community. both are concise, expressive languages, certainly, with a focus on getting stuff done.

2:59 godd2: Even in Rich's talks you'll see various examples of things which include Ruby in the list

3:07 ooooh, I like this ->> thingy

3:07 arrdem: -> and ->> are awesome

3:07 factor of at least four readability increase once I got used to it

3:13 sam122: Hi, I'd like to contribute to Clojure and hopefully try out for gsoc 2015. Is it too late to start?

3:13 And how much knowledge of Clojure is required?

3:14 godd2: sam122 when you say "contribute to Clojure" do you mean Clojure itself, or something that happens to be written in Clojure?

3:15 sam122: Clojure, Typed Clojure etc

3:16 godd2: Is this a good way of formatting? https://gist.github.com/nicklink483/65b1801b00e7e0bfb816

3:16 arrdem: Speaking as an ex-gsoc student, getting changes into clojure/core itself is basically impossible unless you are actually Rich

3:16 that said anyone can propose changes with no background

3:16 it's just that Rich'll take only what he likes

3:16 contributing to clojure.* is easy tho

3:17 godd2: Also, is there a go-to format guide for writing Clojure?

3:17 arrdem: ambrosebs, the core.typed maintainer and the other contrib libraries are awesome to a man

3:17 godd2: there is a community style guide

3:17 $google clojure style guide

3:17 lazybot: [bbatsov/clojure-style-guide · GitHub] https://github.com/bbatsov/clojure-style-guide

3:18 arrdem: there's also Eastwood, which tries to lint for unidiomatic code,

3:18 but form the most part formatting isn't standardized

3:18 godd2: alright, thank you

3:19 arrdem: godd2: functions on the same line as arguments, arguments broken by line only when you'd go over 80 or it'd be detrimental to readability.

3:19 godd2: the = and seq/reverse here

3:19 godd2: otherwise looks fine

3:19 sam122: Would a basic knowledge be sufficient?

3:19 nonuby: i have this in my project.clj https://www.refheap.com/92897 yet running lein with-profile couchexport uberjar still produces project name version (e.g. ncdoffice-0.0.2-snapshot.jar) and not couchexport.jar, any ideas?

3:20 arrdem: sam122: well you have to convince a maintainer or two to support you for GSoC... so prior experience/interest is a huge help

3:20 sam122: Ok :)

3:20 Thanks!

3:21 I hope there are more slots in 2015.

3:22 arrdem: shrug. find something to work on and seriously put some time into it ahead of time. I wouldn't say that getting accepted to GSoC is a horribly high bar for Clojure

3:22 not that we've had a slack project I know of so... shrug

3:51 wildharvest: I'm stuck on problem #22 on 4clojure, counting a sequence without using count. It's saying I tripped the alarm when I haven't used count.

3:52 I'm assuming its a macro thing, but I'm not sure if its a bug or if my solution is wrong

3:55 TEttinger: ,(reduce (fn [c _] (inc c)) 0 [1 2 3])

3:55 clojurebot: 3

3:55 TEttinger: what's your solution so far, wildharvest?

3:56 wildharvest: My solution was (fn [s] (let [r 0] (doseq [i s] (swap! r inc)) r))

3:57 TEttinger: well, swap! only works on atoms

3:58 so since r is a number, it wouldn't run anyway

3:58 arrdem: do you really need mutability here?

3:58 ^ always ask this in Clojure

4:01 wildharvest: I knew I was headed in the wrong direction with swap! but wasn't quite sure how to do it with filter/reduce/map but your solution cleared that up for me

4:03 Thanks TEttinger & arrdem

4:03 TEttinger: no prob

4:03 arrdem: my pleasure

4:04 I'll be here, with beer, telling you to do it better all night :P

4:41 ingsoc: anyone use counterclockwise, I am wondering how you can get the saved changes immediately reflected in the integrated REPL - save + load

4:43 amalloy: arrdem: another thing to always reconsider: whether you really need the integer indices of a seq

4:44 ingsoc: CTRLK+ALT+K seems to compile into REPL window

5:15 crocket: Does clojure suffer java's null pointers?

5:17 amalloy: basically

5:18 borkdude: crocket yes, but you can use core.typed to prevent some

5:19 crocket: JAva libraries throw NPEs which clojure can't prevent.

5:19 borkdude: crocket most NPEs will come from interop code. Clojure's composable functions and datastructures cope with nil in a sane way.

5:19 TEttinger: also, many of clojure's core functions handle nil better.

5:19 crocket: Can programmers write clojure codes that throw NPEs not because of java libraries?

5:19 TEttinger: ,(map inc nil)

5:19 clojurebot: ()

5:20 TEttinger: crocket: of course

5:20 ,(+ 1 nil)

5:20 clojurebot: #<NullPointerException java.lang.NullPointerException>

5:20 crocket: nil == null?

5:20 TEttinger: yes, in clojure

5:20 borkdude: ,(throw (NullPointerException.))

5:20 clojurebot: #<NullPointerException java.lang.NullPointerException>

5:20 crocket: That's no good

5:20 null is a mistake.

5:21 borkdude: crocket maybe you can try Haskell then ;)

5:21 TEttinger: not having nil would mean clojure couldn't use any java libs, which would be a worse mistake

5:22 crocket: What about clojurescript?

5:22 borkdude: crocket same thing

5:22 crocket: null in javascript is different from null in java.

5:22 TEttinger: javascript also has the concept of null, yeah

5:23 borkdude: crocket Crockford said that he only uses undefined and not null

5:23 TEttinger: you of course won't get NPE in clojurescript because that's an error defined on the Java VM

5:23 (technically, maybe you could if you mis-wrote a macro, but it would show up at compile time)

5:24 there's probably something similar in JS, though I wouldn't know what it is

5:24 crocket: javascript doesn't have NPE.

5:25 clojure looks amusing to my eyes.

5:25 JAva is too verbose.

5:25 Clojure seems to beat scala on JVM.

5:25 borkdude: crocket it is very amusing and also addicting

5:25 TEttinger: crocket, yeah, agreed about scala

5:25 crocket: Scala is becoming the next C++.

5:25 TEttinger: scala is a very large language that suffers from bloat yes

5:26 crocket: Yet, scala still has some advantages.

5:26 TEttinger: clojurescript's macros are done in clojure in the process of generating the javascript, and the clojure part of the compiler is on the JVM, so that's the only place CLJS can technically throw NPEs, at compile-time

5:27 never in production, which is nice

5:28 clojure is definitely a very succinct language, short code is common where in java it would be many lines

5:28 crocket: A fellow programmer at my company showed how beautiful clojure was compared to javascript and java.

5:29 Yet, there is one doubt.

5:29 When coding in nodejs, I needed a lot of documentations.

5:29 Do I need a lot of documenatations due to dynamic nature?

5:29 Do I need a lot of documenatations due to dynamic nature in clojure?

5:30 TEttinger: the docs are good, certainly, and there's a lot of effort to improve them further

5:30 once you know the core functions in the standard lib, there's a lot less to look up

5:31 crocket: TEttinger, no

5:31 I want to know if the dynamic nature of clojure requires me to attach a lot of documentations to my code.

5:31 ok

5:31 In nodejs, there was no standardized way to document codes.

5:31 because static analysis fails.

5:31 TEttinger: well if you're working with other programmers, they would appreciate docs. there is a standard here

5:32 crocket: JSDoc fails to document JS codes.

5:32 No single document lib documents JS codes well.

5:34 TEttinger: ,(defn map-indexed-2 "Runs function f on the first elements of coll1 and coll2, passing the index as the first argument, then the second elements, etc." [f coll1 coll2] (map f (range) coll1 coll2))

5:34 clojurebot: #'sandbox/map-indexed-2

5:34 TEttinger: ,(doc map-indexed-2)

5:34 clojurebot: "([f coll1 coll2]); Runs function f on the first elements of coll1 and coll2, passing the index as the first argument, then the second elements, etc."

5:35 ingsoc: my first impressions of clojure (an hour or so) are that the tooling leiningen and counterclockwise(eclipse plugin) are very nice and this is my first lisp and although early days I am findign the whole environment more approachable than Ocaml (which I dipped my toes into yesterday), also I like the python style documentation for functions - dosctrings?

5:35 TEttinger: ,(map-indexed-2 + [0 100 200 300] [0 10 20 30])

5:35 clojurebot: (0 111 222 333)

5:36 TEttinger: ingsoc, yep, docstrings are nice

5:36 crocket: OCaml

5:36 The razor of Ocaml

5:36 oops

5:36 TEttinger: Occam's razor?

5:36 crocket: It's Ocam's razor.

5:38 TEttinger: OCaml is a strongly typed functional language with a very good, but very strict, compiler. technomancy wrote a faster-starting substitute for part of leiningen in OCaml, called Grenchman IIRC

5:38 one of the cool things OCaml can do is debug in reverse

5:39 not many libs for OCaml though

5:40 rritoch: Does clojure use any classloaders other than the thread's context class loader and Compiler/LOADER ?

5:40 ingsoc: well i haven't abandoned trying Ocaml, I just had a few problems early on. I had shortlisted Ocaml or Clojure to learn as a next language

5:40 TEttinger: clojure has more momentum, I'd say

5:41 it's definitely advancing into some rarely-found features, like the "transducers" being introduced with clojure 1.7

5:41 core.async I have heard good things about

5:44 rritoch: I setup the following function to call methods on OSGi services http://pastebin.com/b7shFxXK but I'm not sure if there are any other classloaders I need to override.

5:50 ingsoc: TEttinger: the main thing that puts me off clojure is JVM being a big beast (slow startup), but on the plus side it means it has access to all of the java ecosystem. Ocaml is much lighter weight in this regard and it also has pattern matching which I have really enjoyed in erlang.

5:57 TEttinger: ingsoc, I've been curious about a new project called Pixie that runs a clojure-like lisp on PyPy's VM

5:57 I'm not sure if it can call python code yet https://github.com/pixie-lang/pixie

5:58 but it does get fast startup times from that VM

5:58 tbaldridge is likely asleep, but he's the guy to ask

6:24 massi`: hello *

6:27 annelies: hello

6:51 godd2: is there a way to not print the next return value in lein repl?

6:56 hyPiRion: godd2: I usually do `(do (my-expr) nil)` to print nil instead

6:57 ,(map #(throw (Exception. %)) ["foo"])

6:57 clojurebot: #<Exception java.lang.Exception: foo>

6:57 hyPiRion: ,(do (map #(throw (Exception. %)) ["foo"]) nil)

6:57 clojurebot: nil

6:58 godd2: okay cool, thanks

7:09 Is there a reason that leiningen won't claim more than 4 to 4.5 GB of ram?

7:10 annelies: Running a 32-bit JVM?

7:11 godd2: "Java HotSpot(TM) 64-Bit Server VM 1.7.0-b147" when lein repl starts up

7:12 annelies: What is the value of :jvm-opts in project.clj?

7:13 godd2: That key isn't in the project.clj that boots with that repl

7:13 its just the default project file from lein new app

7:14 it's not a big deal, I was just somewhat curious.

7:16 rritoch: ,(.maxMemory (Runtime/getRuntime))

7:16 clojurebot: #<CompilerException java.lang.SecurityException: Reference To Runtime is not allowed, compiling:(NO_SOURCE_PATH:0:0)>

7:17 rritoch: godd2: I suspect it has something to do with that, I have 8GB ram, but my max memory is 2GB

7:18 annelies: I have 4GB and maxMemory returns 1GB.

7:20 godd2: ah okay got it. I did the maxMemory thing before and after adding :jvm-opts ["-Xmx12G"] to the project file and got 3.5 GB before and ~10.8 GB after

7:21 annelies: GB vs GiB perhaps.

7:22 godd2: yes /GB/GiB/g

7:22 I divided by 1024^3

7:23 awesome, thanks guys. I super promise not to thoughtlessly set max ram higher :P

7:25 annelies: I wish I wrote software where memory limits were actually a thing. :(

7:27 godd2: Oh I was just messing around in Clojure. apparently (reduce + (take 40000000 (range))) takes up around 5 gigs once it's finished

7:27 Bronsa: godd2: (take n (range)) is just (range n) btw

7:28 annelies: There is an O(1) algorithm to do that. :p

7:28 sum of integer range

7:28 godd2: n * (n+1) / 2 I know

7:28 I just wanted to see how far Clojure would dutifully be persistent along the way

7:29 hyPiRion: godd2: huh, that shouldn't take 5 gigs

7:31 godd2: hyPiRion You're right, sorry. I did a (def a (take 40000000 (range))) and then (reduce + a) on a new line

7:31 hyPiRion: I'm not able to reproduce that with (reduce + (range 40000000)) actually

7:31 ah, right

7:31 yeah, if you retain the head, you're going to have a bad time. But if you don't, then it should either store 1 or 32 elements only

7:32 godd2: because of the lazy eval of range?

7:32 hyPiRion: yup

7:34 ingsoc: TEttinger: "transducers" ?, also i hear protocols are raved about but i don't know much about them are they kinda like interfaces

7:35 godd2: ingsoc: https://www.youtube.com/watch?v=6mTbuzafcII

7:35 hyPiRion: ingsoc: protocols are like interfaces, but unlike interfaces, you can implement the protocol outside the record/class

7:36 this means if I have a protocol P in lib A, and a record R in lib B, and that I can implement the protocol for R in my app without changing lib B

7:36 ingsoc: Rich Hickey's hair gets wilder

7:37 :D

7:37 SagiCZ1: ingsoc: i just wanted to say that

7:38 godd2: "As time goes on his hair just gets better and better." - top comment from reddit thread of that video

7:38 ingsoc: Brian May

7:39 godd2: It reminds me of Steven Pinker's hair

7:39 ingsoc: Hair proportional to features ?

7:40 godd2: Hickey might be able to join The Luxuriant Flowing Hair Club for Scientists

7:41 ingsoc: Isaac Newton had a fair barnet on him also :)

7:44 how come clojure is so fast even with it appearing to be so dynamic ? Is this just testament to the power of JVM JIT etc. ?

7:46 Lowl3v3l: ingsoc, i believe it is primarily, yes.

7:47 ingsoc: I know you shouldn't choose a language because of the tooling counterclockwise for eclipse and leiningen are just making clojure so much easier to use than Ocaml (I don't use or have the time to invest in learning Emacs)

7:47 Lowl3v3l: ingsoc, you should take the time, it is worth.

7:50 SagiCZ1: ingsoc: but eclipse is so horrible i cant imagine any sane person could use it

7:50 ingsoc: Lowl3v3l: I have heard this a lot

7:50 I have also heard that a lot

7:50 :D

7:50 SagiCZ1: http://www.ihateeclipse.com/

7:51 ingsoc: eclipse appears overwhelmingly complex (considering most people just want to code in an editor)

7:51 but I kinda forced myself to use it (not knowing any better) and I spose now I know my way around it i like it

7:51 :/

7:52 SagiCZ1: ingsoc: i dont think its complex, but its bloated, buggy and incredibly slow

7:52 ingsoc: version 4+ is ridiculously slow on linux atm

7:52 3.7 works fine

7:53 I code in isolation and have never been exposed to Emacs to "see the light"

7:53 maybe I will have a look one day

7:53 SagiCZ1: ingsoc: see intellij if you want a good ide for java and cant cope with emacs

7:54 ingsoc: SagiCZ1: I use intellij (Webstorm) for web dev

7:54 annelies: I once wrote a function that returned whether an editor is good or not.

7:54 ingsoc: and I like it

7:54 I use eclipse for python and erlang - at the time if I wanted an IDE for erlang it was the only resonably mature option

7:54 annelies: It was (partial contains? #{:emacs :vim})

7:55 ingsoc: :)

7:55 SagiCZ1: ingsoc: alright, cant believe you can still go back to eclipse.. its so bad :D

7:55 ingsoc: I would NOT be able to code for the web now without Webstorm

7:56 godd2: never heard of it. what's webstorm?

7:56 annelies: IntelliJ specialised for client-side web dev.

7:57 godd2: ah okay

7:57 ingsoc: godd2: from the intelliJ IDE guys (Jetbrains)

7:57 SagiCZ1: annelies: well i cant say that vim or emacs is bad, but it was just too much to learn new language (clojure) and a completely new editor (emacs)

7:58 ingsoc: It is focussed for web dev and at the time i didn;t want to have all the other features confusing the IDE (like what happens with eclipse with all its different "perspectives")

7:59 not sure if thre is an intelliJ/Webstorm plguin for clojurescript though yet

7:59 plugin*

7:59 SagiCZ1: ingsoc: i still distinctly remember the wtf moment i experienced when trying to turn debugging on in eclipse..

8:00 ingsoc: there is Cursive

8:00 ingsoc: https://cursiveclojure.com/

8:00 it is amazing

8:01 m1dnight: ugh, i've about had it with emacs and cider

8:01 thing randomly "cant find file on classpath"

8:01 ingsoc: anyone using lightable

8:01 Lowl3v3l: SagiCZ1, is cursive ready to use yet?

8:01 ingsoc: light table*

8:02 the demos show some great promise, looks to be implementing Bret Victors demo of an interactive IDE

8:04 SagiCZ1: Lowl3v3l: its not finished, but i use it every day without a problem

8:04 annelies: What'd you call (fn [& fs] (apply comp (reverse fs)))? pmoc?

8:04 ingsoc: http://vimeo.com/36579366 skip to 16:45 and see how he interactively develops binary search

8:04 Lowl3v3l: SagiCZ1, to sad i do not like non-open-source products

8:04 ingsoc: apparently that kind of thing is avaiulable in light table for clojure

8:05 annelies: May be better to use #(-> % ...) though I guess.

8:05 SagiCZ1: Lowl3v3l: yeah... ive seen how open source eclipse is great.. i would rather pay a couple $$ for a good editor than tear my hair

8:06 Lowl3v3l: SagiCZ1, well. Emacs is Open Source and i like it. Vim too.

8:07 SagiCZ1: Lowl3v3l: yeah, but those are decades old.. i guess they are polished now

8:07 Lowl3v3l: SagiCZ1, and they are still good. I just don't like closed source in general^^

8:07 SagiCZ1: Lowl3v3l: i understand

8:13 ingsoc: so what language did you guys use prior to clojure ?, are there a lot of java converts or from totally different environment (non JVM)

8:13 SagiCZ1: ingsoc: for me it was mostly Java

8:14 Lowl3v3l: i use a whole couple of languages upt to now, clojure isn't even my only lisp^^

8:14 SagiCZ1: yeah i actually had a brief episode with Common Lisp before discovering Clojure

8:14 ingsoc: SagiCZ1: it looks WAY more concise than Java so I am guessing for you clojure has been a productivity enhancer

8:14 ok

8:15 a guy at a local tech meetup keeps telling me how clojure changed his views on programming and loves it keeps asking me to try it, I do the same to him but with erlang

8:15 SagiCZ1: ingsoc: definitely, the only gripe with clojure i have, is not understanding it as much as i understand java, so some things which should be quicker and easier to do in clojure are actually harder.. but i am getting there

8:15 ingsoc: :)

8:17 my concern with clojure is do i inevitably have to learn java to become truly competent. I know I am comparing apples and oranges a bit here but I use coffeescript but in the end I had to know javascript to use it effectively

8:17 godd2: same coming from Ruby. everything looks out of order...

8:17 hyPiRion: I started out with Java/Common Lisp. Really hard to understand how to do purely functional programming in the beginning, but with experience that feels superior in many cases.

8:17 Guess coming from Erlang makes that transition a bit easier

8:17 SagiCZ1: ingsoc: i am not sure you would have to know java, but it might help a lot

8:18 hyPiRion: ingsoc: Can't speak for Clojure/Java, but I don't know JavaScript properly and managed to create rather "sophisticated" ClojureScript programs

8:19 godd2: But I have found a couple amazing Clojure tutorials. http://www.braveclojure.com/getting-started/ for text (you can skip the emacs part if you don't emacs) and for video: https://www.youtube.com/watch?v=9A9qsaZZefw&list=PLAC43CFB134E85266

8:19 hyPiRion: As long as you find non-Java libraries for the things you want to do, life should be easy without Java knowledge.

8:19 ingsoc: hyPiRion: yeah, erlang was originally a bit painful as it was my first ever functional language. No loops (only recursion), single assignment, no objects or global anything etc.

8:20 big shift, but now i find it a better way to structure programs

8:20 seems to force you down the path of divide and conquer with small independent easily understood functional components

8:21 SagiCZ1: ingsoc: i guess thats a common experience with most functional languages.. it is hard at the beginning but you can appreciate it later.. especially testing just seems so easy compared to java mutant world

8:21 ingsoc: hyPiRion: I am hoping to try clojurescript at some point as I still haven't found a nice language for client side web dev yet. Coffeecript is a nicer face to JS but it is still quite fragile

8:23 Lowl3v3l: SagiCZ1, there is a reason why i prefer teaching with functional languages.

8:23 hyPiRion: Leaky abstractions, eh

8:23 Lowl3v3l: i believe in general functional programming is, for someone who didn't program before, easier

8:24 SagiCZ1: Lowl3v3l: i am not sure.. maybe for mathematcians.. imperative programming is easy because it is just a sequence of steps.. the computer follows it like a cooking recipe

8:24 ingsoc: one problem I find people have is recursion, it seems some people have real trouble visualising in their minds eye what is occurring

8:25 SagiCZ1: ingsoc: it is definitely not trivial.. especially trying to visualize the call stack

8:25 godd2: Some otherwise imperative languages offer recursive tools, so it's not all bad depending on the transition

8:25 Lowl3v3l: the problem is that imperative programming allows for constructs like x = x+1; which is kind of absurd if you think about it^^

8:25 ingsoc: actually, do you have to be mindful in clojure of the stack or is there tail call optimisations like in erlang/Ocaml

8:26 Lowl3v3l: ingsoc, there is a possibility for tail calls

8:26 SagiCZ1: there are ONLY tail recursions in clojure, right?

8:26 godd2: SagiCZ1 yes but not all tail recursions are tco'd

8:26 SagiCZ1: godd2: i see

8:27 godd2: at least, that's my understanding

8:27 Lowl3v3l: well no. There is recur.

8:27 ingsoc: tco means that the compiler/runtime knows that to continue next recursion it doesn't need to push anything else onto stack ?

8:27 Lowl3v3l: But in general you could write a non-tail-recursion by directly calling a function generating a stack overflow with enough calls

8:28 SagiCZ1: does functional programming imply immutable data?

8:30 godd2: SagiCZ1 not necessarily. in Clojure you can tap into java data structures which are mutable

8:30 ingsoc: SagiCZ1: my understanding is that immutable data is a key trait of functional language

8:30 Lowl3v3l: SagiCZ1, depends on. There is up to my mind at least the theoretical possibility to do it without by not using the von-neumann-architecture... But practical i believe so.

8:30 godd2: SagiCZ1 there'

8:31 SagiCZ1 there's also the difference between "pure" functional and functional. a "pure" function never returns anything different given some inputs

8:31 Lowl3v3l: godd2, well, but foing that you leave the functional space, don't you? Functional means side-effect-free which is why clojure isn't strictly functional in the sense haskell, for example, is.

8:31 SagiCZ1: godd2: i wasnt talking about clojure specifically.. its possible to write a clearly imperative code in clojure.. if you use atoms and mutate states of java objects using interop.. but it is still a functional language

8:32 godd2: SagiCZ1 right, Clojure doesn't restrict you from not being functional, but if you want to be funcitonal, it provides every opportunity

8:32 SagiCZ1: godd2: i see your point

8:52 oskarkv: Hm, what is going on here? https://www.refheap.com/919221bb6a9664a3485c8cb01

8:53 Oh, literals...

8:56 justin_smith: oskarkv: looks like you should just match on PRIMARY / SECONDARY / MIDDLE I guess?

8:56 I haven't tried matching enums in a case before

9:01 ,(case java.time.format.FormatStyle/FULL FULL :true LONG nil MEDIUM nil SHORT nil)

9:01 clojurebot: #<CompilerException java.lang.ClassNotFoundException: java.time.format.FormatStyle, compiling:(NO_SOURCE_PATH:0:0)>

9:01 justin_smith: oh, new in 1.8, duh

9:02 anyway, yeah, it seems there is no way to match on an enum (none I could figure out, at least)

9:03 oskarkv: justin_smith "The test-constants are not evaluated." So I guess Class/Something is just a symbol in the case

9:03 justin_smith: hmm

9:03 yeah, I guess so, I thought the reader did that, but OK

9:03 oh right, the reader could not do that

9:10 ingsoc: hmmm, jobs in UK are pretty thin on the ground for clojure devs . Maybe people wanting to use clojure get java jobs and introduce clojure into their workplace

9:10 (not that I care about popularity but it would be interesting to know if clojure IS getting more popular in industry)

9:11 annelies: Where is the transducer library?

9:11 I cannot find the functions mentioned in the talk on this page: http://clojure.github.io/clojure/

9:12 SagiCZ1: ~lazy-logs

9:12 clojurebot: lazy-logs is http://logs.lazybot.org/

9:14 SagiCZ1: ingsoc: if you want a language that is widely used and get a job with it, java is the surest way to go.. there is just so many java jobs its mind boggling.. i was looking for a java job and was employed within 5 days

9:14 Glenjamin: is anyone else seeing all the gravatars missing on github.com?

9:15 AeroNotix: Glenjamin: force refresh

9:15 Glenjamin: seems like github itself is now breaking anyway

9:15 all the graphs on https://status.github.com/ just shot up

9:16 ingsoc: SagiCZ1: I was just curious as to whether clojure is becoming an employable skill and popularity increasing or has it topped out

9:16 Glenjamin: ingsoc: where in the UK are you looking?

9:17 i know thoughtworks are pushing Clojure quite a bit, and there's some GDS stuff thats starting to use it

9:18 AeroNotix: uswitch are big clojure users

9:18 in the UK

9:18 Glenjamin: i think mail online do a bunch of clojure as well

9:19 ingsoc: Glenjamin: currently in Manchester, and I have been to some of the their tech talks. I was just curious as to the general trend of whether companies are seeing the benefits of moving away from traditional languages like java/.net for greenfield projects

9:19 AeroNotix: The Guardian do a bit here n there, though mainly Scala.

9:20 ingsoc: Scala seems overly complicated

9:20 AeroNotix: ingsoc: you should look at the financial sector in London

9:20 Glenjamin: ingsoc: outside of London i mostly see companies playing it safe with PHP/Java/.net/Python/Ruby

9:20 ingsoc: yeah, erlang seems popular in London too in finance

9:20 Glenjamin: and really, who wants to go live in London?

9:20 ingsoc: yeah exactly

9:20 AeroNotix: meh, rough with the smooth

9:21 I moved from Blackpool to Poland to write Erlang+Clojure

9:21 Glenjamin: if you fancy heading over to Sheffield we're doing some ClojureScript at the functional programming meetup on tuesday

9:21 ingsoc: whatever you extra case you earn will be absorbed by property costs, unless you want shit loads of commuting wasting your life away

9:21 Glenjamin: http://defshef.github.io

9:21 AeroNotix: Sheffield/Leeds is where I am thinking of moving back to

9:21 Glenjamin: There's a lot more jobs in Leeds unfortunately :(

9:21 ingsoc: i meant, whatever extra you earn by working in London will be absorbed by property costs

9:22 AeroNotix: Glenjamin: that's what I've heard as well

9:22 Glenjamin: I think Sheffield is much nicer, but I'm biased

9:22 justin_smith: ingsoc: that's what folks say about SF around here

9:22 AeroNotix: my brother is in Leeds at the moment

9:22 Glenjamin: Where's he working?

9:22 AeroNotix: Just at Uni

9:23 the_frey: ingsoc you looking for a clojure job in manchester?

9:24 SagiCZ1: justin_smith: i mean... living in SF is exactly the same as anywhere else in the US.. except when you open the door outside.. you are in SF, haha

9:24 Glenjamin: the_frey: do some exist?

9:24 the_frey: our company is moving some infrastructure to it, I'm having to learn clojure for work atm :)

9:24 ingsoc: the_frey: no, I was just curious as to where the job market is heading, whether more opportunities are being created over time. I am a complete clojure noob, just started out today pretty much lol, I am an erlang and frontend web dev

9:25 the_frey: though tbf we are tiny

9:25 right k

9:25 Glenjamin: oh neat, i could probably do some clojure in manchester

9:25 justin_smith: SagiCZ1: I meant in terms of the money you make / how much you pay for rent

9:25 the_frey: but yeah we are hiring (I think)

9:25 lemme find the link

9:25 http://www.swirrl.com/jobs

9:26 our clojure yoda is the guy who runs lambda lounge in mcr, really really clever dude

9:26 SagiCZ1: justin_smith: you make more, you spend more.. you are living in Cali..

9:26 Glenjamin: is lambda lounge still going? i heard it had fizzled out

9:27 justin_smith: SagiCZ1: it seems like half of Cali is trying to move here

9:27 the_frey: Glenjamin: it became a lot more infrequent for a while because of the difficulty of finding speakers

9:27 but it's got a bit more momentum of late

9:27 Glenjamin: oh cool, i should try and head across the pennines then

9:28 SagiCZ1: justin_smith: and half of the world is trying to move to Cali ...

9:28 the_frey: I _believe_ we might be sponsoring beers at the next one because I think we might be doing one of the talks

9:28 Glenjamin: might be able to blag some (def shef) speakers out of it

9:28 the_frey: about the graph data & RDF stuff we're doing in clojure

9:28 hence why a rubyist like me is shifting over to it :)

9:29 justin_smith: I hear many stories of folks who get hired at a ruby shop and slowly push everything into clojure

9:29 ingsoc: the_frey: Rick ?

9:30 I did an erlang talk there a while back

9:30 AeroNotix: ingsoc: what're jobs like in the UK for Erlang?

9:30 ingsoc: was my first tech talk so was not as smooth as i wanted

9:30 :)

9:30 AeroNotix: I'm writing Erlang as a dayjob at the moment

9:30 the_frey: ingsoc yeah Rick, really nice guy to work with, gotta say

9:31 ingsoc: AeroNotix: mainly London based work, but there are some companies using it outside of London but it seems to be not widely publicised

9:31 AeroNotix: hmm, ok

9:33 Glenjamin: Someone's doing an Erlang POC at the mo in the company in Leeds I'm working for

9:33 ingsoc: AeroNotix: keyword search on a local jobsite brings back 18 with clojure and 12 with erlang, there are obviously thousands of java and .net and 100's of python/ruby

9:33 Glenjamin: but I suspect hiring concerns will mean it never makes it to production

9:34 AeroNotix: ingsoc: interesting. I write Erlang and Clojure at work but I am based in Poland (blackpool originally). Thinking of coming home soon.

9:34 Glenjamin: we're having enough issues hiring people who are any good at Node.js

9:34 AeroNotix: Glenjamin: then stop using node.js

9:34 Solved.

9:34 That'll be my daily fee, thanks

9:34 Glenjamin: hah

9:34 the_frey: Glenjamin to be fair we have trouble hiring rubyists :) there are crap programmers in every lang

9:34 ingsoc: AeroNotix: well I think these technologies are still kinda a technical edge over the competition that use traditional languages

9:35 Glenjamin: it's not so bad really, being JS you can write it functionally

9:35 ingsoc: so maybe their use doesn't get shouted about outside of their respective tech communities

9:35 Glenjamin: supervisord + rabbitMQ + node.js processes = poor man's erlang

9:35 AeroNotix: At that point just use Erlang

9:36 Glenjamin: well yes, but that doesn't really help us deal with the the 3 years-worth of code that's running and works

9:36 annelies: Write a JavaScript-to-BEAM compiler.

9:36 ingsoc: yeah in clojure

9:36 Glenjamin: which is why someone is doing an erlang proof-of-concept

9:37 ingsoc: someone created a javascript project that can interpret beam files in browser

9:37 annelies: Speaking of writing compilers in Clojure, core.logic seems a good fit for implementing type inference.

9:38 ingsoc: AeroNotix: Funny you say you moved from UK to Poland, usually it is the other way around

9:38 AeroNotix: ingsoc: tell me about it

9:38 ingsoc: did you meet a Polish girl in UK then emigrate with her

9:38 AeroNotix: duh

9:38 :)

9:39 ingsoc: lol

9:39 what's wrong with meeting a nice English girl on a hen do in Blackpool

9:39 :P

9:39 lol

9:40 AeroNotix: yeah and be disgusted 24/7

9:40 ingsoc: tray of fish and chips and a couple of bacardi breezers for her

9:41 and you're in

9:41 AeroNotix: too easy, in my youth I took advantage of this :)

9:42 ingsoc: AeroNotix: what's the salary to living cost ration like in Poland ?

9:42 hoping it is better than what it appears to be for unskilled Polish workers

9:42 (which causes them to move here)

9:43 AeroNotix: ingsoc: I'm in a unique field so it's pretty good for me

9:43 but for regular folk, it's hard. Of course.

9:43 but I make 4kGBP a month so I'm not complaining.

9:43 over here that's extremely good

9:44 ingsoc: how much is a tyskie over there ?

9:44 :)

9:44 AeroNotix: I don't drink piss

9:44 ingsoc: loool

9:44 well i don;t drink it, but I don;t know any other Polish beers

9:44 AeroNotix: Keep an eye out for Pinta or Ale Browar

9:45 ingsoc: i guess you would have to earn a fair bit more than that to live a similar standard in UK

9:46 AeroNotix: What are you getting?

9:46 ingsoc: sounds like you are doing pretty good then

9:48 I am currently taking time out to learn other things (living off investments) but when I was working it would be circa 55-60k per annum although this was not programming, I was working as operations management type role

9:48 I just have an interest in programming

9:48 AeroNotix: ok

9:49 What're people using to generate documentation/

9:49 ?

9:50 ingsoc: AeroNotix: are you using clojure and erlang on the same system, or are these separate projects

9:51 just interested to how they are being used together

9:52 SagiCZ1: ingsoc: is it rude to ask people how much they make in UK?

9:52 AimHere: It can be, yes

9:52 ingsoc: erm, possibly yeah, but obviously it depends on individual. IRC is anonymous though

9:53 AeroNotix: ingsoc: Erlang is used for maintaining a high number of connections to hardware devices

9:53 ingsoc: CLojure is used because Erlang isn't a general purpose language

9:53 ingsoc: I wouldn't walk up to someone in person and say oh btw what do you earn

9:53 AeroNotix: AimHere: yes it's rude but we are anonymous

9:54 SagiCZ1: ingsoc: i see, thanks

9:54 AimHere: Well he asked about the UK; on the Internet, the concept of 'rudeness' has long gone out of fashion

9:54 ingsoc: AeroNotix: so are you communicating with clojure over ports or some other mechanism

9:54 (erlang ports)

9:54 AeroNotix: ingsoc: typically HTTP

9:54 ingsoc: ok

9:54 AeroNotix: ingsoc: you could call it a microservices architecture

9:54 Erlang forms the hub

9:54 AimHere: On the internet, you're a sophisticated gentleman, if you don't call people by racial or offensive epithets, or post pictures of people being beheaded more than once a day or so

9:55 ingsoc: I have used python (for certain libs not available in erlang) and communicated over port (stdio)

9:55 SagiCZ1: off topic, i am using joda time, and i have a date [year month day], and i need to know which week in the month is the day in.. first, second, third or fourth week.. how can i do that?

9:55 AeroNotix: ingsoc: I'd prefer HTTP over ports as a first pass, optimize as necessary

9:56 ingsoc: AeroNotix: i found it useful as you get to have the processes supervised by erlang so you only have to worry about keeping the erlang node running (which is generally bullet proof)

9:56 SagiCZ1: wait.. i could just do (quot 30 day) i guess

9:57 ingsoc: it wasn;t about optimisations

9:57 AeroNotix: ingsoc: meh, just use a proper init system which keeps processes alive

9:57 ingsoc: (OS Process running python/JVM)

9:57 yeah i notice ubuntu has upstart that can do that

9:58 restart mnechanism etc.

9:58 AeroNotix: indeed

9:58 ingsoc: (I am a windows guy originally but switched to linux as the open source ecosystem is much better)

9:59 annelies: SagiCZ1: just (quot day 7)

9:59 ,(map #(quot % 7) (range 31))

9:59 clojurebot: (0 0 0 0 0 ...)

9:59 annelies: lol

10:00 ingsoc: does the "?" in odd? empty? have any special relevance other than it makes it visually appear as a question

10:00 AimHere: No. That's it's sole purpose

10:00 AeroNotix: ingsoc: just makes it a question

10:00 AimHere: There are no side effects

10:00 AeroNotix: some lisps use the -p suffix

10:01 integerp stringp etc

10:01 for predicate

10:01 SagiCZ1: zerop?

10:01 AeroNotix: SagiCZ1: just zero? or zerop

10:01 justin_smith: ,(defn !? [a] (+ a a))

10:01 clojurebot: #'sandbox/!?

10:02 justin_smith: ,(!? 2)

10:02 clojurebot: 4

10:02 justin_smith: ingsoc: clojure has very few operators / special symbols. It's usually just part of a name.

10:04 in fact, the only things other than white space that I can think of that are contiguous with a name, but not part of it, would be () {} # . ^ [] (I may have missed one or two)

10:04 / of course has special meaning inside a symbol too

10:05 @

10:06 ` and '

10:07 annelies: You can have foo'bar as name.

10:07 justin_smith: ahh, and foo@bar too

10:07 ,(def foo@bar 0)

10:07 clojurebot: #<CompilerException java.lang.RuntimeException: Too many arguments to def, compiling:(NO_SOURCE_PATH:0:0)>

10:08 justin_smith: or not

10:08 heh

10:08 annelies: you can with #

10:08 justin_smith: yeah, many of those are only special as the first character

10:08 none special as last

10:08 SagiCZ1: clj-time uses system language for the formatter, how can i switch it to english?

10:08 annelies: Here is the exact syntax: http://clojure.org/reader

10:08 SagiCZ1: this should give me the name of the month, but its in my local language:

10:08 (f/unparse (f/formatter "MMMMM") (t/date-time 2010 6))

10:08 annelies: Under "Symbols"

10:09 justin_smith: annelies: thanks

10:10 annelies: that's not really accurate, though, because it doesn't indicate that ' can be used (which is commonly used in symbols in practice)

10:11 annelies: SagiCZ1: eww assumptions. Anyway: (with-locale (f/formatter "MMMMM") java.util.Locale/ENGLISH)

10:11 Or Locale/ENGLAND maybe.

10:12 SagiCZ1: annelies: where is with-locale from? is it clojure.core?

10:12 annelies: in clj-time.format

10:13 SagiCZ1: annelies: thank you so much, works well

10:13 (inc annelies)

10:13 lazybot: ⇒ 1

10:14 annelies: I wish tools did away with assuming default locales and time zones and stuff like that.

10:14 s/tools/libraries/

10:14 Such defaults are only useful in a very small set of programs.

10:15 SagiCZ1: very true

10:16 ingsoc: Ithought clojure was single-assignment so why does the repl allow reassignment ? just for convenience ? or is there something different at work ?

10:16 justin_smith: ingsoc: not single assignment at all

10:16 vars are mutable

10:16 ingsoc: ok it is within a defined namespace it is single assignment

10:16 justin_smith: no, vars are mutable

10:17 the value in the var is usually immutible, a var itself is not

10:17 and every var used in practice is in a namespace (def / defn can only make namespaced global definitions)

10:18 Glenjamin: SagiCZ1: i think you can set the default JVM locale to english, and most libs will use that as their default

10:19 i've got :jvm-opts ["-Duser.language=en" "-Duser.country=GB"] in my project.clj, which i think is related

10:19 m1dnight: how are macros expanded, from the outside in, or the inside out?

10:19 SagiCZ1: Glenjamin: thanks

10:19 justin_smith: m1dnight: outside in - a macro decides how to handle each of its arguments

10:19 Glenjamin: ,(macroexpand-1 '(and (and 1 2) 3))

10:19 clojurebot: (clojure.core/let [and__4069__auto__ (and 1 2)] (if and__4069__auto__ (clojure.core/and 3) and__4069__auto__))

10:20 m1dnight: aha excellent :) thank you

10:20 Glenjamin: forgot about symbol expansion, that's not as clear as i was expecting it to be

10:20 justin_smith: m1dnight: otherwise things like when / and etc. couldn't short circuit

10:20 m1dnight: ah, valid point

10:20 hadn't thought about ti that way

10:21 Wild_Cat: hold on, why is and a macro?

10:22 justin_smith: ~source and

10:22 it uses if

10:22 if is the more fundamental

10:22 Wild_Cat: oh, because it does shortcut evaluation

10:23 justin_smith: as does or

10:23 Wild_Cat: right, makes sense.

10:23 gfredericks: if or and when, let not but-last.

10:23 Wild_Cat: I actually wouldn't have expected Clojure's boolean operators to do shortcut eval.

10:23 annelies: Why not?

10:23 gfredericks: new game - make english sentences out of clojure functions.

10:24 justin_smith: hah

10:24 gfredericks: "vector is not list."

10:26 annelies: ,is

10:26 clojurebot: #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: is in this context, compiling:(NO_SOURCE_PATH:0:0)>

10:26 justin_smith: ,(require 'clojure.test)

10:27 clojurebot: nil

10:27 justin_smith: ,#'clojure.test/is

10:27 clojurebot: #'clojure.test/is

10:27 justin_smith: it's a macro though

10:28 ,(doc future-cancel)

10:28 clojurebot: "([f]); Cancels the future, if possible."

10:28 justin_smith: my favorite bit of poetry in the clojure codebase

10:28 Glenjamin: when short reductions compare and repeatedly cycle, double key locking

10:28 annelies: Sometimes I wish I were a prn-str.

10:28 Glenjamin: there's not many nouns :(

10:29 m1dnight: not any?

10:29 :D

10:29 justin_smith: the hard part is the lack of articles

10:29 Glenjamin: "do reductions keep rational?"

10:30 justin_smith: haha

10:30 agent prefers locking intersection

10:31 that would be better if I could use "the"

10:31 Glenjamin: "do some parents compare distinct?"

10:32 justin_smith: aha

10:32 annelies: do not take hash

10:32 justin_smith: parernts reverse, locking intersection

10:32 much better

10:34 annelies: Hmm, speaking of rearranging words, I should port my Markov chain library to Clojure.

10:34 justin_smith: I did one - I was amazed how succinct I could do everything in clojure actually

10:35 complete with optional seed and variable memory

10:35 annelies: Here is the existing one in Scala: http://ideone.com/Do2DTU

10:36 m1dnight: oh dear, second time this week i misspell "filter" with "fitler"

10:36 annelies: (def fitler filter) and nobody will notice :)

10:36 justin_smith: annelies: ah, yourse is by word, I did mine by character - which means with a shorter memory it is prone to inventing "words"

10:36 m1dnight: :D

10:37 annelies: Oh I meant just porting MarkovChain, not NonsenseGenerator

10:37 justin_smith: annelies: oh, that will be like a four liner I bet

10:38 annelies: Yeah. :P

10:38 Well, a protocol and a function transition

10:39 Mine is bugged actually. It fails if the PRNG returns exactly 0.0.

10:39 Then it throws a NotImplementedException :v

10:42 justin_smith: annelies: I am not very good at reading scala - does yours use start / stop tokens?

10:42 annelies: No idea what those are. :P

10:42 The nonsense generator just constructs a map of (current word, set of possible next words) pairs

10:43 And then it starts at a random word.

10:43 justin_smith: annelies: when analyzing an input, a start token is inserted at the beginning, a stop token appended at the end, then "generate" will start with one of the start tokens (with a weighed probability) and stop if it reaches a stop token.

10:44 ingsoc: AeroNotix :name <- is this kinda like an atom in erlang

10:44 annelies: Oh no it just picks a random word to start with. There is no stop token, it stops when you stop calling transition.

10:45 So to construct a nonsense paragraph just reduce with transition and string concatenation

10:45 AeroNotix: ingsoc: yeah

10:45 ingsoc: but there's no atom table

10:45 oskarkv: Say I want to use JavaFX or Swing or some other Java lib. And I have an idea for a new Node/Control (like Label, Image, Button). Then I would like to create a named class, that can extend a class and implement interfaces. What would you guys use for that? It almost seems like the easiest choice would be to forget about the named class thing and make a proxy for each instance.

10:45 justin_smith: annelies: an interesting side effect of using start/stop tokens is that if your input was grammatical, the output will start with a capitalized word, and end with a period / newline

10:45 AeroNotix: ingsoc: so you can make as many as you want

10:45 annelies: justin_smith: a right :p

10:46 justin_smith: oskarkv: yeah, proxy or refiy likely

10:46 *reify

10:46 time for coffee

10:46 grandy: anyone know the best practice for server side session state in compojure ?

10:46 oskarkv: but reiddraper can't extend classes, right?

10:46 ops

10:47 reify*

10:47 justin_smith: I am pretty sure reiddraper has extended quite a few classes :)

10:47 oskarkv: hehe

10:47 Wouldn't it make sense for clojure to be able to make new named classes for interop purposes?

10:47 justin_smith: oskarkv: reify can implement any number of interfaces

10:48 grandy: is it ring-clojure ?

10:48 oskarkv: or maybe that's what genclass does

10:48 justin_smith yeah but not extend classes right?

10:48 justin_smith: oskarkv: right, but swing should only care about interfaces, not classes for the most part, I would hope

10:48 oskarkv: maybe my optimism is misplaced

10:48 oskarkv: hehe

10:49 Sometimes it saves work to extend :p

10:49 justin_smith: anyway, if interfaces are sufficient (hopefully they are), with the help of defprotocol you can extend however you like - unless it actually needs you to inherit specific classes

10:50 annelies: Weighted choice is one of those things I love implementing imperatively rather than functionally.

10:50 justin_smith: heh

10:50 ingsoc: AeroNotix: ok thanks

10:50 AeroNotix: ingsoc: nw

10:51 justin_smith: annelies: my rng is of course imperative, but I actually did the weighted choice as a pure function otherwise

10:51 annelies: You can write pure functions using imperative programming.

10:51 justin_smith: of course

10:51 but I used standard fn / reduce and no state mutation is what I mean

10:53 grandy: ok fine

10:54 justin_smith: grandy: ring-clojure is a session state?

10:54 grandy: it has a session namespace

10:54 justin_smith: yeah - compojure is just a routing lib

10:54 for the other stuff, you want to look at ring middlewares

10:55 grandy: justin_smith: cool that's what i thought but wanted to make sure i hadn't missed something... there have been a few deprecated projects in this area

10:55 justin_smith: it's true

10:56 grandy: I've never even heard of someone using compojure without ring

10:56 though it may be hypothetically possible

10:56 grandy: justin_smith: cool yeah i think there have been some other libs that may do some session stuff too, also on top of ring

10:57 justin_smith: right, and they will all act as a ring middleware

10:57 annelies: Hmm, I guess I can use reductions for it.

10:57 SagiCZ1: ,(for [i "abc"] (for [j (range 3)] (str i j)))

10:57 i need this to return ("a0" "a1" "a2" "b0"... should i use flatten?

10:57 clojurebot: (("a0" "a1" "a2") ("b0" "b1" "b2") ("c0" "c1" "c2"))

10:58 justin_smith: grandy: I use ring.middleware.session/wrap-session

10:58 grandy: justin_smith: ahh ok perfect that looks useful

10:58 justin_smith: grandy: you can specify what sort of storage you want with that

10:59 grandy: justin_smith: cool

10:59 SagiCZ1: nevermind, got it

11:00 justin_smith: SagiCZ1: you don't need to ever nest for calls

11:00 ,(for [i "abc" j (range 3)] (str i j))

11:00 clojurebot: ("a0" "a1" "a2" "b0" "b1" ...)

11:01 SagiCZ1: yeah i found that out, thanks

11:01 justin_smith: OK - just making sure you figured out the simple way

11:05 annelies: I think I got it: https://gist.github.com/rightfold/a2394f6d9cd785fcc990

11:05 justin_smith: very nice

11:05 better than mine

11:05 https://github.com/noisesmith/markov-toy/blob/master/src/markov/core.clj#L14

11:08 oskarkv: ,(for [i "abc" j (range 3)] (str i j))

11:09 clojurebot: ("a0" "a1" "a2" "b0" "b1" ...)

11:09 oskarkv: oh, was scrolled up :p

11:17 m1dnight: guys, I'm having a brainy problem. At runtime I want to add stuff to a list and then return that list.

11:17 The reason is that I need the values of the expression before.

11:17 Is there an idiomatic way?

11:18 since immutability and all ..

11:18 wait a minute

11:19 yeah, still. I have a function that does a message send to a thread. But this send could contain values that are in the current lexical scope. However, I want to do those message sends during a commit. Ergo, I have to get the values out of scope to use them in a differnet one

11:20 So I figured I could 'cons' them to a list (to say it in lisp terms) and then return that list to the other scope

11:20 Glenjamin: m1dnight: can you provide a code sample i'm not clear why (cons) isn't enough here?

11:21 m1dnight: well, I have a meta-circular STM implementation. I also have an implementation of Erlang actors. Now in my state change of my actors (ie the body) I want to send messages to other actors.

11:21 But, i'm experimenting with an actor that has a dosync in his body, and inside that dosync, sends a message to another actor

11:22 I want to hold that message back until commit.

11:22 but, since the commit happens in a different scope, i need to get the values that are sent to an actor in a message out of the scope

11:24 Glenjamin: you might be able to do something with http://clojure.github.io/clojure/clojure.core-api.html#clojure.core/add-watch

11:24 m1dnight: wait a minute, i think you gave me an idea :D


11:24 Glenjamin: if i'm understanding, you want to queue up message sends until your current actor transaction is finished, then send them

11:24 m1dnight: yes, indeed

11:25 but that's easy, because a message is a keyword (e.g., :message)

11:25 so I can do something like (! actor :message <var> <var>..)

11:25 that sends the message :message to the actor and attaches the values <var>

11:30 cristian: Hi guys. I wonder what's the idiomatic way in clojure to define functions that might fail or that might return null. In Java 8, I'm mostly using Optional. In Haskell I use Maybe and Either.

11:31 How do you usually implement such functions in Clojure?

11:31 Glenjamin: generally i'd just return null

11:31 ingsoc: AeroNotix: lein repl :connect seems like a it provides some of the remsh stuff of erlang

11:31 Glenjamin: i think core.typed has a way of saying whether a function will or wont return null

11:31 ingsoc: have you sued this ?

11:31 used*

11:31 AeroNotix: ingsoc: it does

11:32 Glenjamin: a lot of core functions do something useful if you pass null

11:32 ,(assoc nil :a 1)

11:32 clojurebot: {:a 1}

11:33 ingsoc: AeroNotix: can you reload new version of code ?

11:33 ambrosebs: cristian: do you want to know how to define such functions or use their outputs?

11:33 AeroNotix: ingsoc: yes, much better than the way Erlang does it, too.

11:33 ingsoc: because you don't have supervision trees to tear down as a whole, you can just redefine whatever you need in-place and the running code picks it up.

11:34 Glenjamin: AeroNotix: as long as there's no state :D

11:34 justin_smith: ingsoc: as I mentioned before, vars are mutable, so to the extent that your code is all vars, yes - the tricky thing is of course any closed over state, sometimes to get a good reload you need to define a restart of some sort

11:34 Glenjamin: see also, the "component" library

11:34 AeroNotix: Yeah component is really good

11:34 justin_smith: Glenjamin: yes, component was what I was getting at :)

11:34 ingsoc: hmmm, to get this straight in my mind, does the Java VM when running clojure listen on the nrepl port all the time

11:35 so you can connect at any time or do you have to enable something in the project ?

11:35 Glenjamin: ingsoc: when you run "lein repl", it starts a client+server

11:35 justin_smith: ingsoc: only if you open an nrepl listener

11:35 lein opens one for you

11:35 or you can do so yourself in production code if you wish

11:35 but you should not use lein in production

11:35 AeroNotix: In production code I have nrepl spawning a listener as part of main

11:36 ingsoc: ok i see. I was doing this in counterclockwise. I spose when you run your project in counterclockwise it does plumbing for you

11:36 annelies: I wish I wrote production code.

11:36 AeroNotix: annelies: Why don't you?

11:36 ingsoc: (it runs lein)

11:37 justin_smith: ingsoc: the code to start your own nrepl server is clojure.tools.nrepl package

11:37 it's pretty easy

11:38 cristian: ambrosebs: I want to know how you define such functions. For instance, you can define a function that returns Either in Scala (or haskell), and the client of the function knows that it has to pattern match the result to know if the computation succeeded or not (and if not, you get useful data about what went wrong). How do you guys handle such cases in clojure? I don't want to just emulate what I do in

11:38 imperative languages... I want something more Clojure-idiomatic

11:38 annelies: AeroNotix: I mean in Clojure.

11:39 I write it in Python though.

11:39 ambrosebs: cristian: in Clojure you just return null in the function and document it in the docstring or contract.

11:39 cristian: Ok

11:39 Thanks

11:40 Glenjamin: ambrosebs: does core.typed let you annotate as "will not return null" ?

11:40 ambrosebs: Glenjamin: yes, references are non-nullable

11:40 annelies: cristian: it's better to use \/ than Either for that in Scala. Either isn't designed for failure vs. success, but just as a utility union type.

11:40 Glenjamin: and presumably with anything that can return null i have to handle it to type check?

11:40 ambrosebs: cristian: check out some->, when for some macros to help *use* nullable values

11:41 cristian: annelies: pardon my ignorance... what do you mean by \/

11:41 ingsoc: i need to learn how this works then. I thought this wasn't possible on JVM and afaict all clojure code is compiled into java classes / byte code ? so what's the deal there ? Or could you also do this with java code ?

11:41 ambrosebs: Glenjamin: yes, just in the same way you'd do it in clojure. (fn [a :- (U nil Int)] (when a (inc a)))

11:42 Glenjamin: i think mostly i forget to check for nil :) i should really find an excuse to play with core.typed

11:42 justin_smith: ingsoc: it's the opposite - every object in the jvm is nullable, and we just adapt to that

11:42 annelies: cristian: http://docs.typelevel.org/api/scalaz/nightly/#scalaz.$bslash$div has a right-bias (right indicates success) for map, filter etc... which is far more useful than Either's left and right projections when dealing with failure vs. success

11:44 ingsoc: just looking at jetty, looksamazingly easy to providew a simple http api

11:44 justin_smith: ingsoc: in clojure, use ring

11:44 ingsoc: fun stuff :)

11:44 ring ?

11:44 oh ok

11:44 justin_smith: there are very few reasons not to use the ring abstraction

11:45 cristian: annelies: thanks. That's interesting. Why doesn't clojure have something like that? Is it not need ti?

11:45 ambrosebs: Glenjamin: a good excuse, but my advice is to become comfortable with some-> and the like.

11:45 justin_smith: it turns mutating code on streams into pure functions of request-map / response-map

11:45 annelies: cristian: No idea. I always throw exceptions when something goes wrong.

11:46 ambrosebs: Glenjamin: or least use contracts to be explicit about what values you think are allowed at certain points.

11:46 justin_smith: correct me if I am wrong, but my gist is that as opposed to the scala approach where they try to define a more sane semantics (and all the work that goes into that...) clojure takes the lazier approach of taking the java semantics as a given and dealing with it in a way that tries to minimize complexity

11:46 Glenjamin: ambrosebs: i suspect the greater benefit to me would be the tool reminding me i forgot to use some/when/if/or etc

11:46 ambrosebs: Glenjamin: sure, core.typed is the perfect tool for that.

11:46 it will find *all* the cases you forget in typed code.

11:48 the only time I've described core.typed as the perfect tool for anything.

11:49 Glenjamin: haha

11:49 ambrosebs: but you exactly described the reasons for core.typed's existence

11:49 justin_smith: ambrosebs: your humility is appreciated

11:49 ambrosebs: :)

11:54 ingsoc: AeroNotix: last question for the day (hopefully :P). Overall what are your impressions of clojure as a compliment to erlang and how it compares on productivity to alternatives ?

11:57 annelies: Heh, clojure as a compliment to erlang. "Hey erlang, you've got a nice clojure there!"

11:57 ingsoc: :)

11:57 :P

11:57 justin_smith: "hey erlang, love those actors, mind if I borrow a few ideas?"

11:58 annelies: such as lightweight processes ;_;

11:58 justin_smith: annelies: isn't this what core.async was going for?

11:59 annelies: Never looked into core.async.

11:59 ingsoc: well erlang = (robustness, concurrency, stability) clojure = (speed, libraries, deployability, lisps - so worth learning to expand programming knowledge)

11:59 this is how i am viewing it

12:00 annelies: Elixir runs on the Erlang VM and borrows many ideas from Clojure.

12:00 pdk: it's got...

12:00 a promising future

12:00 annelies: Such as macros and protocols.

12:00 justin_smith: ingsoc: clojure is no slouch on concurrency eitehr, if you compare it to anything *but* erlang :)

12:00 annelies: If you are into that stuff.

12:03 andyf: ambrosebs: core.typed is also the perfect tool to break Eastwood, and/or stretch it to its limits :)

12:03 ambrosebs: andyf: glad to be of service

12:03 andyf: I think I?ll declare it done when it gives correct warnings for core.typed :)

12:04 ambrosebs: hehe

12:04 andyf: That reminds me, there is a pretty darn big function generated via macro in one namespace I wanted to note to you. Let me find its name.

12:05 justin_smith: andyf: I've wondered, is eastwood named after the actor?

12:05 andyf: justin_smith: Clojure LINT :)

12:05 justin_smith: omg it's worse than I imagined

12:05 thanks

12:06 andyf: Jonas Enlund came up with the name, so I can't take credit. I wish I would have thought of it.

12:07 Glenjamin: thats genius

12:09 andyf: ambrosebs: Also, I have to ask, what do you use to navigate your 150+ namespaces? :)

12:09 ambrosebs: andyf: is it that many?! vim's Command-T

12:10 andyf: Counting test namespaces, definitely. I don't recall if non-test namespaces exceed that on their own.

12:12 ambrosebs: well that's a great success. I had a few 8000 liners a few years ago.

12:14 andyf: ambrosebs: Namespace clojure.core.typed.base-env-clj-rclass, the delay-and-cache-env call. It is only too large for Eastwood, not Clojure, I think because of extra tools.reader metadata and the way syntaxquote works. That means it is probably within a factor of 2 of being too large for Clojure, though.

12:15 ambrosebs: andyf: oh that's a stupid hack. I can fix that for you.

12:15 andyf: it should really be reading those forms from a separate file, the code should be minimal.

12:16 andyf: No need to fix it for me, but I certainly won't stop you if you wish ;)

12:16 ambrosebs: sure

12:17 andyf: You aren't the first to auto-generate huge Clojure functions, and you won't be the last. 64KB max method size seems strangely small for the JVM bytecode, but I understand there has to be a limit somewhere.

12:17 annelies: After being here for a few hours I can say I like this chatroom.

12:18 ambrosebs: the other delay-and-cache-env calls hit the method limit all the time.

12:22 andyf: core.typed: 161 non-test namespaces, 143 test namespaces. 304 total. Not counting cljs

12:22 ambrosebs: wow!

12:23 justin_smith: I have libraries with fewer lines than that

12:24 Glenjamin: does that include all the clojure.core annotations?

12:24 ambrosebs: Glenjamin: that's just one file

12:26 andyf: Glenjamin: If you were asking me regarding core.typed namespaces, I don't know which ones contain those annotations.

12:26 ambrosebs: https://github.com/clojure/core.typed/blob/master/module-check/src/main/clojure/clojure/core/typed/base_env.clj

12:26 it's a big un

12:27 Glenjamin: i love how a "big" clojure file is < 2k lines

12:27 i've had similar "this is getting a bit big" feelings, then looked to note the file is ~250 lines

12:27 justin_smith: Glenjamin: yeah, seriously

12:28 Glenjamin: I propose that the platonic ideal of a clojure namespace is a perfect square: longest line is 80 chars, 80 lines long.

12:29 Glenjamin: otoh, a huge flat namespace of non-interacting pure functions is probably still quite tidy

12:29 justin_smith: of course

12:29 Glenjamin: did you see the joe armstrong post about namespaces recently?

12:30 ambrosebs: if anyone needs a big ns form for some reason: https://github.com/clojure/core.typed/blob/master/module-check/src/main/clojure/clojure/core/typed/check.clj

12:30 Glenjamin: http://erlang.org/pipermail/erlang-questions/2011-May/058768.html

12:30 read that this week - only just noticed it's > 3 years old

12:30 justin_smith: Glenjamin: the one where he digressed to talk about letrec, yeah

12:31 I think technomancy brought it up recently

12:31 Glenjamin: aha

12:32 i have occasionally thought to build to "lein util" plugin, that lets you build your util.clj namespace by pulling functions from a remote repo w/ metadata into one file

12:33 andyf: Glenjamin: To avoid the extra dependency for utils only?

12:34 Glenjamin: andyf: yeah, and flatten it a bit

12:34 core.experimental, useful, medley etc could all just be functions in a util-function repository

12:35 andyf: I've got a pre-alpha 'dolly' lib that helps me copy code into Eastwood source and rename its namespaces, to avoid namespace version conflicts with projects being linted.

12:35 Glenjamin: similar sort of idea i guess, but for fns

12:35 andyf: I wouldn't recommend it for general use: https://github.com/jafingerhut/dolly

12:35 Glenjamin: that sounds like it'd be very useful for lein itself too

12:36 andyf: Glenjamin: Are there often conflicts between Leiningen namespaces and namespaces of projects managed by Leiningen?

12:36 Glenjamin: i've had issues between lein and speclj before

12:37 only affects plugins, not app code

12:37 unless the app pulls in lein for some reason

12:41 andyf: Yes, my guess was that something like dolly would be useful for some plugins, but not a lot else.

12:49 m1dnight: Hmm, I get "can not embed object in code" when I try to build a macro

12:49 I want to grab a variable defined in the scope of macro expansion, is that not possible? (a macro to be specific)

12:50 I.e., create a variable in your macro function, and make the expanded code use it

12:50 I'll build a minimal testcase, to make things clear perhaps

12:50 AeroNotix: show the code

12:51 m1dnight: okay, but it might be confusing :p

12:51 hold on

12:52 AeroNotix: because it sounds like you just want a gensym

12:52 unless you're making an anaphoric macro, of which I am not going to help anyone make one of those.

12:52 justin_smith: AeroNotix: how principled of you

12:53 AeroNotix: justin_smith: I find anaphoric macros incredibly annoying

12:53 justin_smith: AeroNotix: does #(= x %) count?

12:54 AeroNotix: justin_smith: no

12:54 justin_smith: you provide the symbol, technically

12:55 m1dnight: https://www.refheap.com/92918

12:55 justin_smith: oh, so as-> would be anaphoric

12:55 m1dnight: what is an anaphoric macro? :p

12:55 justin_smith: http://en.wikipedia.org/wiki/Anaphoric_macro

12:56 m1dnight: I have a list of expressions, but I want to modify them, such that they instead of execute, put their parameters in an atom

12:56 afterwards, I'll execute another function that will do something with those parameters

12:56 ingsoc: Macros scare me. Well, I mean maintaining code that someone had gone macro crazy with would be scary

12:56 m1dnight: in a different lexical scope

12:56 hyPiRion: m1dnight: imagine if-let worked like this: (if-let (get my-map :foo) (+ 2 it) 1) – where it is the result of the if-let expression

12:57 AeroNotix: ingsoc: it's all about using them judiciously

12:57 justin_smith: ingsoc: to be fair, things like ->, ->>, or, and, when, def, defn are indespensible - but making new macros definitely demands a compelling reason

12:57 m1dnight: I'm just trying to make a proof of concept here, not production code :p

12:58 AeroNotix: m1dnight: what are you actually trying to accomplish

12:58 m1dnight: well, I have a list of expressions that I execute in a dosync block. One of those expressions can be "(! actor message [values])"

12:58 but, in a dosync block we can retry, so I have to make sure to send those messages only once.

12:59 arrdem: for those of you who hanve't tried it, I highly reccomend core.logic+pldb if you want to play with a smallish dataset

12:59 * m1dnight just realized something, but lets nvm that for now

12:59 justin_smith: m1dnight: what about using a delay for that? a delay will only be realized once

12:59 m1dnight: euhm

12:59 holy *beep beep beep*

12:59 justin_smith: ,(def d (delay (do (println "realized") 1)))

12:59 clojurebot: #'sandbox/d

12:59 justin_smith: ,@d

12:59 clojurebot: realized\n1

13:00 justin_smith: ,@d

13:00 clojurebot: 1

13:00 m1dnight: that could work as well

13:00 but what I was trying to accomplish was

13:01 transform any expression in the dosync of form (send actor message [vars]) to (swap! storage (fn [msgs] (cons {:msg message :actor actor :vars vars} msgs))

13:01 this way, I can send the messages during commit phase

13:02 but since that commit phase happens in a different lexical scope I have to figure out something such that I can write to an atom or something outside the scope of my actual dosync body

13:02 which I can then access in the scope present during committing

13:02 hence, I tried putting my code in a let as yo ucan see

13:03 AeroNotix: m1dnight: your juxt function doesn't seem right

13:03 m1dnight: oh, it is

13:03 output is right, is what i mean by that :p

13:03 justin_smith: AeroNotix: what's wrong with that juxt?

13:04 AeroNotix: justin_smith: looks like they wanted to split the expressions into things which begin with #'! and those which don't

13:04 justin_smith: ,((juxt filter remove) even? (range 10))

13:04 clojurebot: [(0 2 4 6 8) (1 3 5 7 9)]

13:04 justin_smith: and that's what it does

13:04 m1dnight: AeroNotix: yes so I can then transform those to the form I showed above

13:04 AeroNotix: Right yeah I expected that to remove them altogheter

13:05 justin_smith: m1dnight: I can't prove it, but this almost smells like a hand rolled monad

13:05 m1dnight: hahaha

13:06 spare me monads, please

13:06 :'(

13:06 arrdem: hahaha

13:06 don't fear the state monad :P

13:06 m1dnight: I don't fear it, if I can keep it at a safe distance in a cage

13:06 \o/

13:07 justin_smith: your problem is that you are using ~ on delayed-msgs

13:07 that doesn't really make sense

13:07 m1dnight: yeah, when i remove it I get what I want, but then it says it cant find the variable

13:07 justin_smith: remember that your macro should build the form to compile, not run the code you want run directly

13:07 m1dnight: no such var: meta-clojure.stm.actor-friendly/delayed-msgs

13:08 justin_smith: m1dnight: right, because it is not bound in that scope - I think you want to return a binding form that captures the atom

13:08 m1dnight: oh

13:08 justin_smith: `(let [delayed-msgs# (atom {})] ...)

13:09 AeroNotix: >>> because it sounds like you just want a gensym

13:09 justin_smith: AeroNotix: right, some of us were a bit slower connecting the dots

13:09 * m1dnight points at himself

13:09 AeroNotix: No, I just called it. I didn't look too hard at the code! :)

13:09 justin_smith: good job on figuring it out :)

13:10 justin_smith: but the gensym isn't the crux of it, the need to capture the binding is - the gensym is just one tool in doing that

13:11 madscientist`: 0

13:11 doh

13:11 m1dnight: yeah, I was too focused on capturing the atom and forgot about just putting it in the macro as well

13:11 thanks a bunch :) really

13:12 justin_smith: m1dnight: yeah a macro body can capture a literal form to be embedded, but cannot capture a value

13:12 m1dnight: my head is de-hurting at the moment :D

13:12 I get it \o/

13:12 justin_smith: awesome

13:19 m1dnight: what does wrong number of args (-1) mean, actually?

13:19 0+ would be more logical, no? :p

13:25 justin_smith: yes, that is weird

13:25 andyf: m1dnight: There is a bug in Clojure for wrong arity errors for macros that subtracts 2 because macros have &form &env hidden args.

13:25 justin_smith: m1dnight: but macros get two invisible arguments

13:25 andyf: I've seen a CLJ ticket for it.

13:25 I think

13:25 m1dnight: oh that might explain :D

13:25 justin_smith: yeah, that is about it

13:26 clojure, the land of leaky abstractions

13:30 andyf: http://dev.clojure.org/jira/browse/CLJ-1279 Vote early, vote often.

13:34 arrdem: justin_smith: eh could leak worse

13:34 justin_smith: arrdem: sure, but we do have a lot of them if you go looking

13:35 arrdem: I guess

13:38 justin_smith: arrdem: I never really got the impression that seamlessness in abstractions was even a goal with clojure. I mean we don't really make much effort to hide implementation details in general.

13:38 not a dig or a complaint, just an observation of the design style

13:39 bbloom_: i think that if an abstraction is well designed, you don't have to bother hiding the implementation details: people simply won't go looking for them

13:40 justin_smith: bbloom_: right, so we let them leak, they are useful regardless

13:40 bbloom_: ,(.tail []) ; whoops!

13:40 clojurebot: #<Object[] [Ljava.lang.Object;@189f393>

13:41 AeroNotix: Yeah the JVM leaks through everywhere

13:41 bbloom_: ,clojure.lang.PersistentVector/EMPTY_NODE

13:41 clojurebot: #<Node clojure.lang.PersistentVector$Node@537a5a>

13:41 bbloom_: ,(.tail clojure.lang.PersistentVector/EMPTY_NODE)

13:41 clojurebot: #<IllegalArgumentException java.lang.IllegalArgumentException: No matching field found: tail for class clojure.lang.PersistentVector$Node>

13:42 bbloom_: ,(.tail (clojure.lang.PersistentVector/EMPTY_NODE))

13:42 clojurebot: #<IllegalArgumentException java.lang.IllegalArgumentException: No matching field found: tail for class clojure.lang.PersistentVector$Node>

13:42 bbloom_: ,(.array (clojure.lang.PersistentVector/EMPTY_NODE)) ; ah of course

13:42 clojurebot: #<Object[] [Ljava.lang.Object;@8ded54>

13:43 bbloom_: ,(.shift [])

13:43 clojurebot: 5

13:43 bbloom_: ,(set! (.shift []) 0)

13:43 clojurebot: #<IllegalAccessException java.lang.IllegalAccessException: Can not set final int field clojure.lang.PersistentVector.shift to java.lang.Integer>

13:43 bbloom_: aw, final

13:44 oh well, still

13:44 AeroNotix: bbloom_: yes Clojure is on the JVM :)

13:44 bbloom_: AeroNotix: i was trying to break all vectors w/o reflection :-P

13:45 well, w/o nefarious reflection

13:46 andyf: bbloom_: You can break their immutability without much effort by aset'ing .tail

13:46 bbloom_: andyf: that i know / have done in this very channel before :-) i was trying to break ALL vectors

13:47 andyf: You mean, one Java interop call that would cause every instance of a vector to behave incorrectly from that point forward?

13:47 bbloom_: yes

13:47 justin_smith: bbloom_: we played with a similar trick for breaking the number 5

13:47 it was amusing

13:47 bbloom_: justin_smith: do share

13:48 justin_smith: finding it in my notes

13:48 gfredericks: (.tail [1 2 3])

13:48 ,(.tail [1 2 3])

13:48 clojurebot: #<Object[] [Ljava.lang.Object;@1ba146b>

13:48 justin_smith: ,(let [field (nth (.getDeclaredFields Long) 3)] (.setAccessible field true) (.set field 5 2))

13:48 clojurebot: nil

13:48 justin_smith: ,(inc 5)

13:48 clojurebot: 3

13:48 andyf: You can break the JVM's 5, but Plato's 5 is safe in the world of forms

13:49 justin_smith: haha

13:49 gfredericks: ~5 is the set of all sets with 5 elements

13:49 clojurebot: Ik begrijp

13:49 bbloom_: , (.getDeclaredFields Long) 3)

13:49 clojurebot: #<Field[] [Ljava.lang.reflect.Field;@5753b0>

13:49 bbloom_: ,(.getName (.getDeclaredFields Long) 3))

13:49 clojurebot: #<IllegalArgumentException java.lang.IllegalArgumentException: No matching method found: getName for class [Ljava.lang.reflect.Field;>

13:49 bbloom_: ,(.name (.getDeclaredFields Long) 3))

13:49 clojurebot: #<IllegalArgumentException java.lang.IllegalArgumentException: No matching method found: name for class [Ljava.lang.reflect.Field;>

13:49 bbloom_: ,(clojure.reflect/reflect (.getDeclaredFields Long) 3))

13:49 clojurebot: #<ClassNotFoundException java.lang.ClassNotFoundException: clojure.reflect>

13:49 bbloom_: ,(require 'clojure.reflect)

13:49 clojurebot: nil

13:49 bbloom_: eh wahtever... how do i get the name of a field?

13:50 gfredericks: .getName?

13:50 bbloom_: i tried that

13:50 oh dur it's an array

13:50 gfredericks: with 3?

13:50 bbloom_: ,(.name (nth (.getDeclaredFields Long) 3))

13:50 clojurebot: #<IllegalArgumentException java.lang.IllegalArgumentException: No matching field found: name for class java.lang.reflect.Field>

13:50 bbloom_: i suck

13:50 ,(.getName (nth (.getDeclaredFields Long) 3))

13:50 clojurebot: "value"

13:51 andyf: The world of forms: Bringing you real immutability since 348 BC

13:51 bbloom_: ah ok i gotcha. boxed small numbers are interned

13:51 justin_smith: , (nth (.getDeclaredFields Long) 3)

13:51 clojurebot: #<Field private final long java.lang.Long.value>

13:51 justin_smith: ,(.getName (nth (.getDeclaredFields Long) 3))

13:51 clojurebot: "value"

13:51 bbloom_: andyf: https://en.wikipedia.org/wiki/348_BC <- i was hoping you knew the actual year

13:51 justin_smith: bbloom_: ^

13:52 bbloom_: justin_smith: i got there eventually :-P

13:52 justin_smith: bbloom_: aha, I missed it while I was finding it in my own repl

13:52 andyf: Sorry, I don't know when he wrote about it first, so I approximated by the year Plato died.

13:53 justin_smith: ,(= 5 3)

13:53 clojurebot: false

13:53 justin_smith: ,(= 5 2)

13:53 clojurebot: true

13:54 justin_smith: ,(let [field (nth (.getDeclaredFields Long) 3)] (.setAccessible field true) (.set field 5 (inc 4)))

13:54 clojurebot: nil

13:54 justin_smith: ,(= 5 2)

13:54 clojurebot: true

13:54 justin_smith: I thought I fixed that...

13:54 ,(let [field (nth (.getDeclaredFields Long) 3)] (.setAccessible field true) (.set field (inc 4) (inc 4)))

13:54 clojurebot: nil

13:54 justin_smith: ,(= 5 2)

13:54 clojurebot: true

13:54 justin_smith: ,(inc 2)

13:54 clojurebot: 3

13:54 justin_smith: ,(inc 5)

13:54 clojurebot: 3

13:54 mearnsh: this is why we can't have nice things

13:55 AeroNotix: ,(inc (+ 3 2))

13:55 clojurebot: 6

13:55 justin_smith: :( I forgot how to fix it

13:55 AeroNotix: ,(inc 5)

13:55 clojurebot: 3

13:55 AeroNotix: 5

13:55 ,5

13:55 clojurebot: 2

13:55 justin_smith: ,(let [five (long (int (+ (int 1) (int 4)))), field (nth (.getDeclaredFields Long) 3)] (.setAccessible field true) (.set field five (int (+ (int 1) (int 4)))))

13:55 clojurebot: nil

13:55 andyf: Once you make 5 equal to something else, the JVM extrapolates and is able to prove that all numbers are simultaneously equal to, and not equal to, all others.

13:55 justin_smith: ,5

13:55 clojurebot: 5

13:55 justin_smith: ok, found the fix

13:55 andyf: if only

13:55 andyf: It's downhill from there

13:56 bbloom_: this statement is false.

13:56 andyf: and simultaneously not downhill from there

13:56 justin_smith: I can't take credit for the trick, I just made a note of it to study, amalloy_ was who I saw do it

14:00 AeroNotix: ,(inc [])

14:00 clojurebot: #<ClassCastException java.lang.ClassCastException: clojure.lang.PersistentVector cannot be cast to java.lang.Number>

14:08 m1dnight: What function do I have to map over a list of functions to execute all of them?

14:09 justin_smith: #(%)

14:09 equivalently (fn [f] (f))

14:09 m1dnight: riiight!

14:09 thanks justin_smith

14:09 justin_smith: np

14:10 if you want to get way into semantic overload, (fn [fn] (fn)) actually works

14:10 m1dnight: hahaha

14:10 arrdem: hehe

14:10 justin_smith: but that shadows fn which is weird so don't do that

14:11 m1dnight: :D

14:11 andyf: justin_smith: Please, no. Zach Tellman's Manifold library defines a function called 'catch' that uses try/catch in its definition.

14:11 justin_smith: ,(take 42 (map (fn [fn] (fn)) (repeat (constantly 42))))

14:11 clojurebot: (42 42 42 42 42 ...)

14:11 justin_smith: andyf: ouch

14:12 andyf: It all works, where the catch occurrences inside try are try/catch, and the ones not inside try are the function, but yeah, weird.

14:13 justin_smith: yeah, that seems gratuitously clever

14:13 gfredericks: ,((fn [fn] (fn fn fn fn fn fn fn)) list)

14:13 clojurebot: (#<clojure.lang.PersistentList$1@f90a8b> #<clojure.lang.PersistentList$1@f90a8b> #<clojure.lang.PersistentList$1@f90a8b> #<clojure.lang.PersistentList$1@f90a8b> #<clojure.lang.PersistentList$1@f90a8b> ...)

14:13 justin_smith: haha

14:13 gfredericks: it's now reminding me of "Being John Malkovich"

14:14 but instead of crawling in to be Malkovich, you crawl into the weird little door and suddenly you are an anonymous function...

14:14 * gfredericks is suddenly an anonymous function

14:14 justin_smith: https://www.youtube.com/watch?v=Q6Fuxkinhug

14:14 andyf: self reference isn't what i used to be

14:15 justin_smith: classic scene

14:15 nor is semantic satiation

14:52 ghadishayban: about to release this tiny library of clojure 1.7 "helpers" https://github.com/ghadishayban/reducers

14:52 more reducible sources, reduce-based ops and a couple other novel things

14:53 would love to get some eyes on it

14:54 inspired by some an musing from hiredman

14:55 the implementation of select-keys with transducers becomes super nice (and fast):

14:56 (defn select-keys

14:56 [map keyseq]

14:56 (into {} (keep #(find map %)) keyseq))

14:57 justin_smith: ,(doc find)

14:57 clojurebot: "([map key]); Returns the map entry for key, or nil if key not present."

14:57 justin_smith: is that an optimization for get?

14:58 ghadishayban: it returns the whole MapEntry. sister function to get

14:58 justin_smith: oh, interesting

14:59 ,(find [:a] 0)

14:59 clojurebot: [0 :a]

14:59 ghadishayban: ,(conj {} [:a :b])

14:59 justin_smith: assuming that's odd

14:59 clojurebot: {:a :b}

14:59 gfredericks: useful for implementing plumbing.core/safe-get

14:59 or more generally, for doing both contains? and get in one lookup

15:01 ghadishayban: ,(class (find {:a :b} :a))

15:01 clojurebot: clojure.lang.MapEntry

15:01 justin_smith: ,(type (find [:a] 0))

15:01 clojurebot: clojure.lang.MapEntry

15:02 gfredericks: lifehack: to protect yourself against accidentally evaling a scratch file, put (don't load this) on the first line

15:02 I guess it works just as well without the parens

15:02 could even be englishified as "Don't load this."

15:02 justin_smith: alternatively (why did you load this file? you shouldn't have tried)

15:03 gfredericks: the bonus with the parens I think is that you would get the whole thing, not just the first invalid symbol

15:03 ghadishayban: ,filter-key

15:03 clojurebot: #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: filter-key in this context, compiling:(NO_SOURCE_PATH:0:0)>

15:03 ghadishayban: ,*clojure-version*

15:03 clojurebot: {:interim true, :major 1, :minor 7, :incremental 0, :qualifier "master"}

15:03 justin_smith: gfredericks: err... I guess not

15:05 ghadishayban: (defn filter-key [keyfn pred coll] (into (empty coll) (filter (comp pred keyfn)) coll))

15:05 ,(defn filter-key [keyfn pred coll] (into (empty coll) (filter (comp pred keyfn)) coll))

15:05 clojurebot: #'sandbox/filter-key

15:06 ghadishayban: (filter-key val even? {:a 2 :b 1 :c 4 :d 5})

15:06 ,(filter-key val even? {:a 2 :b 1 :c 4 :d 5})

15:06 clojurebot: {:c 4, :a 2}

15:06 ghadishayban: ,(filter-key key string? {:a 2 :b 1 "HI" 4 :d 5})

15:06 clojurebot: {"HI" 4}

15:06 justin_smith: oh, that's very nice

15:07 ghadishayban: transducers are the shit

15:07 that's all using transients

15:07 justin_smith: so I am seeing

15:08 ghadishayban: similarly,

15:09 ,(filter-key :a string? [{:a 3} {:a "foo"}])

15:09 clojurebot: #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: filter-key in this context, compiling:(NO_SOURCE_PATH:0:0)>

15:09 ghadishayban: guess that var expired?

15:09 justin_smith: clojurebot protects us from ourselves with periodic automatic resets

15:09 gfredericks: ~transducers |are| the shit

15:09 clojurebot: Ack. Ack.

15:20 ghadishayban: what do people normally call the find-first function:

15:20 (first (filter pred coll))

15:21 bbloom_: ghadishayban: i usually just do (let [[x] (filter pred coll)] ...

15:21 ghadishayban: slick

15:22 i called it any...and i hate it

15:22 https://github.com/ghadishayban/reducers/blob/master/src/ghadi/reducers.clj#L66-L80

15:22 bbloom_: ghadishayban: i've seen it called "one" in ORMs ಠ_ಠ

15:23 ghadishayban: let's call it some!

15:23 jk

15:25 SagiCZ1: if i have a custom loop in which i am building a list (adding an element to it in each iteration) is there any way to make this lazy?

15:25 justin_smith: cinderella (like how the prince lines up all the women and takes the first one that can wear the shoe)

15:25 ghadishayban: nice

15:26 justin_smith: SagiCZ1: use a function that self calls within lazy-seq

15:26 bbloom_: SagiCZ1: just use a recursive call and lazy-seq

15:26 justin_smith: heh

15:26 SagiCZ1: (doc lazy-seq)

15:26 clojurebot: "([& body]); Takes a body of expressions that returns an ISeq or nil, and yields a Seqable object that will invoke the body only the first time seq is called, and will cache the result and return it on all subsequent seq calls. See also - realized?"

15:26 SagiCZ1: this one right?

15:26 justin_smith: right

15:26 @grim lazy-seq

15:26 SagiCZ1: k thanks

15:26 justin_smith: $grim lazy-seq

15:26 not in yet, OK

15:27 SagiCZ1: what is grim?

15:27 justin_smith: it would have found this http://grimoire.arrdem.com/1.6.0/clojure.core/lazy-seq/

15:27 ghadishayban: SagiCZ1: depending on what you're doing, look at iterate

15:27 justin_smith: has some examples

15:27 oh yeah, iterate sometimes works - depends

15:28 ghadishayban: i added a reducible iterate that little reducers lib: https://github.com/ghadishayban/reducers/blob/master/src/ghadi/reducers.clj#L43-L50

15:28 SagiCZ1: and is it generally a good idea to make your functions return lazy seqs? i mean i just end up rewriting it to use lazy seq..

15:28 justin_smith: SagiCZ1: in some cases lazy-seqs are very handy

15:30 ghadishayban: SagiCZ1: though i will say, almost in 100% of cases there a way using clojure seq functions (like iterate, map, mapcat, filter) without having to call lazy-seq manually

15:30 i mean, to express a loop

15:30 if you can paste your loop to refheap...

15:31 SagiCZ1: ghadishayban: but loop is specifically for cases where you cant express it another way

15:32 ghadishayban: unless you can't see that there is another way to express it :)

15:32 SagiCZ1: ghadishayban: which might be very possible.. i have no problem pasting it on refheap, maybe you can take a look if you want

15:32 ghadishayban: usually if you're iterating simultaneously through two collections, then loop is your only option

15:33 amalloy: ghadishayban: in many of those cases, map is fine

15:33 i definitely wouldn't say "usually"

15:33 SagiCZ1: i guess i am doing all kinds of weird stuff https://www.refheap.com/92926

15:35 justin_smith: as-is, that could be a reduce on ticks

15:35 where events is the accumulator

15:36 SagiCZ1: justin_smith: is reduce lazy?

15:36 justin_smith: and uncompleted bars is also an accumulator

15:36 no

15:37 SagiCZ1: you are just saying i dont necessarily need loop

15:37 justin_smith: it could also be a (:events (last (take-while pred (iterate f [ticks bars]))))

15:37 or something like that

15:37 definitely don't need loop

15:38 ghadishayban: justin_smith: that's kinda hard to grok

15:38 justin_smith: there may be a more straightforward way to use iterate there actually

15:38 ghadishayban: yeah, it's a mess, sorry

15:39 SagiCZ1: i just need to make it lazy..

15:40 justin_smith: SagiCZ1: it would be fairly straightforward to make it lazy with reductions, where you would have completed-bars and uncomplete-bars for each step

15:41 SagiCZ1: i thought reduce is not lazy?

15:41 reductions not= reduce

15:42 (doc reductions)

15:42 clojurebot: "([f coll] [f init coll]); Returns a lazy seq of the intermediate values of the reduction (as per reduce) of coll by f, starting with init."

15:43 SagiCZ1: i need to learn this stuff.. i will probably head to 4clojure, before i tackle this big loop

15:45 justin_smith: SagiCZ1: something like this I think https://www.refheap.com/92929

15:46 no wait...

15:46 SagiCZ1: wow, thanks for taking the time to write that.. i will look into it

15:46 justin_smith: I just saw a mistake in that actually

15:48 SagiCZ1: updated, I am sure it is still imperfect https://www.refheap.com/92929

15:48 but may be a good starting point

15:49 SagiCZ1: the big picture is that at each step it generates a two element vector of the events (completed bars) and the bars (the ones still being used) and you get a lazy-seq with one pair of these generated from each tick

15:49 (or that is what it does if it isn't still buggy)

15:50 amalloy: SagiCZ1's loop looked a lot like a filter and/or a mapcat to me; i don't have time to write it up atm, but i don't see any steps depending on the results of previous steps

15:50 justin_smith: amalloy: it moves things between completed / uncompleted

15:50 well, one way

15:50 amalloy: okay

15:51 justin_smith: it does an update of the previous "completed" bars at each step

15:51 that's why I think it need accumulators

15:52 but I have been known to use reduce / reductions when a filter or mapcat would do, so it's worth a second check on that

15:53 SagiCZ1: one trivial change I did is replace #(:complete %) with :complete in a couple places - in that context it was identical

15:54 but I tried to keep each of the steps of the core logic the same as your version, so the adaptation is clear

15:55 *should be clear, barring more mistakes on my part

15:58 SagiCZ1: amalloy: in one iteration some bars get completed (and they get replaced by new bars) but others have to be past to the next step

15:58 justin_smith: thanks again, i will try it out once i get back to it

15:59 justin_smith: np, I was just spinning my wheels before trying a big db migration on my scratch db, that I am procrastinating on because it will probably fail and I will need to reset the db again...

15:59 :)

16:11 SagiCZ1: :)

16:19 justin_smith: well, I sure did call that one, time to wipe the test db again!

16:58 donbonifacio: I have a hash, with a lazy-seq somewhere, how can I find it

17:00 justin_smith: so it's a hash map with a lazy-seq inside it?

17:00 do you have a handle to that hash-map?

17:01 or maybe the better question is - where did this hash map and lazy seq come from, and what do you expect to find in them?

17:03 donbonifacio: I have a hash that I'm passing to monger, and it's complaining clojure.lang.LazySeq cannot be cast to java.lang.String

17:04 I do have a key that's an array, I'm gessing that it can't convert that to a string and maybe it's calling it a LazySeq

17:04 justin_smith: I doubt it

17:05 you could use clojure.walk/postwalk

17:09 ,(clojure.walk/postwalk (fn [el] (when (isa? (type el) clojure.lang.LazySeq) (println el)) el) {:a 0 :b 1 :c {:d (range 10)}})

17:09 clojurebot: #<ClassNotFoundException java.lang.ClassNotFoundException: clojure.walk>

17:10 justin_smith: maybe something like that? but there is probably a more elegant way to do it

17:10 ,(require 'clojure.walk)

17:10 clojurebot: nil

17:10 justin_smith: ,(clojure.walk/postwalk (fn [el] (when (isa? (type el) clojure.lang.LazySeq) (println el)) el) {:a 0 :b 1 :c {:d (range 10)}})

17:10 clojurebot: (0 1 2 3 4 ...)\n{:a 0, :b 1, :c {:d (0 1 2 3 4 ...)}}

17:18 justin_smith: ,(do (clojure.walk/postwalk (fn [el] (when (isa? (type el) clojure.lang.LazySeq) (println el)) el) {:a 0 :b 1 :c {:d (range 10)}}) nil) ; a little more clear maybe?

17:18 clojurebot: (0 1 2 3 4 ...)\n

17:27 irctc: Would anyone have any idea why my tiny Clojure server will not read from a Socket before the Python Client closes its own socket. -> gist https://gist.github.com/KristoKoert/3d1aa3ccd90a8bfcc341

17:30 justin_smith: irctc: how do you know the clojure code is not reading?

17:32 are you developing inside an editor by any chance? because your defns are in the wrong order

17:33 irctc: I had a load of printlns in between every step, The server executed till the comment i left. At the same time the python server continued sending its message until I exit the python script and once I exit it all the messages are recieved and the Clojure program continues as expected (will read every time), but will not hear the client if I try reconnecting.

17:34 It might be that my python script is wrong as well..

17:34 Inside emacs, I am just trying it out, so evaling :)

17:35 justin_smith: irctc: using cider?

17:35 look for an *nrepl-connection* buffer - that should get your .println output

17:36 irctc: Yes, cider.

17:36 justin_smith: yeah, the way emacs/cider/clojure handle stdout is way weird, some things from threads go in the wrong buffer due to dynamic binding and how that works when spawning threads

17:37 irctc: Actually I DO get all the messages and I have the cider repl open and see them in there. But the problem is that the messages only come through AFTER I stop the Python script. For whatever reason..

17:37 And all of them at the same time.

17:39 justin_smith: oh, sorry, yeah

17:39 is that python code sending full lines?

17:40 because .readLine might be waiting for a newline

17:40 maybe socket.send does not insert newlines?

17:40 irctc: Oh? I will try that right now!

17:40 justin_smith: actually I would be surprised if it did

17:45 irctc: Nice, it worked! Great, a really simple mistake... Thanks guys :)

17:49 justin_smith: np

18:22 is there a paredit command that is like C-t but for list elements and not characters?

18:22 so if I have [a b |c d] and I run that command, it should become [a c b |d]

18:23 Bronsa: justin_smith: isn't that transpose-sexps?

18:24 justin_smith: Bronsa: probably, I didn't find it on my paredit cheat-sheet

18:24 Bronsa: justin_smith: don't think it's a paredit function

18:25 justin_smith: Bronsa: yeah, it kind-of works, but totally doesn't respect hash-map structure

18:25 but better than nothing

18:25 Bronsa: justin_smith: yeah looks like it's in emacs and bound to C-M-t

18:25 justin_smith: yeah

18:27 annelies: oh the joy of writing code in Java

18:49 amalloy: justin_smith: doesn't respect hash-map structure how?

18:49 justin_smith: it transposes keys and values separately, not as a pair

18:49 not that it would be reasonable to expect that I guess

18:50 maybe I will write a nice dwim that moves key value pairs forward and back in hashmap literals

18:50 and otherwise acts just like transpose-sexps

19:38 annelies: I am going to sleep ladies and gentlemen.

19:38 Bronsa: bye

19:38 annelies: goodbye

19:41 There is get and get-in, assoc and assoc-in, and update-in, but why not update?

19:41 andyf: annelies: There will be in Clojure 1.7

19:41 Bronsa: annelies: update has been added in 1.7

19:41 annelies: Nice. :)

19:42 andyf: you ask interesting questions while you sleep :)

19:43 annelies: I also really wish numerator and denominator worked on integers. :c There's a bug report of it already though.

19:43 andyf: have you voted for it?

19:43 annelies: Yeah

19:44 andyf: Then except for encouraging others to vote on it and writing a patch that works, you've done all you can :)

19:45 Bronsa: in my experience, a ticket with no patch will hardly get considered unless it's a serious bug

19:49 andyf: Bronsa: I think it matters more whether Rich or a screener like Alex think the description is something they agree is a problem, not whether there is currently a patch.

19:50 A screener triaging a ticket, or Rich vetting one, seem to me to have little to do with the presence/absence of a patch, but I'm guessing based on watching, not knowing.

19:50 Bronsa: andyf: I would like to agree with you but I'm pretty sure there is a *large* number of valid tickets that have never been seen by Rich or by any screener

19:51 andyf: Alex Miller has seen every one multiple times, I'm sure.

19:52 Summer 2013 he checked and/or updated the state of every single open ticket, and he's vetted about 1/5 of the open ones.

19:52 sorry, triaged, not vetted

19:52 justin_smith: andyf: is 0.1.5 the latest eastwood available from maven?

19:52 andyf: justin_smith: yes

19:52 justin_smith: cool, thanks

19:52 so this does not have the from-repl stuff you talked about recently, right?

19:52 andyf: You can check on clojars.org for any project hosted there what all version are that have been released, fyi, but I don't mind answering.

19:53 justin_smith: OK

19:53 andyf: It can be run from the REPL, and you don't need Leiningen.

19:53 justin_smith: oh, cool

19:53 andyf: Instructions here: https://github.com/jonase/eastwood#running-eastwood-in-a-repl

19:53 With I hope appropriate and not-too-scary warnings

19:54 justin_smith: andyf: I had assumed, given the big version difference between github and clojars, that the newer feature was not available or maybe I just wasn't finding it

19:54 andyf: Don't do it in a live production JVM is the most important warning.

19:54 justin_smith: right, I wouldn't need that anyway, thanks

19:54 andyf: Oh, you mean the 0.2.0-SNAPSHOT on github?

19:54 justin_smith: right

19:55 that's what confused me

19:55 andyf: That is not binding, but I am hoping it encourages me to add the feature for source code annotations to disable linters on a per-file and/or per-expression basis, which I consider worth bumping the version to 0.2.0 when released.

19:56 annelies: well, time to really sleep

19:56 goodbye! <3

19:56 andyf: I'm doing development on master. You have to checkout a version-specific tag if you want to see source code for a specific release (or unzip the jar)

19:57 Bronsa: andyf: eh well, updating the status of a ticket doesn't mean it has been considered, it's just maintainance from my POV. there are a lots of "dead" tickets (i.e. that see no activity whatsoever) in jira

19:58 andyf: I'm gradually becoming accustomed to taking the long view, e.g. 5 years out :)

19:58 justin_smith: andyf: thanks. This message is confusing (caused by a misnamed file that I forgot to delete) - is it worth filing a ticket for? https://www.refheap.com/92941

19:58 Bronsa: andyf: I'm not criticizing Alex's work btw, the process is just really frustrating sometimes

19:59 andyf: Understood. Paraphrasing Sir Lawrence of Arabie from the movie, the trick is not minding that it takes the time it does :)

19:59 Arabia, even.

20:00 Bronsa: andyf: it's counterproductive though. Say I open a ticket and attach a patch and that ticket doesn't get considered until 2 years later when the patch doesn't apply anymore

20:00 in the meantime I've lost interest in clojure and/or don't use it anymore for my work and I'm not going to update the patch, and the ticket becomes stale

20:00 andyf: Bronsa: That is the same situation we would be in even if all of the other 400 open tickets were considered before that ticket's patch -- most likely it wouldn't apply cleanly any more

20:01 justin_smith: andyf: update with suggested replacement message https://www.refheap.com/92941

20:02 andyf: justin_smith: Sure, open a ticket for that. The message you see now is correct, but I agree a bit verbose for the common special case you have.

20:02 Bronsa: andyf: I'm not sure it would be this bad. consider patch 1 that affects file a and patch 2 that affects the same file is written 3 months later

20:03 andyf: if patch 1 has been merged within the 3 months period, patch 2 will be writte on top of patch 1 and will apply cleanly

20:03 justin_smith: andyf: the "has namespace" / "should have namespace" are identical, which I thought may have been a bug. I'll file it as a suggestion.

20:03 Bronsa: andyf: if patch 1 has not been merged, patch 1&2 will conflict and once one gets merged the other will not apply anymore

20:04 andyf: justin_smith: I'd call it a confusing message, to be sure, and worth a special case in the code that prints the messages.

20:04 justin_smith: that sentence fragment combined with the "or should be in file" are technically correct, where it is really the second part after the or that is true in this instance. I'm all for clearer warning messages.

20:05 justin_smith: cool, thanks

20:06 andyf: Bronsa: We are not alone in wishing the process went faster sometimes. To me, the heart of the issue is: our wishes do not trump someone else's free will in choosing what they do with their time.

20:08 Another way of looking at it is this: ~8 years after first working on the project, the creator still spends a chunk of his free time every month enhancing it. i.e. it is not abandoned.

20:10 And, he adds things to it like transducers, rather than restricting himself to considering problem reports that have been created by others.

20:11 Bronsa: andyf: I envy your ability to feel this way knowing the amount of time you spend around JIRA and noticing the (mostly) lack of activity around it by any core member other than Alex

20:12 andyf: Bronsa: I would not have spoken like this 2 years ago. It is an acquired attitude :)

20:13 Bronsa: andyf: I don't see your last point as a positive thing. To me that shows exactly how little issues reported by community members are valued

20:13 andyf: In the mean time, I think you are having a big impact on projects like core.typed, core.async, Eastwood, and whatever else tools.analyzer.* are getting use in.

20:15 Bronsa: I don't know exactly how much time is spent by who on what, but I get the distinct impression that if all they did was focus on tickets from community members, they wouldn't have time/energy left for adding cool new stuff.

20:16 Bronsa: Out of curiosity, do you know of any other projects besides the ones I mentioned using tools.analyzer?

20:17 Bronsa: andyf: crossclj uses t.a AFAIK

20:17 andyf: Oh, yeah. That site is amazing.

20:19 Francesco even found and fixed an issue I reported recently, where many of the "this var is used in places x, y, z, ..." had a bug in it.

20:19 Bronsa: it is indeed. my only complaint is that the UI feels a bit too "heavy" sometimes

20:22 andyf: ah, nrepl-refactor or however it's called uses t.a too. not sure if in a released version or a still in dev

20:25 andyf: I bet the list will grow as more people think of uses for it. Hats off to you, my friend.

20:26 justin_smith: (inc andyf)

20:26 lazybot: ⇒ 5

20:26 justin_smith: eastwood is awesome, thanks

20:26 I just regret I didn't start using it sooner

20:27 Bronsa: (inc andyf)

20:27 lazybot: ⇒ 6

20:28 andyf: Got to go for a while. Talk to you folks later.

20:28 Bronsa: have some internet points. I'll need yo buy you a beer if we ever get the chance to meet, for having my back when I break things

20:30 andrewhr: Bronsa: maybe a stupid question, but there is any work around a t.e.js? found only the t.e.jvm

20:31 Bronsa: andrewhr: no and I honestly have no interested in forking the cljs compiler to adapt its emitter to compiler t.e.js's AST rather than cljs.analyzer's one

20:32 andrewhr: *you* don’t have any interest or the *community* don’t see any value with that?

20:33 nonuby: destructing question, i dont what the difference is between defn x [handlers] and defn x [[& handlers]]

20:33 andrewhr: btw, I’m just asking to you bc your work with t.e.jvm

20:34 not want to mean anything bad, please

20:35 Bronsa: andrewhr: *I* don't have interest nor time, and I guess neither does the community. There's not much value in another cljs compiler, t.a.js otoh is valuable because it is (in my biased opinion) a lot more powerful than cljs.analyzer

20:35 amalloy: nonuby: the second version is just silly

20:36 you are correct in implying that there is no difference

20:36 Bronsa: amalloy: there is though, the first will accept "1", the second won't

20:36 amalloy: well, yes

20:36 Bronsa: it's a silly way to assert (coll? arg)

20:36 amalloy: and the second will convert [] to nil

20:36 Bronsa: wut?

20:36 nonuby: so its like some form of weak typing checking... ah you said first

20:36 amalloy: won't it?

20:37 Bronsa: no idea

20:37 amalloy: ,((fn [[& xs]] xs) [])

20:37 clojurebot: nil

20:37 amalloy: Bronsa: because & destructuring never returns an empty seq, only nil or non-empty

20:37 Bronsa: TIL

20:37 nonuby: amalloy, cool. thanks just something i noticed on compojure.core/routes

20:38 andrewhr: Bronsa: thanks. just want to know how the clj(s) community feels about that

20:38 Bronsa: amalloy: do you happen to know if that was a conscious decision or an accident of the impl?

20:38 amalloy: Bronsa: i believe it's a legacy of the time when there was no such thing as a non-empty seq

20:39 Bronsa: and/or if there's an obvious reason why it doesn't return () that I'm missing

20:39 amalloy: it's a decision that i really wish we could undo

20:39 er, no such thing as an empty seq

20:40 Bronsa: andrewhr: well I'm not the right person to ask such a thing then :) I'm not really part of the cljs sub-community

20:41 amalloy: the problem is that it means you should never use & xs destructuring in a lazy function. consider this reasonable implementation of map: (fn map [f xs] (lazy-seq (when-let [[x & xs] (seq xs)] (cons (f x) (map f xs)))))

20:41 it looks correct, but because xs will never be nil, you end up forcing one more element of the input collection than the user asks for

20:41 andrewhr: Bronsa: still think it’s a valulable opinion :)

20:43 another shot for you: t.a is capable of doing some kind of incremental analysis? let’s say - to use it for making some kind of code highlight for example

20:43 Bronsa: amalloy: makes sense, thanks

20:47 andrewhr: t.a assumes fully evaluated env but there are ways to analyzing code w/o evaluating it, even though that requires a bit of configuration & the analysis might be inaccurate

20:47 andrewhr: not sure if that's what you were asking me though

20:49 andrewhr: Bronsa: so you will only be able to really analyze code in a “live runtime”, if I get it right

20:49 (in a precise way)

20:49 Bronsa: andrewhr: in t.a.jvm yes. for cljs it's a bit different because it has no resident compiler & reified namespaces

20:50 andrewhr: got it

20:50 thanks again!

20:51 Bronsa: andrewhr: silly example, "(defmacro foo [] (list 'def 'bar 1)) (foo) bar", the analyzer has no way to know that "bar" refers to a var if you don't evaluate the defmacro expr and it's invocation before analyzing the symbol "bar"

20:53 andrewhr: I mean, there are certainly techniques it could use to figure it out in this case, but that's out-of-scope for t.a

21:01 andrewhr: Bronsa: I see. requiring a live environment will not be a true problem for what I have in mind

21:08 puredanger: Bronsa (and andyf ) : just browsing the back chat. just fyi, the ticket situation is frustrating for me too.

21:08 dc_: whats the best way to combine two lists in clojure like this: [1 2 3] [4 5 6] => [[1 4][2 5][3 6]]

21:08 like is there a function that does that?

21:08 godd2: interleave?

21:08 hyPiRion: ,(apply map list [[1 2 3] [4 5 6]])

21:09 clojurebot: ((1 4) (2 5) (3 6))

21:09 dc_: ahh ok yep, that's what i'm looking for

21:09 hyPiRion: If you want vectors

21:09 ,(apply mapv vector [[1 2 3] [4 5 6]])

21:09 clojurebot: [[1 4] [2 5] [3 6]]

21:09 dc_: godd2 hipirion: thanks

21:09 hyPiRion: np

21:10 Bronsa: puredanger: yeah I don't find it hard to believe that. I'm sorry if you've been named in my small rant but I assure you I that I (and I hope to talk for most of the community) really apprecciate your work

21:10 puredanger: I do what I can

21:11 godd2: ,(map vector [1 2 3] [4 5 6])

21:11 clojurebot: ([1 4] [2 5] [3 6])

21:11 godd2: oh I see that doesn't return a vector

21:12 ,(mapv vector [1 2 3] [4 5 6])

21:12 clojurebot: [[1 4] [2 5] [3 6]]

21:25 smnirven: okay folks, let's say I have a sequence of maps, and I want to call a certain function once for every map in the sequence, but for use in the -> macro

21:27 any ideas on how i might accomplish that?

21:28 Bronsa: smnirven: you want to map inside a -> expression?

21:28 smnirven: yeah something like that

21:29 Bronsa: you can do (-> coll ... (as-> coll (map f coll)) ..)

21:29 TEttinger: (doc as->)

21:29 Bronsa: smnirven: assuming you can't use ->>

21:29 clojurebot: "([expr name & forms]); Binds name to expr, evaluates the first form in the lexical context of that binding, then binds name to that result, repeating for each successive form, returning the result of the last form."

21:30 justin_smith: ,(-> [{:a 0 :b 1} {:a 1 :b 2}] (#(map :a %))) ; another option

21:30 clojurebot: (0 1)

21:31 TEttinger: ,(-> [{:a 0 :b 1} {:a 1 :b 2}] ((partial map :a))) ; yet another option

21:31 clojurebot: (0 1)

21:32 smnirven: ahh, partial might be the ticket here

21:32 Bronsa: justin_smith: I find that really ugly

21:33 justin_smith: ,(-> [{:a 0 :b 1} {:a 1 :b 2}] (->> (map :a))) ; yet another

21:33 clojurebot: (0 1)

21:33 Bronsa: whenever I find myself wanting to (-> .. (#(..))) I just lift the lambda in a let over the -> expr

21:33 TEttinger: that last one looks like a winner, justin_smith

21:34 justin_smith: TEttinger: and of course it can bump up a level again if you need -> again

21:34 Bronsa: and I also tend to avoid nesting ->/->>/doto as that gets unreadable pretty fast :P

21:34 smnirven: let's say the collection coll [{:a 1} {:a 2}]

21:35 I want to insert the same function in an existing thread macro once for each map in that collection

21:35 (-> orig (f1) (f2 {:a 1}) (f2 {:a 2})

21:36 trying to figure out how to do that with any number of maps in that collection

21:36 justin_smith: smnirven: that does not work in general unless you know the maps (or at least how many there are) when the macro is expanded

21:36 TEttinger: that sounds like a different use case

21:37 Bronsa: smnirven: are you sure you want (f2 (f2 (f1 orig) {:a 1}) {:a 2})?

21:38 smnirven: Bronsa: yep

21:40 Bronsa: that's (reduce f2 (f1 orig) [{:a 1} {:a 2}]), I wouldn't really insert it in a -> expr

21:40 smnirven: there's a pretty good chance im attacking this in the wrong way entirely -- basically im trying to compose a sqlkorma select with the possibility of multiple joins

21:55 arrrms: What are people's opinions on the Web Development with Clojure book? There are only two Amazon reviews (http://www.amazon.com/Web-Development-Clojure-Build-Bulletproof/dp/1937785645/ref=sr_1_1?ie=UTF8&qid=1415500923&sr=8-1&keywords=clojure+web+development)

22:19 godd2: Is there a way to have lein repl print out transients in a prettier way?

22:20 gfredericks: godd2: check out print-method

22:20 ,(transient [1 2 3])

22:20 clojurebot: #<TransientVector clojure.lang.PersistentVector$TransientVector@13c422e>

22:21 gfredericks: ,(defmethod print-method clojure.lang.TransientVector [tv pw] (print-method (into [] (map #(get tv %) (range (count tv)))) pw))

22:21 clojurebot: #<CompilerException java.lang.ClassNotFoundException: clojure.lang.TransientVector, compiling:(NO_SOURCE_PATH:0:0)>

22:21 gfredericks: ,(defmethod print-method clojure.lang.PersistentVector$TransientVector [tv pw] (print-method (into [] (map #(get tv %) (range (count tv)))) pw))

22:21 clojurebot: #<MultiFn clojure.lang.MultiFn@18eaab5>

22:21 gfredericks: ,(transient [1 2 3])

22:21 clojurebot: [1 2 3]

22:21 godd2: oh wow

22:21 gfredericks: or if you want it to be less ambiguous

22:21 godd2: did you just change clojurebot for good? (or at least for a while)

22:22 gfredericks: ,(defmethod print-method clojure.lang.PersistentVector$TransientVector [tv pw] (.write pw "#transient ") (print-method (into [] (map #(get tv %) (range (count tv)))) pw))

22:22 clojurebot: #<MultiFn clojure.lang.MultiFn@18eaab5>

22:22 gfredericks: ,(transient [1 2 3])

22:22 clojurebot: #transient [1 2 3]

22:22 godd2: I like that even more

22:22 gfredericks: godd2: I think it'll reboot after 10 minutes or something

22:23 godd2: Where should I put code for lein repl to run as it's booting up?

22:23 in a dependency?

22:24 justin_smith: godd2: clojure will load user.clj

22:24 src/user.clj for example

22:24 more detail here http://dev.solita.fi/2014/03/18/pimp-my-repl.html

22:25 godd2: yay!

22:25 minaminamina: Hey there! I was trying to write a cljs library that I could deploy to clojars, and require in another project. The library is written, it's simple, and it works, but when I try to require it somewhere else, the only visible namespace is my-namespace.core

22:25 Would anyone mind looking at the project.clj file to see what I'm doing wrong?

22:25 smnirven_: link plz

22:26 minaminamina: https://github.com/minasmart/squelch/blob/master/project.clj

22:27 including it in the dependencies section of another project doesn't produce errors, but trying to require anything other than squelch.core makes it complain: WARNING: No such namespace: squelch.audio-context at line 1...

22:27 justin_smith: minaminamina: you have - in your file names

22:28 smnirven_: yep thats it

22:28 justin_smith: clojure cannot find files named that way

22:28 smnirven_: underscores to the rescue

22:28 minaminamina: OK, I was wondering about that. Should they be underscored?

22:28 justin_smith: rename audio-context.clj to audio_context.clj

22:28 minaminamina: Then should namespaces be named with hyphens or underscores?

22:28 justin_smith: yeah, the namespace can keep the same name, just rename all the files

22:28 smnirven_: filenames should be underscored, but the namespace names can still be hypens

22:28 justin_smith: so ns is audio-context, file is audio_context

22:29 minaminamina: For namespace naming, what is more typical? Hyphen or underscore?

22:29 justin_smith: minaminamina: there is a nice tool called eastwood (a lein plugin) that detects these kinds of issues

22:29 hyphen is preferred for namespaces

22:29 but it has to be underscore in the file

22:29 minaminamina: OK, cool! And thanks Justin! I'll check out that plugin!

22:29 Thanks alot!

22:30 justin_smith: np

22:49 grandy: i'm new to clojure and a bit confused about how to use sessions in compojure, anyone know of a public repo that does this?

22:50 godd2: how do you get the keys from a transient hashmap?

22:50 ,(keys (transient {:a 1 :b 7}))

22:50 clojurebot: #<IllegalArgumentException java.lang.IllegalArgumentException: Don't know how to create ISeq from: clojure.lang.PersistentArrayMap$TransientArrayMap>

22:52 justin_smith: grandy: https://www.refheap.com/92948 you can use this definition as a middleware foar a cookie session

22:53 grandy: justin_smith: thanks!

22:53 justin_smith: that uses ring.middlware.session/wrap-session

22:53 there are other options for in-memory rather than server sessions

22:53 grandy: justin_smith: dumb question but how do I set the session to {:hello "world"}

22:53 justin_smith: of course you probably want to fix the key, cookie-name, max-age

22:54 verma: how do I run the jar chestnut gives me? just doing a java -jar app.jar doesn;t seem to work,

22:54 justin_smith: grandy: in your handler create a response map, with {:body "text of page" :status 200 :session {:hello "world}}

22:54 verma: it just drops me into a clojure repl

22:54 grandy: justin -- I tried that but then I removed it and refreshed the page and it was gone from the session data,

22:55 justin_smith: verma: you can specify a class / method to run, if you have a -main defined and aot compile that namespace

22:56 grandy: with the middleware set up properly, you should see the same data come in under :request

22:56 grandy: hmm

22:56 justin_smith: grandy: you need to watch out for accidentally attaching a null :session in between of course

22:56 verma: justin_smith, :uberjar profile says :aot :all, so I guess it'd be aot compiled, I am also not sure what the command line would look like

22:57 justin_smith: verma: if your main ns is set up properly (such that lein run works) the compiled jar will work too

22:57 grandy: justin_smith: this is my handler, do you see anything obviously wrong with it? quite possible there is something very dumb going on: https://gist.github.com/mmmurf/0cfe722ad60c47c34b1f

22:57 verma: justin_smith, oh let me try lein run

22:57 justin_smith: you aren't returning the right thing

22:58 grandy: you are passing the session as the response map

22:58 you want to pass the session INSIDE the response map

22:58 verma: justin_smith, does the class with -main needs to have :gen-class, I was just wondering since chestnut didn't do that

22:58 grandy: justin_smith: hmm I think I have to review the signatures that are going on there... I'll try w/ a simple text response

22:58 justin_smith: grandy {:body [:body ...] :session (assoc (:session params) :count 1)}

22:59 grandy: you need to put what you were previously returning into the :body key

22:59 right now, [:body ...] inside common is doing nothing, it's just a data literal that is not used or returned by the function

22:59 grandy: justin_smith: ahh so {:body is not a hiccup function it's a map for ring?

23:00 amalloy: grandy: yes

23:00 justin_smith: grandy: yes, ring accepts multiple return values

23:00 amalloy: justin_smith: how do you mean?

23:00 justin_smith: if you specify a string, that becomes the page body, if you return a map, the :body key is used for that

23:00 amalloy: just that it is polymorphic on what you return to it

23:00 grandy: justin_smith: ahh ok, so does this mean that in my compojure code all handlers that update hte session need to return a map?

23:01 justin_smith: right

23:01 amalloy: I should have said "accepts multiple return types"

23:01 grandy: justin_smith: ahh ok i see, now it is starting to make sense

23:02 justin_smith: grandy: and I was wrong above, you want {:body (common [:body ...]) :session ...} in the response map

23:02 or bind the rendered result of common in a let, of course

23:02 grandy: justin_smith: ok cool I think I've done that...

23:03 justin_smith: https://gist.github.com/anonymous/586bf33aea6347999969

23:03 justin_smith: verma: you can specify an arg that says run clojure.core and then another arg that tells clojure.core to run a specific function in a specific ns - one moment, I need to find it

23:04 grandy: yeah, that looks about right

23:04 verma: justin_smith, nice! I actually tried to run lein run and it had problems, so I fixed those and running a lein uberjar right now

23:04 51seconds to compile clojurescript :(

23:05 grandy: justin_smith: oddly it's not persisting

23:06 justin_smith: grandy: so :count 1 is not coming in on the next load?

23:06 grandy: justin_smith: correct, not if I comment out line 8 above

23:07 justin_smith: grandy: and you have the ring-session middleware in place?

23:07 grandy: justin_smith: in other words, the line that prints the session (line 5 above) prints {}

23:07 justin_smith: [ring.middleware.session :refer :all]

23:07 justin_smith: that requires the session, are you putting it in your middleware?

23:07 grandy: https://www.irccloud.com/pastebin/INl3FSu0

23:08 I think so, see the paste

23:08 justin_smith: OK, you might want add some arguments to wrap-session

23:08 also check in your browser if the cookie is being created

23:08 grandy: justin_smith: ahh good idea

23:09 justin_smith: maybe create an unencrypted cookie while debugging

23:09 verma: java -cp foo.jar clojure.main -m foo

23:09 where foo/-main is the main function

23:10 verma: you may not need that, but the advantage there is you don't need any aot for that to work

23:10 clojure finds and loads your code

23:11 zerkms: guys, could you please give me some hints about how idiomatically implement a file reader that would read all the lines that are added in runtime (which is more or less obvious) with ability to gracefully stop it

23:14 justin_smith: zerkms: basic idea is to create a file reader using clojure.java.io (io/reader (io/file "name")) and then you have a few options, probably easiest is to put it in a future, (def reader-thread (future (while (not (.isInterrupted (Thread/currentThread))) (.readLine reader))))

23:14 then you can call (future-cancel reader-thread) if you want it to stop

23:14 and probably you want to do something with the return value of .readLine of course :)

23:15 zerkms: I've head similar thoughts

23:15 but

23:15 .readLine is blocking

23:15 justin_smith: yeah, put it in a future

23:15 zerkms: what? (.readlLine reader)?

23:15 justin_smith: zerkms: the whole loop, like I did above

23:15 grandy: justin_smith: hmm do you see anything wrong w/ this?

23:15 https://www.irccloud.com/pastebin/rqHj35ln

23:16 justin_smith: or, use polling and non-blocking read

23:16 polling is guaranteed more complex though, of course

23:17 grandy: that isn't a valid key I don't think - the number of X in my example was exactly the number of characters that need to be in the key

23:17 zerkms: I see, so in your solution you don't immediately terminate .readLine() but just don't care if it's still there in memory awaiting for next line

23:17 grandy: justin_smith: ahh ok

23:18 justin_smith: zerkms: well, it checks if the thread is interrupted (future-cancel will do the thread-interruption for you)

23:18 zerkms: justin_smith: for the check to occurr a next line should arrive

23:19 justin_smith: right, polling is more complicated, but also possible

23:19 zerkms: ok

23:19 justin_smith: zerkms: like adding an if based on whether data is available, and a sleep if it isn't

23:19 then you are guaranteed to check the condition more often

23:20 zerkms: I'm not caviling (not sure if it's a correct word here, cannot find better in my dictionary) - just pretty newbie with clojure so want to make sure I'm not missing something basic

23:20 verma: justin_smith, nice! that seems to work great! thanks for your help

23:20 (inc justin_smith)

23:20 lazybot: ⇒ 120

23:20 justin_smith: zerkms: and you just need to look out for the pathological condition where there is data, but it freezes in the middle of giving you a line

23:20 verma: which one, the fixing lein run, or specifying the main class?

23:21 zerkms: honestly I tried implementing polling then realized the code looks like java

23:21 justin_smith: heh

23:21 there isn't much purely functional about a polling loop

23:22 zerkms: tried to reimplement simplified http://commons.apache.org/proper/commons-io/apidocs/src-html/org/apache/commons/io/input/Tailer.html which is I find nice implementation for this task (in java though)

23:22 verma: justin_smith, oh actually chestnut comes with a Procfile which had the exact same command :P

23:22 justin_smith: zerkms: there is java.nio.* too, I don't have a whole lot of experience with it though

23:23 verma: haha, nice

23:23 verma: so I could have just said rtfpf

23:23 verma: justin_smith, totally :P

23:24 zerkms: " java.nio.* too" --- yep, I deliberately want to do that as much manually as possible, as a person who only read A LOT and watched A LOT of different things about clojure but have written < 100 lines in total in clojure

23:24 justin_smith: grandy: small thing about your last paste, the comment about (:session session) isn't quite accurate, for what it's worth - you probably meant (:session params), but that's just a nitpick

23:25 zerkms: interop isn't super hard, and this is the sort of thing clojure just doesn't have a simple clojure-wrapped solution for

23:25 sorry

23:25 grandy: justin_smith: please do nitpick, this is my first clojure project so I need to be informed of any/all stupidity :)

23:25 zerkms: (inc justin_smith)

23:25 lazybot: ⇒ 121

23:25 grandy: justin_smith: ok so now it works nearly as expected, with the following three handlers:

23:26 zerkms: would it ban me if I inc myself? :-D

23:26 grandy: https://www.irccloud.com/pastebin/X5Wu3LCN

23:26 justin_smith: it'll just be sassy about it

23:26 grandy: justin_smith: those map to /session /session1 and /session2

23:26 justin_smith: grandy: cool

23:27 grandy: what's handy for this kind of thing is update-in / assoc-in

23:27 grandy: justin_smith: hmm how woudl I modify those?

23:27 justin_smith: ,(update-in {:session {:count 0}} [:session :count] inc)

23:27 clojurebot: {:session {:count 1}}

23:27 justin_smith: ,(update-in {:session {:count 0}} [:session :count-2] (fnil inc 0))

23:27 clojurebot: {:session {:count-2 1, :count 0}}

23:28 justin_smith: grandy: update-in is pretty much perfectly designed for this kind of case (I intentionally burried :session deeper than needed to show how it digs in)

23:29 &*clojure-version*

23:29 lazybot: ⇒ {:major 1, :minor 4, :incremental 0, :qualifier nil}

23:30 verma: TIL fnil

23:30 justin_smith: fnil is my friend

23:30 (inc fnil)

23:30 lazybot: ⇒ 3

23:31 grandy: justin_smith: thanks!

23:31 justin_smith: grandy: np, glad you figured it out

23:36 zerkms: justin_smith: cannot get it working :-( (while ...) blocks while not finished which is never

23:37 justin_smith: zerkms: did you put it in a future?

23:37 zerkms: yep, and whern I'm dereferencing it - it blocks

23:37 since `while` works forever

23:37 justin_smith: yeah, deref is not what you want

23:38 unless you want it to be done, and get the return value

23:38 futures run whether you deref them or not

23:38 zerkms: yep, but how to get the value from it then

23:38 a global atom would be ugly

23:38 justin_smith: zerkms: you could send the values to an agent or queue

23:39 or act on the data within the loop itself

23:39 zerkms: or that... doesn't look idiomatic hmm

23:39 I thought it will be trivial to implement an infinite list

23:39 s/list/sequence/

23:39 Raynes: Well that's not great.

23:41 justin_smith: zerkms: hmm (defn f [handle] (when more-data (cons (read-available handle) (lazy-seq (f handle)))))

23:41 that's kind of like line-seq

23:41 maybe that's all you need? but line-seq will block too won't it?

23:41 zerkms: handle is the last resort for me, but yes

23:53 grandy: justin_smith: oddly it appears that it's not using the cookie params I am setting, it is also not using the name, therefore I think it is ignoring the configuration info for cookie sessions -- thoughts?

23:53 https://www.irccloud.com/pastebin/thNcygv4

23:56 justin_smith: that looks right

Logging service provided by n01se.net