#clojure logs

2015-01-15

00:22zanesI wish core.async/merge could take a transducer. 😕
00:26zaneskoreth_: I’m torn between following you down that path and just using Boot.
00:34clojurenubhi! 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,
00:36amalloyclojurenub: you seem to have some sort of weird {}/() disorder. what are the inputs and outputs you are looking for?
00:37clojurenubamalloy: oh yeah i mixed those up typing up the example. the inputs were all just supposed to be lists
00:37clojurenubso (4 5) (6 7 8) (9) (10) (11)
00:38clojurenubinstead of the stuff with curly braces
00:38clojurenubid also need to quote them if was actually using lists over vectors
00:39mercwithamouthk
00:39clojurebotNo entiendo
01:54fUDHello
01:54fUDIs there a good clojure docker for a starter?
01:57fairuzfUD: You just need java and lein normally
01:57fairuzmaybe mvn too
01:57koreth_zanes: How does Boot address those needs? I have looked at its home page but haven't tried it out yet.
01:58fUDfairuz: ok, maybe I'll just try that on my mac
02:00fairuzfUD: plus, lein is just a bash script :)
02:05fUD:)
02:06zaneskoreth_: It just feels cleaner. http://adzerk.com/blog/2014/11/clojurescript-builds-rebooted/
02:06zanesThe paragraph beginning with "http://adzerk.com/blog/2014/11/clojurescript-builds-rebooted/“.
02:06zanesWhoops.
02:06zanesBeginning with, "The current state of the art in this area is things like chestnut…"
02:08koreth_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.
02:08zaneskoreth_: I’d love to hear about your experiences if you do give it a try!
02:32koreth_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
02:32koreth_L to a live server.
02:32koreth_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.
03:36Empperihi, any ideas how to implement following logic:
03:36Empperilet's say I have a vector of data, eg. [3 5 7 1]
03:36Empperiand I have another vector of data [7 6 5 4 3 2 1]
03:36Glenjaminjustin_smith: came back to look this morning, ended up with this to list current threads and what they're doing:
03:36Glenjamin(pprint (mapv (fn [[^Thread t s]] [(.getName t) (first s)]) (Thread/getAllStackTraces)))
03:37EmpperiI want to sort the first vector in such a way that it's elements are sorted according to the second vector ordering
03:37Empperieg to [7 5 3 1]
03:37mikkerHow do I convert string to an input-stream?
03:37Empperi,(clojure.java.io/as-stream "foo")
03:37clojurebot#<CompilerException java.lang.RuntimeException: No such var: clojure.java.io/as-stream, compiling:(NO_SOURCE_PATH:0:0)>
03:37opqdonutEmpperi: use sort-by
03:37mikkerEmpperi: I'll try!
03:38opqdonutEmpperi: and have the key function look up the index of the value in the order vector
03:38Empperimikker: nah, not like that
03:38Empperibut there is a function for that
03:38opqdonutEmpperi: for added performance, invert the order vector into a map
03:38Empperinot that exact name though I think
03:38Empperiopqdonut: yeah, was thinking something like that
03:38Empperiwas just wondering if there was something "out-of-the-box" for this job :)
03:39opqdonutcan't think of anything
03:39Empperineither can I
03:39Empperiguess it's sort-by then
03:41hyPiRionEmpperi: Are there any duplicates in the longer vector?
03:42hyPiRionif not then
03:42hyPiRion,(sort-by (into {} (map-indexed vector [7 6 5 4 3 2 1])) [3 5 7 1])
03:42clojurebot(7 5 3 1)
03:43EmpperihyPiRion: no duplicates in either one
03:43Empperithat looks nice
03:43Empperiof course my example was a simplified one but that might actually work
03:45opqdonuthyPiRion: I think your map is the wrong way around
03:45hyPiRionyeah, it's opqdonut's solution in Clojure code
03:45opqdonut,(into {} (map-indexed vector [7 6 5 4 3 2 1]))
03:45clojurebot{0 7, 1 6, 2 5, 3 4, 4 3, ...}
03:45Empperiin truth I don't have just vectors and neither single dimensional vectors but I think I might get that solution to work anyway
03:46Empperithanks guys
03:46hyPiRionopqdonut: Oh dang, yeah.
03:46hyPiRionFunny how the example still worked =/
03:46opqdonutyeah :)
03:46opqdonut,(sort-by (into {} (map-indexed vector [:a :b :c])) [:c :a :b]) -- here you can see it not working
03:46clojurebot(:c :a :b)
03:48opqdonut,(sort-by (zipmap [:a :b :c :d] (range)) [:d :a :b]) -- correct
03:48clojurebot(:a :b :d)
03:48hyPiRion(inc opqdonut)
03:48lazybot⇒ 2
03:51Empperigot it working thanks to you guys (thumbsup)
03:51Empperiin my more complex scenario that is
03:56hyPiRionnice
05:34nicferrierI 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??
05:34lazybotnicferrier: What are you, crazy? Of course not!
05:35nicferrierI am confused.
05:37hyPiRionRC releases are usually postfixed with -RC
05:37hyPiRionor something like that
05:37TEttingernicferrier: lazybot responds to any message ending in ?? or ???
05:37lazybotTEttinger: Yes, 100% for sure.
05:39nicferrierhuh. well it doesnt seem to work.
05:44mpenetnicferrier: 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
05:45nicferrierI just need an http/websockets async lib
05:45mpenetit has both, clients as well
05:49nicferrierhmmm
05:49sverinicferrier: I used sente successfully with http-kit
05:50sverisente supports websockets and long-polling as well
05:50nicferrierwhat's sente?
05:50SagiCZ1hi.. 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
05:51sverinicferrier: https://github.com/ptaoussanis/sente
05:52nicferrierwhy do I need that? I should be able to use httpkit? no?
05:53sveriyea, you can stay with http-kit
05:53sveriI just like abstractions in form of libraries
05:58nicferrierand http-kit doesn't work :-)
06:07clgvSagiCZ1: Swing callbacks will only use the on UI thread for example
06:08clgvSagiCZ1: 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)
06:19SagiCZ1clgv: 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?
06:21kaiyinIs anonymous function inducive to better performance?
06:22clgvSagiCZ1: exactly. that is why some applications freeze after clicks. they don't move the expensive work to other threads.
06:23mpenetkaiyin: not really
06:23CookedGryphonHey 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?
06:24CookedGryphonit's doing a load of reflection etc and killing my startup time
06:24mpenetkaiyin: I guess #(..) doens't have to deal with arg destructuring, but it's taken care of by hotspot in most cases
06:25SagiCZ1cglv: i see.. so what core.async does in go blocks works similary? also only on one thread?
06:25clgvkaiyin: no, it is just syntactic sugar
06:26kaiyingood to know, because I hate it in most cases. Just makes things unnecessarily difficult to read.
06:27justin_smithwait, is this a question about #() or about named vs. anonymous functions?
06:27clgvSagiCZ1: you gotta ask someone with core.async experience ;)
06:27clgvkaiyin: yeah, you can just use (fn [...] ...) then
06:28justin_smithSagiCZ1: core.async uses a thread pool, and a given go block csn switch threads after parking
06:28clgvkaiyin: named arguments are usually much better documentation of what you are doing.
06:28kaiyinyeah.
06:29mpenetSagiCZ1: go blocks run on 42 * proc/2 (or something) threads.
06:29SagiCZ1justin_smith: i dont understand this.. what is thread parking?
06:29justin_smithSagiCZ1: the threads don't park, the go blocks do
06:30justin_smithwhen waiting on a channel
06:30mpenetSagiCZ1: 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
06:31justin_smithparking says "I don't need sny thread until I get a message on this channel"
06:31SagiCZ1justin_smith: and they use state machine to remember where they parked?
06:32justin_smithit's a state machine, yeah
06:32mpenetThat 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
06:32SagiCZ1i am not sure i understand how is thread block with >!! different then
06:32mpenet>!! blocks the current thread
06:32SagiCZ1>! does not?
06:33mpenetyes it doesn't
06:33SagiCZ1ok
06:33mpenetgo block gets rewrited as a state machine
06:33justin_smithblockinh and parking are different
06:33SagiCZ1justin_smith: i understand they are different but until now i understood "parking" only in the context of parking my car
06:34justin_smithparking is effevtively registering a callback for when a channel op completes
06:35SagiCZ1okay
06:35doritostainslein repl isn't printing out the port. how do I figure out the port it's connecting to?
06:35justin_smithbut syntax wise it doesn't look like a callback
06:35mpenetfyi, if you have interest in what I was mentioning, vote here http://dev.clojure.org/jira/browse/ASYNC-94
06:36SagiCZ1justin_smith: thank you.. and do you think that core async chan can substitute java's BlockingQueue for any purposes?
06:37clgvdoritostains: it usually does
06:37justin_smithNlockingQueue ltd you fo things that chan does not
06:37clgvdoritostains: it is also creating a temporary file for that
06:37doritostainsclgv: yeah but it isn't for what ever reason :(
06:37_1_tragaklk
06:37clgvdoritostains: .nrepl-port
06:37clgvdoritostains: does it fail to start?
06:38justin_smithargh... Blockingqueue lets you do etc. chan is intentionally more limited
06:38SagiCZ1justin_smith: let's me do what?
06:38doritostainsclgv: no .nrepl-port but it starts up just fine
06:38SagiCZ1more things?
06:39mpenetSagiCZ1: https://github.com/ztellman/manifold wants to bridge the gap between all these abstraction it seems
06:40justin_smithSagiCZ1: yeah, chan is more restrictef
06:40SagiCZ1justin_smith: thank you
06:43justin_smithfor example BlockingQueue has contains and remainingCapacity
06:43SagiCZ1justin_smith: yeah i think all i really need chans can do
06:45justin_smithSagiCZ1: core.async implements CSP (concurrent sequential processes) which is a well designed formal model for concurrency semantics
06:45SagiCZ1justin_smith: i guess i should read about CSP in general
06:49justin_smithit ism't neccesary, buy it all makes more sense if you understand that model imho
06:53jonasenWhat 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]])
06:55SagiCZ1jonasen: i use the square brackets as in your second example
06:58jonasenAccording to http://clojure.github.io/clojure/clojure.core-api.html#clojure.core/ns ":refer takes a list of symbols ..."
06:58sverinicferrier: it works for me ;-)
06:58jonasensorry the link should be http://clojure.github.io/clojure/clojure.core-api.html#clojure.core/require
06:58nicferriersveri: yeah, I've got it worked now.
06:58nicferriersveri: thanks!
06:58spradnyeshanyone 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)
07:42CookedGryphonis there a way to make AOT compilation bake in macro expansions?
07:46clgvjonasen: 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."
07:46clgvjonasen: that would warrant the use of (:require ...) instead of [:require ..] as well ;)
07:52sverinicferrier: nice to hear that
07:54katratxoclgv: that's a good rule to remember
07:54hellofunkwhat 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
08:05sverihellofunk: boot?
08:05justin_smithCookedGryphon: wait, do you mean the unexpanded form? Because of course macros are expanded before compilation.
08:05sverisry, its not a lein template
08:06daniel`hellofunk: why exclude chestnut
08:13hellofunkdaniel` chestunut has a few bugs that i don't like
08:15daniel`who likes bugs
08:15daniel`wasnt aware of any
08:17the-kennyIs there a specific reason clojure-mode 4.x lost its special-casing for indenting (assoc obj \n :foo 42) (\n = newline)?
08:18the-kennyit used to indent the kv-pairs on new lines with 2 spaces instead of aligning it with the first arg
08:19hellofunkdaniel`: a lot of chestnut users have this problem with the latest cider: https://github.com/clojure-emacs/cider/issues/853
08:19hellofunkdaniel` but i have other issues also
08:19CookedGryphonjustin_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
08:19CookedGryphonso why do I still need that dependency at runtime when I have AOT'd
08:24the-kennyOk nevermind, the new indentation is expected.
08:28CookedGryphonalso, is there any reason clojurescript's (:require-macros ...) form isn't supported in clojure?
08:28CookedGryphonsurely it would be trivial to add, and mean that you could write one version for both
08:44krat0sprakharhi all, how can i add a clojurescript repl
08:44krat0sprakharon a website
08:44krat0sprakharany ideas?
08:54Kneivakrat0sprakhar: http://himera.herokuapp.com/index.html
08:54krat0sprakharKneiva: What about http://clojurescript.net?
08:55krat0sprakhari've tried adding it in my application but it seems to be not working
08:55Kneivaseems pretty similar =)
08:55daniel`i see hellofunk, i dont use cider thats probably why
08:56nicferrierwhen 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?
08:56daniel`normally i tweak things how i like anyway, the lein template is just a start surely
08:57daniel`im not starting 50 new projects exactly the same every day
08:57daniel`that need to work perfectly from get go
08:57hellofunkdaniel`: i get you. what editor do you use?
08:57daniel`vim/fireplace
08:58daniel`i dont take advantage of the interactive workflows as often as i perhaps should
08:59hellofunki'm trying to find a good tutorial on how to write my own lein template
08:59daniel`i usually isolate the part im interested in to play with, rather than develop a whole project in that manner
09:02hellofunkis creating a lein template really as simple as doing lein create-template existing-project-skeleton ?!
09:03hellofunkoh i guess that's just one way
09:03nicferrierI looked at it. it looks easy,
09:06daniel`wouldnt imagine it to be much harder
09:06daniel`but never done it
09:25hellofunkwhy 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?
09:25hellofunkit is usually implicit, hence why it is ommitted nearly all the time?
09:27kaiyinWhat is wrong with this: (take 4 (take 3 (repeat (repeat 5)))) ?
09:28kaiyinI intend to take a 4x3 array out of an infinite 2D array.
09:30hellofunk,(take 4 (take 3 (repeat (repeat 5))))
09:30clojurebot((5 5 5 5 5 ...) (5 5 5 5 5 ...) (5 5 5 5 5 ...))
09:30krat0sprakharhellofunk: doesn't work for me in the REPL
09:30krat0sprakharO.o
09:31krat0sprakharhow is the bot compiling it?
09:31hellofunkwhat happens in your repl?
09:31hyPiRionkrat0sprakhar: it works, but those 5-lists are infinite
09:31hyPiRionyour repl tries to print them all out
09:31hellofunkhyPiRion: even with take it tries to print them?
09:31krat0sprakharso one more (map take n) is required?
09:31hellofunkoh i see, nevermind
09:32hyPiRionkrat0sprakhar: You need to reorder the takes
09:33krat0sprakhar,(map #(take 4 %) (take 3 (repeat (repeat 5))))
09:33clojurebot((5 5 5 5) (5 5 5 5) (5 5 5 5))
09:33hyPiRion,(take 3 (repeat (take 4 (repeat 5)))
09:33clojurebot#<RuntimeException java.lang.RuntimeException: EOF while reading>
09:33hyPiRion,(take 3 (repeat (take 4 (repeat 5))))
09:33clojurebot((5 5 5 5) (5 5 5 5) (5 5 5 5))
09:33hyPiRionor equivalently
09:34hyPiRion,(repeat 3 (repeat 4 5))
09:34clojurebot((5 5 5 5) (5 5 5 5) (5 5 5 5))
09:34krat0sprakharnaice!
09:35kaiyinvery cool.
09:35krat0sprakharhyPiRion: how is the clojurebot so fast/
09:35krat0sprakhar?
09:36puredangerit's on speed
09:36daniel`presumably it does an implicit take on lazy seqs
09:36krat0sprakharwhereas, http://himera.herokuapp.com/index.html is quite slow
09:38kaiyinHow 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).
09:39hellofunkkaiyin: you must have one heck of a large file to slurp to require that!
09:39krat0sprakharhaha.. was thinking the same..
09:39kaiyinhellofunk, yes I do, I some times have files larger than 50GB.
09:39hyPiRionkrat0sprakhar: Himera is CLJS, whereas the bots here are CLJ ones. I'm not sure that's the reason, but it may be a reason
09:39hellofunkwow, a single text file that big?
09:39hyPiRionmay affect performance* I meant
09:40kaiyinhellofunk, yes, a single file that big, but not necessary text.
09:40kaiyinnecessarily.
09:40hellofunkhyPiRion: 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
09:40ziltikaiyin: Then I definitely wouldn't use slurp, but the cloure.java.io namespace.
09:40krat0sprakharhellofunk: it fires off text to a compiler running on the serve
09:41krat0sprakharreturns js
09:41krat0sprakharwhich is then read and shown in the console
09:41hyPiRionkaiyin: I tend to use buffered readers and wrap them in iterator-seqs
09:41krat0sprakharhellofunk: try out clojurescript.net
09:41krat0sprakharthat is diff
09:42hellofunkkrat0sprakhar: that site seems pretty fast to me
09:42krat0sprakharthat = ?
09:42kaiyinzilti, hyPiRion, could you give a little more detail? I just started learning clojure a few days ago, so I don't have much experience.
09:42krat0sprakharhellofunk: you mean clojurescript.net?
09:42hellofunkyeah
09:42krat0sprakharthats because it is doing all compilation IN the browser
09:42krat0sprakharunlike chimera
09:42krat0sprakhar*HIMERA
09:42hellofunki thought it was just stated that himera was cljs
09:43krat0sprakharclojurescript.net is not himera
09:43hellofunkare you saying himera is doing cljs on the server?!
09:43krat0sprakharnope
09:43krat0sprakhar:D
09:43krat0sprakharclojurescript.net is doing cljs on the browser
09:43hellofunki know they are two different sites, by it was said earlier that himera is cljs, thus it is also on the browser
09:43krat0sprakharits class on cljs
09:43krat0sprakharah ok.. my bad
09:44krat0sprakharclojurescript.net is CLJS on CLJS
09:45hellofunkthough i'm curious how it can eval cljs since i thought it requires compilation to js first, and there is no eval in cljs
09:45ziltikaiyin: 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
09:50puredangerkaiyin: 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
09:50puredangerrequires being able to tell record boundaries in your file, etc)
10:00hyPiRionkaiyin: 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:08kaiyinhyPiRion, cool. What do you mean "laziness is not passed around"?
10:14hyPiRionkaiyin: 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:16hyPiRionIf 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:18hyPiRionAnd 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:19hyPiRionNot sure if I explained that very well.
10:19hyPiRionHas anyone written a blogpost about this? I'd be surprised if noone haven't, because it seems to be a common issue.
10:26myguidingstarhi all, does ring-anti-forgery help with RESTful apis?
10:52kaiyinhow does recur solve the lack of support for tail call optimization?
10:53Tritlokaiyin: recur allows for self-recursive functions
10:53Tritlokaiyin: and basically turns them into a loop
10:53Tritlokaiyin: but it isn't proper tail recursion
10:53Tritlokaiyin: and doesn't support mutually recursive functions
10:54Tritlokaiyin: so it is a partial solution
10:54hellofunkarchitecturally, however, there is really no difference as a developer in using recur vs. true TCO, the effect is the same for your process
10:54Tritlohellofunk: what about mutually recursive functions?
10:55hellofunkyou mean non-stack-consuming functions that call each other?
10:55Tritlono, stack consuming
10:55hellofunkbut TCO and recur are about non-stack-consuming
10:55Tritloisn't that the point with TCO? To turn stack consuming functions into non stack consuming?
10:56hellofunkTritlo: more or less, yes
10:57Tritloand recur doesn't solve that for mutually recursive functions
10:57hellofunki was not aware that mutual recursion in scheme, for example, was optimized, is it?
10:57hellofunkif you are calling another function, that is not recursion is it?
10:57andyfhellofunk: The scheme spec requires implementations to optimize all tail calls
10:57Tritloscheme allows for mutual recursion
10:58andyfWhether there is recursion involved or not
10:58hellofunkandyf: tail calls to *any* function, including another function that is mutually recursive?
10:58Tritloclassic example being
10:58Tritlohttps://www.irccloud.com/pastebin/2ocmIKN1
10:58andyfYou can have tail calls with no recursion, too
10:59hellofunkandyf: 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:59TritloWithout TCO, this is sure to cause stack overflow for large numbers
11:00TimMcAlso we live in a finite universe, so there;s that.
11:00andyfI believe main motivation is for deeply recursive functions, but scheme spec requires tco whether there is recursion or not
11:01hellofunkandyf: 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:01Tritlohellofunk: well, there you have it
11:01Tritlohellofunk: you can kind of get around it with trampoline though
11:02Tritlohellofunk: but it gets messy
11:02hellofunkTritlo: 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:02hellofunk*design
11:03hyPiRionTritlo: it's not that bad. Just prepend all tail calls with # and call trampoline on the result of a call.
11:03hellofunklet me think about your even/odd example
11:03Tritlohellofunk: well, you can say that about most anything :P
11:03hyPiRionTritlo: it's somewhat annoying though, I agree
11:04andyfwww.r6rs.org/final/html/r6rs/r6rs-Z-H-8.html#node_sec_5.11
11:04hellofunkhyPiRion: or Tritlo could you provide an example of what you mean with # and trampoline?
11:04hellofunknow you guys got me curious
11:05TritloThis seems to be a good writeup
11:05Tritlohttp://jakemccrary.com/blog/2010/12/06/trampolining-through-mutual-recursion/
11:06hellofunkTritlo: exactly what i was looking for
11:06hyPiRionyeah, that's a good link. The Art of Clojure also discusses it somewhat
11:08hellofunkhyPiRion: what is ARt of Clojure?
11:08hellofunkyou mean Joy of Clojure?
11:08hyPiRionhellofunk: ...yes
11:09hyPiRionclojurebot: art |is| joy
11:09clojurebotIn Ordnung
11:11hellofunkreading that article makes me think trampoline was implemented specificly to address TCO.
11:12hyPiRion(doc trampoline) =)
11:12clojurebot"([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:13andyfI 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:13hellofunkah, joy
11:14hellofunkwonder 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:15Tritlowell, it makes debugging a lot harder,
11:15CookedGryphonIf 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:15Tritlofinding out from where the bug originates etc
11:15Tritloa lot more to keep track of
11:16andyfIt 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:17zerokarmalefthellofunk: it's well documented, guy steele was an important advocate while he was working on fortress
11:17nilernthere was a JVM security mechanism that relied on counting stack frames
11:18hellofunkinteresting stuff for sure
11:18hellofunkseeing where the lines are drawing between language design and platform design
11:18nilernbut that mechanism was recently removed so TCO might be coming
11:18zerokarmaleftyea, and hopefully lambdas push that need to closer to the forefront
11:19zerokarmaleftjava 8 lambdas, that is
11:19Tritlonot even python has TCO :/
11:19TritloGuido is explicitly against it
11:19Tritlothough you can shoehorn it in with decorators and exceptions
11:19nilernbtw JVM Schemes have TCO, but that requires a different calliing convention from Java
11:20nilernI recall Rich didn't do that for Clojure because it would complicate interop
11:22csd_Can anyone recommend a good tutorial for core.async?
11:23zerokarmaleftcsd_: there's a walkthrough example in the core.async repo that teaches you the basic primitives
11:25daniel`csd_: there was recently a chapter of clojure for the brave and true covering core.async
11:25daniel`havent read it yet, so can't recommend it
11:25hellofunkcsd_: 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:25kaiyinHow do you get [1 2 3 4 5] out of [1 2 3 4 5 6]? Like init in haskell.
11:25zerokarmaleftkaiyin: butlast
11:25kaiyincool
11:26CookedGryphonDoes anyone know if require is multithread safe in clojure?
11:26CookedGryphoncan I run multiple requires in parallel? Or is there a risk of doing the same work twice
11:27andyfkaiyin: Pop is more efficient way to do that, only for vectors
11:27clgvCookedGryphon: if you are talking about dynamic parallel require at runtime, it is not!
11:27CookedGryphonMy intuition was that it wasn't, but I couldn't remember why I thought that
11:28kaiyinandyf, why is it more efficient?
11:28clgvCookedGryphon: there are multiple error scenarios: namespaces loaded twice, namespace loading failed because a definition in a dependency namespace was not loaded yet ...
11:28Glenjamin(doc butlast)
11:28clojurebot"([coll]); Return a seq of all but the last item in coll, in linear time"
11:28CookedGryphonclgv: back to plan F then...
11:28clgvCookedGryphon: do you definitely need that? then I might have a small tool for you
11:29csd_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:29andyfkaiyin: Butlast takes linear time, pop can be done in log n time due to way vectors are implemented
11:29CookedGryphonI'm just doing what I can to get startup time under a second in my android app
11:29clgvCookedGryphon: since I ran into it myself and there was no alternative
11:29clgvCookedGryphon: I have written and using that library in the problematic scenario https://github.com/guv/txload
11:29clgv+am
11:29zerokarmaleftandyf: nice
11:30CookedGryphonand 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:31zerokarmaleftcsd_: <!! is a blocking take
11:31CookedGryphonclgv: multithreaded requires seems to me like a feature core might be interested in... if it can be done cleanly
11:32andyfkaiyin: 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:32clgvCookedGryphon: if you limit the scope to requiring namespaces dynamically at runtime that's totally doable. the lib is a proof of concept ;)
11:32kaiyinandyf, cool, thanks.
11:33clgvCookedGryphon: loading arbitrary files is problematic
11:33CookedGryphonclgv: as opposed to? This is all supposed to be aot compiled already, it still needs to load namespaces
11:34ziltiCookedGryphon: AOT'ing your whole app didn't help either?
11:34clgvCookedGryphon: 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:34csd_zerokarmaleft: (<!! (go (<! chan))) seems to be have similarily
11:34clgvCookedGryphon: you can just check the test cases of the lib
11:35gfredericksyesterday I saw an example of a macro accidentally working that I had never seen before
11:36clgvgfredericks: gist :)
11:36CookedGryphonzilti: nope
11:36CookedGryphonclgv: okay, I might give this a go
11:37zilticsd_: Yes, because then <!! blocks until the go-block has finished, which takes until the chan returns.
11:37kaiyinWhat is wrong with this implementation of comp? https://gist.github.com/kindlychung/e4b5e4fb226449bad83c
11:38csd_zilti: ok-- why then does the walkthrough.clj wrap the go block in <!!?
11:38gfredericksclgv: https://www.refheap.com/96148
11:38SagiCZ1kaiyin: i dont think that destructuring is correct
11:38Bronsakaiyin: recur is a special form not a function, you can't apply it
11:38zilticsd_: 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:38clgvgfredericks: uh. shouldnt that resolve to foo.string/join ?
11:39gfredericksclgv: nope
11:39gfredericks,`string/join
11:39clojurebotstring/join
11:39csd_zilti: i just want to see what the first value in the channel is. how do i do that?
11:39hellofunkkaiyin: this looks like a 4clojure problem. i think i solved it by reducing over the fns
11:39clgvah right, because there is a namespace already
11:40clgvgfredericks: it would resolve correctly if you had that alis defined in `foo` right?
11:40gfredericksclgv: yep
11:41zilticsd_: 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:41clgvgfredericks: humm, isn't that a feature that should be added?
11:41csd_zilti: but <! just returns another channel
11:41gfredericksclgv: I'm not sure what you're referring to
11:41andyfclgv: What should be added?
11:42SagiCZ1,(let [[& f g] [:a :b :c]] [f g])
11:42clojurebot#<CompilerException java.lang.Exception: Unsupported binding form, only :as can follow & parameter, compiling:(NO_SOURCE_FILE:0:0)>
11:42zilticsd_: No, <! returns the first value of a channel as soon as it's available.
11:42SagiCZ1kaiyin: see you cant destructure like this
11:42andyfI think gfredericks is saying his example works, but expected it not to work ?
11:43csd_i dont know, maybe its the API i'm using, but i'm definitely getting a channel back
11:43gfredericksthe code is definitely bad
11:43gfredericksand should be fixed
11:43gfrederickssince it only works by accident
11:43clgvgfredericks: 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:43csd_=> #<ManyToManyChannel clojure.core.async.impl.channels.ManyToManyChannel@308e19b>
11:43clgvgfredericks: so we could have a warning or an error there
11:43zerokarmaleftcsd_: sorry, got called away...the API call sends a channel over a channel?
11:43zilticsd_: So (type (<! channel)) gives you the ManyToManyChannel? Did you put a channel onto the channel?
11:43zerokarmaleftcsd_: a gist or something might help us out here
11:44gfredericksclgv: 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:44csd_one sec
11:44gfredericksthere might really be a namespace called string somewhere
11:44clgvgfredericks: but it can distinguish aliases?
11:45clgv,(require '[clojure.string :as str])
11:45clojurebotnil
11:45clgv,`(str/join ~'a)
11:45clojurebot(clojure.string/join a)
11:45gfredericksclgv: yeah, that's local to the current namespace
11:45andyfgfredericks: Yeah, what you said :) syntax quote messes with my head
11:45gfrederickseverything backtick does is just based on the current namespace
11:45gfredericksand just the namespace config, not any vars in it
11:45clgvyeah and that would be fine to detect this error
11:46gfrederickshow?
11:46clojurebotwith style and grace
11:46clgvgfredericks: if "str" does not resolve to any alias or namespace
11:46gfredericks"resolving to a namespace" is a global concern
11:46clgvgfredericks: ah ok. so that is not checked
11:47gfredericksI believe not
11:47gfredericksand it'd be tricky if you wanted to -- users might expect their macros to compile without all the other namespaces being loaded yet
11:47csd_zerokarmaleft zilti: not much code to show you though https://www.refheap.com/96149
11:48andyfYou can use a symbol like foo/bar whenever in Clojure, even if there is no namespace or alias foo
11:48zilticsd_: Yes, that's correct that way - (go ...) returns a channel
11:48csd_but how do I get the first value from the channel?
11:49zilticsd_: And that cannel will have one entry with the return value of the go block as soon as the go block finished
11:50clgvandyf: but it needs to be quoted if contained as a literal ;)
11:50zilticsd_: 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:50andyfSure and symbols are quoted when used in syntax quote
11:51clgvright
11:51csd_zilti: how would i use an atom to get it?
11:52clgvandyf: what do you think about transactional namespace loading? I have a test case demonstrating the problem over here: https://github.com/guv/txload
11:53zilticsd_: 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:53andyfI 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:53clgvandyf: but I am not sure if there was any desire to patch the clojure runtime such that dynamic parallel requires work.
11:55clgvandyf: 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:55zilticsd_: 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:56csd_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:56csd_zilti: is it not possible to println inside a go-block?
11:56hiredmanI played with parallel code loading on our larger code base at work, a few years ago, it broke things a lot
11:56SagiCZ1csd_: it is
11:57zilticsd_: Last time I tried it failed, but it can be unpredictable I guess. core.async uses a thread pool in the background
11:58csd_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:58csd_How do I get those keys?
11:58andyfclgv: 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:59zilticsd_: Which docs are you looking at?
11:59csd_zilti: 3rd party api docs: https://github.com/thieman/clojure-zulip/blob/master/src/clojure_zulip/core.clj
12:00clgvandyf: you mean the current require/use implementation? I doubt that
12:00clgvandyf: except there are changes in 1.7
12:01clgvandyf: just remove (tx/enable) from the test implementation and run the test
12:02andyfclgv: 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:03zilticsd_: Hmm no idea. It's a somewhat weird docstring. I'd guess it is a channel that returns maps with those keys each?
12:03clgvandyf: ah ok. I am not sure that I understand where defprotocol might fail if the namespaces are loaded transactionally
12:04CookedGryphonDoes anyone have any hints/ideas why loading ioc-macros namespace is taking 18seconds in my android app
12:04CookedGryphonthe startup time isn't actually too bad for the rest of it
12:04csd_zilti: yeah idk
12:04clgvandyf: the hack I made assures that every namespace is loaded exactly once which holds for all transitive dependency namespaces as well
12:05CookedGryphonbut core.async_init is taking 19 seconds, and 18 of those are spent loading ioc_macros
12:05csd_i guess i'll just read that chapter from Brand and True and hopefully that will give me some crucial incite
12:05zilticsd_: I'd really recommend playing around with core.async a bit before using a library that uses core.async
12:05clgvandyf: if two threads end up requiring the same namespace transitively, one is doing the work, while the other waits until its done
12:05csd_zilti: whys that?
12:05andyfSure, but what if defprotocol is not thread safe, and two defprotocols execute simultaneously in 2 namespaces loaded in parallel?
12:06zilticsd_: Because as you've said you don't fully understand it yet, if I've understood you correctly
12:06clgvandyf: ah, you mean the java implementation backing up defprotocol, ok.
12:06andyfclgv: Java or Clojure part, either or both
12:07csd_zilti: fair enough
12:07csd_yes my understanding is a little above zero
12:07clgvandyf: the number of use cases that need this is definitely pretty limited, anyway
12:07andyfClojure isn't exactly thread-safe magic pixie dust, even if lots of it is :)
12:08zilticsd_: 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:09clgvandyf: yeah, a little disappointment accompagnied that discovery ;)
12:10brainproxyconcurrency is hard, reactive programming is hard
12:11ziltiMore different than hard, I'd say.
12:11brainproxyi'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:11csd_zilti: thanks
12:12zilticsd_: You're welcome :)
12:22mmghi, 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:22mmgcan I do this with proxy or by any other means in clojure/
12:25llasrammmg: 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:25ziltimmg: You have to define a protocol first, then use that one using extend, extend-type or extend-protocol. Or proxy.
12:25llasrammmg: in my experience these approaches are rarely necessary -- why do you need this extra method on the class?
12:26mmgI 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:27mmgso 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:28mmgI’ll try gen-class, thanks
12:28llasramErrrg
12:28llasramNo no
12:28llasramAnything is better than gen-class :-)
12:28ziltimmg: This should work: https://www.refheap.com/96154 Avoid gen-class
12:28ziltiAnd proxy is kinda ugly as well in my opinion
12:28mmgthanks zilti
12:29mmgyeah 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:29mmgso it goes
12:29ziltimmg: yw. It should work that way, though I didn't test that code. But I'm working with extend-protocol right now anyway
12:30ziltimmg: I'm writing a JavaFX wrapper and extend-* seem to be awesome
12:33clgva clojure.java.jdbc query with COUNT(*) leads to a keyword :count(*) - what is the idiomatic query to avoid that?
12:40clgvguess renamig via "AS" is the key :)
12:40Beamedzilti: 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:42ziltiBeamed: 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:45clgvzilti: java lambdas do not implement Runnable or Callable?
12:47zilticlgv: Hm, I don't think so. But anyway, java lambdas are... weird.
12:47timvisheryou can create sub-cursors in om by using keyword accessors, right?
12:47timvisheri'm trying to debug why my app is re-rendering everything every time, although it's ostensibly only changing 2 nodes.
12:48timvisherstaging.nhss.twonegatives.com if you're interested in looking at it
12:48timvisheri'm suspicous that it has something to do with not properly initializing the component cursor
12:48timvishermany of them are pointed at strings, which the docs say is a no no
12:49timvishercurrent branch: https://github.com/timvisher/nhss-cljs/tree/performance-optimization
12:50timvisherinterestingly, i implemented IShouldUpdate on one of my components, and it doesn't appear to ever get called?
12:50clgvzilti: do they share a common interface?
12:50zilticlgv: 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:51clgvzilti: ok
12:51timvisherif IRender/State is called, the DOM is updated with that component, right? or is IRender called and then the diff happens?
12:51zilticlgv: 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:52kaiyinwhy is it not ok to use recur here?
12:52kaiyinhttps://gist.github.com/kindlychung/1b10842c22236427ac9c
12:53ziltikaiyin: 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:53kaiyinok
12:54ziltikaiyin: 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:54timvisherthe app is spending ~40% of its time in React `batchedUpdate`
12:54kaiyinzilti, good to know.
12:59timvisherif a parent component is dirty, are all children forced to updated no matter what?
12:59timvisherthat wouldn't seem to make any sense
12:59Glenjamintimvisher: by default, yes
13:00Glenjaminbut they can optimise this by implementing shouldComponentUpdate
13:00timvisherGlenjamin: i thought that was the whole point of using sub-compenents and reference equality?
13:00Glenjaminthere's a React.Perf thing which can tell you which components are wasting time recalculating updates to apply no changes
13:01Glenjamintimvisher: React can't do that out of the box, because JS is full of mutability - most cljs wrappers enable this though
13:01timvisherthat you can dirty a parent component without actually forcing all sub-components to re-render, because their sub-cursor hasn't changed
13:01Glenjaminoh, i see - you're in Om
13:01timvisheraye :)
13:01Glenjaminah, this is a quirk to do with cursors, which i think reference cursors are better at
13:02Glenjaminiirc
13:02timvisherGlenjamin: unable to parse :)
13:02timvisherreference cursors?
13:02Glenjaminyeah, look up "reference cursors" in the Om docs
13:02Glenjaminthey're fairly new
13:06clgvzilti: if you'd use a wrapper approach as in seesaw you could wraper clojure functions into the appropriate functional interfaces
13:06clgvwrap*
13:07zilticlgv: 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:11timvisherdoes implementing IShouldUpdate in om not work as advertised? are local implementations ignore in some way?
13:15timvisheror 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:33kaiyinwhat's wrong with this: (fn [& xs x] x)
13:33kaiyin,(fn [& xs x] x)
13:33clojurebot#<CompilerException java.lang.RuntimeException: Unexpected parameter, compiling:(NO_SOURCE_PATH:0:0)>
13:33puredangerany of the Venanti / Standard Treasury team on here?
13:36fairuzkaiyin: shouldn't & xs be the last argument?
13:37justin_smithkaiyin: & can only be followed by one argument
13:37kaiyinok
13:37fairuz,(fn [x & xs] x)
13:37clojurebot#<sandbox$eval49$fn__50 sandbox$eval49$fn__50@4f6047f9>
13:37kaiyinbut I am trying to implement last
13:38justin_smithkaiyin: that can't be done witj destructuring
13:45ntietzhey, 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:46AimHereJoy of Clojure tends to be considered the more 'advanced' clojure book
13:46ntietzokay, I'll take a look at that, thanks
13:54krat0sprakharhow can I add the Access-Control-Allow-Origin: * to a ring app
13:54krat0sprakhar?
13:54scottjntietz: clojurebook.com seems like it would be a good fit for covering the language and ecosystem
13:55fairuzkrat0sprakhar: You can add a middleware that modifies the header
13:55Frozenlockkrat0sprakhar: depending on your setup, this could be sufficient https://www.refheap.com/96164
13:57ntietzscottj: thanks! I'll take a look at that, too
13:57krat0sprakharthanks a lot Frozenlock
13:58krat0sprakharone quick question, how do I call the handler through this function?
13:58ggherdovHi. I want to use the first element of a vector as a key to access a value in a map. Trying this:
13:58ggherdov(get {:a 1 :b 2 :c 3} (first ["a" "b" "c"]))
13:58ggherdovbut the REPL says "nil". I expected "1". What's my mistake?
13:59zilti(doc get)
13:59clojurebot"([map key] [map key not-found]); Returns the value mapped to key, not-found or nil if key not present."
13:59zilti,(get {:a 1 :b 2 :c 3} (first [:a :b :c]))
13:59clojurebot1
13:59krat0sprakharzilti: you need to convert the string to symbol
14:00ziltiggherdov: A String isn't a keyword
14:00ggherdovuh. Thanks zilti. Checking my book again then. krat0sprakhar ok
14:00Frozenlockbut a string can be a key ;-)
14:00krat0sprakharzilti: right, i was assuming his vector has string only
14:00krat0sprakhar*strings
14:00ggherdovI see.
14:00Frozenlockkrat0sprakhar: http://clojure-doc.org/articles/cookbooks/middleware.html
14:01krat0sprakharthanks Frozenlock
14:02ziltiAre defmethods having an effect across all namespaces?
14:11foofoobarWhat is the go-to framework for doing web development with clojure? compojure?
14:14fairuzfoofoobar: usually a stack of these libs
14:14fairuzcompojure + liberator + component
14:14fairuzand some others
14:15chouserzilti: 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:15ordnungswidrigI recently advocate bidi instead of compojure as it has reverse routing aka url generation
14:15ziltichouser: Ok! Thanks!
14:15chouserzilti: np
14:15ziltiordnungswidrig: I started using it as well. It's especially nice that I can also do client-side routing with it
14:16ordnungswidrigthat's also a plus, yes.
14:19foofoobarfairuz: thanks
14:20Gazaflink to bidi please? can't seem to find it
14:20ziltiGazaf: https://github.com/juxt/bidi
14:21Gazafthank you
14:22fairuzI personally use compojure api
14:22fairuza swaggered version of compojure
14:23foofoobarfairuz: 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:24foofoobarFor learning-by-doing I’m trying to build a simple web app (user auth, user dashboard (maybe with react.js), some static pages)
14:25fairuzI think it's good enough
14:25fairuzYou add more and more libraries as you progress
14:25foofoobarfairuz: So where to start? With compojure?
14:26foofoobarThe 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:27wkffoofoobar: have you tried enlive
14:27wkf?
14:28ziltifoofoobar: There's also Selmer
14:29fairuzfoofoobar: As you can see here, everyone has its own preference :)
14:29fairuzhttp://www.clojure-toolbox.com/
14:29krat0sprakharone question - i'm trying to add CORS to this server
14:29krat0sprakharhttps://github.com/fogus/himera/blob/master/src/clj/himera/server/service.clj#L17-L21
14:29fairuzthis can help you cherry-picking some libraries
14:29krat0sprakharany idea whats wrong?
14:29wkfall useful, for different situations/preferences
14:29krat0sprakhari just added "Allow-Access-Control-Origin" "*"
14:29krat0sprakharon line 20
14:29Gazaffoofoobar: Luminus for a more structured approach http://www.luminusweb.net
14:30krat0sprakharmy requests are still failing from cross origin
14:30fairuzkrat0sprakhar: What is the error on client side?
14:30fairuzDoes your server handle the preflight request?
14:30fairuzaka the OPTION request
14:30krat0sprakharthe usual No 'Access-Control-Allow-Origin' header is present on the requested resource.
14:31krat0sprakharalthough when i try, doing the same from the same origin
14:31krat0sprakharthe header is coming correctly
14:31krat0sprakharoh so i need to specify that route separately?
14:31fairuzYou need to response to the OPTIONS request separately yes
14:31krat0sprakharoh
14:31fairuzsimplest is just to say all is ok
14:32krat0sprakharoh just 200 then?
14:32foofoobarThanks, I’m checking the links you send me
14:32fairuzin cors, the browser will actually send 2 requests
14:32krat0sprakharright..
14:32fairuzone OPTIONS (preflight) then the actual request
14:32fairuzthe latter will only be sent if the former returns ok
14:33krat0sprakhari've never actually done that in Flask (python) hence didn't that one needs to define /options as well
14:33krat0sprakharprobably the framework was doing that for me and i didn't notice :D
14:33fairuzprobably :)
14:33krat0sprakharok, so i'll add the route and see
14:34fairuzand most probably you will need more headers
14:34fairuzthat's why I asked what was the error in the browser
14:38krat0sprakharfairuz: weird, i'm getting an exception: OPTIONS is not defined
14:39krat0sprakharalthough compojure documentation does define it
14:41fairuzcheck your imports
15:02kaiyinhow do you get rid of the outer parenthesis/brackets/braces of the current expression?
15:02kaiyinfor example trun [2 3] into 2 3
15:04xonevkaiyin: what for? to pass as arguments to a function? to print?
15:04justin_smithkaiyin: there is no such thing, but there is still a way to do what you are actually trying to do
15:05justin_smith,(apply + 1 2 3 [4 5])
15:05justin_smithfor example
15:05clojurebot15
15:05xonevyeah, it sounds like you're wanting to use apply…
15:07kaiyinxonev, justin_smith I am looking for a keyboard shortcut to edit my code, :-D
15:08justin_smithkaiyin: ahh, that will depend on your editor, of course
15:08justin_smithbut paredit has "barf" for that
15:08kaiyinyeah, I am using intellij with cursive.
15:08kaiyinok, that's barf.
15:08kaiyinI see.
15:08justin_smithunappealing name, I know
15:09kaiyinjustin_smith, barf seems to just move things out the brackets?
15:10kaiyinIn cursive, it turns [2 3] into [2] 3, and if you barf again, it becomes [] 2 3
15:11xonevkaiyin: yes, that's what it does in paredit, as well, i believe.
15:11xonevIt doesn't completely remove the brackets
15:11ziltikaiyin: What you're looking for is paredit's splice
15:11scottjkaiyin: paredit-splice-sexp
15:12kaiyinok, i see.
15:12kaiyinthanks
15:12justin_smithI would usually just barf out all the contents then remove the empty braces, but splice is more direct I guess, yeah
15:12ziltiThere are really weird things in paredit ^^ And paxedit goes even further
15:13kaiyinthose names are really weird. :-)
15:13ziltiYeah, plus the names
15:32kaiyinWhat is wrong with this? https://gist.github.com/kindlychung/0749c3380eff319ed4d4
15:33AimHereTry :else
15:33gfrederickskaiyin: clojure functions are not infix
15:33AimHereAlso what he said
15:33gfredericks,(3 > 10)
15:33imanccan any explain how the anon functions get %1 and %2 params passed to them in this code fragment: http://pastie.org/9834054
15:33clojurebot#<ClassCastException java.lang.ClassCastException: java.lang.Long cannot be cast to clojure.lang.IFn>
15:33gfredericks,(< 3 10)
15:33clojurebottrue
15:33gfredericks,(> 3 10) ; I guess is the equivalent one
15:33clojurebotfalse
15:34gfredericksimanc: nothing is calling those functions so I'm not sure what you're asking
15:34imancgfredericks: so they're not being called at that stage? I'm just trying to understand what the code is doing.
15:35imancgrr
15:35gfredericksimanc: the code creates a local called `cmd` that is a function
15:35gfredericks,(let [cmd #(+ %1 %1 %2)] (cmd 3 4))
15:35clojurebot10
15:35mavbozo,(#(= %1 %2) 'a 'b)
15:35clojurebotfalse
15:35gfredericks^ you can call such a thing like so
15:35imancdamn, that's so obvious now
15:36imancso it's binding one of those functions to the cmd based on whether coll is a map
15:36gfredericksyep
15:37kaiyinOh my. Old habits die hard...
15:37gfrederickselse: => :else is also important
15:38gfredericks:else is just a generic keyword in this usage, you could change it to :or-whatever and it would work the same way
15:38gfredericks:else is used idiomatically for readability
15:38kaiyinok.
15:38kaiyinelse: is from python, :P
15:39imancha ha
15:39gfredericksI wish cond took a default expr like case does
15:39gfredericksjust for consistency
15:39gfredericksless explaining to do, not much lost
15:40justin_smithgfredericks: yeah, and fully unambiguous based on arg count, bad impl choice imho
15:40imancI thought cond did support a default expression ..
15:40justin_smithone of the few bad choices in clj
15:40gfredericksjustin_smith: wait can't we change it backwards compatibly?
15:40gfredericks,(cond 1 2 3 4)
15:40clojurebot2
15:40gfrederickserm
15:40gfredericks,(cond 1 2 3 4 5)
15:41clojurebot#<CompilerException java.lang.IllegalArgumentException: cond requires an even number of forms, compiling:(NO_SOURCE_FILE:0:0)>
15:41gfredericksyeah
15:41gfrederickscould totally just add that
15:41justin_smithgfredericks: 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:41gfredericksjustin_smith: in that sense every change is breaking though
15:41justin_smithindeed
15:41justin_smithyeah, I would call it effectively non-breaking :)
15:42justin_smithgfredericks: just the compulsion to look for the weird edge case, ya know
15:43gfredericksI don't see a ticket for this
15:44gfredericksI'll just make one what could it hurt
15:44gfrederickswait
15:44gfredericks,(case 3 4 5)
15:44clojurebot#<IllegalArgumentException java.lang.IllegalArgumentException: No matching clause: 3>
15:44gfredericks,(cond false 3)
15:44clojurebotnil
15:45gfredericksis that difference potentially an issue at all, or is it totally orthogonal?
15:45justin_smith,(case 3 3 true false)
15:45clojurebottrue
15:45TimMcgfredericks: http://xkcd.com/1172/
15:45TimMc("Workflow")
15:46justin_smith,(case case case case)
15:46clojurebot#<CompilerException java.lang.RuntimeException: Can't take value of a macro: #'clojure.core/case, compiling:(NO_SOURCE_PATH:0:0)>
15:46justin_smithhaha
15:46TimMc,(cond)
15:46clojurebotnil
15:46gfredericks,(cond cond cond cond cond)
15:46clojurebot#<CompilerException java.lang.RuntimeException: Can't take value of a macro: #'clojure.core/cond, compiling:(NO_SOURCE_PATH:0:0)>
15:46TimMc\o/
15:46justin_smith,(case #'case #'case #'case)
15:46clojurebot#<IllegalArgumentException java.lang.IllegalArgumentException: No matching clause: #'clojure.core/case>
15:46gfredericksanyhow does this still sound worth proposing?
15:48justin_smithgfredericks: I think so, yes
15:48amalloyi don't see any advantage to supporting a default case for cond. it makes the API less regular
15:48amalloy"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:49amalloyand 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:50TimMcamalloy: Is this something you dislike about case as well?
15:50amalloyTimMc: no, case has no choice
15:50mavbozo,(doc cond)
15:50clojurebot"([& 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:51amalloysimilarly condp has no choice
15:51TimMcHah, it actually documents the nullary case.
15:51mavbozowhy there's no mention of :else ?
15:51justin_smithmavbozo: because :else is just a convention
15:51justin_smith,(cond 1 nil true :yolo :else)
15:51clojurebot#<CompilerException java.lang.IllegalArgumentException: cond requires an even number of forms, compiling:(NO_SOURCE_FILE:0:0)>
15:51justin_smithblerg
15:51TimMcYou could instead use :suddenly or any other truthy value.
15:52amalloyTimMc: 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:52amalloyit's all relative to whatever expression you're comparing to
15:52justin_smith,(cond nil true false :whatever :yolo :else)
15:52clojurebot:else
15:52TimMc,(cond (= 2 :cats) :wow, :nil :oh-i-see)
15:52clojurebot:oh-i-see
15:52TimMcamalloy: Fair point. :-)
15:53gfredericksamalloy: I think it will read as well as any other implicit-pairs syntax
15:53gfredericksin particular as well as case does
15:53mavbozo,(cond (= 2 :cats) :wow, :yolo :oh-i-see)
15:53clojurebot:oh-i-see
15:54mavbozois there any conditional expression that throws exception if no test match?
15:54mavbozo,(doc condp)
15:55clojurebot"([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:55amalloycase
15:55mavbozo,(doc case)
15:55clojurebot"([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:55amalloy&(case 1)
15:55lazybotjava.lang.IllegalArgumentException: No matching clause: 1
16:00TimMcsadness
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{blake}TimMc: What's up?
16:02TimMc{blake}: amalloy's (case 1) demo
16:03gfredericksTimMc: you want a compile error?
16:03{blake}amalloy: Was ist?
16:04TimMcgfredericks: It should yield 1.
16:04amalloyTimMc: what???? no it shouldn't
16:04TimMcFour question marks, I must be super wrong.
16:04amalloyyou could argue that (case 1 1) should, but certainly not (case 1)
16:05TimMcOh! Whoops.
16:05TimMcForgot the input. :-P
16:06TimMcYes, compile error would be nice there.
16:07amalloyTimMc: for (case 1)? i suppose so
16:09TimMcFor my next trick, I'll argue that (case 2) should *also* yield 1.
16:11amalloynono, 1 is truthy. you mean 0
16:12TimMcNonsense, for any compile error it should count the arguments.
16:12TimMcYou're thinking of (case).
16:13amalloyhah, i love it. (defn foo (+ 1 2 3)) ;; succeeds, yields 2
16:17TimMcReminds me of that compiler that will agressively remove chunks of your code until compilation succeeds. Was it for JS?
16:21amalloyTimMc: fuckitjs
16:23TimMcyeah!
16:24TimMcI knew there was profanity in the naem but couldn't come up with the right combination.
16:25amalloyi have this vague notion that there's a ruby port, but i can't find it
16:25amalloyoh, https://github.com/programble/fuckit.rb
16:26hlshipAnyone familiar with Leiningen deployments handy? I'm having trouble deploying to a Nexus repository.
16:26amalloyinterestingly doesn't show up at all under a google search for "fuckitrb"
16:27amalloy~anyone
16:27clojurebotJust 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:27amalloyhiredman: 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:27hlshipIt's an https://... URL, but I get an error "No connector available ... of type default ..."
16:28hlshipAnd it lists WagonRepositoryConnectorFactory, which I believe should be able to do an HTTPs upload
16:30hiredmanamalloy: I'll but it on my trello board before "make a ladder" but after "lambda lifting letfns"
16:30hiredmanput
16:31hlshipInterestingly, Gradle *can* deploy to this repository, and both Gradle and Lein are just wrappers around the Maven libs for doing all this
16:31ghadishayban,(into (map inc) [1 2 3 4 5])
16:31clojurebot#<ClassCastException java.lang.ClassCastException: clojure.core$map$fn__4507 cannot be cast to clojure.lang.IPersistentCollection>
16:31ghadishayban,(into [] (map inc) [1 2 3 4 5])
16:31clojurebot[2 3 4 5 6]
16:34TimMcoh right, transducers
16:34hyPiRionhlship: is this with 2.5.1 or 2.5.0 or something else?
16:34hlship2.5.0 on OS X
16:34hlshiphave to run shortly
16:34hlshiplet me try an upgrade
16:36hlshipSame behavior
16:38hlshiphttps://gist.github.com/hlship/5dc0e03ee42652a48537
16:38hlshipttyl
16:40hyPiRionbleh, the aether/proxy/download issues are piling up
16:41nicferrierworking out data structures. lah dee dah.
16:56djamesIs there already a function that I've overlooked that iterates until stable (I wrote this: https://gist.github.com/xpe/46128da5accb0acdf30d)
16:58gfredericks(->> (iterate f x) (partition 2 1) (filter (fn [[x1 x2]] (= x1 x2))) (ffirst))
16:58gfredericks^ another way to do it
16:58kaiyinloop can be implemented with reduce, right?
16:59djamesgfredericks: that's a fun way to do it
16:59gfredericksyeah
16:59amalloygfredericks: (partial apply =)
16:59djameskaiyin: you can't add a terminating condition to reduce. it cranks until its input collection is exhausted.
16:59gfredericksamalloy: bleck I hate partial apply
17:00amalloyreally? why?
17:00amalloydjames: ##(doc reduced)
17:00lazybot⇒ "([x]); Wraps x in a way such that a reduce will terminate with the value x"
17:00gfredericksit's so long
17:00djameskaiyin: *some* examples of loop can be better represent as reduce
17:00gfredericksamalloy: I also hate it more if it's going to be applied to a tuple rather than a homogeneous variable length collection
17:01amalloygfredericks: (def ap (partial partial apply))
17:01amalloy(ap =)
17:01djamesamalloy: good point!
17:01gfredericksyeah I've definitely thought about aliasing it before
17:01djamesamalloy, kaiyin : I'd still challenge someone to write repeat-until-stable with reduce :)
17:01gfredericksI should get plumbing to add it
17:02gfredericks(defn repeat-until-stable [f x] (reduce (fn [x1 x2] (if (= x1 x2) (reduced x1) x2)) (iterate f x)))
17:02djameskaiyin: I was incorrect before, you can use reduced to terminate a reduce early
17:03amalloydjames: now, reduce is still less general than loop. but not because you can't abort early
17:04djamesgfredericks: excellent. you win a trip to the Bahamas
17:07hellofunkwhat is responsible in emacs for adding those red squiggly underlines when things go long, usually for me under a ns form?
17:07hellofunk*wrong
17:09gfredericksI only see that in magit commit msgs
17:09gfredericksmust be a shared functionality
17:09hellofunki thought maybe it was a linter or something, but i don't have the clojure linting installed
17:15dagda1can I pass arguments that are not destructured and arguments that are, e.g. [coll [x xs]]
17:15djamesdagda1: yes
17:15djamesoh, pass?
17:16djamesyes
17:19nicferriercan I put a buffer on a core.async queue?
17:19gfredericksdestructuring is just something the function does to its arguments, it's not visible or relevant to the caller
17:19nicferrieror channel.
17:20nicferrierooo. yes.
17:21justin_smithnicferrier: 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:21nicferrierjustin_smith: I want to buffer the channel so it doesn't block immediately.
17:21amalloyi think you get a warning, not an error
17:21justin_smith{blake}: right, another reason not to er... "use" use
17:22amalloyjustin_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:22amalloysadly, only lazybot
17:23{blake}justin_smith: Damn rookies!
17:23justin_smithnicferrier: I trust you found the optional arg to chan
17:23nicferrierjustin_smith: I did.
17:24nicferrierI'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:24nicferrierI'm trying to use it to bridge between 2 httpkit async stacks.
17:24nicferrierand it's confusing.
17:25kenrestivoo_0
17:25justin_smithnicferrier: 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:29tcrayford____justin_smith: it's on the goggle grup
17:33justin_smithtcrayford____: 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:33tcrayford____haha
17:34amalloyjustin_smith: http://www.reddit.com/r/bestof/comments/216ov7/utheoman333_misspells_a_word_so_horribly_that_it/
17:35tcrayford____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:36amalloy|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|blake|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:38justin_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|blake|justin_smith: I know muffins.
17:39justin_smith|blake|: /msg nickserv ghost {blake} pwd
17:39|blake|But I'll check it out.
17:39justin_smiththat will kick the ghost {blake} off irc
17:39amalloybut {blake} isn't on irc now
17:40|blake|justin_smith: OK, I'll try that next time.
17:40|blake|Well, okay, yesterday I fixed my NVidia drivers so that it would use all four monitors.
17:40justin_smithamalloy: 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|blake|No, when I got everything sorted out HexChat refused to go past ident. So I was using an online IRC.
17:40amalloythat'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:41justin_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:41amalloymaybe you never bought a pillow at all
17:42amalloy#clojure minutes, 2015-01-15, 22:40 UTC. justin_smith excommunicated for using the word "lappy"
17:42justin_smithhaha
17:42|blake|justin_smith: I've been sitting here with two working monitors, and two none for a year.
17:42|blake|Then I got a new box, and managed to get three working.
17:45TimMctcrayford____: I thought "goggle grup" was intentional. :-)
17:46justin_smithI have definitely seen "rubby" used intentionally (to great comic effect)