#clojure log - Jan 15 2015

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

0:22 zanes: I wish core.async/merge could take a transducer. 😕

0:26 koreth_: I’m torn between following you down that path and just using Boot.

0:34 clojurenub: hi! does someone know how I should combine all lists under a certain length? For example, going from [(1 2 3) {4 5) {6 7 8) {9} {10} {11}] [(1 2 3) (4 5 6 7 8) (9 10 11)] if min list size was 3,

0:36 amalloy: clojurenub: you seem to have some sort of weird {}/() disorder. what are the inputs and outputs you are looking for?

0:37 clojurenub: amalloy: oh yeah i mixed those up typing up the example. the inputs were all just supposed to be lists

0:37 so (4 5) (6 7 8) (9) (10) (11)

0:38 instead of the stuff with curly braces

0:38 id also need to quote them if was actually using lists over vectors

0:39 mercwithamouth: k

0:39 clojurebot: No entiendo

1:54 fUD: Hello

1:54 Is there a good clojure docker for a starter?

1:57 fairuz: fUD: You just need java and lein normally

1:57 maybe mvn too

1:57 koreth_: zanes: How does Boot address those needs? I have looked at its home page but haven't tried it out yet.

1:58 fUD: fairuz: ok, maybe I'll just try that on my mac

2:00 fairuz: fUD: plus, lein is just a bash script :)

2:05 fUD: :)

2:06 zanes: koreth_: It just feels cleaner. http://adzerk.com/blog/2014/11/clojurescript-builds-rebooted/

2:06 The paragraph beginning with "http://adzerk.com/blog/2014/11/clojurescript-builds-rebooted/“.

2:06 Whoops.

2:06 Beginning with, "The current state of the art in this area is things like chestnut…"

2:08 koreth_: Thanks. Getting late here but I will take a look at it tomorrow. From a quick glance it looks like it could be more straightforward than what I'm doing now.

2:08 zanes: koreth_: I’d love to hear about your experiences if you do give it a try!

2:32 koreth_: zanes: So much for going to bed on time. Just played with it really briefly. I like that it moves a bunch of dev environment setup out of the actual code. But its CLJS REPL setup is, at least in the demos, the same as the normal one: connect to Clojure REPL, start CLJS REPL, reload page in browser, start evaluating expressions. My setup gets rid of the need for the "reload page in browser" step, so you can treat it more like connecting via nREP

2:32 L to a live server.

2:32 But it's likely the same trick I used (sending the REPL URL to the browser via server push) will work in the Boot environment too. THAT, I will play with tomorrow. Thanks again for the pointer.

3:36 Empperi: hi, any ideas how to implement following logic:

3:36 let's say I have a vector of data, eg. [3 5 7 1]

3:36 and I have another vector of data [7 6 5 4 3 2 1]

3:36 Glenjamin: justin_smith: came back to look this morning, ended up with this to list current threads and what they're doing:

3:36 (pprint (mapv (fn [[^Thread t s]] [(.getName t) (first s)]) (Thread/getAllStackTraces)))

3:37 Empperi: I want to sort the first vector in such a way that it's elements are sorted according to the second vector ordering

3:37 eg to [7 5 3 1]

3:37 mikker: How do I convert string to an input-stream?

3:37 Empperi: ,(clojure.java.io/as-stream "foo")

3:37 clojurebot: #<CompilerException java.lang.RuntimeException: No such var: clojure.java.io/as-stream, compiling:(NO_SOURCE_PATH:0:0)>

3:37 opqdonut: Empperi: use sort-by

3:37 mikker: Empperi: I'll try!

3:38 opqdonut: Empperi: and have the key function look up the index of the value in the order vector

3:38 Empperi: mikker: nah, not like that

3:38 but there is a function for that

3:38 opqdonut: Empperi: for added performance, invert the order vector into a map

3:38 Empperi: not that exact name though I think

3:38 opqdonut: yeah, was thinking something like that

3:38 was just wondering if there was something "out-of-the-box" for this job :)

3:39 opqdonut: can't think of anything

3:39 Empperi: neither can I

3:39 guess it's sort-by then

3:41 hyPiRion: Empperi: Are there any duplicates in the longer vector?

3:42 if not then

3:42 ,(sort-by (into {} (map-indexed vector [7 6 5 4 3 2 1])) [3 5 7 1])

3:42 clojurebot: (7 5 3 1)

3:43 Empperi: hyPiRion: no duplicates in either one

3:43 that looks nice

3:43 of course my example was a simplified one but that might actually work

3:45 opqdonut: hyPiRion: I think your map is the wrong way around

3:45 hyPiRion: yeah, it's opqdonut's solution in Clojure code

3:45 opqdonut: ,(into {} (map-indexed vector [7 6 5 4 3 2 1]))

3:45 clojurebot: {0 7, 1 6, 2 5, 3 4, 4 3, ...}

3:45 Empperi: in truth I don't have just vectors and neither single dimensional vectors but I think I might get that solution to work anyway

3:46 thanks guys

3:46 hyPiRion: opqdonut: Oh dang, yeah.

3:46 Funny how the example still worked =/

3:46 opqdonut: yeah :)

3:46 ,(sort-by (into {} (map-indexed vector [:a :b :c])) [:c :a :b]) -- here you can see it not working

3:46 clojurebot: (:c :a :b)

3:48 opqdonut: ,(sort-by (zipmap [:a :b :c :d] (range)) [:d :a :b]) -- correct

3:48 clojurebot: (:a :b :d)

3:48 hyPiRion: (inc opqdonut)

3:48 lazybot: ⇒ 2

3:51 Empperi: got it working thanks to you guys (thumbsup)

3:51 in my more complex scenario that is

3:56 hyPiRion: nice

5:34 nicferrier: I am trying to use httpkit with-channel for async stuff... it doesn't seem to work. the docs say "The with-channel API is not compatible with the RC releases. The new one is better and much easier to understand and use." - I am using 2.1.6 - is this an rc release??

5:34 lazybot: nicferrier: What are you, crazy? Of course not!

5:35 nicferrier: I am confused.

5:37 hyPiRion: RC releases are usually postfixed with -RC

5:37 or something like that

5:37 TEttinger: nicferrier: lazybot responds to any message ending in ?? or ???

5:37 lazybot: TEttinger: Yes, 100% for sure.

5:39 nicferrier: huh. well it doesnt seem to work.

5:44 mpenet: nicferrier: you could give https://github.com/mpenet/jet a try, it's a bit different (core.async based api), but I am not sure what you're looking for exactly

5:45 nicferrier: I just need an http/websockets async lib

5:45 mpenet: it has both, clients as well

5:49 nicferrier: hmmm

5:49 sveri: nicferrier: I used sente successfully with http-kit

5:50 sente supports websockets and long-polling as well

5:50 nicferrier: what's sente?

5:50 SagiCZ1: hi.. when i am using some simple callback mechanism in java, am i somehow creating new threads or using more threads from fixed threadpools? i am having hard time understanding how it works.. i always thought it could be done in one thread

5:51 sveri: nicferrier: https://github.com/ptaoussanis/sente

5:52 nicferrier: why do I need that? I should be able to use httpkit? no?

5:53 sveri: yea, you can stay with http-kit

5:53 I just like abstractions in form of libraries

5:58 nicferrier: and http-kit doesn't work :-)

6:07 clgv: SagiCZ1: Swing callbacks will only use the on UI thread for example

6:08 SagiCZ1: for anything else it depends how the caller calls your callbacks (in his own thread, in another thread or as a submission to a thread pool)

6:19 SagiCZ1: clgv: so swing callbacks which i am pretty familiar with use only one thread right? when i click on the button, the event is generated in the ui thread and action listener's method is executed on the same thread, correct?

6:21 kaiyin: Is anonymous function inducive to better performance?

6:22 clgv: SagiCZ1: exactly. that is why some applications freeze after clicks. they don't move the expensive work to other threads.

6:23 mpenet: kaiyin: not really

6:23 CookedGryphon: Hey all, is there a way to omit the tools.analyzer etc dependencies from AOT'd code? Or does macroexpansion with core async have to happen at run time?

6:24 it's doing a load of reflection etc and killing my startup time

6:24 mpenet: kaiyin: I guess #(..) doens't have to deal with arg destructuring, but it's taken care of by hotspot in most cases

6:25 SagiCZ1: cglv: i see.. so what core.async does in go blocks works similary? also only on one thread?

6:25 clgv: kaiyin: no, it is just syntactic sugar

6:26 kaiyin: good to know, because I hate it in most cases. Just makes things unnecessarily difficult to read.

6:27 justin_smith: wait, is this a question about #() or about named vs. anonymous functions?

6:27 clgv: SagiCZ1: you gotta ask someone with core.async experience ;)

6:27 kaiyin: yeah, you can just use (fn [...] ...) then

6:28 justin_smith: SagiCZ1: core.async uses a thread pool, and a given go block csn switch threads after parking

6:28 clgv: kaiyin: named arguments are usually much better documentation of what you are doing.

6:28 kaiyin: yeah.

6:29 mpenet: SagiCZ1: go blocks run on 42 * proc/2 (or something) threads.

6:29 SagiCZ1: justin_smith: i dont understand this.. what is thread parking?

6:29 justin_smith: SagiCZ1: the threads don't park, the go blocks do

6:30 when waiting on a channel

6:30 mpenet: SagiCZ1: but in a "smart" way, when ops on channels are "blocking" (<! >! etc), it parks the whole thing and releases the thread in use, until the expression triggers a state change. So it's fairly efficient

6:31 justin_smith: parking says "I don't need sny thread until I get a message on this channel"

6:31 SagiCZ1: justin_smith: and they use state machine to remember where they parked?

6:32 justin_smith: it's a state machine, yeah

6:32 mpenet: That said being able to specify an executor for a given go block would be nice, but apparently it's not a priority for c/core

6:32 SagiCZ1: i am not sure i understand how is thread block with >!! different then

6:32 mpenet: >!! blocks the current thread

6:32 SagiCZ1: >! does not?

6:33 mpenet: yes it doesn't

6:33 SagiCZ1: ok

6:33 mpenet: go block gets rewrited as a state machine

6:33 justin_smith: blockinh and parking are different

6:33 SagiCZ1: justin_smith: i understand they are different but until now i understood "parking" only in the context of parking my car

6:34 justin_smith: parking is effevtively registering a callback for when a channel op completes

6:35 SagiCZ1: okay

6:35 doritostains: lein repl isn't printing out the port. how do I figure out the port it's connecting to?

6:35 justin_smith: but syntax wise it doesn't look like a callback

6:35 mpenet: fyi, if you have interest in what I was mentioning, vote here http://dev.clojure.org/jira/browse/ASYNC-94

6:36 SagiCZ1: justin_smith: thank you.. and do you think that core async chan can substitute java's BlockingQueue for any purposes?

6:37 clgv: doritostains: it usually does

6:37 justin_smith: NlockingQueue ltd you fo things that chan does not

6:37 clgv: doritostains: it is also creating a temporary file for that

6:37 doritostains: clgv: yeah but it isn't for what ever reason :(

6:37 _1_traga: klk

6:37 clgv: doritostains: .nrepl-port

6:37 doritostains: does it fail to start?

6:38 justin_smith: argh... Blockingqueue lets you do etc. chan is intentionally more limited

6:38 SagiCZ1: justin_smith: let's me do what?

6:38 doritostains: clgv: no .nrepl-port but it starts up just fine

6:38 SagiCZ1: more things?

6:39 mpenet: SagiCZ1: https://github.com/ztellman/manifold wants to bridge the gap between all these abstraction it seems

6:40 justin_smith: SagiCZ1: yeah, chan is more restrictef

6:40 SagiCZ1: justin_smith: thank you

6:43 justin_smith: for example BlockingQueue has contains and remainingCapacity

6:43 SagiCZ1: justin_smith: yeah i think all i really need chans can do

6:45 justin_smith: SagiCZ1: core.async implements CSP (concurrent sequential processes) which is a well designed formal model for concurrency semantics

6:45 SagiCZ1: justin_smith: i guess i should read about CSP in general

6:49 justin_smith: it ism't neccesary, buy it all makes more sense if you understand that model imho

6:53 jonasen: What is your preferred way to :refer in ns forms? I do (:require [foo.bar :refer (a b c)]) but the clojure style guide at https://github.com/bbatsov/clojure-style-guide#prefer-require-over-use uses square brackets instead: (:require [foo.bar :refer [a b c]])

6:55 SagiCZ1: jonasen: i use the square brackets as in your second example

6:58 jonasen: According to http://clojure.github.io/clojure/clojure.core-api.html#clojure.core/ns ":refer takes a list of symbols ..."

6:58 sveri: nicferrier: it works for me ;-)

6:58 jonasen: sorry the link should be http://clojure.github.io/clojure/clojure.core-api.html#clojure.core/require

6:58 nicferrier: sveri: yeah, I've got it worked now.

6:58 sveri: thanks!

6:58 spradnyesh: anyone using cider? i'm facing the same issue as the last comment in http://stackoverflow.com/a/25401281/4329629 w/ cider-nrepl 0.9.0-SNAPSHOT and cider 20150114.512 (works flawlessly when put inside project.clj, but not when inside ~/.lein/profiles.clj)

7:42 CookedGryphon: is there a way to make AOT compilation bake in macro expansions?

7:46 clgv: jonasen: some one on here had a good rule of thumb "use a vector if all elements are treated equally. use a list if the first element is different from the others."

7:46 jonasen: that would warrant the use of (:require ...) instead of [:require ..] as well ;)

7:52 sveri: nicferrier: nice to hear that

7:54 katratxo: clgv: that's a good rule to remember

7:54 hellofunk: what is a good lein template that has clj and cljs all setup, with cljs compile output going into the appropriate directory for the clj handlers to load it? *excluding* chestnut

8:05 sveri: hellofunk: boot?

8:05 justin_smith: CookedGryphon: wait, do you mean the unexpanded form? Because of course macros are expanded before compilation.

8:05 sveri: sry, its not a lein template

8:06 daniel`: hellofunk: why exclude chestnut

8:13 hellofunk: daniel` chestunut has a few bugs that i don't like

8:15 daniel`: who likes bugs

8:15 wasnt aware of any

8:17 the-kenny: Is there a specific reason clojure-mode 4.x lost its special-casing for indenting (assoc obj \n :foo 42) (\n = newline)?

8:18 it used to indent the kv-pairs on new lines with 2 spaces instead of aligning it with the first arg

8:19 hellofunk: daniel`: a lot of chestnut users have this problem with the latest cider: https://github.com/clojure-emacs/cider/issues/853

8:19 daniel` but i have other issues also

8:19 CookedGryphon: justin_smith: perhaps I'm misinterpreting what's going on in my profiling... But starting up my program using core async is spending an inordinate amount of time pulling in the namespaces and making calls which do reflection in tools.analyzer, and I was under the impression that tools analyzer was only used in the macroexpansion phase

8:19 so why do I still need that dependency at runtime when I have AOT'd

8:24 the-kenny: Ok nevermind, the new indentation is expected.

8:28 CookedGryphon: also, is there any reason clojurescript's (:require-macros ...) form isn't supported in clojure?

8:28 surely it would be trivial to add, and mean that you could write one version for both

8:44 krat0sprakhar: hi all, how can i add a clojurescript repl

8:44 on a website

8:44 any ideas?

8:54 Kneiva: krat0sprakhar: http://himera.herokuapp.com/index.html

8:54 krat0sprakhar: Kneiva: What about http://clojurescript.net?

8:55 i've tried adding it in my application but it seems to be not working

8:55 Kneiva: seems pretty similar =)

8:55 daniel`: i see hellofunk, i dont use cider thats probably why

8:56 nicferrier: when I'm using async io, for example in an http-kit handler, I don't seem to be able to print to the console. do libs routinely disassociate themselves from System.out?

8:56 daniel`: normally i tweak things how i like anyway, the lein template is just a start surely

8:57 im not starting 50 new projects exactly the same every day

8:57 that need to work perfectly from get go

8:57 hellofunk: daniel`: i get you. what editor do you use?

8:57 daniel`: vim/fireplace

8:58 i dont take advantage of the interactive workflows as often as i perhaps should

8:59 hellofunk: i'm trying to find a good tutorial on how to write my own lein template

8:59 daniel`: i usually isolate the part im interested in to play with, rather than develop a whole project in that manner

9:02 hellofunk: is creating a lein template really as simple as doing lein create-template existing-project-skeleton ?!

9:03 oh i guess that's just one way

9:03 nicferrier: I looked at it. it looks easy,

9:06 daniel`: wouldnt imagine it to be much harder

9:06 but never done it

9:25 hellofunk: why does the lein new app name project output have (:gen-class) in the ns form, somethign i've never seen in any other lein template?

9:25 it is usually implicit, hence why it is ommitted nearly all the time?

9:27 kaiyin: What is wrong with this: (take 4 (take 3 (repeat (repeat 5)))) ?

9:28 I intend to take a 4x3 array out of an infinite 2D array.

9:30 hellofunk: ,(take 4 (take 3 (repeat (repeat 5))))

9:30 clojurebot: ((5 5 5 5 5 ...) (5 5 5 5 5 ...) (5 5 5 5 5 ...))

9:30 krat0sprakhar: hellofunk: doesn't work for me in the REPL

9:30 O.o

9:31 how is the bot compiling it?

9:31 hellofunk: what happens in your repl?

9:31 hyPiRion: krat0sprakhar: it works, but those 5-lists are infinite

9:31 your repl tries to print them all out

9:31 hellofunk: hyPiRion: even with take it tries to print them?

9:31 krat0sprakhar: so one more (map take n) is required?

9:31 hellofunk: oh i see, nevermind

9:32 hyPiRion: krat0sprakhar: You need to reorder the takes

9:33 krat0sprakhar: ,(map #(take 4 %) (take 3 (repeat (repeat 5))))

9:33 clojurebot: ((5 5 5 5) (5 5 5 5) (5 5 5 5))

9:33 hyPiRion: ,(take 3 (repeat (take 4 (repeat 5)))

9:33 clojurebot: #<RuntimeException java.lang.RuntimeException: EOF while reading>

9:33 hyPiRion: ,(take 3 (repeat (take 4 (repeat 5))))

9:33 clojurebot: ((5 5 5 5) (5 5 5 5) (5 5 5 5))

9:33 hyPiRion: or equivalently

9:34 ,(repeat 3 (repeat 4 5))

9:34 clojurebot: ((5 5 5 5) (5 5 5 5) (5 5 5 5))

9:34 krat0sprakhar: naice!

9:35 kaiyin: very cool.

9:35 krat0sprakhar: hyPiRion: how is the clojurebot so fast/

9:35 ?

9:36 puredanger: it's on speed

9:36 daniel`: presumably it does an implicit take on lazy seqs

9:36 krat0sprakhar: whereas, http://himera.herokuapp.com/index.html is quite slow

9:38 kaiyin: How do you use multiprocessing for reading a file and parsing? For example, (parse (slurp filename)) , I would like the slurp part take one process, and the parse part take another, so that the reading and the parsing can go on in parallel (I mean using two CPU cores).

9:39 hellofunk: kaiyin: you must have one heck of a large file to slurp to require that!

9:39 krat0sprakhar: haha.. was thinking the same..

9:39 kaiyin: hellofunk, yes I do, I some times have files larger than 50GB.

9:39 hyPiRion: krat0sprakhar: Himera is CLJS, whereas the bots here are CLJ ones. I'm not sure that's the reason, but it may be a reason

9:39 hellofunk: wow, a single text file that big?

9:39 hyPiRion: may affect performance* I meant

9:40 kaiyin: hellofunk, yes, a single file that big, but not necessary text.

9:40 necessarily.

9:40 hellofunk: hyPiRion: if that's the case then the cljs himera should be really fast, cuz it's all running locally and browsers today are quite speedy with that stuff

9:40 zilti: kaiyin: Then I definitely wouldn't use slurp, but the cloure.java.io namespace.

9:40 krat0sprakhar: hellofunk: it fires off text to a compiler running on the serve

9:41 returns js

9:41 which is then read and shown in the console

9:41 hyPiRion: kaiyin: I tend to use buffered readers and wrap them in iterator-seqs

9:41 krat0sprakhar: hellofunk: try out clojurescript.net

9:41 that is diff

9:42 hellofunk: krat0sprakhar: that site seems pretty fast to me

9:42 krat0sprakhar: that = ?

9:42 kaiyin: zilti, hyPiRion, could you give a little more detail? I just started learning clojure a few days ago, so I don't have much experience.

9:42 krat0sprakhar: hellofunk: you mean clojurescript.net?

9:42 hellofunk: yeah

9:42 krat0sprakhar: thats because it is doing all compilation IN the browser

9:42 unlike chimera

9:42 *HIMERA

9:42 hellofunk: i thought it was just stated that himera was cljs

9:43 krat0sprakhar: clojurescript.net is not himera

9:43 hellofunk: are you saying himera is doing cljs on the server?!

9:43 krat0sprakhar: nope

9:43 :D

9:43 clojurescript.net is doing cljs on the browser

9:43 hellofunk: i know they are two different sites, by it was said earlier that himera is cljs, thus it is also on the browser

9:43 krat0sprakhar: its class on cljs

9:43 ah ok.. my bad

9:44 clojurescript.net is CLJS on CLJS

9:45 hellofunk: though i'm curious how it can eval cljs since i thought it requires compilation to js first, and there is no eval in cljs

9:45 zilti: kaiyin: Well, first I'd use an input-stream to read http://clojuredocs.org/clojure.java.io/input-stream and for this particular case I guess I'd work with core.async for parallelism, maybe combine it with other techniques as described on http://clojure.org/concurrent_programming, but that's probably not necessary

9:50 puredanger: kaiyin: don't use slurp for anything performance sensitive, instead stream the data as hyPiRion suggests. if you want to use multiple cpus, have one thread reading chunks and pushing tasks out for execution (several ways to do this - Java executors, future, pmap, etc with various tradeoffs). Or getting extra fancy, memory-map the file and have multiple threads via Java NIO and operate on it with multiple threads (general

9:50 requires being able to tell record boundaries in your file, etc)

10:00 hyPiRion: kaiyin: https://www.refheap.com/96142 is a small example on how I'd build a parser in Clojure. It sort-of depends on how your parser works, of course, but if you're able to work with lazy-seqs, you don't have to read in the whole file at once etc

10:08 kaiyin: hyPiRion, cool. What do you mean "laziness is not passed around"?

10:14 hyPiRion: kaiyin: If you do something like (with-open [rdr (io/reader "/etc/passwd")] (line-seq rdr)) you will get an "IOException: Stream closed" error. That's because the with-open macro is converted to something like (let [rdr (io/reader "/etc/passwd") value ...] (close rdr) value) – except that it will handle errors as well

10:16 If the file isn't completely read before the reader is closed, you'll try reading from a closed stream. (Because laziness only read values from the stream when they are "needed")

10:18 And since many of the functions working over lazy-seqs (map, filter, remove, ...) also return lazy seqs, it's a common problem people new to Clojure tend to fall into

10:19 Not sure if I explained that very well.

10:19 Has anyone written a blogpost about this? I'd be surprised if noone haven't, because it seems to be a common issue.

10:26 myguidingstar: hi all, does ring-anti-forgery help with RESTful apis?

10:52 kaiyin: how does recur solve the lack of support for tail call optimization?

10:53 Tritlo: kaiyin: recur allows for self-recursive functions

10:53 kaiyin: and basically turns them into a loop

10:53 kaiyin: but it isn't proper tail recursion

10:53 kaiyin: and doesn't support mutually recursive functions

10:54 kaiyin: so it is a partial solution

10:54 hellofunk: architecturally, however, there is really no difference as a developer in using recur vs. true TCO, the effect is the same for your process

10:54 Tritlo: hellofunk: what about mutually recursive functions?

10:55 hellofunk: you mean non-stack-consuming functions that call each other?

10:55 Tritlo: no, stack consuming

10:55 hellofunk: but TCO and recur are about non-stack-consuming

10:55 Tritlo: isn't that the point with TCO? To turn stack consuming functions into non stack consuming?

10:56 hellofunk: Tritlo: more or less, yes

10:57 Tritlo: and recur doesn't solve that for mutually recursive functions

10:57 hellofunk: i was not aware that mutual recursion in scheme, for example, was optimized, is it?

10:57 if you are calling another function, that is not recursion is it?

10:57 andyf: hellofunk: The scheme spec requires implementations to optimize all tail calls

10:57 Tritlo: scheme allows for mutual recursion

10:58 andyf: Whether there is recursion involved or not

10:58 hellofunk: andyf: tail calls to *any* function, including another function that is mutually recursive?

10:58 Tritlo: classic example being

10:58 https://www.irccloud.com/pastebin/2ocmIKN1

10:58 andyf: You can have tail calls with no recursion, too

10:59 hellofunk: andyf: ah, i thought TCO was mainly about recursion, i.e. calling the same function from within itself. didn't realize it referred to calling any function whatsoever

10:59 Tritlo: Without TCO, this is sure to cause stack overflow for large numbers

11:00 TimMc: Also we live in a finite universe, so there;s that.

11:00 andyf: I believe main motivation is for deeply recursive functions, but scheme spec requires tco whether there is recursion or not

11:01 hellofunk: andyf: fascinating. didn't know that. i always thought the TCO vs recur debate didn't make much sense, since recursion was handled equally well in either scenario.

11:01 Tritlo: hellofunk: well, there you have it

11:01 hellofunk: you can kind of get around it with trampoline though

11:02 hellofunk: but it gets messy

11:02 hellofunk: Tritlo: i can't say it seems like a major obstsacle in algorithm desing, to be honest. i would think there are elegant alternatives to most mutually recursive fn combos

11:02 *design

11:03 hyPiRion: Tritlo: it's not that bad. Just prepend all tail calls with # and call trampoline on the result of a call.

11:03 hellofunk: let me think about your even/odd example

11:03 Tritlo: hellofunk: well, you can say that about most anything :P

11:03 hyPiRion: Tritlo: it's somewhat annoying though, I agree

11:04 andyf: www.r6rs.org/final/html/r6rs/r6rs-Z-H-8.html#node_sec_5.11

11:04 hellofunk: hyPiRion: or Tritlo could you provide an example of what you mean with # and trampoline?

11:04 now you guys got me curious

11:05 Tritlo: This seems to be a good writeup

11:05 http://jakemccrary.com/blog/2010/12/06/trampolining-through-mutual-recursion/

11:06 hellofunk: Tritlo: exactly what i was looking for

11:06 hyPiRion: yeah, that's a good link. The Art of Clojure also discusses it somewhat

11:08 hellofunk: hyPiRion: what is ARt of Clojure?

11:08 you mean Joy of Clojure?

11:08 hyPiRion: hellofunk: ...yes

11:09 clojurebot: art |is| joy

11:09 clojurebot: In Ordnung

11:11 hellofunk: reading that article makes me think trampoline was implemented specificly to address TCO.

11:12 hyPiRion: (doc trampoline) =)

11:12 clojurebot: "([f] [f & args]); trampoline can be used to convert algorithms requiring mutual recursion without stack consumption. Calls f with supplied args, if any. If f returns a fn, calls that fn with no arguments, and continues to repeat, until the return value is not a fn, then returns that non-fn value. Note that if you want to return a fn as a final value, you must wrap it in some data structure and unpack it after trampoline returns."

11:13 andyf: I believe the trampoline technique has been well known for decades, and yes, not much reason other than tail call optimization (or lack of it) to use tranpoline

11:13 hellofunk: ah, joy

11:14 wonder why this can't just be implemented on the JVM level, seems straightforward enough. or for that matter, seems like a clojure compiler could automatically trampoline to provide this benefit and TCO transparency

11:15 Tritlo: well, it makes debugging a lot harder,

11:15 CookedGryphon: If do-reflect is being called in my profiling.... does that mean undesirable reflection is happening in my code, or is that unavoidable and probably not a problem?

11:15 Tritlo: finding out from where the bug originates etc

11:15 a lot more to keep track of

11:16 andyf: It has been discussed in Clojure Google group years back, I think. I recall that keeping Clojure's efficient java interop technique and having tco everywhere would require JVM changes

11:17 zerokarmaleft: hellofunk: it's well documented, guy steele was an important advocate while he was working on fortress

11:17 nilern: there was a JVM security mechanism that relied on counting stack frames

11:18 hellofunk: interesting stuff for sure

11:18 seeing where the lines are drawing between language design and platform design

11:18 nilern: but that mechanism was recently removed so TCO might be coming

11:18 zerokarmaleft: yea, and hopefully lambdas push that need to closer to the forefront

11:19 java 8 lambdas, that is

11:19 Tritlo: not even python has TCO :/

11:19 Guido is explicitly against it

11:19 though you can shoehorn it in with decorators and exceptions

11:19 nilern: btw JVM Schemes have TCO, but that requires a different calliing convention from Java

11:20 I recall Rich didn't do that for Clojure because it would complicate interop

11:22 csd_: Can anyone recommend a good tutorial for core.async?

11:23 zerokarmaleft: csd_: there's a walkthrough example in the core.async repo that teaches you the basic primitives

11:25 daniel`: csd_: there was recently a chapter of clojure for the brave and true covering core.async

11:25 havent read it yet, so can't recommend it

11:25 hellofunk: csd_: the braveclojure.com site just added a new chapter on core.async. the rest of the site is decent and useful for beginners so the async stuff probably will be too

11:25 kaiyin: How do you get [1 2 3 4 5] out of [1 2 3 4 5 6]? Like init in haskell.

11:25 zerokarmaleft: kaiyin: butlast

11:25 kaiyin: cool

11:26 CookedGryphon: Does anyone know if require is multithread safe in clojure?

11:26 can I run multiple requires in parallel? Or is there a risk of doing the same work twice

11:27 andyf: kaiyin: Pop is more efficient way to do that, only for vectors

11:27 clgv: CookedGryphon: if you are talking about dynamic parallel require at runtime, it is not!

11:27 CookedGryphon: My intuition was that it wasn't, but I couldn't remember why I thought that

11:28 kaiyin: andyf, why is it more efficient?

11:28 clgv: CookedGryphon: there are multiple error scenarios: namespaces loaded twice, namespace loading failed because a definition in a dependency namespace was not loaded yet ...

11:28 Glenjamin: (doc butlast)

11:28 clojurebot: "([coll]); Return a seq of all but the last item in coll, in linear time"

11:28 CookedGryphon: clgv: back to plan F then...

11:28 clgv: CookedGryphon: do you definitely need that? then I might have a small tool for you

11:29 csd_: zerokarmaleft: I'm writing a Zulip bot for fun, and the API uses core.async. One of the API calls returns a channel after registering an event with Zulip. But when I try to use (<!! ch), the code hangs

11:29 andyf: kaiyin: Butlast takes linear time, pop can be done in log n time due to way vectors are implemented

11:29 CookedGryphon: I'm just doing what I can to get startup time under a second in my android app

11:29 clgv: CookedGryphon: since I ran into it myself and there was no alternative

11:29 CookedGryphon: I have written and using that library in the problematic scenario https://github.com/guv/txload

11:29 +am

11:29 zerokarmaleft: andyf: nice

11:30 CookedGryphon: and all the loading is happening in one big block, thought I could pull it in. Current strategy is using lazy var loading and separating my code into "runlevels" which are careful what they require and make sure all the essentials are loaded first

11:31 zerokarmaleft: csd_: <!! is a blocking take

11:31 CookedGryphon: clgv: multithreaded requires seems to me like a feature core might be interested in... if it can be done cleanly

11:32 andyf: kaiyin: Pop will only be faster if you already have a vector. I wouldn't recommend making a vector from a sequence just to get fast pop, unless you plan on doing many pops after creating the vector

11:32 clgv: CookedGryphon: if you limit the scope to requiring namespaces dynamically at runtime that's totally doable. the lib is a proof of concept ;)

11:32 kaiyin: andyf, cool, thanks.

11:33 clgv: CookedGryphon: loading arbitrary files is problematic

11:33 CookedGryphon: clgv: as opposed to? This is all supposed to be aot compiled already, it still needs to load namespaces

11:34 zilti: CookedGryphon: AOT'ing your whole app didn't help either?

11:34 clgv: CookedGryphon: being able to load arbitrary files in clojure was the frequent argument against transactional loading of namespaces when I brought up the topic here ;)

11:34 csd_: zerokarmaleft: (<!! (go (<! chan))) seems to be have similarily

11:34 clgv: CookedGryphon: you can just check the test cases of the lib

11:35 gfredericks: yesterday I saw an example of a macro accidentally working that I had never seen before

11:36 clgv: gfredericks: gist :)

11:36 CookedGryphon: zilti: nope

11:36 clgv: okay, I might give this a go

11:37 zilti: csd_: Yes, because then <!! blocks until the go-block has finished, which takes until the chan returns.

11:37 kaiyin: What is wrong with this implementation of comp? https://gist.github.com/kindlychung/e4b5e4fb226449bad83c

11:38 csd_: zilti: ok-- why then does the walkthrough.clj wrap the go block in <!!?

11:38 gfredericks: clgv: https://www.refheap.com/96148

11:38 SagiCZ1: kaiyin: i dont think that destructuring is correct

11:38 Bronsa: kaiyin: recur is a special form not a function, you can't apply it

11:38 zilti: csd_: I assume it is to have a simple way to show the result in the walkthrough. You can't "println" out of a go-block since it's in another thread

11:38 clgv: gfredericks: uh. shouldnt that resolve to foo.string/join ?

11:39 gfredericks: clgv: nope

11:39 ,`string/join

11:39 clojurebot: string/join

11:39 csd_: zilti: i just want to see what the first value in the channel is. how do i do that?

11:39 hellofunk: kaiyin: this looks like a 4clojure problem. i think i solved it by reducing over the fns

11:39 clgv: ah right, because there is a namespace already

11:40 gfredericks: it would resolve correctly if you had that alis defined in `foo` right?

11:40 gfredericks: clgv: yep

11:41 zilti: csd_: Well, technically using <!. You can also use (take! port fn1) which takes a callback fn. But usually you want to avoid callbacks by using core.async, not create them

11:41 clgv: gfredericks: humm, isn't that a feature that should be added?

11:41 csd_: zilti: but <! just returns another channel

11:41 gfredericks: clgv: I'm not sure what you're referring to

11:41 andyf: clgv: What should be added?

11:42 SagiCZ1: ,(let [[& f g] [:a :b :c]] [f g])

11:42 clojurebot: #<CompilerException java.lang.Exception: Unsupported binding form, only :as can follow & parameter, compiling:(NO_SOURCE_FILE:0:0)>

11:42 zilti: csd_: No, <! returns the first value of a channel as soon as it's available.

11:42 SagiCZ1: kaiyin: see you cant destructure like this

11:42 andyf: I think gfredericks is saying his example works, but expected it not to work ?

11:43 csd_: i dont know, maybe its the API i'm using, but i'm definitely getting a channel back

11:43 gfredericks: the code is definitely bad

11:43 and should be fixed

11:43 since it only works by accident

11:43 clgv: gfredericks: I mean it does try to resolve "string/join" if "string" and fully qualify it if "string" is an alias. and we generally want to avoid that kind of name captureing

11:43 csd_: => #<ManyToManyChannel clojure.core.async.impl.channels.ManyToManyChannel@308e19b>

11:43 clgv: gfredericks: so we could have a warning or an error there

11:43 zerokarmaleft: csd_: sorry, got called away...the API call sends a channel over a channel?

11:43 zilti: csd_: So (type (<! channel)) gives you the ManyToManyChannel? Did you put a channel onto the channel?

11:43 zerokarmaleft: csd_: a gist or something might help us out here

11:44 gfredericks: clgv: the question is if the backtick part of the reader has any business checking if certain namespaces and vars exist, because otherwise it can't distinguish 'string/join from a fully qualified symbol

11:44 csd_: one sec

11:44 gfredericks: there might really be a namespace called string somewhere

11:44 clgv: gfredericks: but it can distinguish aliases?

11:45 ,(require '[clojure.string :as str])

11:45 clojurebot: nil

11:45 clgv: ,`(str/join ~'a)

11:45 clojurebot: (clojure.string/join a)

11:45 gfredericks: clgv: yeah, that's local to the current namespace

11:45 andyf: gfredericks: Yeah, what you said :) syntax quote messes with my head

11:45 gfredericks: everything backtick does is just based on the current namespace

11:45 and just the namespace config, not any vars in it

11:45 clgv: yeah and that would be fine to detect this error

11:46 gfredericks: how?

11:46 clojurebot: with style and grace

11:46 clgv: gfredericks: if "str" does not resolve to any alias or namespace

11:46 gfredericks: "resolving to a namespace" is a global concern

11:46 clgv: gfredericks: ah ok. so that is not checked

11:47 gfredericks: I believe not

11:47 and it'd be tricky if you wanted to -- users might expect their macros to compile without all the other namespaces being loaded yet

11:47 csd_: zerokarmaleft zilti: not much code to show you though https://www.refheap.com/96149

11:48 andyf: You can use a symbol like foo/bar whenever in Clojure, even if there is no namespace or alias foo

11:48 zilti: csd_: Yes, that's correct that way - (go ...) returns a channel

11:48 csd_: but how do I get the first value from the channel?

11:49 zilti: csd_: And that cannel will have one entry with the return value of the go block as soon as the go block finished

11:50 clgv: andyf: but it needs to be quoted if contained as a literal ;)

11:50 zilti: csd_: You normally just use the return values in go blocks or functions called by the go blocks since you normally don't want to block your main thread. What I normally do to get the values on the REPL is that I use Timbre to log the result of (<! chan) so I can see it. Or put it into an atom.

11:50 andyf: Sure and symbols are quoted when used in syntax quote

11:51 clgv: right

11:51 csd_: zilti: how would i use an atom to get it?

11:52 clgv: andyf: what do you think about transactional namespace loading? I have a test case demonstrating the problem over here: https://github.com/guv/txload

11:53 zilti: csd_: e.g. (go (reset! some-atom (<! chan))) and then you can always @some-atom to see the current value, or attach a watcher to the atom, but I find it handier to use a logger. But I never so far faced the problem that I needed the value on the main thread other than for debugging purposes.

11:53 andyf: I can see why some would want to improve performance of code loading by parallelizing it. Not clear to me whether there might be other gotchas besides require/use

11:53 clgv: andyf: but I am not sure if there was any desire to patch the clojure runtime such that dynamic parallel requires work.

11:55 andyf: no, I came from another scenario, where arbitrary actions need to be executed in parallel. an action is described by a symbol and parameters that are passed to the function the symbol refers to

11:55 zilti: csd_: Really what a go-block does is to deconstruct the code inside so you avoid all the callbacks. You can essentially use (<! chan) everywhere inside a go-block where you'd use a symbol (be it as a function or as an argument to a function or as a value inside a map, and so on).

11:56 csd_: zilti: im guessing the atom method is working as i set it to nil and when i check its value afterward it is {}... so i guess there's more than im not understanding, either with core.async or the api i'm using

11:56 zilti: is it not possible to println inside a go-block?

11:56 hiredman: I played with parallel code loading on our larger code base at work, a few years ago, it broke things a lot

11:56 SagiCZ1: csd_: it is

11:57 zilti: csd_: Last time I tried it failed, but it can be unpredictable I guess. core.async uses a thread pool in the background

11:58 csd_: zilti: looking at the docs here, it says "Register a queue to listen for certain event types. Returns a channel with :queue_id, :max_message_id, and :last_event_id keys."

11:58 How do I get those keys?

11:58 andyf: clgv: It might all be thread-safe already, but I would want to scrutinize defrecord, deftype, gen-class, defprotocol implementations before feeling safe about it

11:59 zilti: csd_: Which docs are you looking at?

11:59 csd_: zilti: 3rd party api docs: https://github.com/thieman/clojure-zulip/blob/master/src/clojure_zulip/core.clj

12:00 clgv: andyf: you mean the current require/use implementation? I doubt that

12:00 andyf: except there are changes in 1.7

12:01 andyf: just remove (tx/enable) from the test implementation and run the test

12:02 andyf: clgv: Not sure if we are talking about same thing here. I mean that making require/use transactional might not be enough to enable correct parallel code loading. If other clojure things like defprotocol are not thread safe, then transactional require/ use do not solve the whole problem

12:03 zilti: csd_: Hmm no idea. It's a somewhat weird docstring. I'd guess it is a channel that returns maps with those keys each?

12:03 clgv: andyf: ah ok. I am not sure that I understand where defprotocol might fail if the namespaces are loaded transactionally

12:04 CookedGryphon: Does anyone have any hints/ideas why loading ioc-macros namespace is taking 18seconds in my android app

12:04 the startup time isn't actually too bad for the rest of it

12:04 csd_: zilti: yeah idk

12:04 clgv: andyf: the hack I made assures that every namespace is loaded exactly once which holds for all transitive dependency namespaces as well

12:05 CookedGryphon: but core.async_init is taking 19 seconds, and 18 of those are spent loading ioc_macros

12:05 csd_: i guess i'll just read that chapter from Brand and True and hopefully that will give me some crucial incite

12:05 zilti: csd_: I'd really recommend playing around with core.async a bit before using a library that uses core.async

12:05 clgv: andyf: if two threads end up requiring the same namespace transitively, one is doing the work, while the other waits until its done

12:05 csd_: zilti: whys that?

12:05 andyf: Sure, but what if defprotocol is not thread safe, and two defprotocols execute simultaneously in 2 namespaces loaded in parallel?

12:06 zilti: csd_: Because as you've said you don't fully understand it yet, if I've understood you correctly

12:06 clgv: andyf: ah, you mean the java implementation backing up defprotocol, ok.

12:06 andyf: clgv: Java or Clojure part, either or both

12:07 csd_: zilti: fair enough

12:07 yes my understanding is a little above zero

12:07 clgv: andyf: the number of use cases that need this is definitely pretty limited, anyway

12:07 andyf: Clojure isn't exactly thread-safe magic pixie dust, even if lots of it is :)

12:08 zilti: csd_: You'll save a lot of time that way. Here are core.async's API docs by the way: http://clojure.github.io/core.async and I've heard good things about http://www.braveclojure.com/core-async/. And of course just ask in here in case you run into problems!

12:09 clgv: andyf: yeah, a little disappointment accompagnied that discovery ;)

12:10 brainproxy: concurrency is hard, reactive programming is hard

12:11 zilti: More different than hard, I'd say.

12:11 brainproxy: i'm going to say hard period, though like anything else, the more time you spend with it the more you're able to narrow down the areas where you run into trouble

12:11 csd_: zilti: thanks

12:12 zilti: csd_: You're welcome :)

12:22 mmg: hi, I have java class Foo with method .bar, I want to use proxy to add .baz as well. I tried (proxy [Foo] [] (bar [] …) (baz [] …)) the compiler seems ok with this but at runtime I get exception “No matching field found: baz”

12:22 can I do this with proxy or by any other means in clojure/

12:25 llasram: mmg: you can do it with gen-class or you can define an interface w/ the method you want and implement that interface in proxy etc, but

12:25 zilti: mmg: You have to define a protocol first, then use that one using extend, extend-type or extend-protocol. Or proxy.

12:25 llasram: mmg: in my experience these approaches are rarely necessary -- why do you need this extra method on the class?

12:26 mmg: I need to track the state of a stream in progress, I’m trying to expose a new method to InputFilterStream that will expose certain metrics of the underlying stream state

12:27 so I think it is needed, I can return a proxy of the InputFilterStream and also another fn to do this, but I was just trying to use proxy for all of it

12:28 I’ll try gen-class, thanks

12:28 llasram: Errrg

12:28 No no

12:28 Anything is better than gen-class :-)

12:28 zilti: mmg: This should work: https://www.refheap.com/96154 Avoid gen-class

12:28 And proxy is kinda ugly as well in my opinion

12:28 mmg: thanks zilti

12:29 yeah I mean I don’t love java interop but unfortunately there’s a whole empire built on java streams that I have to interop with :/

12:29 so it goes

12:29 zilti: mmg: yw. It should work that way, though I didn't test that code. But I'm working with extend-protocol right now anyway

12:30 mmg: I'm writing a JavaFX wrapper and extend-* seem to be awesome

12:33 clgv: a clojure.java.jdbc query with COUNT(*) leads to a keyword :count(*) - what is the idiomatic query to avoid that?

12:40 guess renamig via "AS" is the key :)

12:40 Beamed: zilti: speaking of javaFX wrappers, how -is- working with javaFX in Clojure right now? I heard someone mention they thought it was great off-hand but I don't know the details

12:42 zilti: Beamed: Well, I wouldn't call it great, but it's quite good. Having some way to "generate" Java-Lambdas from Clojure functions would make it easier to work with the API directly.

12:45 clgv: zilti: java lambdas do not implement Runnable or Callable?

12:47 zilti: clgv: Hm, I don't think so. But anyway, java lambdas are... weird.

12:47 timvisher: you can create sub-cursors in om by using keyword accessors, right?

12:47 i'm trying to debug why my app is re-rendering everything every time, although it's ostensibly only changing 2 nodes.

12:48 staging.nhss.twonegatives.com if you're interested in looking at it

12:48 i'm suspicous that it has something to do with not properly initializing the component cursor

12:48 many of them are pointed at strings, which the docs say is a no no

12:49 current branch: https://github.com/timvisher/nhss-cljs/tree/performance-optimization

12:50 interestingly, i implemented IShouldUpdate on one of my components, and it doesn't appear to ever get called?

12:50 clgv: zilti: do they share a common interface?

12:50 zilti: clgv: Java's lambas basically depend on specially marked functional interfaces, so a method that accepts a lambda also always accepts an anonymous class implementing the specific functional interface

12:51 clgv: zilti: ok

12:51 timvisher: if IRender/State is called, the DOM is updated with that component, right? or is IRender called and then the diff happens?

12:51 zilti: clgv: This for example, when a method wants something of the type of this interface, it's possible to handle a lambda: http://download.java.net/jdk8/jfxdocs/javafx/event/EventHandler.html

12:52 kaiyin: why is it not ok to use recur here?

12:52 https://gist.github.com/kindlychung/1b10842c22236427ac9c

12:53 zilti: kaiyin: recur always has to be the last statement in a block to get executed. In your case, the return type of the recur is still needed inside the recur-calling block.

12:53 kaiyin: ok

12:54 zilti: kaiyin: I rarely use lazy-seq but I'm pretty sure you don't need recur or other tail-call-optimization inside a lazy-seq.

12:54 timvisher: the app is spending ~40% of its time in React `batchedUpdate`

12:54 kaiyin: zilti, good to know.

12:59 timvisher: if a parent component is dirty, are all children forced to updated no matter what?

12:59 that wouldn't seem to make any sense

12:59 Glenjamin: timvisher: by default, yes

13:00 but they can optimise this by implementing shouldComponentUpdate

13:00 timvisher: Glenjamin: i thought that was the whole point of using sub-compenents and reference equality?

13:00 Glenjamin: there's a React.Perf thing which can tell you which components are wasting time recalculating updates to apply no changes

13:01 timvisher: React can't do that out of the box, because JS is full of mutability - most cljs wrappers enable this though

13:01 timvisher: that you can dirty a parent component without actually forcing all sub-components to re-render, because their sub-cursor hasn't changed

13:01 Glenjamin: oh, i see - you're in Om

13:01 timvisher: aye :)

13:01 Glenjamin: ah, this is a quirk to do with cursors, which i think reference cursors are better at

13:02 iirc

13:02 timvisher: Glenjamin: unable to parse :)

13:02 reference cursors?

13:02 Glenjamin: yeah, look up "reference cursors" in the Om docs

13:02 they're fairly new

13:06 clgv: zilti: if you'd use a wrapper approach as in seesaw you could wraper clojure functions into the appropriate functional interfaces

13:06 wrap*

13:07 zilti: clgv: I have to take a closer look at seesaw. What I'm doing now is essentially a lot of extend-interface. Which works like a charm.

13:11 timvisher: does implementing IShouldUpdate in om not work as advertised? are local implementations ignore in some way?

13:15 or is it that i'm responsible for only calling transact! on the cursor that has actually been updated? again, i thought that one of the big deals of React/Om was that i could freely update the state and it would use the persistent data structures to decide what actually needed to be affected

13:33 kaiyin: what's wrong with this: (fn [& xs x] x)

13:33 ,(fn [& xs x] x)

13:33 clojurebot: #<CompilerException java.lang.RuntimeException: Unexpected parameter, compiling:(NO_SOURCE_PATH:0:0)>

13:33 puredanger: any of the Venanti / Standard Treasury team on here?

13:36 fairuz: kaiyin: shouldn't & xs be the last argument?

13:37 justin_smith: kaiyin: & can only be followed by one argument

13:37 kaiyin: ok

13:37 fairuz: ,(fn [x & xs] x)

13:37 clojurebot: #<sandbox$eval49$fn__50 sandbox$eval49$fn__50@4f6047f9>

13:37 kaiyin: but I am trying to implement last

13:38 justin_smith: kaiyin: that can't be done witj destructuring

13:45 ntietz: hey, all. could anyone give me a recommendation for a good Clojure overview or book? a lot of them are geared at introducing people to FP and all that -- my background is strong in both C++ and Scala, with a smattering of Haskell

13:46 AimHere: Joy of Clojure tends to be considered the more 'advanced' clojure book

13:46 ntietz: okay, I'll take a look at that, thanks

13:54 krat0sprakhar: how can I add the Access-Control-Allow-Origin: * to a ring app

13:54 ?

13:54 scottj: ntietz: clojurebook.com seems like it would be a good fit for covering the language and ecosystem

13:55 fairuz: krat0sprakhar: You can add a middleware that modifies the header

13:55 Frozenlock: krat0sprakhar: depending on your setup, this could be sufficient https://www.refheap.com/96164

13:57 ntietz: scottj: thanks! I'll take a look at that, too

13:57 krat0sprakhar: thanks a lot Frozenlock

13:58 one quick question, how do I call the handler through this function?

13:58 ggherdov: Hi. I want to use the first element of a vector as a key to access a value in a map. Trying this:

13:58 (get {:a 1 :b 2 :c 3} (first ["a" "b" "c"]))

13:58 but the REPL says "nil". I expected "1". What's my mistake?

13:59 zilti: (doc get)

13:59 clojurebot: "([map key] [map key not-found]); Returns the value mapped to key, not-found or nil if key not present."

13:59 zilti: ,(get {:a 1 :b 2 :c 3} (first [:a :b :c]))

13:59 clojurebot: 1

13:59 krat0sprakhar: zilti: you need to convert the string to symbol

14:00 zilti: ggherdov: A String isn't a keyword

14:00 ggherdov: uh. Thanks zilti. Checking my book again then. krat0sprakhar ok

14:00 Frozenlock: but a string can be a key ;-)

14:00 krat0sprakhar: zilti: right, i was assuming his vector has string only

14:00 *strings

14:00 ggherdov: I see.

14:00 Frozenlock: krat0sprakhar: http://clojure-doc.org/articles/cookbooks/middleware.html

14:01 krat0sprakhar: thanks Frozenlock

14:02 zilti: Are defmethods having an effect across all namespaces?

14:11 foofoobar: What is the go-to framework for doing web development with clojure? compojure?

14:14 fairuz: foofoobar: usually a stack of these libs

14:14 compojure + liberator + component

14:14 and some others

14:15 chouser: zilti: a defmulti is defined in a particular namespace. Each defmethod applies to a particular namespaces defmulti, but has a global effect for that defmulti.

14:15 ordnungswidrig: I recently advocate bidi instead of compojure as it has reverse routing aka url generation

14:15 zilti: chouser: Ok! Thanks!

14:15 chouser: zilti: np

14:15 zilti: ordnungswidrig: I started using it as well. It's especially nice that I can also do client-side routing with it

14:16 ordnungswidrig: that's also a plus, yes.

14:19 foofoobar: fairuz: thanks

14:20 Gazaf: link to bidi please? can't seem to find it

14:20 zilti: Gazaf: https://github.com/juxt/bidi

14:21 Gazaf: thank you

14:22 fairuz: I personally use compojure api

14:22 a swaggered version of compojure

14:23 foofoobar: fairuz: do you have a good starting guide for me? I did a lot of web dev with rails, node.js, go. I’m total new to clojure and would love to see some good introduction.

14:24 For learning-by-doing I’m trying to build a simple web app (user auth, user dashboard (maybe with react.js), some static pages)

14:25 fairuz: I think it's good enough

14:25 You add more and more libraries as you progress

14:25 foofoobar: fairuz: So where to start? With compojure?

14:26 The first thing I was missing in an introduction I found was a good templating thing. There was hiccup, but I’m used to external template files which are loaded and processed.

14:27 wkf: foofoobar: have you tried enlive

14:27 ?

14:28 zilti: foofoobar: There's also Selmer

14:29 fairuz: foofoobar: As you can see here, everyone has its own preference :)

14:29 http://www.clojure-toolbox.com/

14:29 krat0sprakhar: one question - i'm trying to add CORS to this server

14:29 https://github.com/fogus/himera/blob/master/src/clj/himera/server/service.clj#L17-L21

14:29 fairuz: this can help you cherry-picking some libraries

14:29 krat0sprakhar: any idea whats wrong?

14:29 wkf: all useful, for different situations/preferences

14:29 krat0sprakhar: i just added "Allow-Access-Control-Origin" "*"

14:29 on line 20

14:29 Gazaf: foofoobar: Luminus for a more structured approach http://www.luminusweb.net

14:30 krat0sprakhar: my requests are still failing from cross origin

14:30 fairuz: krat0sprakhar: What is the error on client side?

14:30 Does your server handle the preflight request?

14:30 aka the OPTION request

14:30 krat0sprakhar: the usual No 'Access-Control-Allow-Origin' header is present on the requested resource.

14:31 although when i try, doing the same from the same origin

14:31 the header is coming correctly

14:31 oh so i need to specify that route separately?

14:31 fairuz: You need to response to the OPTIONS request separately yes

14:31 krat0sprakhar: oh

14:31 fairuz: simplest is just to say all is ok

14:32 krat0sprakhar: oh just 200 then?

14:32 foofoobar: Thanks, I’m checking the links you send me

14:32 fairuz: in cors, the browser will actually send 2 requests

14:32 krat0sprakhar: right..

14:32 fairuz: one OPTIONS (preflight) then the actual request

14:32 the latter will only be sent if the former returns ok

14:33 krat0sprakhar: i've never actually done that in Flask (python) hence didn't that one needs to define /options as well

14:33 probably the framework was doing that for me and i didn't notice :D

14:33 fairuz: probably :)

14:33 krat0sprakhar: ok, so i'll add the route and see

14:34 fairuz: and most probably you will need more headers

14:34 that's why I asked what was the error in the browser

14:38 krat0sprakhar: fairuz: weird, i'm getting an exception: OPTIONS is not defined

14:39 although compojure documentation does define it

14:41 fairuz: check your imports

15:02 kaiyin: how do you get rid of the outer parenthesis/brackets/braces of the current expression?

15:02 for example trun [2 3] into 2 3

15:04 xonev: kaiyin: what for? to pass as arguments to a function? to print?

15:04 justin_smith: kaiyin: there is no such thing, but there is still a way to do what you are actually trying to do

15:05 ,(apply + 1 2 3 [4 5])

15:05 for example

15:05 clojurebot: 15

15:05 xonev: yeah, it sounds like you're wanting to use apply…

15:07 kaiyin: xonev, justin_smith I am looking for a keyboard shortcut to edit my code, :-D

15:08 justin_smith: kaiyin: ahh, that will depend on your editor, of course

15:08 but paredit has "barf" for that

15:08 kaiyin: yeah, I am using intellij with cursive.

15:08 ok, that's barf.

15:08 I see.

15:08 justin_smith: unappealing name, I know

15:09 kaiyin: justin_smith, barf seems to just move things out the brackets?

15:10 In cursive, it turns [2 3] into [2] 3, and if you barf again, it becomes [] 2 3

15:11 xonev: kaiyin: yes, that's what it does in paredit, as well, i believe.

15:11 It doesn't completely remove the brackets

15:11 zilti: kaiyin: What you're looking for is paredit's splice

15:11 scottj: kaiyin: paredit-splice-sexp

15:12 kaiyin: ok, i see.

15:12 thanks

15:12 justin_smith: I would usually just barf out all the contents then remove the empty braces, but splice is more direct I guess, yeah

15:12 zilti: There are really weird things in paredit ^^ And paxedit goes even further

15:13 kaiyin: those names are really weird. :-)

15:13 zilti: Yeah, plus the names

15:32 kaiyin: What is wrong with this? https://gist.github.com/kindlychung/0749c3380eff319ed4d4

15:33 AimHere: Try :else

15:33 gfredericks: kaiyin: clojure functions are not infix

15:33 AimHere: Also what he said

15:33 gfredericks: ,(3 > 10)

15:33 imanc: can any explain how the anon functions get %1 and %2 params passed to them in this code fragment: http://pastie.org/9834054

15:33 clojurebot: #<ClassCastException java.lang.ClassCastException: java.lang.Long cannot be cast to clojure.lang.IFn>

15:33 gfredericks: ,(< 3 10)

15:33 clojurebot: true

15:33 gfredericks: ,(> 3 10) ; I guess is the equivalent one

15:33 clojurebot: false

15:34 gfredericks: imanc: nothing is calling those functions so I'm not sure what you're asking

15:34 imanc: gfredericks: so they're not being called at that stage? I'm just trying to understand what the code is doing.

15:35 grr

15:35 gfredericks: imanc: the code creates a local called `cmd` that is a function

15:35 ,(let [cmd #(+ %1 %1 %2)] (cmd 3 4))

15:35 clojurebot: 10

15:35 mavbozo: ,(#(= %1 %2) 'a 'b)

15:35 clojurebot: false

15:35 gfredericks: ^ you can call such a thing like so

15:35 imanc: damn, that's so obvious now

15:36 so it's binding one of those functions to the cmd based on whether coll is a map

15:36 gfredericks: yep

15:37 kaiyin: Oh my. Old habits die hard...

15:37 gfredericks: else: => :else is also important

15:38 :else is just a generic keyword in this usage, you could change it to :or-whatever and it would work the same way

15:38 :else is used idiomatically for readability

15:38 kaiyin: ok.

15:38 else: is from python, :P

15:38 * justin_smith advocates replacing usage of :else with :YOLO

15:39 imanc: ha ha

15:39 gfredericks: I wish cond took a default expr like case does

15:39 just for consistency

15:39 less explaining to do, not much lost

15:40 justin_smith: gfredericks: yeah, and fully unambiguous based on arg count, bad impl choice imho

15:40 imanc: I thought cond did support a default expression ..

15:40 justin_smith: one of the few bad choices in clj

15:40 gfredericks: justin_smith: wait can't we change it backwards compatibly?

15:40 ,(cond 1 2 3 4)

15:40 clojurebot: 2

15:40 gfredericks: erm

15:40 ,(cond 1 2 3 4 5)

15:41 clojurebot: #<CompilerException java.lang.IllegalArgumentException: cond requires an even number of forms, compiling:(NO_SOURCE_FILE:0:0)>

15:41 gfredericks: yeah

15:41 could totally just add that

15:41 justin_smith: gfredericks: the other version wouldn't compile, so there would be no compatibility issue unless someone's code relied on some cond form failing to compile which would be fucked up...

15:41 gfredericks: justin_smith: in that sense every change is breaking though

15:41 justin_smith: indeed

15:41 yeah, I would call it effectively non-breaking :)

15:42 gfredericks: just the compulsion to look for the weird edge case, ya know

15:43 gfredericks: I don't see a ticket for this

15:44 I'll just make one what could it hurt

15:44 wait

15:44 ,(case 3 4 5)

15:44 clojurebot: #<IllegalArgumentException java.lang.IllegalArgumentException: No matching clause: 3>

15:44 gfredericks: ,(cond false 3)

15:44 clojurebot: nil

15:45 gfredericks: is that difference potentially an issue at all, or is it totally orthogonal?

15:45 justin_smith: ,(case 3 3 true false)

15:45 clojurebot: true

15:45 TimMc: gfredericks: http://xkcd.com/1172/

15:45 ("Workflow")

15:46 justin_smith: ,(case case case case)

15:46 clojurebot: #<CompilerException java.lang.RuntimeException: Can't take value of a macro: #'clojure.core/case, compiling:(NO_SOURCE_PATH:0:0)>

15:46 justin_smith: haha

15:46 TimMc: ,(cond)

15:46 clojurebot: nil

15:46 gfredericks: ,(cond cond cond cond cond)

15:46 clojurebot: #<CompilerException java.lang.RuntimeException: Can't take value of a macro: #'clojure.core/cond, compiling:(NO_SOURCE_PATH:0:0)>

15:46 TimMc: \o/

15:46 justin_smith: ,(case #'case #'case #'case)

15:46 clojurebot: #<IllegalArgumentException java.lang.IllegalArgumentException: No matching clause: #'clojure.core/case>

15:46 gfredericks: anyhow does this still sound worth proposing?

15:48 justin_smith: gfredericks: I think so, yes

15:48 amalloy: i don't see any advantage to supporting a default case for cond. it makes the API less regular

15:48 "args should be a sequence of test/expr pairs" is much nicer than "args should be a sequence of test/expr pairs, plus if you feel like it a default case at the end"

15:49 and uses of it won't read well: (cond a b c d e f g h i), even with newlines in it, might make you wonder what that i is doing there: paired with h, or a default?

15:50 TimMc: amalloy: Is this something you dislike about case as well?

15:50 amalloy: TimMc: no, case has no choice

15:50 mavbozo: ,(doc cond)

15:50 clojurebot: "([& clauses]); Takes a set of test/expr pairs. It evaluates each test one at a time. If a test returns logical true, cond evaluates and returns the value of the corresponding expr and doesn't evaluate any of the other tests or exprs. (cond) returns nil."

15:51 amalloy: similarly condp has no choice

15:51 TimMc: Hah, it actually documents the nullary case.

15:51 mavbozo: why there's no mention of :else ?

15:51 justin_smith: mavbozo: because :else is just a convention

15:51 ,(cond 1 nil true :yolo :else)

15:51 clojurebot: #<CompilerException java.lang.IllegalArgumentException: cond requires an even number of forms, compiling:(NO_SOURCE_FILE:0:0)>

15:51 justin_smith: blerg

15:51 TimMc: You could instead use :suddenly or any other truthy value.

15:52 amalloy: TimMc: because case and condp aren't testing the truthiness of the test exprs themselves, there's no value you *could* use as a conventional default like :else

15:52 it's all relative to whatever expression you're comparing to

15:52 justin_smith: ,(cond nil true false :whatever :yolo :else)

15:52 clojurebot: :else

15:52 TimMc: ,(cond (= 2 :cats) :wow, :nil :oh-i-see)

15:52 clojurebot: :oh-i-see

15:52 TimMc: amalloy: Fair point. :-)

15:53 gfredericks: amalloy: I think it will read as well as any other implicit-pairs syntax

15:53 in particular as well as case does

15:53 mavbozo: ,(cond (= 2 :cats) :wow, :yolo :oh-i-see)

15:53 clojurebot: :oh-i-see

15:54 mavbozo: is there any conditional expression that throws exception if no test match?

15:54 ,(doc condp)

15:55 clojurebot: "([pred expr & clauses]); Takes a binary predicate, an expression, and a set of clauses. Each clause can take the form of either: test-expr result-expr test-expr :>> result-fn Note :>> is an ordinary keyword. For each clause, (pred test-expr expr) is evaluated. If it returns logical true, the clause is a match. If a binary clause matches, the result-expr is returned, if a ternary clause matches, i...

15:55 amalloy: case

15:55 mavbozo: ,(doc case)

15:55 clojurebot: "([e & clauses]); Takes an expression, and a set of clauses. Each clause can take the form of either: test-constant result-expr (test-constant1 ... test-constantN) result-expr The test-constants are not evaluated. They must be compile-time literals, and need not be quoted. If the expression is equal to a test-constant, the corresponding result-expr is returned. A single default expression can foll...

15:55 amalloy: &(case 1)

15:55 lazybot: java.lang.IllegalArgumentException: No matching clause: 1

16:00 TimMc: sadness

16:00 {blake}: So...I've got an app that works fine locally but then gives me a "Rounding necessary" error in deployment. (Same code, same data.)

16:01 TimMc: What's up?

16:02 TimMc: {blake}: amalloy's (case 1) demo

16:03 gfredericks: TimMc: you want a compile error?

16:03 {blake}: amalloy: Was ist?

16:04 TimMc: gfredericks: It should yield 1.

16:04 amalloy: TimMc: what???? no it shouldn't

16:04 TimMc: Four question marks, I must be super wrong.

16:04 amalloy: you could argue that (case 1 1) should, but certainly not (case 1)

16:05 TimMc: Oh! Whoops.

16:05 Forgot the input. :-P

16:06 Yes, compile error would be nice there.

16:07 amalloy: TimMc: for (case 1)? i suppose so

16:09 TimMc: For my next trick, I'll argue that (case 2) should *also* yield 1.

16:11 amalloy: nono, 1 is truthy. you mean 0

16:12 TimMc: Nonsense, for any compile error it should count the arguments.

16:12 You're thinking of (case).

16:13 amalloy: hah, i love it. (defn foo (+ 1 2 3)) ;; succeeds, yields 2

16:17 TimMc: Reminds me of that compiler that will agressively remove chunks of your code until compilation succeeds. Was it for JS?

16:21 amalloy: TimMc: fuckitjs

16:23 TimMc: yeah!

16:24 I knew there was profanity in the naem but couldn't come up with the right combination.

16:25 amalloy: i have this vague notion that there's a ruby port, but i can't find it

16:25 oh, https://github.com/programble/fuckit.rb

16:26 hlship: Anyone familiar with Leiningen deployments handy? I'm having trouble deploying to a Nexus repository.

16:26 amalloy: interestingly doesn't show up at all under a google search for "fuckitrb"

16:27 ~anyone

16:27 clojurebot: Just a heads up, you're more likely to get some help if you ask the question you really want the answer to, instead of "does anyone ..."

16:27 amalloy: hiredman: speaking of ~anyone, is there any way we can get him to stop responding occasionally with "anyone is anybody"? it makes the factoid totally useless

16:27 hlship: It's an https://... URL, but I get an error "No connector available ... of type default ..."

16:28 And it lists WagonRepositoryConnectorFactory, which I believe should be able to do an HTTPs upload

16:30 hiredman: amalloy: I'll but it on my trello board before "make a ladder" but after "lambda lifting letfns"

16:30 put

16:31 hlship: Interestingly, Gradle *can* deploy to this repository, and both Gradle and Lein are just wrappers around the Maven libs for doing all this

16:31 ghadishayban: ,(into (map inc) [1 2 3 4 5])

16:31 clojurebot: #<ClassCastException java.lang.ClassCastException: clojure.core$map$fn__4507 cannot be cast to clojure.lang.IPersistentCollection>

16:31 ghadishayban: ,(into [] (map inc) [1 2 3 4 5])

16:31 clojurebot: [2 3 4 5 6]

16:34 TimMc: oh right, transducers

16:34 hyPiRion: hlship: is this with 2.5.1 or 2.5.0 or something else?

16:34 hlship: 2.5.0 on OS X

16:34 have to run shortly

16:34 let me try an upgrade

16:36 Same behavior

16:38 https://gist.github.com/hlship/5dc0e03ee42652a48537

16:38 ttyl

16:40 hyPiRion: bleh, the aether/proxy/download issues are piling up

16:41 nicferrier: working out data structures. lah dee dah.

16:56 djames: Is there already a function that I've overlooked that iterates until stable (I wrote this: https://gist.github.com/xpe/46128da5accb0acdf30d)

16:58 gfredericks: (->> (iterate f x) (partition 2 1) (filter (fn [[x1 x2]] (= x1 x2))) (ffirst))

16:58 ^ another way to do it

16:58 kaiyin: loop can be implemented with reduce, right?

16:59 djames: gfredericks: that's a fun way to do it

16:59 gfredericks: yeah

16:59 amalloy: gfredericks: (partial apply =)

16:59 djames: kaiyin: you can't add a terminating condition to reduce. it cranks until its input collection is exhausted.

16:59 gfredericks: amalloy: bleck I hate partial apply

17:00 amalloy: really? why?

17:00 djames: ##(doc reduced)

17:00 lazybot: ⇒ "([x]); Wraps x in a way such that a reduce will terminate with the value x"

17:00 gfredericks: it's so long

17:00 djames: kaiyin: *some* examples of loop can be better represent as reduce

17:00 gfredericks: amalloy: I also hate it more if it's going to be applied to a tuple rather than a homogeneous variable length collection

17:01 amalloy: gfredericks: (def ap (partial partial apply))

17:01 (ap =)

17:01 djames: amalloy: good point!

17:01 gfredericks: yeah I've definitely thought about aliasing it before

17:01 djames: amalloy, kaiyin : I'd still challenge someone to write repeat-until-stable with reduce :)

17:01 gfredericks: I should get plumbing to add it

17:02 (defn repeat-until-stable [f x] (reduce (fn [x1 x2] (if (= x1 x2) (reduced x1) x2)) (iterate f x)))

17:02 djames: kaiyin: I was incorrect before, you can use reduced to terminate a reduce early

17:03 amalloy: djames: now, reduce is still less general than loop. but not because you can't abort early

17:04 djames: gfredericks: excellent. you win a trip to the Bahamas

17:07 hellofunk: what is responsible in emacs for adding those red squiggly underlines when things go long, usually for me under a ns form?

17:07 *wrong

17:09 gfredericks: I only see that in magit commit msgs

17:09 must be a shared functionality

17:09 hellofunk: i thought maybe it was a linter or something, but i don't have the clojure linting installed

17:15 dagda1: can I pass arguments that are not destructured and arguments that are, e.g. [coll [x xs]]

17:15 djames: dagda1: yes

17:15 oh, pass?

17:16 yes

17:19 nicferrier: can I put a buffer on a core.async queue?

17:19 gfredericks: destructuring is just something the function does to its arguments, it's not visible or relevant to the caller

17:19 nicferrier: or channel.

17:20 ooo. yes.

17:21 justin_smith: nicferrier: hell you can put a chanel on a channel if you want - or do you mean add buffering...

17:21 {blake}: Hmmm. If I have a ns A with a (def x 1) and an ns B with a (def x 2), I cannot then "use" both A & B because of the conflict, yes?

17:21 nicferrier: justin_smith: I want to buffer the channel so it doesn't block immediately.

17:21 amalloy: i think you get a warning, not an error

17:21 justin_smith: {blake}: right, another reason not to er... "use" use

17:22 amalloy: justin_smith: the other day i was looking through the 4clojure source code, and i was like "wait a minute, why are there all these :use calls, i thought justin_smith fixed that"

17:22 sadly, only lazybot

17:23 {blake}: justin_smith: Damn rookies!

17:23 justin_smith: nicferrier: I trust you found the optional arg to chan

17:23 nicferrier: justin_smith: I did.

17:24 I'm doing something very messy. I know I need core.async... but fitting it in is very hard.

17:24 {blake}: amalloy:Seems to have broken compilation for me.

17:24 nicferrier: I'm trying to use it to bridge between 2 httpkit async stacks.

17:24 and it's confusing.

17:25 kenrestivo: o_0

17:25 justin_smith: nicferrier: ztellman has some enlightening perspective on buffering queues and backpressure, I forget where though

17:28 |blake|: So, if I want to route my users to the log in screen if they're not logged in (Compojure), this is a job for...middleware!

17:29 tcrayford____: justin_smith: it's on the goggle grup

17:33 justin_smith: tcrayford____: in my ranking of typos I have seen today (ordered by amusement), "goggle grup" is second only to "Robert Cop, law enforcement of the furniture"

17:33 tcrayford____: haha

17:34 amalloy: justin_smith: http://www.reddit.com/r/bestof/comments/216ov7/utheoman333_misspells_a_word_so_horribly_that_it/

17:35 tcrayford____: justin_smith: my favorite mispellings: "Athur write this" : https://twitter.com/Apriim/status/549989239426121730, and "rubby": https://twitter.com/jamesgolick/status/106847523670462465

17:35 |blake|: That's so excgarated.

17:36 amalloy: |blake|: what is the deal with the punctuation around your name? it has changed like three times since i "met" you

17:36 |blake|: amalloy: I fail at IRC.

17:37 amalloy: Is the short story. I've registered one of the punctuated versions. {Blake}, I think. But I can't always seem to authenticate it, so my fallbacks are...weird.

17:38 justin_smith: |blake|: do you know about /msg nickserv ghost ?

17:38 |blake|: Like, I tried to authenticate {Blake} just now and it said there already was one.

17:39 justin_smith: I know muffins.

17:39 justin_smith: |blake|: /msg nickserv ghost {blake} pwd

17:39 |blake|: But I'll check it out.

17:39 justin_smith: that will kick the ghost {blake} off irc

17:39 amalloy: but {blake} isn't on irc now

17:40 |blake|: justin_smith: OK, I'll try that next time.

17:40 Well, okay, yesterday I fixed my NVidia drivers so that it would use all four monitors.

17:40 justin_smith: amalloy: yeah, but his is initial failure was most certainly a ghosting issue I would assume

17:40 |blake|: And when I woke up, my pillow was gone.

17:40 No, when I got everything sorted out HexChat refused to go past ident. So I was using an online IRC.

17:40 amalloy: that's not the ending i expected to that story

17:41 |blake|: amalloy: All my stories end that way. It can be...awkward...sometimes.

17:41 justin_smith: |blake|: I really want to try out this lappy with five externals (plus the built in) some day, - it can do it but I've never had the requisite hardware handy

17:41 amalloy: maybe you never bought a pillow at all

17:42 #clojure minutes, 2015-01-15, 22:40 UTC. justin_smith excommunicated for using the word "lappy"

17:42 justin_smith: haha

17:42 |blake|: justin_smith: I've been sitting here with two working monitors, and two none for a year.

17:42 Then I got a new box, and managed to get three working.

17:45 TimMc: tcrayford____: I thought "goggle grup" was intentional. :-)

17:46 justin_smith: I have definitely seen "rubby" used intentionally (to great comic effect)

Logging service provided by n01se.net