#clojure log - Feb 11 2014

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

0:01 dobry-den: What database would yall use to log pageviews (just ip, referer, and destination)

0:04 technomancy: dobry-den: that sounds like a canonical redis use case

0:06 or like ... flat files?

0:06 arrdem: (inc flat-files)

0:06 lazybot: ⇒ 1

0:06 technomancy: obligatory http://www.brandonbloom.name/blog/2013/06/26/slurp-and-spit/

0:07 Wild_Cat: I'm thinking sqlite would do the job nicely too

0:07 (or whatever the JVM equivalent is)

0:07 technomancy: Wild_Cat: from any other language, sure

0:07 dobry-den: technomancy: generally speaking, if you were just tracking unique IPs that hit each page, do you generally log everything naively and then post-process to find uniques. or would you just do the uniq check as you go?

0:07 technomancy: the jdbc bindings to sqlite are rubbish though

0:07 Wild_Cat: technomancy: HSQL then, maybe?

0:07 bob2: then you have (inc n) problems?

0:09 technomancy: Wild_Cat: if it fits on a single server I'd just use a file and an atom in memory

0:09 Wild_Cat: technomancy: sure.

0:10 dobry-den: oh duh. that's what i'll do for now

0:10 well, that atom would fill up fast

0:11 Wild_Cat: dobry-den: actually, do you even need to access the data from the process that writes it?

0:12 dobry-den: if not, just open a text file and keep appending lines to it.

0:12 dobry-den: Wild_Cat: all the main process really needs is access to a "Unique Views" counter that's computed elsewhere

0:13 Wild_Cat: cool, that's good enough for now

0:13 Wild_Cat: I'd probably log naively and postprocess later.

0:13 dobry-den: yeah, logging everything would give me insight into actual activity

0:13 thanks

0:14 Wild_Cat: I guess you'd do the write in a future

0:14 Wild_Cat: dobry-den: not even.

0:15 dobry-den: oh, is it thread safe?

0:15 to just write?

0:15 (not that a future would fix it)

0:15 Wild_Cat: dobry-den: if you use a line-buffered output stream, yeah, it is

0:16 arrdem: Wild_Cat: linebuffered is synchronized by default? til....

0:17 dobry-den: Wild_Cat: do i need to do something special for that?

0:17 Wild_Cat: arrdem: I'm actually uncertain what the situation is on the JVM.

0:17 arrdem: dobry-den: worst case, just have a work queue atom and a worker thread that does all the writes...

0:18 message passing FTW

0:19 dobry-den: in fact i'm already using core.async just for (go-loop [] (<! (timeout (* 1000 60 5))) (flush-cache))

0:19 i'll get a channel set up

0:20 when do you know to use a thread vs go block for something like this?

0:21 * arrdem claims no knowledge of core.async and patterns

0:22 Wild_Cat: dobry-den: all java.io.Writer subclasses have a lock attribute, but Writer doesn't specify how or if it should be used.

0:22 ...and then none of the subclasses document how it's used.

0:23 dobry-den: Wild_Cat: exactly. i'll just push views onto an async channel that consumes it on another thread

0:24 Wild_Cat: dobry-den: fair enough. I mean, if you're all-async in the first place, that can't hurt.

0:24 arrdem: that kinda synchronized main print queue is sitll something I want to put in my OS...

0:24 Wild_Cat: man, this is reminding me of how bad the Java I/O class hierarchy is.

0:25 (yay manual buffering and then accidental buffering of buffered buffered buffered buffers >.< )

0:30 arrdem: :D

0:30 yo dawg I heard u like buffers....

0:36 Wild_Cat: arrdem: class XzibitOutputStream...

0:38 sdegutis: Writing ClojureCLR and it's pretty fun :)

0:55 Tolstoy: This OM component state management thing is confusing. At least for big lists of widgets.

1:08 sm0ke: how do i convert a trasient back to immutable?

1:08 TEttinger: sm0ke: persistent!

1:09 ,(doc persistent!)

1:09 clojurebot: "([coll]); Returns a new, persistent version of the transient collection, in constant time. The transient collection cannot be used after this call, any such use will throw an exception."

1:09 sm0ke: TEttinger: thanks!

1:09 (inc TEttinger)

1:09 lazybot: ⇒ 14

1:09 TEttinger: np, transients are neat but you do need to be careful of what functions support them

1:10 sm0ke: yep, i see they normally have ! suffixed function counterparts

1:10 assoc!, dissoc!

1:10 TEttinger: indeed, but there aren't counterparts for most "read" operations. nth and get work on transients, not much else

1:11 sm0ke: ah yea, good one

1:11 i was using get without thinking about it

1:11 amalloy: seq can't work on transients, especially

1:41 systemfault: If I use emacs as my editor, should I spend time learning paredit?

1:42 sdegutis: Woo.

1:44 egghead: yes systemfault

1:44 paredit is great in every lang

1:44 systemfault: Really? I thought it was some cool LISP-only thing

1:45 sdegutis: systemfault: yes.

1:46 egghead: systemfault: it balances syntax like ', ", [, {, (, etc, all langs need those things matched

1:46 but yes it makes programming w/ parens blissful

1:46 systemfault: Hmm, cider already does that

1:46 egghead: not all langs, not apl

1:47 TEttinger: heh, J. [ has no need to be matched!

1:49 Tolstoy: systemfault: The fun with paredit is the other editing stuff. Like "kill to end of line" is remapped to erase everything up to the next balancer paren.

1:49 balanced. ;)

1:50 systemfault: Ah, I see :)

2:43 sdegutis: Yay, it's done-ish.

2:43 https://github.com/sdegutis/ZephSharp

2:48 Uses ClojureCLR for scripting :)

2:50 TEttinger: neat sdegutis

2:51 sdegutis: Thanks TEttinger.

3:07 sm0ke: hmm ok i swear i have something like (when ... (assoc! n [i j] k) (prn i j k)) ... i can see 1 2 3 printed but ..its not present in the final map!

3:08 n is transient, and i did a prersistent! for the final map

3:08 true story.

3:21 ok i replace transient with an atom, and things work!

3:32 ,(let [t (transient {})] (doseq [i (range 20) j (range 20) k (range 20)] (assoc! t [j k] i)) (persistent! t))

3:32 clojurebot: {[0 0] 19, [0 1] 19, [0 2] 19, [0 3] 19, [0 4] 19, ...}

3:32 sm0ke: ,(let [t (atom {})] (doseq [i (range 20) j (range 20) k (range 20)] (swap! t assoc [j k] i)) @t)

3:32 clojurebot: {[2 1] 19, [3 2] 19, [4 3] 19, [5 4] 19, [6 5] 19, ...}

3:33 sm0ke: can you guys try this in your repls?

3:33 why is transient has loss of writes?

3:33 does*

4:03 pyrtsa: sm0ke: Curiously, it's because you shouldn't actually think transient assoc! works (entirely) in-place. Looks like every 8 items inserted, it creates a new return value. Thus, instead of doseq, use reduce.

4:03 * pyrtsa didn't know!

4:04 pyrtsa: Or actually, it's not the transient assoc! but the way transient maps are implemented.

4:05 sm0ke: whatever it is i dont know whats it good for

4:06 i am using a HashMap, ftw

4:06 pyrtsa: sm0ke: Did you read what I just said?

4:07 Transients are pretty much only good for optimizing the construction of a collection, single-threaded. They could be more but they aren't.

4:08 For an example, see (source into)

4:14 The documentation of ##(doc assoc!) is slightly off.

4:14 lazybot: ⇒ "([coll key val] [coll key val & kvs]); Alpha - subject to change. When applied to a transient map, adds mapping of key(s) to val(s). When applied to a transient vector, sets the val at index. Note - index must be <= (count vector). Returns coll."

4:14 pyrtsa: It doesn't always return `coll`.

4:46 bob2: Expected: (clojure.lang.IPersistentMap clojure.lang.Symbol java.lang.String)

4:46 Actual: (IPersistentMap (U Symbol (Value :dark-feature-value)) String)

4:46 shouldn't they match?

5:01 ivan: bob2: :dark-feature-value is a Keyword, no?

5:02 (note I don't know core.typed so I'm guessing what that means, sorry)

5:10 borkdude: What is that irc client that is always connected, starting with a z?

5:11 somehow I only remember first letters of things

5:11 algernon: znc?

5:11 borkdude: yes, tnx

5:11 Anderken1: in all fairness, znc is a prettty hard name to remember

5:11 what does it stand for?

5:13 borkdude: I have no clue

5:13 I think it is a play on bnc, which means bouncer

5:14 Anderken1: yeah, that'd fit

5:56 AeroNotix: Does Ring work with Clojurescript?

5:57 or portions of it

5:57 dsrx: what do you mean by that?

5:57 AeroNotix: I just saw this: http://clojurescriptone.com/documentation.html

5:57 Anderkent: yeah, there's also some middleware that lets you recompile scripts on every request while developing etc.

5:57 AeroNotix: huh

6:10 d11wtq: I grapple with this. Do you reckon if you've written (and tested) a convenience function for pulling something from a data store (for example), you should be able to use that function in assertions in other tests?

6:11 If you use it, you get more readable tests, but on the other hand, if you at some point introduce a regression that breaks the convenience function, you get a cascade of failures through your test suite, making it hard to identity the root cause.

6:11 s/identity/identify/

6:11 AeroNotix: Yes.

6:12 Because you're testing the convenience function so you tests should fail in a predictable manner.

6:13 Anderkent: d11wtq: that's fine; another approach is to mock the conveniance function for other tests. Depending on how common it is through your code it might or might not be worth the effort

6:14 d11wtq: AeroNotix: Yeah, but if the convenience function test failures are buried in a sea of thousands of other failures, it might not be obvious that it is the cause. I suppose this is entirely academic in practice.

6:14 I've been bitten by it once or twice in a 10 year career, not much.

6:14 Anderkent: yeah, it's a minor inconveniance; I'd guess if you went to mocking it you'd be just as likely to have an error in your mock than in the original function :P

6:14 d11wtq: Anderkent: I tend to agree.

6:15 Was just thinking out loud in here as I was about to go down this path :)

6:15 Thanks for the input!

6:16 AeroNotix: You need to fix your error reporting if you get lost

7:01 bob2: ivan`, oh, you're totally right - thanks!

8:39 mdrogalis: cemerick: ping once more :) Sorry

8:43 cemerick: mdrogalis: go for it

8:43 mdrogalis: cemerick: Heh. Philly ETE, yeah?

8:43 Saw your tweet yesterday.

8:44 cemerick: mdrogalis: I don't remember what I tweeted an hour ago :-P

8:45 mdrogalis: cemerick: Haha, fair. Your talk just sounded interesting.

8:46 cemerick: mdrogalis: ah, right. Yeah, I hope so

8:46 I certainly think so :-)

8:47 mdrogalis: I live in Philly if you want to get drinks after and geek out. Stalking ambrosebs too. :P

8:47 cemerick: I hope the organizers aren't aggro'd; I think they thought I'd be talking about Clojure

8:47 Oh, sure, I'm sure all the Clojure folk will rove about in unison.

8:47 mdrogalis: Hm. Yeah, not sure how they'll react to that.

8:48 Cool.

8:48 cemerick: They gave me carte blanche, so I'm not going to worry so much.

8:48 I just hope I don't get slotted opposite Jeff Hodges or something. :-P

8:49 mdrogalis: That wouldn't feel so great.

8:49 read: That won't feel great for whoever gets it.

9:03 cmiles74: 16:11 *** LLKCKfan QUIT Excess Flood

9:11 effy: is there something analog to ML pattern matching in clojure (outside of multimethod) more like a "cond-ish" thing ?

9:12 Anderkent: effy: I'm not sure what ML pattern matching is, but maybe core.match?

9:13 effy: Anderkent: sweet, i think you pointed just in the middle :)

9:16 mathw: yes, core.match is rather like ML-ish pattern matching

9:16 at least as far as I've used it

9:32 krl: anyone know a channel for datastructures?

9:33 chouser: core.async provides channels for data structures. <rimshot />

9:35 AimHere: krl, ##programming will be a general CS/programming channel, where datastructures will be on topic

9:38 krl: AimHere: thanx

9:39 ambrosebs: $200 bounty to build an Emacs plugin for Typed Clojure https://www.bountysource.com/issues/1406536-emacs-plugin-for-typed-clojure

9:50 pcn: Is there documentation on what thatwould mean?

9:51 ambrosebs: pcn: for the emacs plugin? rough notes here, get in touch with me if you're considering it and we can talk http://dev.clojure.org/jira/browse/CTYP-103

9:52 not looking for much

10:06 pcn: I've got no skillz for that, but I'd be interested in trying it out - maybe chipping in a few bucks if I understand what's going on there.

10:12 ambrosebs: pcn: cool. Right now Typed Clojure just spews out type errors, it would be nice if they were hyperlinked to the sources. And just some bindings that type check specific forms and do some refactorings.

10:12 That's all I'm really after

10:12 I implemented the hyperlinking for vim in about 150 lines of viml

10:13 to give an idea of the scope

10:17 ohcibi: hi, is there something like map, but like that it also replaces the values if f returns a trueish value?

10:18 teslanick: Can you provide an example of the transformation you're looking for?

10:18 Anderkent: ohcibi: to make it clearer, do you want to replace every value x for which (f x) is true with (g x), and otherwise leave x unchanged?

10:19 the simplest way to do that is just (map (fn [x] (if (f x) (g x) x)) xs)

10:19 ohcibi: (magic-map #(when (= 1 %) "hello") [0 1 2]) --> [0 "hello" 2]

10:20 like replacing only one value that matches a predicate

10:20 Anderkent: ooh, only one?

10:20 ohcibi: uhm

10:20 lemme think if it must be limited to one...

10:20 Anderkent: if it's all values that match, see my post above

10:20 cark: how about (map #(if (=1 %) "hello" %) ... )

10:21 oh only one

10:22 Anderkent: if it must be just the first, I think you have to do first split-with to find the first occurence, then replace the single element, then concat

10:25 pcn: ambrosebs: yeah, the update to the jira makes it clearer what you're asking for

10:26 ambrosebs: pcn: ok

10:26 ohcibi: hm okay.. the solution with (if) would replace the values that should not be changed with the same values (thus leaving them unchanged) is there no way that would just only touch the ones that should be replaced?

10:26 sdegutis: I wrote a window manager for Windows that's scriptable in ClojureCLR! So excited :)

10:27 chouser: sdegutis: wow, that sounds powerful.

10:27 sdegutis: https://github.com/sdegutis/ZephSharp

10:27 It's API is a little limited compared to Zephyros, because it's only a few days old. But the plan is to get there soon.

10:27 Anderkent: ohcibi: well, you have to look at every value to decide if it matches the condition anyway; returning it unchanged or not touching it are the pretty much equivalent

10:28 sdegutis: chouser: :)

10:37 ohcibi: lets say I have a map that contains a vector, like {:myvector [1 2 3]} with (assoc-in mymap [myvector 3] 4), I would append a 4 to this vector... is this possible by appending (i.e. without needing to specify the 3 as index?)

10:39 mikerod: ,(update-in {:myvector [1 2 3]} [:myvector] conj 4)

10:39 clojurebot: {:myvector [1 2 3 4]}

10:39 mikerod: ohcibi: How's that

10:40 ohcibi: mikerod: sweet... thanks

10:42 mikerod: ohcibi: `update-in` is intended to let you make an "update" to the map that is a function of what is already there (or nil if missing). `conj` on a vector returns a vector with the args appended to the end (the efficient end for a vector).

10:43 ohcibi: yep... basically I wanted to ask for a function that would "somehow work with conj" but I didn't know how to explain it, so I asked for the basecase 8-))

10:44 mikerod: ohcibi: I see

10:44 if you were unsure of the map having a vector already at that key, and you wanted to have the value be a vector, you could have it like:

10:44 ,(update-in {:myvector [1 2 3]} [:myvector] (fnil conj []) 4)

10:44 clojurebot: {:myvector [1 2 3 4]}

10:44 mikerod: ,(update-in {:myvector nil} [:myvector] (fnil conj []) 4)

10:44 clojurebot: {:myvector [4]}

10:45 mikerod: ,(update-in {} [:myvector] (fnil conj []) 4)

10:45 clojurebot: {:myvector [4]}

10:48 ben-o: byte and/or byte-array question: how can I select the first n bytes of a byte-array? Thanks.

10:49 llasram: ,(let [ba (byte-array (map byte [1 2 3 4]))] [ba (take 5 ba)])

10:49 clojurebot: [#<byte[] [B@1b8d481> (1 2 3 4)]

10:50 ben-o: @llasram-let me give that a quick try- thanks!

10:51 llasram: ben-o: np. And FYI, the convention on IRC is to just refer to someone's handle directly -- no '@'-prefix

10:51 ben-o: oh ok

10:52 sdegutis: Couldn't figure out the syntax for accessing enumeration values in ClojureCLR.

11:01 dobry-den: How do you decide between a core.async `go` block and a dedicated `thread`?

11:02 AeroNotix: coin flip

11:02 CookedGryphon: dobry-den: things like whether there are any blocking operations happening

11:02 if you are using an api which blocks for a while for example, use a thread, otherwise you will interfere with the thread pool that gets used for go blocks

11:02 there's probably other considerations too

11:04 dobry-den: CookedGryphon: Honestly I thought the point of a go block was that you could do something that would otherwise block the flow of execution.

11:04 teslanick: dobry-den: The go block only protects you from channel blocking, if you're using an API that does other blocking, go blocks can't help you.

11:05 dobry-den: Ohh.

11:05 teslanick: At least, that's my understanding.

11:05 "Blocking" in channels actually parks the go, and frees up the thread for other code to run.

11:06 dobry-den: So `go` is really for servicing channels

11:07 Anderkent: yeah; for interacting with external event-based or blocking interfaces the common thing to do is to have a very simple poller / thread that just reads from the external interface and puts stuff into channels (or the other way around)

11:07 so your business logic can live in go blocks and service only channels

11:09 dobry-den: What kind of benefits do you lose if you naively use `thread` instead of a `go` block for servicing a channel?

11:10 Anderkent: well, every read / write will actually block the thread; you can have many more go routines than threads

11:11 dobry-den: Anderkent: i guess my problem is that i read that, and i can nod along, but i don't really grasp it. what kind of resources should i check out to get a better mental model of how threads work?

11:11 i've read java's docs on threads/concurrency, but they don't really answer those questions.

11:11 they just explain the API

11:11 Anderkent: each thread is an actual OS threads; they have their own stacks, related data structures etc.

11:12 it's basically about the memory cost

11:12 dobry-den: for example, I don't understand why read/write "blocks" a thread (or what that means) and why go can ameliorate that

11:12 Anderkent: oh

11:12 well, in a (go) routine if your code tries to read from an empty channel

11:12 it'll just 'park', which means it will stop execution, save the current state and let another goroutine run on the same machine thread

11:12 whereas if a (thread) tries to read from an empty channel

11:13 it will 'block' the machine thread - i.e. this thread will not do anything until the channel can produce a value

11:13 pbostrom: dobry-den: this is a pretty good read: http://martintrojer.github.io/clojure/2013/07/07/coreasync-and-blocking-io/

11:13 dobry-den: oh, so that's what it means when there's a "pool of special go threads" - they just take turns on the same OS thread

11:13 Anderkent: yeah

11:14 teslanick: You can configure it to use any Java thread pool (IIRC, I've never fooled with it)

11:14 Anderkent: now it sometimes makes sense to have a lot of blocked threads

11:14 dobry-den: pbostrom: thanks, that looks awesome. i'll check that out

11:14 Anderkent: for example if you only have the old fashioned io interfaces, you don't want to be polling from hundreds of sockets; you want to make a thread for each and let them block

11:15 otherwise if all the sockets are empty you'll just waste cpu spinning around

11:15 (of course this is all irrelevant if you have an event based io interface)

11:15 but in general, tens of thousands of go routines shouldn't be a problem

11:15 whereas tens of thousands of threads can be onew

11:16 (since each thread has its own allocated stack space - I think 128k minimum)

11:16 (so a thousand threads uses 128M of memory ; ten thousand brings you into gigabytes *just* for the stack space)

11:16 (and linux threads used to be notoriously expensive; I heard it's better now)

11:17 dobry-den: Anderkent: where did you learn about OS-level things like IO and threads? Do you have a background in lower level languages like C?

11:18 Anderkent: college :P

11:18 the details are fuzzy but I remember the general idea

11:18 dobry-den: i got into programming 75% of the way through a finance degree.

11:18 teslanick: Yeah, that's totally a thing they stomp into you in a CS program. THREADS HARD, THREADS EXPENSIVE :)

11:18 dobry-den: didn't even teach us cobol :(

11:19 cleatoma: Your smiley is the wrong way around there.

11:19 Anderkent: D:

11:20 dobry-den: what language did yall predominantly use in your CS programs?

11:20 teslanick: Eh. It kept me away from it for ten years. When I first learned programming, it didn't make sense to parallelize because everything was single-core. Now it doesn't make sense not to, and the abstractions have gotten pretty good.

11:21 Anderkent: dobry-den: AFAIR it went haskell -> java -> c (total of 1 week) -> x86 assembly (another 1 week) -> C++ (2 weeks) -> java

11:21 teslanick: The first language anyone taught me was C. Before that I taught myself (terrible terrible) JS, which is how I snuck into college with terrible grades. After C was C++ and then finally Java.

11:21 Anderkent: but honestly for everything after hte first year it was fairly language agnostic

11:22 you'd learn stuff like compilers or software engineering practices or maths (lots of maths) or type theory

11:22 sdegutis: dobry-den: VB.NET

11:22 Anderkent: practicals in language of choice, which for some ment java, some c#, and for some vimscript (once.)

11:22 teslanick: Yeah. It becomes less about what you write and how you write it, and how you should think about it.

11:22 Anderkent: seriously, don't do vimscript.

11:22 dobry-den: well i switched to emacs like an adult

11:23 i realized that my vimrc rested precariously on the productivity of tpope

11:23 Anderkent: haha

11:24 I've been thinking of moving to evil for like 2 years now

11:24 sdegutis: It's a trap.

11:24 Anderkent: no time to really do it

11:24 dobry-den: Anderkent: were you previous a vim user in your life

11:24 Anderkent: I'm a vim user right now

11:25 sdegutis: Anderkent: There's never time, you just have to make time for it.

11:25 Anderkent: And that's only worth it if you're convinced that you'll actually be more productive after learning it.

11:25 dobry-den: i was all vim and a fulltime ruby developer when i decided to jump in to clojure + emacs + evil + nrepl all at once.

11:26 sdegutis: I'm now convinced I'm more productive in emacs than vim. I still hate emacs though.

11:26 Anderkent: yeah, I guess I haven't yet

11:26 AimHere: You tried one of emacs vi emulation modes yet?

11:26 sdegutis: I'm pretty sure text editors are a practical joke that computer scientists play on programmer communities at large just for fun.

11:26 Anderkent: no, as I said, I'd be switching to one of these

11:26 sdegutis: It's kind of mean-spirited of them if you think about it.

11:26 Anderkent: but it's everything *around* the core comands that I'd have to learn

11:27 dobry-den: evil is almost perfect. in fact, once you install emacs + evil, it's pretty much vim once you open a file

11:27 Anderkent: now, given, I've been withdrawing from my vim plugins recently, so it might be an opportunity

11:27 but still, I rarely sit down with vim when not trying to get something done; switching the editor would cause me to take much more time to get it done

11:27 for any value of it

11:28 and I'm not putting enough time into cloverage as-is :(

11:28 though, I suppose, if someone has a nice evil emacs setup for clojure that they'd like to share

11:28 I'm listening :P

11:28 dobry-den: https://gist.github.com/danneu/7185465

11:29 Anderkent: I've tried emacs live once, but it was a bit too much; and I think the keys conflicted with evil in some parts

11:29 dobry-den: yeah it's way too much

11:34 Anderkent: whee, second 'external' pull request for cloverage! I'm getting so popular.

12:06 technomancy: "don't get cocky, kid." - Han Solo

12:06 sdegutis: Anyone wanna upvote this sucker? https://news.ycombinator.com/item?id=7218521

12:07 I love popularity contests!

12:07 `cbp: upvoted

12:08 sdegutis: :)

12:08 Thanks you two!

12:08 `cbp: Also will try next time I'm forced to use windows

12:08 sdegutis: :D

12:09 Anderkent: needs screenshots in the readme :P

12:10 sdegutis: Anderkent: It's the kind of window manager where you write a Clojure script that registers callback functions for global hot keys, which move/resize windows according to your likes.

12:10 Thus the closest thing to a screenshot is an example config. Which it has :)

12:10 Anderkent: yeah; so write a couple simple scripts and show what results they produce

12:10 sdegutis: Ooh, a screencast!

12:11 Anderkent: yeah, or the written form - text with screenshots / gifs :P

12:11 sdegutis: Hmm, that sounds easier.

12:12 Anderkent: just a couple examples like how to script a 2 column layout, 3 column, etc. (can it access multiple windows or just the active one?)

12:12 is there like a stack of recently opened windows on windows?

12:12 justin_smith: ,(apply str (map (comp char inc int) "gdkkn"))

12:12 clojurebot: "hello"

12:13 Anderkent: hm, no 'get-nth-active-window' in the api, so I gues not

12:13 sdegutis: Anderkent: Dunno about recent ones, but (get-all-windows) works.

12:14 Anderkent: mhm

12:14 well, from my experience trying to interact with the winapi windows api (goddamnit, microsoft) it's usually really painful

12:14 like, I remember tring to bring a window to front

12:14 sdegutis: Anderkent: Meh, it's actually pretty easy these days.

12:15 Anderkent: there's bringWindowToFront function, but it doesn't bring the window to the front unless a number of preconditions is met

12:15 sdegutis: Anderkent: See https://github.com/sdegutis/ZephSharp/blob/master/Zephyros/Window.cs

12:15 Oh maybe we just ran into different things.

12:16 andyf: Bronsa: ping

12:16 Bronsa: andyf: hi

12:16 andyf: Bronsa: Howdy. I guess you can tell I am back to testing Eastwood again :-)

12:17 Bronsa: heh, yeah I noticed :P

12:18 andyf: There is an exception during analyzing a namespace in core.async because it refers to a constant in another namespace that was defined with an ^int type hint. Older t.a(.jvm) didn't throw an exception for this case, but the newest one does.

12:18 The exception goes away if I delete the ^int type hint. I guess file a JIRA ticket and let you take a closer look?

12:19 Bronsa: andyf: yeah, definitely a bug

12:19 andyf: OK. Filing ...

12:20 Anderkent: andyf: wouldnt it be http://dev.clojure.org/jira/browse/TANAL-24 though ?

12:20 or is that a different pass

12:21 wait, that's your bug

12:21 andyf: Anderkent: I honestly don't know. I file bugs on the symptoms, not the causes :-)

12:22 Bronsa is cool that way

12:22 Anderkent: yeah, I suppose you'd know if the symptops are the same; I didn't notice the old one was also reported by you and thus figured it might be the same symptom

12:22 (it does look similar - exception on tag that is a primitive)

12:23 Bronsa: yeah, there's no point in making andyf figure out the cause of the bug since I can do that way faster.

12:23 if it turns out that it's the same bug it takes ~2 seconds to close as duplicate.

12:24 Anderkent: i suppose :)

12:31 Bronsa: andyf: Anderkent yeah, it's indeed a duplicate of #24 and thus a bug in core.async

12:31 andyf: Bronsa: OK, so just not caught by earlier t.a(.jvm) versions?

12:31 Bronsa: andyf: looks like so

12:32 andyf: Bronsa: You interested in filing a ticket for core.async?

12:33 The suggested patch is trivial enough -- it is the precise explanation of why that you are much better at than I am :)

12:34 Bronsa: andyf: heh, opening the ticket now

12:40 seangrove: Does anyone have a link that talks about the performance characteristics of clojure's persistent data structures?

12:48 dnolen_: seangrove: pretty sure Rich covers this in his early talks?

13:11 Anderkent: whee, merging pull requests is fun

13:20 gtrak: does anyone know any interesting, surprising, or heinous ways to mess with jruby from clojure?

13:21 technomancy: gtrak: there was a talk on that at the first clojure/west

13:21 gtrak: oh ha

13:21 I see it

13:22 dobry-den: ive interoped with JRuby once when I was too lazy to read Javadocs for the java bindings of a lib

13:22 technomancy: tl;dr: you can do this, but you really shouldn't

13:22 iirc

13:22 gtrak: I'm just going to start with trying to get a jruby proc to work in reducers

13:22 'jruby for performance-sensitive-code'

13:22 dobry-den: opt-in to mutability for perf

13:22 duh

13:23 technomancy: hehe

13:28 dobry-den: Can you really not copy the value of a cookie from Chrome's inspector?

13:28 what a boondoggle

13:34 SegFaultAX: dobry-den: Allow me to blow your mind: http://www.charlesproxy.com/

13:34 Also, you can copy and paste from the network tab.

13:35 teslanick: Charles Proxy is one of those tools you don't always use, but when you need it, it's the perfect tool for the job.

13:37 dobry-den: i hear good things. thanks

13:38 blackrose_: Hey guys, i'm new to irc and clojure

13:38 :)

13:38 technomancy: two of my favourite things

13:39 dobry-den: nice, this might be my chance to answer a question

13:39 blackrose_: Yeah

13:39 dobry-den: i'm deep in an ask deficit

13:39 AimHere: I didn't know someone was keeping a score

13:40 TimMc: AimHere: Yes, we are, and you'll be sent to Collections soon. o\__/o

13:40 dobry-den: lazybot keeps score

13:41 TimMc: where you will be forced to answer Yahoo! Answers questions for a minimum of 40 minutes.

13:44 blackrose_: I have a project. My boss ask to use clojure for server side

13:44 Wild_Cat: TimMc: is that the special-special hell for people too evil for the regular special hell?

13:45 blackrose_: Can you guys suggest where i should start ?

13:45 dobry-den

13:45 ?

13:45 SegFaultAX: blackrose_: What kind of project?

13:45 We need more details to set you on the right direction.

13:46 (Also, you have an awesome boss)

13:46 AimHere: Maybe it's a different kind of bad boss. Maybe three weeks ago, he demanded a server written in Scala, and before that haskell

13:46 SegFaultAX: AimHere: How could weighing all the options be a bad thing? :)

13:47 AimHere: There's weighing all the options, and then there's implementing all the options!

13:47 blackrose_: SegFaultAX It's to develop a tracking system

13:47 SegFaultAX: blackrose_: Go on...

13:47 AimHere: Heyooo!

13:47 blackrose_: base on ruuvitracker

13:48 S11001001: Learned something interesting today. Leiningen uses a *modified* EPL.

13:48 SegFaultAX: Is this backend thing a web service?

13:49 S11001001: Ironically, the paragraph that has been changed comes right after the paragraph that states that modifying its text is forbidden.

13:51 blackrose_: SegFaultAX yes.

13:52 pbostrom: blackrose_: are you asking how to run this: https://github.com/RuuviTracker/ruuvitracker_server

13:53 blackrose_: pbostrom yes, that's right.

13:54 pbostrom: you will need to lein: https://github.com/technomancy/leiningen

13:54 blackrose_: I'm trying

13:57 SegFaultAX: blackrose_: Are you on OSX?

13:57 TimMc: S11001001: I'll submit a PR to tweak that paragraph as well. ^_^

13:57 S11001001: TimMc: that'll do it :)

13:57 blackrose_: pbostrom I'm installing it

13:58 SegFaultAX I'm in ubuntu.

13:58 S11001001: In seriousness, I think, as a result, leiningen should not claim "Distributed under the Eclipse Public License, the same as Clojure uses." Because it *isn't* the same.

13:58 SegFaultAX: blackrose_: Ok, nevermind.

13:59 TimMc: S11001001: You should definitely file an issue, in any event.

13:59 S11001001: TimMc: Yeah, later :)

13:59 pbostrom: blackrose_: run 'lein version' when it's installed to make sure you are at the latest, sometimes the distro repos do not have the latest

14:12 blackrose_: <SegFaultAX> <pbostrom> I'm following the instruction in https://github.com/RuuviTracker/ruuvitracker_web

14:13 If there would be any problem, i will ask you later, ok?

14:13 sdegutis: Homogenous collections are dumb.

14:13 Sorry I meant heterogenous

14:17 bbloom: sdegutis: um, why?

14:18 sdegutis: Collections with different types. I used to love the idea, now it just seems like a useless/dangerous novelty.

14:20 I can't remember ever dealing with a collection that has more than one type in it (excluding nil).

14:20 technomancy: sdegutis: maps included?

14:21 justin_smith: how about maps mixed with records? arraymaps mixed with hashmaps?

14:21 functions mixed with maps even

14:21 sdegutis: Not for maps. They sometimes have number keys, sometimes string keys. Working with one right now (Datomic) that has both actually.

14:21 justin_smith: (both being applied on the same type args0

14:21 sdegutis: So I guess I meant linear collections.

14:21 technomancy: yeah, I'll buy that

14:21 bbloom: sdegutis: what about using collections as paths?

14:21 [:users 5]

14:22 justin_smith: longs mixed with doubles?

14:22 sdegutis: Hmm, that sounds useful. Although I'd mentally consider it a specialized struct with ordinal keys, rather than a vector, despite its implementation.

14:22 justin_smith: Heresy!

14:22 technomancy: also mapentry is technically sequential, but that's fairly pedantic

14:22 sdegutis: Actually wait bbloom, you're totally right.

14:23 bbloom: sdegutis: except that "specialized" implies taking something generic, and intentionally eliminating the universal nature of it in order to benefit from particular aspects of a particular instantiation of it

14:23 sdegutis: Each element in [:users 5] is typically grabbed as a sequence to reduce a tree into a value.

14:23 bbloom: sdegutis: technically, those collections *are* homogenous

14:23 they are vectors of Object

14:24 justin_smith: this is also mixed type - [[0 1 2] '(3 4 5) [6 7 8]] - and due to how clojure coerces sequences, not at all hard to end up with

14:24 but also not hard to use

14:24 sdegutis: ,(reduce get {:users [10 11 12]} [:users 2])

14:24 clojurebot: 12

14:24 sdegutis: Neat.

14:25 justin_smith: sdegutis: looks a lot like get-in :)

14:25 sdegutis: bbloom: But when I think of homogeneous vs heterogeneous, I'm assuming stronger types than a void* equiv.

14:25 SegFaultAX: That's basically exactly get-in

14:25 sdegutis: Cool, I just invented get-in.

14:25 Yay me.

14:26 ,(source get-in)

14:26 clojurebot: #<SecurityException java.lang.SecurityException: denied>

14:27 amalloy: ~def get-in

14:27 bbloom: sdegutis: the problem is that homogenous vs heterogenous isn't a useful distinction of any kind

14:27 sdegutis: Shut up your face clojurebot.

14:27 justin_smith: yours is basically identical to the version with no not-found

14:27 (reduce1 / reduce)

14:27 sdegutis: bbloom: Fine point indeed.

14:27 amalloy: justin_smith: it's also very wasteful for (reduce get {} (range 100))

14:27 sdegutis: I was mostly thinking about C#'s generic collections compared to ObjC's dumb old NSArray.

14:27 amalloy: the one in clojure.core short-circuits

14:27 bbloom: sdegutis: all collections are always homogenous, since you must always lift several types to a sum (or union) type

14:28 sdegutis: And how much cooler C#'s VS integration is than Xcode's with ObjC arrays.

14:28 bbloom: sdegutis: the question is whether you feel it's a good or bad idea to have a universal union type

14:28 sdegutis: and if you decide yes, you want a universal union type (which i believe in, and most lispers / dynlang do) then supporting "heterogenous" collections is a no brainer

14:29 justin_smith: amalloy: only for the case with an explicit not-found though?

14:29 amalloy: no?

14:29 clojurebot: no is tufflax: there was a question somewhere in there, the answer

14:29 amalloy: &(get {} (range))

14:29 lazybot: ⇒ nil

14:29 sdegutis: bbloom: Wow you're obviously pretty educated on language design and/or type system design.

14:29 justin_smith: amalloy: I don't see that in the source linked above at all

14:29 amalloy: &(get-in {} (range))

14:29 really? wow, i had no idea

14:29 that's terrible

14:29 lazybot: Execution Timed Out!

14:29 SegFaultAX: Or if your language happens to have sub-type polymorphism with covariant sequences.

14:30 justin_smith: amalloy: see the link from clojurebot above

14:30 sdegutis: By the way, that line of reduce/get code was meant to show that a path is accessed as a sequence or linear collection.

14:30 justin_smith: moral: provide a not-found value to get-in I guess

14:30 sdegutis: ,(range)

14:30 clojurebot: (0 1 2 3 4 ...)

14:30 dobry-den: what's the simplest way to split a vector into equal parts?

14:30 sdegutis: Neat. Replacing (iterating inc 0) from now on with (range).

14:31 insamniac: partition?

14:31 clojurebot: partition is probably not what you want; see partition-all.

14:31 justin_smith: dobry-den: partition?

14:31 SegFaultAX: dobry-den: partition and its cousins.

14:31 justin_smith: if "equal" is a hard req, partition, otherwise partition-all

14:31 insamniac: ,(partition-all 4 (range 9))

14:31 clojurebot: ((0 1 2 3) (4 5 6 7) (8))

14:31 ToBeReplaced: i've got a deep directory structure i've inherited of non-source code, and i want to create a file explaining it that can generate READMEs down the tree saying what the directory is and what its children are -- anyone know of a project that does that or something similar?

14:31 bbloom: sdegutis: the more i study type systems, the more i believe that sum types are a bad idea :-P

14:32 sdegutis: Good to know that I can draw out half the channel by just throwing out a controversial language design argument.

14:32 :)

14:32 bbloom: Why?

14:32 bbloom: sdegutis: b/c it is anti-reuse

14:32 dobry-den: i meant "Split this vector of arbitrary size into 4 equal parts". I ended up just doing partition-all and dividing count by 4

14:33 sdegutis: bbloom: related to m:n problem?

14:33 justin_smith: bbloom: isn't clojure effectively unityped with a huge sum type? or at least mostly so?

14:33 amalloy: bbloom: you don't like sum types, but you argue for a super-sum union-everything type?

14:33 bbloom: justin_smith: it's a union type, not a sum type

14:33 justin_smith: ahh

14:34 bbloom: amalloy: i don't like sum types b/c if you can't reuse constructors between the types

14:34 justin_smith: bbloom: I am fairly ignorant, but wikipedia describes sum types as being a safer alternative to union types

14:34 amalloy: justin_smith: by the way, the link clojurebot gave was to a four-years-old snapshot of the code

14:34 bbloom: justin_smith: that's just propaganda the static typing people want you to believe :-P

14:34 sdegutis: The biggest challenge I'm facing in my Clojure code these days is how to turn implicit system contracts into explicit verifiable safe contracts.

14:34 amalloy: it's still just as bad, but it might have been out of date

14:35 sdegutis: What library solves this problem completely for us?

14:35 justin_smith: amalloy: my 1.5 gives a similar function though

14:35 bbloom: sdegutis: no library will solve that problem for you completely

14:35 sdegutis: bbloom: In Haskell it does :P

14:35 bbloom: sdegutis: most, if not all, interesting properties of real problems can not be proven

14:35 sdegutis: (joking!)

14:35 bbloom: Maybe through machine learning they can?

14:36 bbloom: sdegutis: statically insignificant risk of incorrectness is different than "proven"

14:36 sdegutis: I think using clojure.typed with explicit interfaces may be a good start, if I put much of the contracts in message passing.

14:36 bbloom: sdegutis: i'm a big believer that the former is A-OK, but logisticians don't necessarily see it that way

14:36 sdegutis: you'll note that core.typed works with union types

14:37 ie (U Integer Nil) can share the Nil constructor with (U Map Nil)

14:37 sdegutis: Actually no wait, there's another solution that's kind of escaping me, that I want in Clojure.

14:37 bbloom: justin_smith: amalloy: that ^^ is the distinction between sum and union types

14:37 sdegutis: Ah yes, Sing#'s contracts!

14:37 thearthur: I have always used pallet in async mode, and now im trying to figure out the proper way to check for success on the result of a syncronous call to converge

14:38 sdegutis: It's basically a verifiable state machine for execution flow.

14:38 It focuses all the risk of an incorrectly specified system into central locations (the contracts).

14:38 amalloy: ,(get (hash-map 1 2) (range)) ;; a bit of silliness i just realized

14:39 clojurebot: #<OutOfMemoryError java.lang.OutOfMemoryError: Java heap space>

14:39 sdegutis: You still have to be diligent to design the state machine properly, but as long as you have, then you have much more confidence that your system works as expected.

14:40 bbloom: sdegutis: the MSR folks do some seriously cool verification research

14:40 sdegutis: people don't realize, but MSR invented all kinds of new static analysis techniques between Windows XP SP1 and SP2

14:40 sdegutis: Wow.

14:41 bbloom: sdegutis: the entire windows code base is crazy advanced in terms of static verification

14:41 sdegutis: Is there a similar system for Clojure yet? That'd be neat.

14:41 bbloom: Probably how they got their OS so stable lately.

14:41 * sdegutis worked on Win 8 last night for hours, not a single crash!

14:41 sdegutis: *in

14:41 bbloom: sdegutis: http://msdn.microsoft.com/en-us/library/windows/hardware/hh454825(v=vs.85).aspx

14:42 some of the tools are available to windows developers, like that one ^^ the static driver verifier

14:42 it analyses things like correct sequencing of system calls

14:43 gfredericks: amalloy: what's interesting about that? the fact that another way you can easily realize the key isn't in the map?

14:45 amalloy: gfredericks: it introduces a lot of non-obvious danger points when using lazy sequences

14:45 and you won't even notice them in testing, because ##(get {1 2} (range)) works fine for array-maps

14:45 lazybot: ⇒ nil

14:46 amalloy: for example, if i can control the args to a memoized function in your program, i can run you out of memory

14:46 (this is sorta true *anyway* with memoized functions, but that was the first obvious example of using hash-maps i could think of)

14:47 gfredericks: amalloy: iiiinteresting

14:47 probably highly unlikely that user input could ever create a (range) without that being expected

14:48 that programmer deserves her OOM

14:48 AeroNotix: ,(range)

14:48 clojurebot: (0 1 2 3 4 ...)

14:50 gfredericks: clojurebot: clojurebot is highly unlikely

14:50 clojurebot: Alles klar

14:50 gfredericks: actually that example sort of proves the point of it being expected :)

14:52 sdegutis: I think I'm going to make use of assertions in my code to verify system contracts. For example an episode must be part of a series. That way there's no cheating in the integration tests by creating an episode and omitting its series, which is not a correct state of the system.

14:52 But I'd love it if there was a more centralized way to specify/assert system contracts than pre/post-conditions inside scattered Clojure functions.

14:52 stuartsierra: Check out core.contracts

14:53 sdegutis: Seeking.

14:53 https://github.com/clojure/core.contracts#example-usage

14:54 When is Clojure gonna move to codeplex already?

14:55 technomancy: not sure why it's on github TBH

14:55 sdegutis: technomancy: What would you recommend?

14:55 technomancy: Trac

14:55 sdegutis: stuartsierra: Looks neat. Seems to have the same isolation problem of pre-conditions though.

14:55 technomancy: Okay now you're just trololing.

14:56 technomancy: sdegutis: what I meant was there hasn't really been any practical difference since moving from assembla

14:57 stuartsierra: sdegutis: Also Prismatic Schema, Herbert, and core.typed :)

14:58 sdegutis: Wow, So picture, Such trendy: https://github.com/miner/herbert

14:58 technomancy: I mean I know why it's on github: because everyone kept bugging rich to move it. but they were actually asking for "move to github and actually start using github's features", which never happened.

14:59 sdegutis: technomancy: yeah, I submitted a pull request to rename it to Lava (Lisp in jAVA) and they never even looked at it

14:59 :(

14:59 stuartsierra: sdegutis: That was you! :)

14:59 technomancy: shame

14:59 sdegutis: technomancy: yeah, totally cooler name, oh well

14:59 mdrogalis: sdegutis: Dire :)

14:59 sdegutis: stuartsierra: shh don't tell!

15:00 stuartsierra: All of these libraries focus on a per-function basis it seems.

15:01 fogus|away: sdegutis: The core.contracts code also allows other ways to attach contracts besides in that basic example.

15:01 sdegutis: That's great, but I'd like a macro (vs micro) approach too, which specifies interactions between functions.

15:01 mdrogalis: An overhead flying Fogus! Duck!

15:01 `fogus: sdegutis: What would that look like?

15:01 sdegutis: fogICantAutoCompleteYourNick: hmm I'll look into that more. Might send a pull request to put an example in the readme.

15:02 mdrogalis: sdegutis: https://github.com/MichaelDrogalis/dire#preconditions

15:03 It has the 'centralized' bit, but not the 'function interaction' piece.

15:03 sdegutis: `fogus: I have no idea, I'm just dreaming. The inspiration came from Sing#'s contracts. (page 3 of http://research.microsoft.com/pubs/69431/osr2007_rethinkingsoftwarestack.pdf )

15:03 mdrogalis: Hmm, will look into it.

15:06 `fogus: sdegutis: Thanks for the link. I've not seen that paper before

15:06 eraserhd: Say I wanted to load a jar off clojars at runtime. Where would the code to do that live? In leiningen?

15:06 sdegutis: `fogus: I imagine in Clojure it would have to be implemented as (1) a state-machine that (2) exercises all the functions it specifies, (3) using generated data based on the contracts.

15:07 I think #3 could be done based on Stuart Halloway's test.generative maybe.

15:08 hyPiRion: sdegutis: or core.check

15:08 (or is it test.check?)

15:08 sdegutis: `fogus: Sure thing. It's an exciting idea, although it implies a reliance on a third party (presumably Microsoft) to verify your app for security before it can be fully trusted by the end-user. Which puts us in the same place as Apple's and MS's app store.

15:09 `fogus: sdegutis: Part of my goal with c.contracts is to provide the substrate for something like what you describe, but yeah that would be a sweet library.

15:09 sdegutis: Although maybe with clojure.analyzer et al. it might even be possible at compile-time rather than run-time.

15:10 Er, tools.analyzer I guess?

15:10 (It changed its name a few times and I'm not sure what the latest one is, but I basically mean CinC.)

15:11 bbloom: sdegutis: you should also look in to substructural types

15:11 sdegutis: technomancy: https://www.assembla.com/home WHOA GIANT TEXT BOX

15:11 `fogus: Well, runtime would have to occur to run the checks, but you could have a contracts checking phase that happens at dev time.

15:12 sdegutis: Hmm right.

15:13 technomancy: eraserhd: look at pomegranate

15:14 logic_prog: anyone have an APL of interprter written in clojure/cljs ?

15:14 dnolen_: sdegutis: `fogus: this also got me thinking - Microsoft has done some really interesting work with CodeContracts - seems like abstract interpretation for compile time verification of contracts is pretty promising.

15:14 now that the Clojure(Script) analyzer story is improving - it would be nice to see this type of literature implemented

15:15 bbloom: dnolen_: abstract interpretation isn't just "pretty" promising, it's, in my opinion, already far more useful than type systems at verifying real world code

15:15 `fogus: dnolen_: Have a favorite paper?

15:15 bbloom: `fogus: good starting point: http://research.microsoft.com/en-us/people/tball/tball_30yai_text.pdf

15:16 `fogus: bbloom: Thanks!

15:16 bbloom: `fogus: talks about the history a bit, so you can go dig in to the literature

15:16 dnolen_: `fogus: bunch of stuff behind ACM - but this is available http://research.microsoft.com/pubs/138696/main.pdf

15:16 sdegutis: Yay! A transcription of a talk, so I don't have to sit through the whole thing!

15:16 My ADHD thanks whoever transcribed that page.

15:18 bbloom: one of the things i most like about abstract interpretation is that it's "functional" in the sense that the flow of analysis matches the data flow of the program, rather than being "relational" in the sense that you have to run a solver over the type annotation of a program

15:19 escherize: hello, may I ask a compojure question

15:20 I'm a little confused about how to allow the http OPTIONS method

15:20 bbloom: also, abstract interpretation is naturally extensible. you can always add more abstract interpreters and run them in parallel over your program

15:21 if you add to your abstract interpretation, you don't break properties of your existing analysis, which you do if you try to extend a type system

15:21 whenever you add a new feature to your type system, you need to go back and make sure it plays nice with every other aspect of your system

15:22 but with abstract interpretation, you just add a domain with monotonic operations. analysis is always monotonic and never codependent with previous analysis

15:22 sdegutis: Welp, my job here is done. Got the smart people talking about a fun problem they can probably solve. Back to my grunt work :)

15:27 gfredericks: are vectors the only persistent data structure that work well with reducers?

15:27 bbloom: gfredericks: maps & sets should work just fine too

15:28 pbostrom: escherize: isn't it just (OPTIONS "/some-path" [] "some response")

15:28 bbloom: gfredericks: plus, reducers are still useful for seqs if you can compose your processing pipeline up front. even if you put a lazy seq in and get a lazy seq out, you save all the allocations of the intermediate objects in the middle

15:28 mikeyg6754: Does anybody know of a good way of validating POSTS with Liberator? For example when a user submits an image upload form I'd like to be able to make sure they are actually uploading an image file.

15:29 I can't seem to cancel the :post! from within the handler function.

15:29 gfredericks: bbloom: I think sets in particular don't work

15:29 or at least aren't nearly as fast as a vector

15:30 * gfredericks crude benchmark disclaimer

15:30 seangrove: technomancy: Any idea if the faster deploy on heroku should significantly affect clojure deploy times?

15:30 gfredericks: bbloom: there parallelism in particular is what I'm after at the moment

15:30 the*

15:31 bbloom: ,(let [s (set (range 100000))] (time (clojure.core.reducers/reduce + 0 s)))

15:31 clojurebot: #<CompilerException java.lang.ClassNotFoundException: clojure.core.reducers, compiling:(NO_SOURCE_PATH:0:0)>

15:31 bbloom: (require 'clojure.core.reducers)

15:31 ,(require 'clojure.core.reducers)

15:31 clojurebot: #<FileNotFoundException java.io.FileNotFoundException: Could not locate clojure/core/reducers__init.class or clojure/core/reducers.clj on classpath: >

15:31 bbloom: &(require 'clojure.core.reducers)

15:31 lazybot: java.io.FileNotFoundException: Could not locate clojure/core/reducers__init.class or clojure/core/reducers.clj on classpath:

15:31 bbloom: wtf?

15:31 ,*clojure-version*

15:31 clojurebot: {:interim true, :major 1, :minor 6, :incremental 0, :qualifier "master"}

15:32 bbloom: :-(

15:32 well there's that one and:

15:32 (let [v (vec (range 100000))] (time (clojure.core.reducers/reduce + 0 v)))

15:32 i got 30ms and 6ms

15:32 gfredericks: so that's supporting my assertion about sets, right?

15:33 wait don't you have to use fold to get parallelization?

15:33 bbloom: ah right, duh

15:34 mikeyg6754: Anyone have experience with liberator?

15:35 bbloom: gfredericks: yeah (let [x (set (range 1000000))] (time (r/fold (r/monoid + (constantly 0)) + x))) seems non parallel

15:35 klokbaske: hi there! i cljs, how do I re-evaluate a (ns ..) form from my ide (lighttable in this case) without getting an exception?

15:36 gfredericks: bbloom: (r/monoid + (constantly 0)) is just +, eh?

15:36 dnolen_: klokbaske: I don't know of a good way to avoid that, might want to ask on the Light Table mailing list or channel

15:37 bbloom: gfredericks: yes, but i had already typed that out before i realized that fold was using a function rather than some data structure with two keys :-P

15:37 * gfredericks nitpicks

15:37 klokbaske: dnolen_: alright - was actually going through your om tutorial and got that problem.

15:37 pbostrom: klokbaske: I usually refresh my page when I change the ns

15:38 klokbaske: pbostrom: tried that - didn't work for some reason. seems odd to me, how the state can be kept alive in the browser ...

15:39 pbostrom: klokbaske: are you also running cljsbuild auto?

15:43 klokbaske: pbostrom: now I am - but it does not seem to make a difference?

15:44 pbostrom: when you save the file it should trigger an recompile, then refresh the compiled js in your browser and whatever you added to your ns should be available

15:45 klokbaske: it does trigger a recompile when I save

15:45 so maybe I just shouldn't re-evaluate then?

15:45 pbostrom: right, no need to re-evaluate the ns

15:45 klokbaske: alright

15:49 stuartsierra: You can't really "evaluate" anything in ClojureScript. It has to be compiled and loaded into a JavaScript runtime like a browser.

15:50 sdegutis: Just like Ruby!

15:51 stuartsierra: Um. No.

15:51 dan`: Hi, does anybody know about the Clojure GSoC projects? I'd love to work on one, but I'm not sure I have the experience..

15:51 xnil: ahahha

15:52 sdegutis: stuartsierra: I meant like how you'd run a .js file in 'node', you'd run a .rb file in 'ruby'. Extra step is that you'd have to compile the .cljs file to .js

15:52 pbostrom: stuartsierra: Lighttable handles the compile/load via a browser connection so it feels like it's evaluating; but doesn't seem to work for changing the ns form

15:53 klokbaske: pbostrom: seems I have to re-evaluate the (ns) form in order to evaluate from Lighttable any expressions that use the updated ns

15:54 refreshing the browser doesn't do it

15:54 and I do make sure that the source is recompiled before I refresh

15:54 it's not that big a problem, it just puzzles me l-)

15:56 sdegutis: I feel like ClojureCLR opens up a whole new host of side income via windows apps possibilities.

16:15 jconnolly: question about using gen-class to implement a java interface and override a method...

16:16 when I use :methods, I'm definining the methods I'm overriding?

16:17 llasram: jconnolly: No -- :methods are additional

16:17 jconnolly: ah i had it backwards

16:17 gfredericks: A non head-holding version of rand-nth: #(->> % (map (juxt (fn [_] (rand)) identity)) (apply max-key first) (second))

16:17 llasram: jconnolly: I personally advise against using gen-class at all. What's your use-case?

16:18 jconnolly: my god, how long do you have?

16:18 i need to register a class a a JAXBContext resolver

16:18 llasram: Reference for context?

16:18 jconnolly: i started with reify, then on to proxy, finally to gen-class

16:19 yes, basically https://jersey.java.net/nonav/apidocs/1.4/jersey/com/sun/jersey/api/client/config/DefaultClientConfig.html

16:19 adding a .class to .getClasses mutable set of context resolver

16:20 i've done it in java dozens of times, I was basically tansliterating from java to clojure without much success

16:20 so down the https://github.com/cemerick/clojure-type-selection-flowchart flowchart i went

16:20 llasram: Ah, annotation-based dependency injection?

16:21 jconnolly: exactly

16:22 llasram: Yeah -- I found even w/ the general issue I have w/ gen-class, annotations make it worse. In particular, I do not believe you can attached an annotation to a gen-class'd constructor

16:23 jconnolly: so I've come to conclude... it's okay, using jaxb was the wrong way to do this anyway

16:23 i thought it might have been the path of least resistence since most of the java code was written already, i'd just need some clojure wrappers around interop...

16:23 llasram: Two options: (a) if you just need one or two specific classes, and can inject your specific logic via normal Clojure methods (passing in an IFn etc), then you can just write some tiny stub classes in Java which call the Clojure API

16:24 Yeah, so just tiny wrappers, only in the other direction :-)

16:24 jconnolly: i had a hunch. i'm still getting acquainted with clojure so this was quite the journey down the rabbithole

16:24 learned a lot though

16:24 thanks llasram

16:25 llasram: np

16:25 And the other option, although is probably too crazy for your use case

16:25 (b) use ASM to dynamically generate stub classes w/ the interface you need

16:25 borkdude: I am trying some clojurescript in lighttable and external browser connection á la the nom tutorial

16:25 llasram: It isn't as bad as you might think -- https://github.com/llasram/esfj

16:26 borkdude: but I keep getting "Namespace already declared"

16:26 even when I refresh the page

16:26 and 'chan' can't be eval-ed, because I can't reload a new namespace definition

16:33 BobSchack: borkdude I've had a similar problem. I had to put the core.aysnc requires in the core / main file.

16:34 borkdude: BobSchack I'm using only one file

16:35 BobSchack: do you mean you are working with only one file?

16:36 sdegutis: I am in a black hole of regular-expression-based migrations.

16:36 BobSchack: I had a foo/core and foo/rules and tried evaling the foo/rules ns but kept on getting errors

16:37 sdegutis: Fortunately it's at least in Clojure.

16:37 BobSchack: when I put the requires in foo/core that solved the problem. I tried it after reading this thread (https://groups.google.com/forum/#!msg/light-table-discussion/I1vFNuCm5zo/bFpGNARwOGEJ)

16:38 borkdude: I also have Uncaught Error: Invariant Violation: prepareEnvironmentForDOM(...): Target container is not a DOM element errors in my console log

16:41 BobSchack: that would be a question for dnolen_

16:42 borkdude: I can evaluate each form without errors

16:42 but the browser thinks differently

16:42 dnolen_: borkdude: it's a known LT issue you can't evaluate the namespace form more than once.

16:43 borkdude: dnolen_ ah ok, I restarted LT already

16:43 dnolen_: borkdude: the error doesn't really affect anything

16:44 borkdude: dnolen_ ok

16:44 BobSchack: dnolen_ have you tried using any cljx projects from lighttable?

16:44 dnolen_: BobSchack: nope, never used cljx ever

16:45 BobSchack: but I'm sure there's gotta be people here or in #lighttable who have

16:46 BobSchack: Ok thanks

16:49 dnolen_: BobSchack: also #clojurescript, also might want to hit up the ClojureScript mailing list as well if you don't get a response from someone on IRC

16:49 kevinfish: what happened to pedistal's site?

16:50 BobSchack: dnolen from what I can tell it tries loading clj namespaces not cljs ones.

16:51 I get js namespace not found

16:53 bbloom: kevinfish: React.js

16:53 dsrx: is there a special clojurescript mailing list?

16:53 bbloom: kevinfish: https://groups.google.com/forum/m/?utm_content=buffer1e113&utm_medium=social&utm_source=twitter.com&utm_campaign=buffer#!topic/pedestal-users/jODwmJUIUcg /cc dnolen, if you didn't see it

16:53 dsrx: ah, nice

16:53 bbloom: dnolen_ ^^

16:54 arrdem: ~next

16:55 dnolen_: bbloom: yeah I saw the post when it came out

16:56 BobSchack: I don't know if LT can understand cljx, cljx is a build phase thing. perhaps cemerick knows something more

16:58 cemerick: BobSchack: there's a Leiningen plugin for cljx, and nREPL integration/support. I don't know anything about LightTable.

16:58 DomKM: I've been unable to get it to work in LT

16:59 works fine through lein repl or cider

17:00 I asked about it on the mailing list (https://groups.google.com/forum/#!topic/light-table-discussion/g54WJuz36ws) but no one replied

17:01 dnolen_: DomKM: people also have problems with setting CLJS Node REPLs - so I suspect this is just a broader problem with LT at the moment.

17:01 BobSchack: Thanks for all the info dnolen_ DomKM looks like I'll be looking at emacs for the time being.

17:02 effy: i dont know how to take a proper memory footprint but looking at a htop while running a `lein repl` i can see ~540M of RAM vanish, i was wondering how small a clojure daemon memory footprint could be (is there a chance that i could make them run on very small vps (ec2 micro-instance style)?)

17:04 DomKM: dnolen_: I'd be happy with only the clj side of cljx for now. It fails because it tries to read #+clj literally, even when connected to an external headless nrepl

17:04 dnolen_: Seems to me like LT is ignoring the cljx middleware, but idk

17:13 sdegutis: Does anyone use https://github.com/sdegutis/clojuredocs/wiki , or can I delete it?

17:14 arrdem: kill it.

17:15 sdegutis: k.

17:15 arrdem: http://brainsyndicate.files.wordpress.com/2010/10/892cap012.jpg

17:16 sdegutis: What's a less dumb way of doing this? ((fnil #(Long/parseLong %) "0") (re-find #"\d+" "looking 4 the number four BUT IT MIGHT NOT BE THERE"))

17:18 arrdem: killd

17:18 seangrove: sdegutis: Probably an if-let

17:18 sdegutis: Oh right.

17:19 seangrove: (if-let [number (re-find #"\d+" "looking 4 the number four BUT IT MIGHT NOT BE THERE")] (Long/parseLong number) 0)

17:20 sdegutis: Much better.

17:20 Thanks seangrove.

17:20 seangrove: No worries

17:20 (dec everyone-but-me)

17:20 lazybot: ⇒ -1

17:20 sdegutis: Ha.

17:32 I'm totally solving a problem with regular expressions!

17:33 * llasram raises his shields and dispatches his crew to battle stations

17:33 oskarkv: I'm using tools.namespace. If I have namespace A and B, and in B do (eval `(var ~(symbol "A/func"))), and refresh, that works. But if I make a change to A, refresh, so that only A refreshes, then that expression gives "Cannot resolve var: A/func in this context", even though A/func exists. Why?

17:34 * arrdem adopts a scottish accent and starts hollering about the main reactor coils

17:34 sdegutis: arrdem, llasram: Just realized you both have double-consonants in your nicks.

17:34 Twins?

17:35 AimHere: Well given one is 'l' and the other is 'r', I expect them to be mirror images of each other, at best

17:35 arrdem: ,(bit-xor (int \r) (int \l))

17:35 clojurebot: 30

17:36 sdegutis: Oh man, I think it's worth changing some data in production to get rid of this outlier in my regular expression inputs.

17:37 Evil, or best plan ever?

17:37 llasram: One bit off from nemeses!

17:37 arrdem: 1d2

17:37 clojurebot: 1

17:37 arrdem: totally evil

17:37 llasram: haha

17:42 sdegutis: This is the data set I'm working with in my migration: https://gist.github.com/sdegutis/97bf0b3ac610cb5405ad

17:42 I've got two options. Cheat and manually normalize data in production, or use some awesome regular expressions.

17:42 I think it's a no-brainer, amirite?

17:44 cark: maybe use some regexes to normalize the data =D

17:45 sdegutis: Oh man, yes totally!

17:46 cark: or go pro and use instaparse

17:47 mvzink: probably won't be the first time someone's written a CFG for episode titles...

17:47 arrdem: haha

17:47 sdegutis: I really hate the idea of manually normalizing the data. It just feels like I'd be giving up.

17:48 arrdem: automated migrations fwt!

17:48 sdegutis: At the same time, just look at all those different ways of specifying Part N!

17:48 arrdem: sdegutis: jnltk is that way...

17:48 sdegutis: eps 6, 11, 19, in the title...

17:51 Raynes: Instaparse is pretty pro

17:51 mvzink: instaparse++

17:53 sdegutis: (inc instaparse)

17:53 lazybot: ⇒ 1

17:53 sdegutis: (inc Instaparse)

17:53 lazybot: ⇒ 2

17:54 sdegutis: (inc instaparse)

17:54 lazybot: ⇒ 3

17:54 sdegutis: oh.

17:54 justin_smith: $karma instaparse

17:54 lazybot: instaparse has karma 3.

17:54 veron: (inc instaparse)

17:54 lazybot: ⇒ 4

17:54 veron: oh sweet, there's a repl here?

17:54 justin_smith: (inc instaparsE)

17:54 lazybot: ⇒ 5

17:54 justin_smith: kinda

17:54 inc is special

17:55 ,(+ 1 1) ; this is more general

17:55 clojurebot: 2

17:55 veron: (* 2 4)

17:55 clojurebot: *suffusion of yellow*

17:55 justin_smith: #(+ 1 1) ; or this

17:55 veron: ,(* 2 4)

17:55 clojurebot: 8

17:55 veron: why do I need a comma

17:55 justin_smith: because clojurebot has to know which things to interpret

17:55 veron: can I break out to shell?

17:56 justin_smith: ##(int \a) ; or this, I mean

17:56 lazybot: ⇒ 97

17:56 veron: I don't know enough clojure for exec

17:56 justin_smith: venron hope not

17:56 it has a sandbox

17:56 veron: haha

17:56 sdegutis: I DID IT!

17:56 veron: ,(use '[clojure.java.shell :only [sh]])

17:56 clojurebot: nil

17:56 veron: ,(sh "free")

17:56 clojurebot: #<SecurityException java.lang.SecurityException: denied>

17:57 veron: hahahahahhaa

17:57 sdegutis: https://gist.github.com/sdegutis/97bf0b3ac610cb5405ad

17:57 justin_smith: ,(slurp "http://goatse.cx")

17:57 clojurebot: #<SecurityException java.lang.SecurityException: denied>

17:57 sdegutis: I cheated by doing four different regexes for the different ways parts are specified in the title.

17:58 llasram: sdegutis: Oh, that's nothing. I thought you were doing something like implementing a 100-line parser in a regular expression

17:58 sdegutis: Nah, I'm not that pro.

17:58 llasram: I'd actually call what you have there "completely reasonable"

17:59 sdegutis: Then you sir are a crazy person.

18:00 llasram: I'm going to call that an orthogonal concern :-)

18:00 veron: you should run that clojurebot inside an lxc container :P

18:00 so even if they "break out" of both the jvm sandbox and clojail, they're only on a container system

18:01 http://docker.io

18:06 arkh_: ping ztellman

18:06 ztellman: arkh_: sup

18:07 arkh_: ztellman: hello sir - I was using byte-streams and found that this still appends (transfer "asdf" (java.io.File. "/home/user/temp") {:append? false})

18:08 I wish I could send you a pull request but I haven't been able to figure it out yet

18:08 ztellman: just a sec, let me check out the code

18:09 arkh_: I'm using 0.1.9

18:10 ztellman: hmm, I see how it *should* be working

18:10 can you open an issue? I'll look at it later today

18:10 oskarkv: Does anyone know what's wrong here? http://stackoverflow.com/questions/21714704/my-logging-with-robert-hooke-does-not-work-properly-with-tools-namespace-refre

18:11 arkh_: will do - thanks

18:20 patchwork: Any reason ring's wrap-content-type defaults to application/octet-stream rather than text/plain?

18:20 It seems that will be the default content type more often by far

18:20 technomancy: patchwork: you can turn bytes into text reliably but not vice versa

18:20 sdegutis: yeah huh, using utf8

18:21 patchwork: Well, not every stream of bytes is valid utf8

18:21 sdegutis: also you pronounced vice versa incorrectly

18:21 * sdegutis is winning this conversation

18:21 technomancy: patchwork: right; the set of valid octet-streams is a superset of text/plain

18:21 sdegutis: I'm hoping one day I'll have enough HN karma to become king of the world

18:21 patchwork: technomancy: Hmm… but it triggers a file download rather than just displaying the text

18:22 amalloy: patchwork: i wouldn't expect text/plain to be right more often than octet-steam

18:22 technomancy: patchwork: yes, but it's lossless

18:22 text is lossy

18:22 amalloy: most files that you're serving as files are things you actually want to download and use for something else; if you wanted to display text frmo your webserver, you'd have used html, not plaintext :P

18:22 weavejester: Basically everything technomancy says is right

18:23 technomancy: whoa, can I quote you on that?

18:23 hyPiRion: haha

18:23 technomancy: completely out of context, I mean?

18:23 patchwork: Okay, so every response should specifically set the [:headers "Content-Type"]

18:23 just seems clumsy for simple tasks, but I see the reasoning

18:23 weavejester: technomancy: Be my guest ;)

18:24 patchwork: Sure, but you can automate it.

18:24 patchwork: You can just add some middleware to give a set of routes a fixed content type if you want.

18:25 patchwork: weavejester: Sure, but not all of them are the same content type, some actually are files or whatever else

18:26 Basically I will just rewrite wrap-content-type to use text/plain as the default

18:26 it is a simple enough function

18:30 fowlslegs: I am having troubles understanding how MVCC works. I played with the example on http://clojure.org/refs, switching alter w/ commute and noticed that commute will end up with less distinct values.

18:30 patchwork: Or rather, "text/html;charset=utf8"

18:31 fowlslegs: Is this because alter will restart the transaction, recording a new in-transaction value if another function commits to one of the values the original transactions doblock is acting on?

18:32 While commit will go ahead and use the original in-transaction value, even if another function has commited to it changing it.

18:32 Sorry, while *commute* will go ahead...

18:33 What exactly is the difference between an end-of-transaction value and a commit?

18:34 hyPiRion: fowlslegs: well, you can only use commute when the applied function is commutative

18:35 not sure if that answers your question, but setting or replacing values certainly isn't commutative

18:36 fowlslegs: I am trying to make sense of the following "the last in-transaction value you see from a commute will not always match the end-og-transaction value of a ref, because of reordering. If another transaction sneaks in and alters a ref that you are trying rocmmute the STM will not restart your transaction. Instead, it will simpll run your commute functionatain, out of order. Your transaction will never even see the ref value that commute ran a

18:37 hyPirion: I get what you are saying, I'm just trying to understand the details of how alter and commute work in the clojure mvcc implementation.

18:37 rocmute should be to commute

18:38 functionatain should be function again

18:38 sorry for the typos

18:39 cark: commute is for those cases where it isn't important to o the updatein order

18:39 like adding a constant to an accumulator

18:40 let's say you have a bank

18:40 fowlslegs: cark: I get when to use them, I'm just trying to understand the internals of the clojurebot

18:40 cark: and you want ot count the total number of transactions

18:40 ok

18:42 why don't you take a look at the source then ?

18:42 hyPiRion: fowlslegs: so if my-ref is a ref with value 0 when `(dosync (commute my-ref inc) (deref my-ref))` is started, then the return of the dosync will be 1 regardless. But if another transaction updates the value before the original transaction has been "commited", the actual update will be with the latest value.

18:42 (doc commute) explains it rather well I think.

18:42 clojurebot: "([ref fun & args]); Must be called in a transaction. Sets the in-transaction-value of ref to: (apply fun in-transaction-value-of-ref args) and returns the in-transaction-value of ref. At the commit point of the transaction, sets the value of ref to be: (apply fun most-recently-committed-value-of-ref args) Thus fun should be commutative, or, failing that, you must accept last-one-in-wins behavior. commute allows for m

18:46 fowlslegs: public Object commute(IFn fn, ISeq args) { return LockingTransaction.getEx().doCommute(this, fn, args);

18:52 teslanick: om question: is it possible to insert html as a string using the builtin om dom api?

18:52 i.e. (dom/div nil "<i>this is italics!</i>")

18:57 ivan: teslanick: maybe (dom/div #js {:dangerouslySetInnerHTML #js{:__html "<i>this is italics!</i>"}})

18:58 that's more om than I expected https://github.com/search?l=clojure&q=dangerouslySetInnerHTML&ref=searchresults&type=Code

19:01 teslanick: That appears to do it, thanks

19:15 That doesn't actually meet my need. Let's change topics:

19:15 What's the advantage over letfn and let?

19:15 *of letfn over let

19:17 amalloy: well, it communicates that you'll be creating just functions, no other locals; and it allows mutually recursive functions, which let doesn't

19:17 AimHere: It sugars the process of assigning names to temporary functions

19:17 dbell: does anyone use types/protocols for polymorphic dispatch in recursive functions?

19:18 AimHere: dbell > I do something like that if I want to spit out JSON

19:18 Actually no, I don't; I just use a multimethod. Ignore me

19:18 dbell: i've got a function recursively dividing a tree, and it checks whether the leaves are a string or a seq; having the coll? check feels inefficient, but types feel like overkill

19:19 AimHere: Would a multimethod triggered on the type help?

19:19 dbell: idk; I guess I'm asking for stylistic intuition more than anything else

19:20 a type-based multi would work too; it's really the choice between different strategies, all of which work

19:20 anyway ty aimhere

19:38 amalloy: dbell: well, dispatching on something like coll? doesn't work very well in the general case. it will work on a tree of strings, but surely you want your generic tree-splitter to also be able to handle a tree of lists, for example

19:39 a common solution in clojure is to have each node in the tree be a map like {:value x, :children [...]}, and then there's no confusion about whether you've gotten to a leaf or not

19:40 (which is a problem that you can't really resolve, if your tree is just a list of lists of lists of...and then eventually something at the bottom which might or might not be a list)

19:42 dbell: amalloy: this is a good point. I'm writing my first decision tree which just happens to be composed of all strings, so i've known ahead of time what the raw materials are. but going more generic would probably be good

20:29 btcNeverSleeps: ,(.bitLength (biginteger "1"))

20:29 clojurebot: 1

20:29 btcNeverSleeps: ,(.modPow (biginteger "1") (biginteger "1"))

20:29 clojurebot: #<IllegalArgumentException java.lang.IllegalArgumentException: No matching method found: modPow for class java.math.BigInteger>

20:30 btcNeverSleeps: I'm probably a Java noob but how comes modPow doesn't work here?

20:30 Java's BigInteger class has a: public BigInteger modPow(BigInteger exponent, BigInteger m) {...} method

20:30 S11001001: TimMc: NB: #4 https://github.com/technomancy/leiningen/issues/1446

20:31 brehaut: btcNeverSleeps: looks like a static method?

20:31 btcNeverSleeps: brehaut: no, it's not static

20:32 Bronsa: btcNeverSleeps: looks like it takes 2 args, not one

20:33 btcNeverSleeps: Bronsa: ooooh, gotcha, silly me!

20:33 ,(.modPow (biginteger "1") (biginteger "1") (biginteger "1")

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

20:33 btcNeverSleeps: pfffft, paredit mode not on in erc-mode

20:34 * btcNeverSleeps gone fixing his Emacs setup

20:55 muhoo: btc sleeps plenty, actually. at least for the moment.

20:56 until they fix the malleable tx problem, at least, and deal with the somewhat janky way most wallets calculate and show balances :-P

20:56 saj: Has anyone used clojure.tools.namespace?

20:57 I'm have a problem where using refresh actually unloads clojure.tools.namespace itself

20:59 muhoo: is stuart still using c.t.n? or has he moved on to his new reloaded workflow?

21:00 ah, i see, it's built on c.t.n

21:01 saj: nevermind, got around it by adding c.t.n.r to my ns header

21:09 dacc: have a school team project and trying to convince my teammates to let me use clojure for my bit

21:09 tough going, they have some weird scheme and prolog nightmares

21:28 teslanick: What's the clojure idiomatic way to walk over each character in a string?

21:29 dnolen_: ,(seq "hello")

21:29 clojurebot: (\h \e \l \l \o)

21:29 dnolen_: teslanick: strings are seqable

21:30 teslanick: I realized that almost immediately after I asked the question. : /

21:30 logic_prog: in building a webpap, is it better to do (1) cljs client side + clj server side or (2) cljs client side + erlang server side ?

21:31 teslanick: cljs client / clj server would theoretically let you share logic client/server, as long as it was pure-clojure.

21:31 And doesn't crash into one of those clj/cljs differences.

21:32 logic_prog: yeah, the _entire_ app is currently written in cjx

21:32 err, clj

21:32 err, cljx

21:32 yet, the more Ithink about the more I'm convinced erlang should be a better server side solution

21:32 but then I lose edn/read-string + pr-str

22:29 RMacy: so, just slightly curious.. why is map-invert in clojure.set? Is it because of the way it handles clashing values?

22:44 technomancy: RMacy: I think clojure.set is more about set theory than set data structures

22:45 RMacy: that makes sense

23:37 hiredman: the reverse

23:39 teslanick: is the gear with the little R next to it

23:40 hiredman: clojure.set is terrible for set theory

23:40 clojure.set is about clojure sets, with some relational algebra type bits throw in

23:41 thrown

Logging service provided by n01se.net