#clojure log - Feb 15 2014

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

0:00 jph-: :)

0:04 TravisD: Does clojure have much of a scientific computing community?

0:05 amalloy: TravisD: probably a little, but i think most of those guys use matlab, python, or fortran or something

0:07 TravisD: amalloy: Yeah, but sadly both matlab and python are too slow to implement any real algorithms in. They're mostly wrappers and glue for hooking together fast implementations of common operations

0:07 jph-: i wonder if julia will supplant them

0:07 TravisD: One hopes

0:11 This isn't meant to be an inflammatory comment, but does clojure have a larger and more active community than the variants of scheme?

0:13 egghead: TravisD i'm not familiar with scheme variants, but clojure has a large and active community

0:13 TravisD: And is clojure mainly used for web development?

0:15 egghead: TravisD: a lot of people use it for web development, but it is general purpose like java, so a lot of people use it for other things as well, clojure has a particular specialty in things like concurrency

0:16 TravisD: alright, thanks :)

0:24 `cbp: suddenly all the bugs are tracked to me typing OAauth

0:25 logic_prog: open awesome Auth

0:27 munderwo: So I'm trying to use the new jdbc API vs the old. But although I am using the clojure.java.jdbc 0.3.3 version in my project.clj, I don't have the insert! function in the repl. How do I verify the version of a library form the repl?

0:31 ddellacosta: munderwo: if you do (require '[clojure.java.jdbc :as j]) you don't have j/insert! available to you?

0:31 munderwo: I don't know how to verify a version number from the repl, but if you run lein deps from another terminal window that should tell you

0:32 munderwo: er, lein deps :tree is what you want, sorry

0:33 TravisD: I know there is a lot of machine learning going on in Clojure as well, for one

0:33 munderwo: ddellacosta: so this is what I'm getting https://www.refheap.com/39074

0:33 and its rather confusing..

0:33 because from what I can tell the jdbc driver from 0.3.0 onwards should have insert!

0:35 If I try to just do the insert! function then it says no such var.

0:36 I'm not sure if somehow I've messed up my class path because I have an older version of the jdbc driver in there? where are these stored?

0:36 ddellacosta: munderwo: does insert! show up when you do this? (keys (ns-publics 'clojure.java.jdbc))

0:37 munderwo: ddellacosta: nope https://www.refheap.com/39075 ...

0:37 Where are the jars that leiningen downloads stored?

0:38 I know that they get caches in ~/.m2 but is there anywhere else?

0:38 ddellacosta: munderwo: I don't get it, I clearly see [org.clojure/java.jdbc "0.3.3"] in your lein deps :tree output

0:38 munderwo: are you running the repl w/a profile?

0:38 munderwo: yeah I know… its kinda got me stump..

0:40 this is my profile.clj https://www.refheap.com/39076

0:40 ddellacosta: munderwo: no, I mean are you running the repl like `lein with-profile dev repl` or something?

0:40 munderwo: nope… just `lein repl`

0:41 ddellacosta: munderwo: and you're definitely running it in the same project directory you showed us that lein deps output from, right?

0:42 munderwo: ddellacosta: I just redid the whole set of steps… https://www.refheap.com/39077

0:42 just to make sure… coz gravity doesn't feel right.. and that normally means I've done something stupid

0:44 ddellacosta: munderwo: yeah, that's weird, that's obviously the deprecated interface

0:45 munderwo: ddellacosta: yeah its weird… thanks for your help. at least I know I'm only going a little crazy.. gotta run.

0:59 danielcompton: Is there a version of cond that will evaluate each test and it's expression if the test is true? The scenario is I'm wanting to validate a form in cljs and set dom error messages for each error message that I find. I could put a number of when statements in a line but I wondered if there was something more idiomatic?

1:01 TravisD: Does anyone know of a quick introduction to clojure? I'm somewhat familiar with lisp and FP, and I have quite a bit of programming experience

1:08 jph-: TravisD, http://adambard.com/blog/clojure-in-15-minutes/

1:09 TravisD: awesome, thanks

1:10 jph-: TravisD, i also refer to http://clojure.org/cheatsheet all the time

1:11 TravisD: hmm, clojure has special forms, no? Like, is (ns test) actually a function call? Or is it a special namespace form?

1:12 oskarkv: TravisD yes there are special forms, but I think `ns` is a macro

1:12 TravisD: ah

1:23 ddellacosta: ,(source ns)

1:23 clojurebot: Source not found\n

1:23 ddellacosta: d'oh

1:24 TravisD: anyways, you can do that ^ in the repl to learn more about a function/macro/special-form

1:24 beamso: ,(doc clojure.core/ns)

1:24 clojurebot: "([name docstring? attr-map? references*]); Sets *ns* to the namespace named by name (unevaluated), creating it if needed. references can be zero or more of: (:refer-clojure ...) (:require ...) (:use ...) (:import ...) (:load ...) (:gen-class) with the syntax of refer-clojure/require/use/import/load/gen-class respectively, except the arguments are unevaluated and need not be quoted. (:gen-class .....

1:24 TravisD: cool, thanks

1:24 normally (source x) gives you the definition of x?

1:25 ddellacosta: TravisD, beamso: yeah, good point--that should tell you if it's a special form too

1:25 ,(doc loop)

1:25 clojurebot: "([bindings & body]); Evaluates the exprs in a lexical context in which the symbols in the binding-forms are bound to their respective init-exprs or parts therein. Acts as a recur target."

1:25 beamso: and it's (clojure.repl/source ns) as well

1:25 ddellacosta: hrm

1:25 &(doc loop)

1:25 dsrx: ,(doc .)

1:25 lazybot: ⇒ "Macro ([bindings & body]); Evaluates the exprs in a lexical context in which the symbols in the binding-forms are bound to their respective init-exprs or parts therein. Acts as a recur target."

1:25 clojurebot: Cool story bro.

1:25 ddellacosta: beamso: I don't need to qualify it with the namespace in my repl...clojure.repl gets loaded automatically by default

1:27 beamso: true

1:27 maybe the bot needs a namespace specified :/

1:27 TravisD: is there a way to get the clojure repo to use readline?

1:27 repl*

1:27 ddellacosta: beamso: naw, it's not that it didn't find it, it probably just doesn't allow you to do that to avoid noise in IRC I suspect

1:28 TravisD: huh, it uses readline by default I thought

1:28 TravisD: hmm, the version I installed through macports doesn't seem to :(

1:28 beamso: lein uses jline by default

1:29 logic_prog: tbaldridge: !!!

1:29 ddellacosta: beamso: ah, I stand corrected

1:29 logic_prog: tbaldridge: your youtube videos are awesome

1:29 TravisD: hm, so now I've installed jline. Is there something more I need to do to get clojure to use it?

1:30 beamso: http://en.wikibooks.org/wiki/Clojure_Programming/Getting_Started#Enhancing_Clojure_REPL_with_JLine

1:30 maybe that

1:30 TravisD: thanks

1:32 amalloy: TravisD: whoa, installing clojure (or lein) through macports is pretty nuts

1:32 TravisD: amalloy: How come?

1:33 * beamso uses homebrew for that stuff

1:33 TravisD: beamso: I switched to macports because they've started shipping binaries

1:33 can save a lot of time

1:33 amalloy: follow the instructions at the lein readme (https://github.com/technomancy/leiningen/blob/master/README.md), which amount to "download this script and put it on your path"

1:33 stuff in package managers is always out of date and/or awful, eg not including jline support

1:34 TravisD: looks like it's up to date, and relatively easy to add jline support

1:35 ddellacosta: TravisD: most Clojure folks I know use the default leiningen setup for installing/update

1:35 TravisD: ah

1:35 ddellacosta: TravisD: especially as you don't need the package manager to get updates for lein

1:36 amalloy: lein really is way better at managing clojure (and itself!) than any package manager

1:36 ddellacosta: ^^ what he says ^^

1:37 TravisD: yeah, I'll probably switch to that

1:37 so the recommended approach is to instal lein manually and use it to install and update clojure?

1:37 ddellacosta: TravisD: yep.

1:38 TravisD: after the initial install it is as simple `lein upgrade`

1:39 TravisD: technomancy makes announcements when a new version gets released on the mailing list

1:39 TravisD: awesome :)

1:39 ddellacosta: TravisD: and upgrading clojure is kind of not exactly how it works; you set the clojure version in your projects' dependencies, so you are not constrained to a specific version.

1:40 TravisD: Ah, I see

1:40 Outside of a project, will there be a clojure repl available?

1:40 ddellacosta: TravisD: yeah, I like lein a lot, after coming from Ruby and using Rake and gem and bundler and whatnot...which is not bad, but I find lein better. Which is amazing considering it's managing maven ugliness.

1:41 TravisD: sure, you can start a repl anywhere.

1:41 TravisD: The closest to lein I've come is (C)makefiles

1:41 ddellacosta: So the globally available version of clojure is also installed by leon?

1:41 lein*

1:42 ddellacosta: TravisD: I don't have a great answer for you on that one--I assume that leiningen has a default Clojure version set, but I'll let someone more knowledgeable than I tell you more... technomancy or amalloy?

1:43 amalloy: TravisD: there's no particular reason to have a version of clojure that's "global". you have a version of clojure specified by each project you're in

1:43 TravisD: amalloy: While I'm learning I might like to have one I can just play around with

1:44 Raynes: `lein repl`

1:44 amalloy: if you're doing something quick outside a project, like a repl, you get the default, which is probably 1.5.1, but you can override that with something in ~/.lein/something

1:44 TravisD: awesome :)

1:44 ddellacosta: amalloy: sorry, I should be more clear about the context--TravisD was asking in the context of running a repl outside of a specific project

1:44 TravisD: I will read some on my own now

1:44 thanks for the advice and tips

1:45 ddellacosta: TravisD: good luck TravisD...enjoy! :-)

1:48 huh, haven't seen this CLJS exception before, any ideas? Exception in thread "main" java.lang.RuntimeException: Unable to resolve var: reader/*alias-map* in this context, compiling:(cljs/analyzer.clj:1498:11)

1:49 just trying to add CLJS to a previously running project, I get this when I run lein cljsbuild auto dev

2:02 TravisD: Is there a translation of SICP to clojure?

2:03 not sure if they are compatible enough languages for that to work

2:04 ddellacosta: TravisD: lots of stuff pops up on Google, but I can't vouch for any of it...I've only ever used racket to try to go through SICP

2:05 TravisD: http://sicpinclojure.com/ for example

2:05 "You should not be here yet."

2:05 amalloy: TravisD: attempts have been made, but really i'd just go through the actual book

2:05 ddellacosta: whoops

2:05 TravisD: amalloy: It would be nice if there was an annotated version of the book that had the rleated clojure information

2:06 amalloy: there's very little syntax used in sicp, so learning the few clojure constructs you'll need for the book is not that big a deal

2:06 TravisD: hehe, alright

2:10 ddellacosta: looks like I had an out-of-date tools.reader for anyone who encounters the same issue with CLJS I had above (ring and lib-noir were the culprits in my case): http://clojure-log.n01se.net/#01:48

2:10 now I have a completely different, lovely Google Closure error

2:15 ...which was caused by stefon loading the google closure compiler in addition to clojurescript. Hope that doesn't break stefon. *sigh*

2:23 szymanowski: hi, is there a function like haskell's 'tails' in clojure?

2:23 seangrove: ddellacosta: On noir eh? Legacy in the Clojure world...

2:23 szymanowski: What does tails do?

2:24 Nevermind, looked it up

2:24 szymanowski: ghci> tails "w00t"

2:24 ["w00t","00t","0t","t",""]

2:24 ddellacosta: seangrove: well, just lib-noir for sessions (https://github.com/noir-clojure/lib-noir). Not a huge fan of it in any case. Lots of state management weirdness in noir, in my opinion

2:24 szymanowski: it is simple to implement but just want to know

2:25 seangrove: szymanowski: I don't think there's one built in

2:25 Looks like someone wrote about it here http://joshrotenberg.com/posts/2013-12-31-datalist-functions-in-clojure.html

2:25 dsrx: ,(take-while not-empty (iterate rest "w00t"))

2:25 clojurebot: ("w00t" (\0 \0 \t) (\0 \t) (\t))

2:26 szymanowski: thank you dsrx

2:26 just-a-dev: interesting...

2:27 ,(str "testing irc bot")

2:27 clojurebot: "testing irc bot"

2:34 just-a-dev: ,(for [c (range 65 91)] [(char c) (char (+ 32 c))])

2:34 clojurebot: ([\A \a] [\B \b] [\C \c] [\D \d] [\E \e] ...)

2:59 szymanowski: i would like to implement a reduce function that stops iteration when returned accumulator is nil, does anyone could help me?

3:01 sk052: how to do xml parsing in clojure

3:01 szymanowski: http://clojuredocs.org/clojure_core/clojure.xml/parse

3:05 sk052: xml parsing api is it stax, sax or dom

3:09 oskarkv: szymanowski what exactly do you need help with

3:11 szymanowski: does my question make sense? or do you want me to rephrase it?

3:12 sk052: i have a zip file with 500+ xml file and each file is 300MB , need to parse them efficiently and load in db

3:12 oskarkv: szymanowski you mean you would like a new reduced function, like reduce', that stops when the the intermediate result is nil?

3:13 reduce*

3:13 szymanowski: yes

3:13 exactely

3:14 maybe i should use reductions for that

3:14 reductions returns a lazy seq?

3:15 oskarkv: yes you could, but it would not be the most performant solution ever

3:15 I think, but not that big of a deal maybe

3:15 szymanowski: ok, if you have a better idea i would like to know it!

3:15 oskarkv: szymanowski maybe this https://www.refheap.com/39081

3:17 szymanowski: i didn't know refheap it looks nice!

3:17 thank you i will try this

3:19 it works well thank you oskarkv

3:19 oskarkv: np

4:17 szymanowski: what is the best way to check if at least 1 item of coll1 is in coll2?

4:18 amalloy: szymanowski: as long as you're on clojure 1.5, you could just use ordinary reduce, and return (reduced nil) to mean "the answer is nil, now stop"

4:18 (some (set coll1) coll2)

4:19 szymanowski: great thank you

4:23 reduced function looks handy, i didn't know it

4:39 muhoo: reduced is nice for when you really don't want to loop/recur

4:46 borkdude: https://gist.github.com/borkdude/9016815

4:53 wow, eh, even this works ;)

4:53 IFn eval = Clojure.var("clojure.core","eval");

4:53 Object expr = Clojure.read("(+ 1 2 3)");

4:53 Long res = (Long) eval.invoke(expr);

4:56 also nice Date d = (Date) Clojure.read("#inst \"2014-12-12\"");

4:56 System.out.println(d);

4:56 I think Clojure can be a nice utility in many java projects =)

5:10 clojure.inspector - why didn't I know about that before? https://www.dropbox.com/s/1t0ftj5bo2qpltg/Screenshot%202014-02-15%2011.05.57.png

5:33 is there a built in clj function which gives me a file tree instead of seq?

5:40 raek: borkdude: there's always the File API... but using that the tree shape is in your recursive calls rather than in some data structure

5:41 http://stackoverflow.com/questions/8566531/listing-files-in-a-directory-in-clojure/8567237#8567237

5:41 borkdude: raek I already found something in Raynes's fs lib "iterate-dir" which gives me something like that

5:42 raek yeah, I even answered in that thread I see, but I'm just too lazy to type that all in ;)

5:42 raek: borkdude: oh, I see :-)

5:42 borkdude: raek I wanted to have a tree to play with in (clojure.inspector/inspect-tree ...)

5:42 raek since I just discovered that neat utility

5:44 I think I could have used inspect-tree when plowing through a lot of json-esque data :-s

5:46 I'm starting to get convinced that I should use mapv filterv etc by default and not map, filter, unless lazyness is explicitly wanted.

5:54 pyrtsa: borkdude: I often do the same. Especially when generating something like JSON output, it's much nicer that any errors in the processing happen at the call site rather than in the final rendering to string.

5:54 borkdude: pyrtsa yes, exactly the problem I had yesterday

5:54 pyrtsa I have been bitten by lazyness in more cases

5:55 pyrtsa: Laziness in Clojure is second-class, unfortunately. :|

5:55 borkdude: pyrtsa for example, someone used a dynamic var and binding. But my lazyseq was evaluated outside the scope of that binding, later. ;)

5:55 pyrtsa I agree that using arguments instead of dynamic vars is better generally

5:56 pyrtsa: I'm trying to do my best to avoid dynamic vars altogether.

5:56 borkdude: it would also prevent this situation

6:11 problem reconstructed: https://gist.github.com/borkdude/10ec65989ef4d371bbcd

6:14 so any recent new clojure (related) books?

6:16 Is this book any good, Clojure high performance? http://shop.oreilly.com/product/9781782165606.do?sortby=publicationDate

6:43 are there any people doing serious java development in emacs btw

6:46 maybe there should be something a la clojure.inspector in emacs, so you can use it also on servers without GUI. does it exist?

7:09 awesome: https://github.com/magnars/clj-refactor.el

8:28 szymanowski: what is the best way to check if multiple preds are true for a value

8:28 ?

8:32 like (all-true? 10 pos? (partial < 11)) => true

8:33 i don't want to write (and (pos? 10) (> 11 10))

8:33 edit: (partial > 11)

8:35 (defn all-true? [d & preds]

8:35 (eval `(and ~@(map #(list % d) preds))))

8:35 is this make sense?

8:37 AimHere: ,(every? identity ((juxt pos? even? #(< % 10)) 10))

8:37 clojurebot: false

8:37 AimHere: ,(every? identity ((juxt pos? even? #(< % 10)) 8))

8:38 clojurebot: true

8:38 AimHere: Seems to take clojurebot too much time to work that out for some reason

8:39 Chances are, if you're using 'eval', whatever you're doing is non-idiomatic

8:41 szymanowski: thank you!

8:42 so it is preferable to make a macro than a function that return (eval `(...)) ??

8:42 lazybot: szymanowski: Definitely not.

8:42 AimHere: Ignore the bot, in that case, a macro would be preferable

8:42 szymanowski: ok

8:54 elephantTechno: Hi, i'm currently writting a program where a global variable shared accross threads can be mutated at a first staged and is guaranteed not to mutate anymore at a second stage. Basically i'm in a "treasure hunting" situation where the fastest pirate gets all the gold while the others get nothing. I could just wrap the value ("treasure!" or nil) into a ref that I'd consider as my treasure chest. But I fear that

8:54 letting all the other pirates engage in STM races for a chest that is guaranteed to be nil at some point and forever, can lead to mismanaging cpu cycles in an impacting way.

8:55 Are my concerns justified ?

8:58 cark: there is no race if you're only reading

8:59 also you might want to consider using an atom

9:02 elephantTechno: Thank you

9:03 cark: to make it clear : transactions only retry when you're modifying the ref

9:03 *risk to retry

9:06 elephantTechno: Because you're forced to proxy the change through a dosync block

9:48 jro_: Exception in thread "main" java.lang.ClassCastException: java.lang.Long cannot be cast to java.lang.String at clojuresque.tasks.repl$eval863$start_repl_task_driver__865.invoke(repl.clj:11) at clojuresque.tasks.repl$eval863$start_repl__868.invoke(repl.clj:9)

9:48 while trying to start clojure repl with gradle clojureRepl

9:49 clojuresque 1.7.0 and nrepl 0.2.3

10:05 sdegutis: Good morning everyone.

10:28 michaniskin: good morning :)

10:28 EST representing

10:28 also it's 2^10 o'clock!

10:43 btcNeverSleeps: Does Clojure's "future" macro exist in JavaScript?

10:44 erf, in ClojureScript I meant of course

11:37 michaniskin: btcNeverSleeps: i don't think so. i don't see it in the source, and i tried on http://himera.herokuapp.com and it wasn't there either

11:37 btcNeverSleeps: however i do not have a repl handy with the latest cljs version

11:38 btcNeverSleeps: what are you trying to do? maybe core.async would be something you could use instead?

12:48 logic_prog: does clojure support setting up callbacks on atoms ?

12:48 i.e. on agents, I have watchers

12:48 can I register something similar for atoms, where it gets fired off whenver the atom changes?

12:50 gfredericks: yes

12:50 dnolen_: logic_prog: add-watch

12:50 qbg: As per the documentation of add-watch: Adds a watch function to an agent/atom/var/ref reference.

12:50 gfredericks: ,(doc add-watch)

12:50 clojurebot: "([reference key fn]); Adds a watch function to an agent/atom/var/ref reference. The watch fn must be a fn of 4 args: a key, the reference, its old-state, its new-state. Whenever the reference's state might have been changed, any registered watches will have their functions called. The watch fn will be called synchronously, on the agent's thread if an agent, before any pending sends if agent or re...

12:50 bbloom: but use them *sparingly* please!

12:51 gfredericks: bbloom: yeah?

12:51 bbloom: i've only ever used add-watch for enhancing my reload-file workflow. you only need ONE-ish callback for that

12:51 essentially to dispose old-val and initialize new-val

13:02 pyrtsa: bbloom: You don't even need add-watch for that. Can achieve the same with compare-and-set!.

13:02 bbloom: pyrtsa: nah, add the watch to a var & then simply reloading the file will cause the watcher to run

13:03 pyrtsa: Ah, I see.

13:03 Thought you were using it for an atom.

13:23 btcNeverSleeps: michaniskin: (was afk)... Thanks for the answer about future. Not trying to do anything in particular: but I'm writing Clojure code and future makes concurrency trivial. I was wondering if my code would be portable to ClojureScript or not : )

13:24 well, "trivial" compared to concurrency in Java I mean (I don't think concurrency is ever trivial)

13:24 bbloom: btcNeverSleeps: core.async is your best bet for concurrency in cljs. you can use channels like futures with relative ease too

13:25 btcNeverSleeps: bbloom: thx a lot, I love the dnolen/swanodette posts and videos about core.async. It's on my "todo list" anyway ^ ^

13:27 btw how do you call it in Clojure when you do '@': say @(future ...) [not that that example would be particularly smart] Do you "deref" a future?

13:27 (not a native english speaker and pretty new to Clojure btw)

13:28 bbloom: yes, which is short for "dereference"

13:28 btcNeverSleeps: but a 'future' ain't really an atom?

13:28 bbloom: dereference is an abstract operation

13:28 btcNeverSleeps: oh, ok.

13:28 bbloom: the concrete operation varies by type of the reference object

13:28 btcNeverSleeps: bbloom: thanks a lot

13:28 bbloom: for a future, you "get" or "await" it

13:56 jro_: jwave.core=> (time (doseq [i (range 1000) j (range 1000)] (aset arr i j (double 1.0))))

13:56 "Elapsed time: 10991.86 msecs"

14:10 logic_prog: For agents, I can attach watchers to it. For atoms, is there anything similar to wathchers I can attach to?

14:10 I.e. some function that is called whenever something changes.

14:11 aphyr: If anyone else has thoughts on (some?), (when-some), (if-some), I'd appreciate your comments here: http://dev.clojure.org/jira/browse/CLJ-1343?focusedCommentId=33790#comment-33790

14:11 not sure if I'm just misunderstanding things or if this is actually confusing.

14:13 Bronsa: aphyr: it is actually confusing.

14:14 teslanick: Seems like some? should be named nnil? or something like that. I haven't looked at the 1.6 docs yet, but I assumed there was a relationship between some and some?

14:14 ambrosebs: It seems Clojure has moved on from c.c/some.

14:16 bbloom: ambrosebs: yeah, i think the word "some" now just means not-nil and the name of c.c/some is now considered a wart?

14:16 ambrosebs: bbloom: seems like it

14:16 gfredericks: some?/if-some/when-some/some-> are as unrelated to clojure.core/some as all the namespace functions are to clojure.core/namespace

14:17 bbloom: yeah especially since some uses traditional truthiness semantics

14:17 Bronsa: I don't really care for the "some" part of the criticism, but the lack of "-let" really bothers me

14:17 gfredericks: yeah that part was pretty unexpected

14:17 bbloom: i think core.async is motivating if-some a bit

14:17 that would be my guess

14:18 gfredericks: six months from now these things will just be endearing

14:18 bbloom: i have a dorecv macro that is basically the same as for/range over a channel in Go

14:18 pretty useful

14:18 ambrosebs: I assume the nil channel semantics for core.async are concrete now.

14:19 otherwise these wouldn't have turned up

14:19 gfredericks: commitment to alpha API details will be announced by adding new core functions that relate to them

14:20 ambrosebs: gfredericks: yep

14:20 bbloom: Bronsa: the lack of the -let doesn't bother me

14:20 Bronsa: there are lots of macros that have bindings w/o a name that hints it

14:20 gfredericks: bbloom: usually because it's obvious they take one?

14:21 there isn't an extremely natural variant without a binding?

14:21 ambrosebs: oh they take a let binding?

14:21 Bronsa: ... see

14:21 bbloom: gfredericks: eh, clojure is anti-anaphoric. so it doesn't make much sense to test an expression without offering a binding for it

14:21 gfredericks: bbloom: if-some and when-some could be just alternate-truthiness versions of if and when

14:22 bbloom: gfredericks: i understand where your confusion comes from, but it's like "oh, these take a let binding? ok then" and i get on with my day

14:22 especially since there isn't much benefit in terms of cleaner syntax without the let binding

14:23 (if-some x y z) vs (if (some? x) y z) vs (if-some [_ x] y z)

14:23 gfredericks: good point

14:23 if-not-nil-and-let's-call-it

14:23 bbloom: lol

14:23 gfredericks: if-some-here-comes-a-binding-wait-for-it

14:25 bbloom: it's funny to me that rich had the foresight to avoid fancy truthiness, but still couldn't avoid the siren song of falsey nils

14:25 then sure enough, lazy seq enhancements come along, and we need (seq ...) everywhere anyway to deal with the subtle nature of next vs rest

14:25 just goes to show that you can solve 783957935 problems in a language design, and still miss.. INFINITELY MANY MORE

14:25 :-P

14:26 TimMc: and nil being punned as the empty seq as wlel

14:26 ambrosebs: bbloom: is this stuff easier to handle with just one false value?

14:27 bbloom: the lazy seq stuff

14:27 bbloom: ambrosebs: and just one true value, yeah i think so

14:28 you'd have (if BOOLEAN x y) and then if-let would only make sense as not-nil

14:28 or None rather

14:28 make nil be the empty seq, use None for logically no value

14:29 dnolen_: ambrosebs: bbloom: I don't see how one value solves the lazy-seq thing. you don't use seq to differentiate rest and next

14:29 seq + rest just works. if you use next you generally only call seq once.

14:30 bbloom: dnolen_: (rest [1]) would return nil and (rest nil) would return None, then you'd iterate until empty?. would be a bit clearer, but is basically a total rewrite of core :-P

14:30 not saying that what we have now isn't good

14:30 just saying that it can, as always with anything, be better

14:32 ambrosebs: bbloom: trying to unlearn clojure to grok your point ..

14:33 bbloom: ambrosebs: actually, (rest nil) could be a type error

14:33 TimMc: &(assoc nil 4 5)

14:33 lazybot: ⇒ {4 5}

14:33 bbloom: ,(first nil)

14:33 clojurebot: nil

14:33 TimMc: ^ seriously bizzare

14:33 bbloom: turns out, in clojure, nil actually represents an infinite list of nils :-P

14:34 gfredericks: each of which in turn,

14:34 TimMc: bbloom: Each one of which is an infinite list of nils...

14:34 * gfredericks wins

14:34 teslanick: That's a pretty awesome language wtf. :)

14:34 bbloom: TimMc: ok, fine an infinite tree of nils :-)

14:34 nil is used for all loads of stuff

14:34 but we're mainly stuck with it thanks to java

14:34 gfredericks: a tree with infinite branches at each node and no leaves

14:35 ambrosebs will save us from the nils

14:35 r0b1: bbloom: mainly stuck with nil due to java?

14:35 bbloom: really, we're stuck with *null* which is a useless form of none :-P

14:35 hyPiRion: gfredericks: and the branches are ordered too

14:35 TravisD: teslanick: Being strange makes it awesome?

14:35 bbloom: r0b1: calling java code can return null, so we need to be able to deal with null references in clojure

14:35 r0b1: ah

14:36 bbloom: but in a sane language, there would be no null references, only null pointers. if you wanted a null reference, you'd have a single instance of a None type

14:36 teslanick: TravisD: Maybe? Does that make Javascript *the most awesome* ?

14:36 TravisD: teslanick: I wouldn't think so :P

14:36 munderwo: Hi all. I've got a question about defining a db connection? code and question here https://www.refheap.com/39431. ...

14:37 TimMc: bbloom: I still don't understand the difference between a null pointer and null reference.

14:37 teslanick: I'm trying to get better string comparisons in a clojure unit test. I'm just using clojure.test right now, does midje offer clearer diffing?

14:38 bbloom: TimMc: a null pointer is a pointer to memory address zero. the pointer is a first class thing you can manipulate. a null reference is a null pointer that you can't talk about directly, ie to differentiate between the reference itself and the thing it refers to

14:38 hyPiRion: TimMc: A null pointer is of type Null/Void, containing nothing. A null reference is of type X

14:38 ambrosebs: I'm working on some destructuring macros that makes this kind of stuff explicit. Map destructuring fails on a missing key (dynamically and statically) unless you provide :or. Vector destructuring statically checks bounds by default, has options to check dynamically or use a default value for nth.

14:38 hyPiRion: Seems like I have completely different ideas about this than bbloom.

14:38 bbloom: TimMc: null references are not possible in C++, for example

14:38 * TimMc so far avoided learning C++

14:39 * hyPiRion high-fives TimMc.

14:39 hyPiRion: I'm not alone.

14:39 bbloom: So you say you cannot do &NULL in C++?

14:39 bbloom: hyPiRion: http://stackoverflow.com/questions/4364536/c-null-reference

14:40 smalltalk (and by extension ruby) got this right: null is an object

14:41 to be pedantic, null can actually be non-zero on some old/weird architectures/operating-systems

14:41 hyPiRion: I feel it's more correct to consider Null/None/Void as a noninstantiable type. But that would of course require statical typing.

14:41 TimMc: Where null is an object, doesn't that mean a null reference?

14:42 bbloom: TimMc: no, it's a reference TO the null object. not a reference that points nowhere

14:42 hyPiRion: void is a class with ZERO instances

14:42 aphyr: munderwo: Use (def ^:dynamic *db* {...})

14:42 bbloom: hyPiRion: where as None is a call with one instance :-P

14:43 aphyr: Then you can override it with (binding [*db* {... some-other-db ...}] (more-functions))

14:43 munderwo: cool, I'll give that a go. Does that make the var definable on a per thread basis? I think I remember reading about that.

14:43 aphyr: Yep.

14:43 hyPiRion: bbloom: yeah, but it's defined differently in different languages. Haskell and Rust uses None, for instance.

14:43 aphyr: But honestly, you may want to consider just making db a parameter to your functions.

14:43 hyPiRion: Oh wait, I gotcha now.

14:43 aphyr: Easier to test and reason about.

14:43 bbloom: hyPiRion: i'm generalizing names across languages. there are several concepts to contend with....

14:44 TimMc: bbloom: So in smalltalk you have a reference to the null object, whose memory location is zero?

14:44 hyPiRion: bbloom: yeah, Void is uninstantiable, whereas None is a singleton

14:44 bbloom: TimMc: no. the memory location of null is not zero in smalltalk or ruby

14:44 irb(main):002:0> nil.object_id

14:44 => 4

14:44 TimMc: So it's not a null pointer either?

14:44 more like Unit

14:45 bbloom: TimMc: yeah, more similar to Unit, which is, THE "unit" type, b/c it has only one instance, but None is *also* a unit type, just not THE unit type

14:45 TimMc: that's why i don't like the name Unit for a type b/c it's confusing... it suggests you can't have other unit types

14:45 TimMc: hmm

14:46 * TimMc digests

14:47 TimMc: f10dd67234035228da3ec382bab7a49b

14:47 bbloom: lol

14:49 hyPiRion: It's a shame Java doesn't have generic enumerations. That would've solved a lot.

14:50 bbloom: anyway, if it were up to me, i'd break everybody and just redefine (if-let [x (evaluates-to-false)] ...)" to be a bug

14:50 actually, hmmm... can we do that? lol

14:51 hyPiRion: bbloom: alter-var-root?

14:51 bbloom: :-)

14:52 hyPiRion: I tried to manipulate false to return true through reflection once, but it segfaults the JVM unfortunately

14:52 bbloom: no seriously... the only difference between if-let and if-some is the handle of false

14:52 handling*

14:52 it would be a breaking change for anybody who passes false to if-let, but could easily be worked around by passing nil instead

14:53 seems like if-let should have always been if-some

14:54 ambrosebs: bbloom: I could add a case in dynalint.. :)

14:55 bbloom: I've considered adding a case for (some #{nil false} ...)

14:56 hyPiRion: ambrosebs: you should, it always return nil regardless.

14:56 dnolen_: bbloom: various proposals for things like if-some have come up in the past, it's an obvious generalization of if-let

14:56 bacon1989: Hello, I was wondering if someone could point me in the right direction with a fairly simple data-restructuring problem. Say I have a hashmap, like {:first-name "John" :last-name "Doe" :age 24} and I wish to create a new hash-map with only the :first-name and :last-name keys, what are some possible ways to do this?

14:56 bbloom: dnolen_: it's not a generalization

14:56 dnolen_: bacon1989: dissoc

14:56 paulswilliamsesq: Hi all, can any kind soles assist in explaining why code seems to execute in functions when the functions haven't been invoked?

14:56 bbloom: dnolen_: it's a workaround for a semantics bug, IMO

14:56 dnolen_: bbloom: how is it not?

14:56 ambrosebs: bacon1989: select-keys

14:57 dnolen_: bbloom: no semantic far as I can see.

14:57 bbloom: dnolen_: "generalization" implies it solves a more general class of problems

14:57 hyPiRion: bacon1989: (select-keys my-map [:first-name :last-name]) will ensure that only first-name adn last-name is contained

14:57 dnolen_: bbloom: it does, multiple bindings, multiple tests

14:57 this happens all the time and it's ugly

14:58 bbloom: dnolen_: i think you didn't follow my though process above

14:58 CaptainLex: So I assume this question is asked all the time

14:58 but

14:58 why doesn't clojure support tail-recursion optimization?

14:58 dnolen_: bbloom: I did, but I also didn't agree or see the point.

14:59 bbloom: dnolen_: the point is that if-let testing truthiness was always an approximation for the desired semantics of checking non-nil-ness

15:00 aphyr: if-let*

15:00 bbloom: dnolen_: (if-let [x false] ....) is just not very useful

15:00 aphyr: bbloom: I actually use that form all the time

15:00 bacon1989: ah thanks guys, i'll look at those functions

15:00 bbloom: aphyr: you use if-let with an expectation of a false value all the time?

15:01 aphyr: With the expectation of a non-false or non-nil value.

15:01 bbloom: aphyr: but do you ever expect false? or always nil vs not nil ?

15:02 aphyr: I typically don't want to bind false.

15:02 munderwo: aphyr: yeah thats probably what I would do in other languages, all the examples I've seen have defined it in the file and then just referred to the global after that. So I wasn't sure if there was some clojure-esque reason to do that, or they were just simplified cases.

15:03 bbloom: aphyr: but do you want to bind true?

15:03 aphyr: presumably when you use (if-let [x ...) you want a useful payload in x

15:03 aphyr: Sometimes the values of x might be either false or a number.

15:03 dnolen_: bbloom: (if-let [x (and (pred? y) (compute z))] ...)

15:04 aphyr: I dunno, I can certainly see an argument for changing if-let and when-let to non-nil as opposed to truthy.

15:04 bbloom: dnolen_: that's not what if-some is

15:04 dnolen_: bbloom: you're right that if-some is generalization of a particular usage of if-let

15:04 aphyr: But that seems confusing when you compare it to (if) and (when)

15:04 bbloom: dnolen_: oh wait....

15:05 dnolen_: sorry, my bad

15:05 dnolen_: (if-let [...] (if-let [...]))

15:05 bbloom: dnolen_: i'm looking at the ticket now

15:05 dnolen_: or the actual patch rather

15:05 instead of the comments in the thread

15:05 dnolen_: heh

15:05 bbloom: oh wow

15:05 dnolen_: starting in the wrong place man

15:05 bbloom: nevermind, these names are mega confusing lol

15:05 gfredericks: oh geez

15:05 bbloom: if-pred

15:05 hyPiRion: what, there's an if-pred?

15:05 bbloom: ok i still stand by all the stuff i said above about if-let

15:06 gfredericks: bbloom: what aspect do you think is confusing?

15:06 sjl: if-some == if-not-nil-let

15:06 aphyr: Yep.

15:06 gfredericks: bbloom: (I'm not sure how you were misunderstanding it)

15:06 bbloom: maybe i'm not... hold on

15:06 i'm looking at http://dev.clojure.org/jira/secure/attachment/12790/clj-1343-4.patch

15:07 that patch seems to not match what rich is saying

15:07 hyPiRion: what. I had the intuition that if-some was (if (not (nil? z))) x y)

15:07 gfredericks: hyPiRion: that's most people's complaints wrt confusing names

15:07 sjl: hyPiRion: no, it binds things like if-let

15:07 even though there's no -let in the name

15:07 bbloom: dnolen_: no no, i'm right

15:07 dnolen_: there is no explicit predicate

15:07 it's not a generalization

15:08 hyPiRion: sjl: yeah, I gathered. I even read the 1.6 changelog and still thought it acted like that.

15:08 sjl: hyPiRion: yeah that's because the naming is confusing

15:08 hah

15:08 bbloom: dnolen_: it would be a generalization if it took an explicit predicate

15:08 aphyr: I could see (let-some)

15:08 bbloom: dnolen_: there is a generalization if if-let and if-some that would be if-pred

15:10 paulswilliamsesq: in particular, defn-ing a function with (defn draw-frame [f x y] (let [frame (java.awt.Frame.)])) causes a Frame to be instanciated yet I haven't invoked the function.

15:10 bbloom: dnolen_: `(defmacro if-some [[k & v] then else] `(if-pred (comp not nil?) [~k ~v] ~then ~else)) ; for some hypothetical if-pred, then if-pred would be the generalization of if-some and if-let, where if-let's explicit predicate is simply `boolean

15:10 i stand by everything i said above :-)

15:12 ambrosebs: paulswilliamsesq: does it still show a frame when compiled in a REPL? Perhaps you're running other things accidentally.

15:12 paulswilliamsesq: ambrosebs: yeah - I've loaded a new repl and defn that function. I can't actually see a frame but a seperate window appears to open.

15:12 bbloom: ,(defn test-pred [pred x] (if (pred x) x nil))

15:12 clojurebot: #'sandbox/test-pred

15:13 bbloom: ,(map #(test-pred odd? %) [3 4 5 6])

15:13 clojurebot: (3 nil 5 nil)

15:13 bbloom: dnolen_: ^^ there, now you don't need if-pred :-)

15:13 ,(if-let [x (test-pred odd? 5]] :yup :nope)

15:13 clojurebot: #<RuntimeException java.lang.RuntimeException: Unmatched delimiter: ]>

15:14 bbloom: ,(if-let [x (test-pred odd? 5)] :yup :nope)

15:14 clojurebot: :yup

15:14 bbloom: ,(if-let [x (test-pred odd? 6)] :yup :nope)

15:14 clojurebot: :nope

15:14 bbloom: :-)

15:14 hyPiRion: ,(if-let [x (test-pred false? false)] :is-false :is-true)

15:14 clojurebot: :is-true

15:14 hyPiRion: :)

15:14 bbloom: hyPiRion: clearly you need to use if-some, since if-let is broken

15:15 hyPiRion: but the bots aren't up to date, so i just assumed clojure 2.0 where this is fixed ;-)

15:15 or maybe it's bbloom 1.0

15:15 hyPiRion: bbloom: good call

15:15 bbloom: whatever :-)

15:15 sjl: ,(if-some [x (test-pred nil? nil)] :is-nil :wat)

15:15 clojurebot: #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: if-some in this context, compiling:(NO_SOURCE_PATH:0:0)>

15:16 bbloom: ,(defmacro if-some [bindings then else] (let [form (bindings 0) tst (bindings 1)] `(let [temp# ~tst] (if (nil? temp#) ~else (let [~form temp#] ~then)))))

15:16 clojurebot: #'sandbox/if-some

15:16 bbloom: ,(if-some [x (test-pred nil? nil)] :is-nil :wat)

15:16 clojurebot: :wat

15:16 bbloom: hyPiRion: there you go

15:17 sjl: bbloom: that's wrong though

15:17 bbloom: the predicate is nil

15:17 ?

15:17 hyPiRion: bbloom: heh.

15:17 sjl: nil satisfies the predicate

15:17 and yet the else clause is returned

15:18 * hyPiRion walks back to the drawing board.

15:18 erdos: hello everybody, i have a symbol object that behaves a little bit strange for me: for (str), (type), (symbol?), (name), (bean) it returns: use, clojure.lang.Symbol, true, nil, {:namespace nil, :name use, :class clojure.lang.Symbol}; my question is, why is it possible it gives nil for (name)? thanks!

15:18 bbloom: sjl: and now you see why type theory people argue for sum types :-)

15:18 sjl: yep

15:18 bbloom: at this point, you need quoting :-P

15:18 b/c you need None and Some(None)

15:18 sjl: you need to disentangle the value from the predicate check

15:18 a hypothetical if-pred would be fine

15:19 bbloom: and an if that only operates on booleans would help too

15:19 sjl: but that if-some form is basing its decision on both the result of the predicate and (if test-pred passes it through) the value itself

15:21 hyPiRion: erdos: That's strange, how did you construct the symbol?

15:21 I can't reproduce that

15:21 ,(name 'use)

15:21 clojurebot: "use"

15:23 paulswilliamsesq: ambrosebs: well, it appears not to draw the frame, but definately starts some other process up. I'm on OSX and get a new window opened with a Main menu item if that makes sense?

15:23 erdos: hyPiRion: hello, i used clojure.tools.reader/read

15:23 hyPiRion: even (.getName) returns the correct value. also (string?) is false.

15:24 heath: i was watching rich give a presentation on csp about a week ago on callbacks

15:24 ambrosebs: paulswilliamsesq: unless there is some macro that spins up a process when it expands, I don't see how that's possible

15:25 heath: he mentioned promise libs are popular again because of this

15:25 ambrosebs: paulswilliamsesq: I guess you've tried restarting your JVM?

15:26 heath: i was under the impression while he was talking that promises are something you wouldn't want to utilize, but i'm seeing in the notes of the latest clojure release that promises are available and stable?

15:26 Why does clojure have promises, and are these the same types of promises he was referencing in the talk?

15:26 ambrosebs: erdos: can you elaborate more on where the symbol is coming from? is it metadata?

15:27 paulswilliamsesq: ambrosebs: no I don't either. yes, I've killed all JVMs.

15:27 egghead: heath: the general idea is that promises are good for one-off async events, but they aren't too good for streams

15:27 paulswilliamsesq: new lein repl from my home directory which has't got a lein project installed.

15:27 ambrosebs: paulswilliamsesq: perhaps try it in a completely empty project? I'm out of ideas.

15:27 paulswilliamsesq: ambrosebs: yeah, wil do.

15:28 erdos: ambrosebs: hello, i am parsing ns declarations of source files with clojure.tools.reader 0.7.7 . strangely .getName is ok.

15:28 ambrosebs: erdos: can you show some code?

15:29 erdos: ambrosebs: working on it

15:29 heath: cool, thanks egghead

15:29 ambrosebs: erdos: would like to know out of morbid curiosity as well ;)

15:29 dnolen_: bbloom: yes I said agreed, it generalizes a very specify use of if-let

15:30 s/specify/specific

15:30 bbloom: dnolen_: i think disagree on what the word "generalizes" means...

15:32 aphyr: haha

15:32 bbloom: dnolen_: it specializes a more general predicate/binding/branching pattern. if-let is also a specialization of that same general thing

15:33 dnolen_: bbloom: macro sugar generalizes patterns as far I am concerned.

15:34 bbloom: dnolen_: generalize is not the word you're looking for

15:35 dnolen_: generalizes syntactical patterns, or perhaps you don't believe that macros do this?

15:35 bbloom: then give me a better word?

15:35 hyPiRion: unboilerplatify them at least

15:35 dnolen_: :P

15:36 bbloom: abbreviate? i dunno

15:36 definitely not generalize

15:36 dnolen_: bbloom: then rewrite in your brain my points and we can move on :)

15:36 * bbloom scrolls up

15:37 bbloom: dnolen_: yeah, the word "abbreviate" works for your points, heh

15:38 benmoss: dnolen_: can you explain the conceptual difference between state stored on the owner vs on the component in Om?

15:38 bbloom: once again, 99% of all disagreements can be divided in to one of two fundamental categories: operating from different definitions or operating from different motivational principals

15:38 i'd imagine 60 to 80% are in the definitions camp :-P

15:39 dnolen_: benmoss: Om uses delegation, there's only one React component type in Om, so we delegate to your reify instance.

15:39 benmoss: component local state is actually stored on the React component that "owns" your reify instance

15:45 benmoss: hmm I'm afraid i don't follow

15:46 dnolen_: benmoss: above you're describing a distinction that does exist. That's what I was trying to explain.

15:46 s/does/doesn't

15:46 benmoss: yeah, that's what i suspected

15:49 so to use a concrete example, in your todo app you set "needs-focus" on the owner, whereas you set "editing" on the component. are you saying they actually are both on the owner?

15:50 dnolen_: benmoss: easier to understand what you're struggling w/ if you give me links to line numbers?

15:50 benmoss: yeah was about to get that

15:50 egghead: hm

15:51 benmoss: https://github.com/swannodette/todomvc/blob/gh-pages/labs/architecture-examples/om/src/todomvc/item.cljs#L31 sets "needs-focus" on the owner, https://github.com/swannodette/todomvc/blob/gh-pages/labs/architecture-examples/om/src/todomvc/item.cljs#L31 reads "editing" off the todo

15:51 egghead: i figured the app-state was things like the stuff that comes over your web api, and the owner-state was stuff that had to do with the state of your components like async chans or things like error messages, etc

15:51 benmoss: woops

15:51 egghead: but I could see something like 'is this component in edit mode' going into owner state

15:51 benmoss: https://github.com/swannodette/todomvc/blob/gh-pages/labs/architecture-examples/om/src/todomvc/item.cljs#L66 for the second link

15:52 egghead: I guess that's just an organization sort of thing?

15:52 dnolen_: benmoss: so the second is link is what is referred to in the React world as "props"

15:52 benmoss: the first link is setting component local state

15:53 benmoss: in Om "props" are values from the app-state atom

15:53 benmoss: yeah

15:53 so i think that is what i was trying to get at, what is the conceptual difference between what you would store in app-state vs component local state

15:53 dnolen_: benmoss: usually anyway, props can actually be anything.

15:54 benmoss: very little should go into local state, like egghead said - channels, transient information (like mouse position, element dimensions), etc

15:55 benmoss: however there is no hard fast rule, if you want to snapshot many points in a graphical editing application, maybe you do want to store what you normally consider transient state

15:57 benmoss: i'm trying to model a chess game and think i need a place for "the possible moves for a given piece/position"

15:58 it both represents the legal moves for that piece, as well as the information for which other positions to highlight

15:59 dnolen_: benmoss: but I don't think you need to store that you can compute that

16:01 benmoss: hm, through each individual square checking to see if it is eligible for being moved from a piece of top-level app state about the currently selected square?

16:03 like the app-state would contain {:currently-selected "e8"} or whatever, and each square could check what piece is on e8 and thus if that piece could move to them?

16:03 TravisD: Can anyone suggest a library that facilitates linear algebra and plotting? I was looking at Incanter, but it seems somewhat outdated

16:04 dnolen_: benmoss: no you would compute the grid based on the information you have and then render it.

16:05 benmoss: individual squares compoent should just render the data they get - no logic except maybe click event

16:07 TravisD: Actually, incanter looks pretty nice.

16:07 dnolen_: benmoss: a better way in mind would be a component to get {:current-selected true} and have some additional behavior because of this.

16:10 benmoss: yeah so a function that passed {:selected true} to the selected square, and like {:targetable true} to the squares the piece can reach

16:10 dnolen_: benmoss: yep

16:11 benmoss: thanks, it seems so obvious now :)

16:12 dnolen_: benmoss: chess is actually a pretty good thing to try with Om.

16:12 benmoss: this actually a pretty presentation that someone did at RubyFuza on Om http://www.slideshare.net/danieroux/rubyfuza-2014, uses chess as an example

16:12 benmoss: yeah, i saw you posted that on twitter

16:13 dnolen_: s/pretty/pretty sweet

16:14 benmoss: looks very similar, i think we both ripped off the same html chess board

16:17 bbloom: dnolen_: thank you so much for helping react take off :-)

16:17 we as a profession will escape the brain dead OOP GUI model some day

16:17 dnolen_: bbloom: haha, yeah it's exploded!

16:17 bbloom: finally people are looking past JSX

16:18 bbloom: dnolen_: my guess was that it was an audience targeting issue. the typical javascript folks didn't understand why it was interesting and the folks who would understand simply have given up looking at javascript stuff

16:18 dnolen_: bbloom: haha

16:18 bbloom: the cljs community was inherently the right overlap

16:19 ie people who care about browser GUIs AND sane semantics

16:19 * bbloom pats collective selfs on back

16:22 dnolen_: bbloom: yeah, I'm starting to see that React/Om really shines though w/ core.async

16:22 bbloom: dnolen_: have you baked it in to Om yet? / will you?

16:22 dnolen_: like multiple om-syncs can write to a channel and you can write batch update logic to server. w/o screwing around w/ your code.

16:22 bbloom: probably won't do that. Om is close to "done". Only interested in internal improvements and more performance.

16:23 bbloom: dnolen_: ok cool

16:23 for further communal self congratulations: gotta love libraries that are "done"

16:26 AmnesiousFunes: dnolen_: Thanks for your work with Om; it's a really pleasant library, and I see myself using it as much as possible in the future.

16:26 benmoss: meanwhile thousands of people use the perpetually in-beta ember-data

16:26 dnolen_: benmoss: lol

16:26 AmnesiousFunes: thanks!

16:27 AmnesiousFunes: benmoss: I remember Discourse (the big forum project) electing to use Ember because they felt it was "future-proof".

16:27 bbloom: benmoss: over 10k of javascript for that thing... and it has dependencies too

16:28 klocs, that is

16:28 not kb

16:29 Ayey: Does Discourse use ember-data? I thought they avoid it because it was unstable.

16:29 benmoss: they don't

16:31 Ayey: ph, okay

16:31 oh*

16:34 benmoss: it is an ORM for APIs, it is a horrible thing

16:36 bbloom: two things i dislike :-P

16:36 i'm pretty sure that my hate gets multiplied together, rather than added

16:38 btcNeverSleeps: ,(doc doc) ; just trying if doc works here

16:38 clojurebot: "([name]); Prints documentation for a var or special form given its name"

16:38 bbloom: btcNeverSleeps: doc also works here without the ,

16:38 (doc doc)

16:38 clojurebot: "([name]); Prints documentation for a var or special form given its name"

16:38 btcNeverSleeps: bbloom: oh cool ^ ^

16:41 I'm doing this: (make-array (type XXX) x y)) because I don't know what type XXX is. Is it ok to use (type ...) on something to pass the type around without knowing what the type is?

16:42 * btcNeverSleeps is sad because Paredit doesn't work in erc-mode

16:42 bbloom: btcNeverSleeps: seems fine, but do you actually want a typed jvm array or do you want Object[] ?

16:44 btcNeverSleeps: bbloom: Object[] would be fine too. In my case I was instantiating an array of sha-256 hashes, so it's an array of byte arrays.

16:44 bbloom: ,(make-array Byte/TYPE 5)

16:44 clojurebot: #<byte[] [B@4ed19b>

16:44 bbloom: btcNeverSleeps: is that what you want?

16:45 btcNeverSleeps: if you know that the array contains only primitives of one type, then you probably want a primitive array to avoid boxing

16:45 btcNeverSleeps: bbloom: well, yes but... My question was more like: is it ok to simply do (make-array (type (byte-array [])) or, more generally, (make-array (type ...)) when you don't know what type you're dealing with.

16:45 bbloom: oooh gotcha

16:45 bbloom: btcNeverSleeps: oh i see, an array of byte arrays

16:45 btcNeverSleeps: arrays are, themselves, boxed types. so it won't matter

16:46 unless you care about interop with some java API

16:46 an array of objects is fine for the outer array

16:48 btcNeverSleeps: make sense? so you can just use object-array or into-array without a type argument

16:48 hyPiRion: it's not hard to just do (make-array (Class/forName "[B") dims) either

16:49 bbloom: hyPiRion: there is no benefit to doing so. actually it probably hurts, since you'll get an extra type check at runtime

16:49 benmoss: is there something more succinct than (if (pred? x) (conj x foo) x)

16:49 bbloom: hyPiRion: java's array variance stuff is all kinds of weird

16:49 btcNeverSleeps: (was afk)

16:49 bbloom: yup, makes lots of sense

16:49 benmoss: like an if/when that defaults to returning the value

16:49 hyPiRion: benmoss: (cond-> x (pred? x) (conj foo))

16:50 benmoss: hyPiRion: thanks

16:50 hyPiRion: bbloom: funny, didn't know that

16:51 bbloom: hyPiRion: i mean, i'm just guessing about how the jvm works here, but think about it.... it has to throw an error if hte type doesn't match

16:51 hyPiRion: but if you already have a boxed pointer, you can just copy it w/o checking it, right?

16:51 hyPiRion: bbloom: right, but then you'd have to check at read time then?

16:52 btcNeverSleeps: hyPiRion: I know it's not hard to do (make-array (Class/forName "[B") ...) but I was wondering, when you don't know if it's [B or [I or whatever, is it ok to just create a "dummy" object and call "type" on it. IOW: (Class/forName "[B") vs (type (byte-array []))

16:52 for it feels like some kind of a "hack" to write (make-array (type ...) ...)

16:52 danneu: (Class/forName "[B") is 'hard' though

16:52 ugh

16:52 btcNeverSleeps: danneu: well, I come from many years of Java so it doesn't look too alien but I tend to agree it's 'hard' ^ ^

16:53 Cr8: ,(class (byte-array []))

16:53 clojurebot: [B

16:53 bbloom: hyPiRion: hm, that is true...

16:53 hyPiRion: btcNeverSleeps: Well, you could just do (def byte-array-type (type (make-array Byte/TYPE))), if you're afraid of perf

16:54 bbloom: hyPiRion: perf likely depends on whether your calling a virtual method or not. if it's a non-virtual method, then yeah, you need to pay a type check cost for that. but if it's a virtual method, you'd likely get a polymorphic cache at the call site, so it wouldn't matter either way

16:55 btcNeverSleeps: either way, use the more specific type if it makes you feel good or if you benchmark it and it matters :-P

16:55 btcNeverSleeps: bbloom: :)

16:55 * btcNeverSleeps gone cooking

16:55 danneu: Clojure has been a joy for working with bytes. (map int <bytes>), (map (partial bit-and 0xff) <bytes>), (map unchecked-byte <ints>)

16:56 hyPiRion: heh, I've sort of given up on an actual analysis of performance wrt. time.

16:56 bbloom: heh

17:05 Nooob: Hi, guys, Im a Clojure newbie, and I have a simple question that I think you guys can help me with... which IDE should I use?

17:05 aphyr: Nooob: most folks use emacs or vim.

17:06 Though any text editor you like should work fine.

17:06 Some folks use LightTable, which is a clojure-specific IDE, but I don't think that's common yet.

17:07 Nooob: aphyr I was messing with emcas, but feels weird

17:08 dnolen_: Nooob: CursiveClojure is very good, probably the best traditional IDE experience

17:08 Nooob: hummm

17:08 dnolen_: Nooob: LT is simple and pretty easy to use

17:08 AmnesiousFunes: CIDER is quite good as well. Light Table is very immediate and accessible.

17:10 r0b1: Nooob: i was going to suggest emacs as well but it doesn't seem to be for everybody. it has the bonus that you can extend the editor with lisp though.

17:10 danneu: I tried various editors when I was learning Clojure. I can't imagine fiddling with an editor during that stage

17:11 qbg: Nooob: Are you comfortable with with an IDE for another programming language?

17:11 Nooob: r0b1 this ability to extend the editor really makes the difference?

17:12 qbg yes =)

17:12 qbg: Which one?

17:12 AmnesiousFunes: Nooob: For "serious" usage, yes. (By the way, Light Table is also extensible.)

17:12 r0b1: Nooob: "with lisp", yeah :) as you learn clojure you'll become more comfortable learning elisp and vice versa i'd guess.

17:12 AmnesiousFunes: (It is much less mature than Emacs with CIDER at this stage, though.)

17:13 danneu: Nooob: For Clojure, what matters is arriving at a quick iteration where you can eval code within the editor (not in a REPL)

17:13 Nooob: qbg Eclipse, NetBeans...

17:13 r0b1: that are horrible "editors"

17:13 those*

17:14 aphyr: (I basically just use vim as a dumb text editor, and use `lein repl` for live evaluation.)

17:14 qbg: In the past I've used Counterclockwise with Eclipse, but I've been out of the Clojure loop for a while

17:14 danneu: aphyr: how do you get code to the repl?

17:16 Nooob: well, I think ill try Cursive and give emcas another shot hehe

17:17 AmnesiousFunes: danneu: lein repl can load namespaces automatically; read about leiningen configuration for more information

17:19 aphyr: danneu: (use 'foo.core :reload)

17:20 Though most often I have lein prism running, so I just write the file and it automatically re-runs the tests.

17:20 danneu: yeah, i don't know why i asked that

17:20 that's how often i've used a repl

17:21 aphyr: have you ever used an editor that lets you eval the buffer? i only ask because evaling the buffer or the selected region or previous form are the most productive things to ever happen to my workflow.

17:21 r0b1: your repl can help in cases like this by better supporting "repl-driven development"

17:24 Nooob: well, guys thank you very much for the tips ^^ I really appreciate, and sorry for my bad english hehe

17:24 koz: Hi everyone! I've just installed Linux Mint 16, and set up leiningen for it. However, when I tried to run 'lein upgrade', it told me that I should be using apt instead of leiningen for upgrades.

17:24 How do I do that?

17:26 benmoss: `apt-get install leiningen`?

17:26 koz: benmoss: really? OK... simpler than I thought.

17:26 Thanks!

17:26 Also, does SciTE have any support for Clojure?

17:27 benmoss: never even heard of SciTE, no idea

17:27 koz: What's a good text editor with Clojure support for Linux. Other than Emacs/vim.

17:28 (Although I should learn Emacs some time)

17:28 systemfault: koz: Perhaps lighttable

17:28 benmoss: people were just talking about this, yeah light table is a popular choice

17:28 danneu: koz: does `lein` do anything when you run it?

17:28 benmoss: if you don't have any prior allegiances

17:28 koz: danneu: Yeah, it works for everything as normal.

17:28 danneu: koz: what version is it

17:28 koz: benmoss: I'm new to Linux. So no, no priors.

17:29 benkay: ,(map #(inc %) [1 2 3])

17:29 clojurebot: (2 3 4)

17:29 koz: danneu: 1.7.1

17:29 benkay: (map #(inc %) [1 2 3 \f])

17:29 koz: Which I assume is the latest.

17:29 benkay: ,(map #(inc %) [1 2 3 \f])

17:29 clojurebot: #<ClassCastException java.lang.ClassCastException: java.lang.Character cannot be cast to java.lang.Number>

17:29 danneu: koz: `apt-get install leiningen` installs an old version. install it by hand

17:29 hyPiRion: koz: no, 2.3.4 is the latest one

17:29 amalloy: $google leiningen readme

17:29 benkay: right, so how do I shoehorn a try/catch into that mapping?

17:29 lazybot: [leiningen/README.md at master · technomancy/leiningen · GitHub] https://github.com/technomancy/leiningen/blob/master/README.md

17:29 danneu: koz: https://github.com/technomancy/leiningen

17:29 koz: Ah, I see.

17:29 Thanks.

17:30 hyPiRion: koz: so you'd do `sudo apt-get remove leiningen` first, to remove the apt installed version

17:30 benmoss: my bad, i had no idea apt was out of date

17:30 amalloy: i don't think apt-get install installs the latest version of *anything*, but it's more out of date than usual for clojure stuff

17:30 koz: Thanks for the warning guys.

17:30 danneu: yeah, it gets brought up some time. it's unfortunate that apt is out of date and it makes things not work in nonobvious ways

17:30 amalloy: danneu: i mean, that's like a core feature of apt. things get in when they're stable, not when they're new

17:30 benmoss: and that the old lein upgrade warning tells you to use apt

17:31 danneu: amalloy: sure, i mean unfortunate for a newcomer that doesn't know

17:31 gws: benkay: do you expect the result to be nil or (2 3 4) or something else?

17:31 benkay: ah it's not the result i'm terrifically concerned with so much as the inputs

17:32 koz: So you want it to fail if you feed it a list with anything other than a number?

17:32 benkay: well, it's an example.

17:32 i want to catch exceptions thrown in the mapped function

17:33 koz: Can't you wrap the whole map call in a try-catch?

17:33 gws: yeah, and then do what with the result

17:33 hyPiRion: koz: unfortunately, map is lazy, so that won't do

17:33 benkay: uh, log it, throw it away, i don't care fuckit.clj

17:34 the root question i'm pursuing here is how best to implement a try/catch with a mapped function

17:34 map the try/catch form?

17:34 (map #(try (my-fn %) (catch some.java.whatever) [list-o-stuff]))?

17:34 koz: benkay: Not what I meant. Wrap the actual map call in a try-catch.

17:35 hyPiRion: ,(try (doall (map inc [1 2 3 \f])) (catch Exception e :error))

17:35 clojurebot: hyPiRion: Cool story bro.

17:35 hyPiRion: &(try (doall (map inc [1 2 3 \f])) (catch Exception e :error))

17:35 lazybot: java.lang.SecurityException: You tripped the alarm! catch is bad!

17:35 hyPiRion: blugh.

17:35 Well, the point is that you have to wrap it in a doall or replace it with mapv. Otherwise the exception could get thrown outside

17:36 benkay: sure, makes sense. the actual funcall is happening inside a doall already and is being pmapped to make things worse and more complex

17:37 so walk me through one more time in words of single syllables why mapping the try/catch is not going to work?

17:38 hyPiRion: Mapping the try/catch would work nice, but I have no idea what you'd like the mapping to return then

17:39 benkay: it's a nasty side-effecty thing don't worry about it

17:39 ,(map #(try (inc %) (catch java.lang.ClassCastException (println "nooooo"))) [1 2 3])

17:39 clojurebot: benkay: No entiendo

17:39 benkay: yeah me neither clojurebot

17:40 okay well in that case i'm going to defer to your sage advice hyPiRion and wrap the doall.

17:41 koz: OK, manual install worked.

17:41 hyPiRion: benkay: well, I mean. It sort of depends on what you want. catching outside would stop the execution of later function calls (sort-of, pmap is its own beast), whereas wrapping it inside the function would not

17:41 koz: Thanks everyone.

17:41 benkay: hyPiRion: just figured that out :(

17:41 yeah! i think i really want to pmap the try/catch itself if i can..

17:42 hyPiRion: benkay: yeah, go ahead. Noone's stopping you

17:42 beamso: ,(doc int?)

17:42 clojurebot: Pardon?

17:43 beamso: you could do a check to ensure every item in the vector was an integer

17:44 benkay: again, beamso, that's not really what's at issue here.

17:44 koz: OK.... maybe not.

17:44 I get

17:44 'THe program 'lein' is currently not installed. You can install it by typing: sudo apt-get install leiningen

17:44 But that will give me the old version

17:45 hyPiRion: koz: okay, where did you place the lein script?

17:45 qbg: lein is probably not on your path

17:45 koz: in ~/bin, which is on my path.

17:45 hyPiRion: koz: did you do `chmod u+x ~/bin/lein` ?

17:46 (to make it executable)

17:46 beamso: move the 'inc' into it's own function where you handle the exception there and provide a default value/no value to return?

17:46 koz: No - I did chmod +x

17:46 So I need the u as well.

17:46 hyPiRion: well, that shouldn't matter I think

17:46 qbg: How long has ~/bin been on your path?

17:46 hyPiRion: I'd try to restart the shell, sometimes it may not detect stuff at once

17:46 koz: I just put it there, and I restarted the shell.

17:47 If I type echo $PATH, it's definitely there.

17:47 (As the very last entry)

17:48 qbg: what does `which lein` return?

17:48 koz: Nothing.

17:48 * hyPiRion scratches his beard.

17:48 qbg: Perhaps PATH is malformed?

17:48 koz: I'll just copy-paste the result of echo $PATH

17:49 /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:home/koz/bin

17:49 qbg: you need /home there

17:49 not home

17:49 koz: Ah,

17:49 OK.

17:50 Fixed. Also FML. I'm too used to Windows shell.

17:50 hyPiRion: koz: It'll go over eventually. We've all been noobs at shell and Linux once

17:51 koz: hyPiRion: Thanks. Appreciate the sympathy. :)

17:51 OK, it's downloaded a jar.

17:51 I guess I have to run it?

17:51 hyPiRion: koz: no, lein does everything by itself, managing upgrades and stuff

17:51 AimHere: I think it's best to remain a noob at shell; learn to invoke perl or python or your scripting language of choice from the command line

17:52 koz: Well, I ran the self-install.

17:52 qbg: just run `lein` then :)

17:52 koz: Ah.

17:52 There we go.

17:52 It's getting a whole shittonne of jars

17:52 Meaning I probably did something right.

17:52 amalloy: that's maven for you

17:53 hyPiRion: koz: yeah, it's downloading the Internet

17:53 koz: Yay, the whole Internet!

17:53 OK, I now have Leiningen 2.3.4

17:53 Success!

17:53 systemfault: Oh yeah

17:54 amalloy: AimHere: i think it's reasonable to be pretty bad at writing .sh files, but some familiarity with the actual shell is good - you can be a lot more concise than you could be if you had to write it as a python script

17:54 koz: In this case, these commands are so simple that knowing them helps. Plus, I've kinda gotten into the CLI habit.

17:54 And I like working with a shell.

17:54 It's easier.

17:54 OK, maybe you guys can help me with this one.

17:55 I've installed Linux Mint, and I want it to dual-boot with my Windows 7.

17:55 I partitioned my drive and everything, and the install went fine.

17:55 But I can't boot the Linux half - at boot time, it just goes straight to Win7.

17:55 Ayey: What order did you install them?

17:55 koz: Win7 was there first.

17:55 systemfault: Sure... Windows doesn't care about your bootloader, it kills it.

17:55 amalloy: windows hates dual-booting iirc, you have to have grub on the MBR

17:56 koz: MBR?

17:56 danneu: AimHere: it's useful to be able to approximate shell scripts that you encounter in the wild though. i.e. a heroku buildpack you might be using

17:56 Ayey: Master boot record i think

17:56 qbg: master boot record

17:56 AimHere: amalloy, well you do need a minimul level of familiarity, but between the bad syntax and the need to invoke 1001 different command line utilities you want to minimise it

17:56 koz: OK... so how do I do that?

17:56 amalloy: koz: install windows first, then mint. tell mint you want to dual-boot; i think it asks when you're installing

17:56 Ayey: Live-CD into a linux, and install Grub on a boot or root partions

17:56 hyPiRion: koz: that's the order I did it when I first started with Linux. I just followed a tutorial really, but then again, I am using Debian

17:56 koz: Yeah - Mint doesn't give me that option on the installer.

17:56 amalloy: or if you don't want to restart stuff from scratch, you can do it some other way; what Ayey says sounds fine

17:57 koz: I had to basically partition manually.

17:57 LiveCD in? OK.

17:57 I can do that.

17:57 How do I install grub after that?

17:57 Ayey: Remeber to install os-proper, so grub-config can detect Windows

17:57 amalloy: i mean, there are a *lot* of resources on the web about doing exactly this

17:57 Ayey: Eh, let me try to find you a proper guide..

17:57 koz: Thanks - much appreciated.

17:57 zoldar: koz: http://community.linuxmint.com/tutorial/view/245

17:58 koz: I've been having some issues with this, since I'm a complete noob at Linux.

17:58 qbg: you could be super lazy and put it in a VM :p

17:58 koz: Another minor thing - my Mint has Firefox as the default browser, which is... undesirable. I'm using Midori, but it's not the default. So if I click a link, it goes to FF.

17:58 How can I change that?

17:59 Midori doesn't seem to have... well, any sort of options menu I could find.

17:59 Ayey: That is the system that contols it

17:59 danneu: google 'default browser debian'

17:59 Ayey: You should be able to find default-applications somewhere in your settings

17:59 koz: Ayey: Thanks - I'll check.

18:00 zoldar: koz - it's update-alternatives for x-www-browser most of the time

18:00 koz: as in "sudo update-alternatives --config x-www-browser"

18:00 koz: Thanks - there seems to be a graphical utility for this under Mint.

18:01 Thanks everyone - you've all been incredibly helpful.

18:01 hyPiRion: koz: good luck fixing stuff :)

18:01 koz: I may well need it.

18:01 Ayey: Indeed, thats where you'll learn the most :)

18:02 koz: Well, I already learned a bit from trying to install Debian and having it fry on me.

18:03 Also, as a complete aside, Pandora is awesome.

18:03 zoldar: koz: there's a nice middleground between plain debian and ubuntu-based mint - linux mint debian edition

18:03 koz: zoldar: I decided to go for the Xfce Mint instead.

18:03 Was that a mistake?

18:04 Ayey: XFCE is a good choice

18:04 koz: It's minimal, and the first machine I installed Linux Mint on is an old Eee-PC.

18:04 Ayey: Mint is a fine distro, just too bloated with stuff for my taste :)

18:04 zoldar: koz: not, it's also a good choice

18:05 koz: I was mostly inspired to get into Linux by 'The Art of Unix Programming'.

18:05 Seriously awesome book.

18:06 alexanderkyte: I was inspired by my grandfather's autocoder operator's manual

18:06 systemfault: I hated linux until I tried FreeBSD... then everything made sense to me after.

18:06 r0b1: hah

18:06 unusual

18:06 akyte: I miss Ctrl+T

18:06 koz: OK, this guide is already doing odd things.

18:07 akyte: Which guide?

18:07 koz: http://community.linuxmint.com/tutorial/view/245

18:07 It says 'type Gparted into the menu from the LiveCD'

18:07 And.... I get nothing.

18:07 akyte: I usually just chroot back in to my old install and use that to install

18:08 Ayey: Just open gparted?

18:08 akyte: Superstition on versioning

18:08 Ayey: systemfault, freebsd? How come? I always wanted to give it a go

18:08 koz: It seems it's not on my LiveCD.

18:08 Or at least I can't find it anywhere.

18:08 akyte: sudo apt-get install gparted

18:08 Ayey: Then install it with apt-get :)

18:08 koz: OK.

18:09 zoldar: koz: if that's only for the purpose of checking partition layout, "fdisk -l" is usually sufficient

18:09 koz: Ah. Well, I started downloading it already, so wfe.

18:09 systemfault: Ayey: FreeBSD felt simpler, more coherant... all the userland utils felt better integrated. Using ports sucks though, I hate compiling software.

18:10 koz: But thanks for that.

18:10 systemfault: *coherent

18:10 akyte: I loved ports. I hated how bad the package defaults were. Vim behaves like it does on no linux distro and ssh is far too nice for my opinion

18:11 systemfault: akyte: I hate compiling :) The flexibility ports provide is really good though

18:12 koz: OK, in this guide, I'm meant to find the Linux Mint partition. I have two - root and the other one.

18:12 (Not swap)

18:12 Which one does it want?

18:12 Ayey: How does ports differ from packages from apt-get/pacman?

18:12 root

18:12 i guess the other one is /home

18:12 akyte: Well it's ostensibly a way for you to use make to build all of your packages

18:12 koz: Yeah, the other one is a home partition. Thanks.

18:12 akyte: But most use portmaster

18:12 Think "patchwork gentoo"

18:13 Ayey: Huh, intresting.. I should give it a go sometime

18:15 akyte: Which distros have you ran before?

18:15 koz: Goddamn it.

18:15 Same as before.

18:16 I get the CLI GRUB.

18:17 Ayey: akyte, Have used arch as my primary for around a year, some ubnuntu/debian before that

18:18 akyte: Arch is cool, but I prefer gentoo. I like to be able to make all of my architectural choices.

18:19 Ayey: what do you me?

18:19 mean*

18:21 koz: OK, thanks guys. Gonna try the Mint irc channel to see if they can help me at all.

18:22 See ya!

18:27 dnolen_: new Om tutorial, Speculative UI Programming - https://github.com/swannodette/om/wiki/Intermediate-Tutorial#wiki-speculative-ui-programming

18:28 * bbloom looks

18:30 bbloom: dnolen_: awesome.

18:30 dnolen_: so i'm i'm understanding this correctly, you're implemented one speculative state... PER COMPONENT right?

18:31 dnolen_: ie two different comment boxes can do optimistic posts in parallel, yes?

18:31 dnolen_: bbloom: yes they could, however how to reconcile those is something that needs thinking

18:32 bbloom: this is why om-sync can write the operation into a channel

18:32 instead of actually doing it

18:32 so you could have independent parties doing things, and I think the coordination logic could happen in another go loop that actually commits these operations and observes their results

18:36 bbloom: pretty interesting... probably works just fine with isolated sub trees, but need a proper computational model for communicative distributed systems once you start trying to merge and whatnot

18:36 clojurebot: Huh?

18:38 dnolen_: bbloom: yes, works great for isolated sub trees - people will need to do some experimenting to figure out the hard

18:38 bbloom: but at least they can now :)

18:38 s/hard/hard stuff

18:39 r0b1: systemfault: yeah compiling can take time but there is prebuilt packages for most of the bigger packages (like X11).

18:40 systemfault: Right

18:40 bbloom: dnolen_: cool stuff

18:40 good work

18:40 dnolen_: bbloom: thanks

18:50 qbg: Om is omsome!

19:20 echosa: Hey, room. What's the preferred/standard/usual way of capturing key presses in a console app? Looking at add vim/rogue style keybindings to a program I'm making.

19:22 sjl: echosa: http://sjl.bitbucket.org/clojure-lanterna/ is what I made/use

19:22 depends on what exactly you need though

19:22 it might be overkill for you

19:23 echosa: You actually made it? That's pretty sweet. I tried it last night, but couldn't get it to work. `lein run` and `lein trampoline run` both resulted in the program producing no output (which it should) and hanging. Maybe I just did something wrong.

19:23 sjl: echosa: I made the clojure wrapper around lanterna

19:23 and wrote the docs

19:23 echosa: ah, cool

19:23 yeah, I tried out lanterna as well as jline

19:23 sjl: I haven't updated it in quite a while so it might be something to do with the latest clojure, but it should at least crash or something, not just hang

19:24 clojurebot: Cool story bro.

19:24 echosa: jline seemed... old and dated.

19:25 I'm surprised clojure doesn't already have an easy way to grab a key press (not read a character, which requires pressing return) already

19:25 sjl: it's a deeper rabbit hole than you might think

19:25 if you want to dive in http://www.linusakesson.net/programming/tty/

19:26 echosa: Oh wow, you have to go all the way to the TTY level? There's not higher level abstractions built in already?

19:26 sjl: (specifically about raw/cooked input in a terminal)

19:27 lanterna *is* the abstraction

19:27 it puts the terminal in raw mode and handles the fiddly bits of writing/reading in that mode

19:27 you could certainly make a lighter-weight version that did less

19:28 echosa: Right, but I'm saying without a third party plugin/dependency, there's nothing built into clojure itself.

19:28 I'll play with lanterna a bit more before I toss it out.

19:29 qbg: The Java Class Libraries don't expose a way to get raw input IIRC

19:29 At least nothing nice

19:29 echosa: Fair enough.

19:30 qbg: (non JNI or the like that is)

19:31 echosa: Speaking of which... coming from Common Lisp (with sbcl) and elisp, when I'm writing clojure I tend to... avoid Java constructs. I use things like (.indexOf) and such, but I don't create/use Java objects. I sort of pretend all that Java stuff isn't there and just write the way I would any other Lisp.

19:31 Is that bad(™)?

19:31 qbg: java.io.Console.readPassword is about as special as you get

19:33 hyPiRion: echosa: that's not bad. I seldom use java unless it's necessary

19:33 AimHere: echosa, no. It's good.

19:33 hyPiRion: unless when it is necesssary, rather.

19:33 sjl: echosa: if you're not specifically interop'ing with Java, no, it's not bad. be thankful you don't have to.

19:33 echosa: I'm glad I'm not alone, then.

19:33 AimHere: The javaisms are just warts you have to use in order to Get Stuff Done

19:33 r0b1: love me some java

19:34 AimHere: When you don't have to Get Stuff Done, you don't need to pretend to use Java!

19:34 qbg: Just bury them with a shov--uh, function and get on with it

19:34 echosa: yeah, sjl: I just tried the "hello world" code for lanterna, and when I `lein run` I get a java process running, no output (which I get if I remove that code) and it it seems to hang. FYI

19:35 qbg: Doesn't lein run do some socket or i/o redirection fun?

19:35 echosa: I'm trying to pick up best practices, not just learn the language raw. I'm learning clojure in an attempt to get a job writing it.

19:36 sjl: echosa: are you pressing a key?

19:36 oh wait, there's a typo in the hello world because I'm an idiot

19:36 the first s/stop should be s/start

19:36 echosa: yes, and FWIW, I have print statements before the lanterna "hello world" code that I would expect to be executed first.

19:36 ah

19:36 I wondered about that

19:37 I figured the first "stop" was more a "reset"

19:37 especially since it deals with TTY

19:37 sjl: nah, it should be start

19:37 oh yeah this example is totally hosed

19:37 hang on

19:38 echosa: Ok, so now it ran, opened another window (wierd?) then waiting for key press before showing my (print) output, which, again, come before the lanterna code in my (-main)

19:38 sjl: ok, thanks.

19:38 sjl: echosa: https://gist.github.com/sjl/9027448

19:39 screens are buffered, so you have to tell it to redraw to make the text actually appear

19:40 echosa: the "second window" is probably it creating a swing terminal emulator. lanterna includes its own little swing "terminal" so you can run your app in places that don't have a decent one

19:40 e.g.: windows

19:40 if you say (s/get-screen :text) instead of just get-screen it will force it to try to actually stay in the shell

19:41 (also the swing terminal is great when you're developing, because you can have the REPL running and the output terminal be separate

19:42 basically once you actually see it working you need to read the docs though, because there's a lot going on to wrap your head around if you want to use it

19:42 echosa: ah, ok. I'm starting to understand. So, if I want to use lanterna, I'll have to use (s/put-string) and (s/redraw) everywhere I was currently using (print)?

19:42 sjl: I promise they docs aren't too horrifying

19:42 yeah, the idea of lanterna is that it takes over your screen, and you write to it as if it were a canvas

19:43 it's great for making e.g. roguelikes, or a text editor or something

19:43 it may be overkill for what you need

19:43 echosa: I'm actually ok with that, because one of the next things I was going to have to write was screen clearing stuff. Looks like this may take care of that, or at least make it easy.

19:43 Well, I'm trying to remake the BSD version of the game "greed".

19:44 which uses hjklyubn movement keys

19:44 akurilin2: Weird quirk, wondering if people might have seen this before: I stated a new lein project recently and clojure won't find clojure.set namespace in my tests.

19:44 When I open up the namespace in a repl, it finds clojure.set just fine

19:44 Never seen anything like this before

19:47 sjl: echosa: oh yeah, that's pretty much exactly what lanterna is designed for

19:48 echosa: e.g. if the user's position changes, you put the @ at the new place and a space at the old place, and tell lanterna to redraw, and it's smart enough to only draw those two characters

19:48 instead of redrawing the entire screen

19:48 echosa: yeah, I've got the internals of moving, replacing moved over positions with spaces, etc. all built and supported with tests (TDD test first, of course)

19:49 and I had display working with print, just not keymapping

19:49 so I"ll just convert my normal prints to lanterna calls and add the key presses and see what happens

19:49 sjl: yeah, testing is tricky with lanterna. there's not a really good way to scrape the screen with it

19:50 echosa: I won't test front end stuff, at least not with clojure.test

19:50 sjl: might be worth looking at then

19:50 echosa: I might add some BDD or spec style tests to test user input, but for now the backend unit tests are more than enough

19:51 qbg: akurilin2: Which namespace are you openning up in the REPL? The namespace with the tests?

19:54 effy: if i understand well, inside a (dosync) body if any operation fail, the whole thing is rollbacked and retried, is there a mechanism in clojure that ensure that behavior not to cause famine? (imagining 2 threads doing dosync operation on the same refs, one of them is a fast dosync operation the other one has a slow dosync operation, would the slow dosync operation have a guarantie to ever finished successfully?)

19:56 akurilin2: qbg: yes

19:59 qbg: effy: http://java.ociweb.com/mark/stm/article.html

20:00 To quote: Suppose transactions A and B start in that order and are running concurrently. If they both attempt to modify the same Ref using ref-set or alter (write conflict), preference is given to transaction A because it has been running the longest (provided it has been running for a minimal amount of time). This avoids livelock that might occur if retries were based on the order in which refs are set.

20:01 akurilin2: Do the test succeed if you run the tests from the REPL?

20:04 akurilin2: qbg: something seems to be off about my environment atm, not sure what's going on, brb

20:04 effy: qbg: this article seems really interesting, thanks

20:10 akurilin: So yeah when I run "lein test" now I get Caused by: java.io.IOException: error=7, Argument list too long

20:10 No idea what I did to cause that

20:11 qbg: Any stack trace?

20:13 akurilin: qbg: oh nvm. I use lein's checkouts and I think I caused a wonderful circular reference of symlinks in there

20:13 * akurilin blush

20:17 aphyr: effy: if I recall, either atoms or the STM is actually missing stochastic backoff.

20:18 echosa: sjl: Whenever the program crahses, I get ";135R" at my prompt. When the program finished running successfully, I see "[[37;135R" in the console output. I realize these are TTY codes, but why are they being returned/displayed?

20:19 aphyr: https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Atom.java#L33-L45 yeah, there really should be a sleep there

20:22 hyPiRion: aphyr: or a Thread.yield() ?

20:23 qbg: stochastic backoff likely isn't good enough

20:23 * hyPiRion has heard something about preferring yield over sleep, but really has no idea.

20:25 effy: aphyr: yeah you are right, this piece seems like it could loop forever if the "IFn f" is slow enough to run and another thread is pummeling at it with a faster "f"

20:28 qbg: If you want to intermix long running and short running functions together at a sufficiently high rate, CAS semantics might not be what you actually want

20:33 echosa: probably a *really* dumb question... but does clojure have an equivalent to elisp's (setq)? For instance, if I do (let [x 0] ...) then inside the body, I want to do something like (setq x (inc x)) to increment x

20:34 qbg: You can use set! with vars

20:34 locals are immutable otherwise

20:34 hyPiRion: echosa: not in general. You'd have to use atoms for such things

20:34 qbg: Though there is this: https://github.com/ztellman/proteus

20:35 aphyr: echosa: typically you want a.) a second let binding or b.) proteus

20:35 Let bindings being the fastest option for limited mutation.

20:35 If you're doing something iteratively, (loop [x 2 y 3] ... (recur (inc x) (inc y))) is best

20:37 hyPiRion: hrmm, proteus

20:37 https://twitter.com/danielwithmusic/status/426133408498995201

20:39 qbg: Functional programmers hate this!

20:40 echosa: Hm. Will recur work with mapcat?

20:40 not sure how it would

20:40 qbg: what do you mean 'with'?

20:40 echosa: you can (recur) inside a (loop) so recur works with loop

20:40 ^ s/loop/mapcat/

20:40 ?

20:41 qbg: Are you talking about using recur in the function passed to mapcat

20:41 without tha function having the loop in it?

20:41 *that

20:41 because that won't work

20:41 echosa: oh, yeah, I guess it would be passed to the function passed to mapcat, since that's where the arguments being incremented would have to be

20:42 hm

20:42 qbg: do you really need to bang on those locals?

20:43 echosa: I need to keep track of x/y coords to pass to lanterna so it knows where to print stuff to the string inside two nested mapcats

20:43 qbg: What if you have the mapcats produce a description of what needs to be done, and then have some other code consume that description and actually do it?

20:44 are you using the mapcats for side effects only?

20:46 echosa: let me gist what I've got

20:46 that'll be easier

20:50 Here's what I'm working with with comments explaining what's going on: https://gist.github.com/echosa/9028090

20:51 qbg: Why not use doseq instead?

20:51 * echosa looks up doseq...

20:52 qbg: for the x/y values, and then look up corresponding value in the grid from that

20:52 echosa: Bear in mind, I'm using this project to learn clojure. I didn't know about doseq.

20:52 benkay: how would i go about starting a lein repl up in such a way that it used as much of the host horsepower as was feasible?

20:52 echosa: corresponding value in the grid? not sure what you mean... like using (.indexOf)?

20:52 qbg: nth

20:53 echosa: oh, right

20:53 duh

20:53 qbg: ,(get-in [[1 2 3] [4 5 6] [7 8 9]] [1 1])

20:53 clojurebot: 5

20:53 echosa: well, let me go look at doseq

20:53 qbg: or that

20:53 echosa: oh wow... (get-in)... that's handy as all hell

20:54 Cr8: And then there's update-in

20:54 qbg: and assoc-in

20:54 Cr8: ,(update-in [[1 0] [0 1]] [0 1] inc)

20:54 clojurebot: [[1 1] [0 1]]

20:54 aphyr: but somehow, no update

20:54 echosa: ...

20:55 you've got to be kidding me

20:55 qbg: aphyr: In what way would update make sense?

20:55 Cr8: qbg: (update {:a 1} :a inc) => {:a 2}

20:55 qbg: ,(update-in {:a 1} [:a] inc)

20:55 Cr8: is to update-in as assoc as assoc-in

20:55 clojurebot: {:a 2}

20:55 echosa: update-in exists and here I went and wrote (and unit tested) this: https://gist.github.com/echosa/9028135

20:55 qbg: not god enough? :)

20:56 Cr8: qbg: sure, but assoc-in and get-in have assoc and get, respectively

20:56 qbg: fair enough

20:56 echosa: I think I can completely replace that function with (update-in)

20:56 qbg: ,(assoc [1 2 3 4] 1 10)

20:56 clojurebot: [1 10 3 4]

20:56 qbg: echosa: You'd want to use that for updating a vector

20:57 echosa: use what? my function or update-in?

20:57 qbg: assoc for a single vector

20:57 echosa: because that's what my fuctnion does

20:57 Cr8: confusingly, synthread calls what we'd call "update" by this convention "assoc" =P

20:57 or really, ->/assoc if you use the recommended ns alias

20:57 https://github.com/LonoCloud/synthread

20:57 qbg: rather than all of those subvec and into calls

20:59 echosa: I basically use the (subvecs) to split the nested vectors into three groups: the ones before the one to be updated, the one to be updated (which is similarly split into three), and the ones after the one to be updated. That way, I can update the one and they all just get conj-ed together

20:59 but, from what I've seen, (update-in) will handle this for me

21:00 qbg: I'm just saying that if you really did need to write set-thing-at-grid-position, you'd want to use assoc instead of that into expression

21:00 echosa: ,(update-in [[1 2 3][4 5 6][7 8 9]] [1 1] (fn [x] 0))

21:00 clojurebot: [[1 2 3] [4 0 6] [7 8 9]]

21:00 echosa: Yep. update-in does exactly what I need for that second gist I posted.

21:00 qbg: ,(assoc-in [[1 2 3][4 5 6][7 8 9]] [1 1] 0)

21:00 clojurebot: [[1 2 3] [4 0 6] [7 8 9]]

21:01 echosa: So much wasted work. Well, not wasted, but I learned a lot about testing and clojure...

21:01 Ah, Even better.

21:01 qbg: I'd recommend skimming through http://clojuredocs.org/quickref/Clojure%20Core if you haven't yet

21:01 echosa: I have. I've even done the clojure-koans thing, though a lot of that info just didn't stick.

21:02 qbg: no problem

21:02 echosa: language familiarity will come with time

21:02 (hopefully)

21:03 Still need to work out my mapcat -> doseq business, though.

21:03 Hooray for learning.

21:03 qbg: doseq is the side effect version of for

21:04 echosa: hm

21:04 qbg: ,(for [y (range 3) x (range 3)] [x y])

21:04 clojurebot: ([0 0] [1 0] [2 0] [0 1] [1 1] ...)

21:07 bob2: is there an elegant way to go from [{:foo A :x somethingelse} {:foo B :z blah}] -> {A {:x somethingelse} B {:z blah}} ?

21:08 echosa: ,(let [grid [[1 2 3][4 5 6][7 8 9]]] (for [x (range (count (first grid))) y (range (count grid))] (print (nth (nth grid y) x))))

21:08 clojurebot: (147nil nil 258nil nil nil 369...)

21:08 echosa: ,(let [grid [[1 2 3][4 5 6][7 8 9]]] (for [x (range (count (first grid))) y (range (count grid))] (print (nth (nth grid x) y))))

21:08 clojurebot: (123nil nil 456nil nil nil 789...)

21:08 echosa: what's with the nils?

21:08 qbg: print returns nil

21:09 echosa: oh right

21:09 qbg: you want to use doseq instead of for

21:09 echosa: I'm getting return val here, not output

21:09 qbg: for produces a lazy seq, so that is why you see the intermixing

21:09 echosa: same syntax as for?

21:09 qbg: ,(let [grid [[1 2 3][4 5 6][7 8 9]]] (doseq [x (range (count (first grid))) y (range (count grid))] (print (nth (nth grid x) y))))

21:09 clojurebot: 123456789

21:09 qbg: yep

21:09 echosa: ,(let [grid [[1 2 3][4 5 6][7 8 9]]] (doseq [x (range (count (first grid))) y (range (count grid))] (print (nth (nth grid x) y))))

21:09 clojurebot: 123456789

21:09 echosa: win

21:10 qbg: ,(let [grid [[1 2 3][4 5 6][7 8 9]]] (doseq [x (range (count (first grid))) y (range (count grid))] (print (get-in grid [y x]))))

21:10 clojurebot: 147258369

21:10 qbg: ,(let [grid [[1 2 3][4 5 6][7 8 9]]] (doseq [x (range (count (first grid))) y (range (count grid))] (print (get-in grid [x y]))))

21:10 clojurebot: 123456789

21:11 qbg: ,(let [grid [[1 2 3][4 5 6][7 8 9]]] (doseq [y (range (count grid)) x (range (count (first grid)))] (print (get-in grid [y x]))))

21:11 clojurebot: 123456789

21:11 qbg: ^ That might be the one you want

21:12 echosa: (get-in)... right.

21:12 I have so much to memorize.

21:12 qbg: you get to dramatically shrink your line count though :)

21:12 echosa: I'm very much looking forward to that.

21:13 In for familiar lisps I'm used to being clever to reduce code amount.

21:13 Clojure is a whole new beast.

21:13 qbg: Now don't just use cl-format because you have it :p

21:13 benkay: how would i determine what brand of jvm a given leiningen install put on my system?

21:14 i just spun up a vm for some processing - would it be the same as the output of `which java`?

21:14 qbg: `java -version` might be of interest

21:15 benkay: mhm.

21:15 echosa: IT LIVES... er, WORKS! Jesus... 4 hours yesterday, give or take, improved drastically by a couple hours on IRC

21:15 bob2: 'lein version'?

21:18 benkay: thanks bob2, qbg.

21:18 har, now do either of you know anything about making the jvm as big as possible on a given host?

21:18 qbg: -Xmx to increase the maximum heap size

21:19 IIRC, there is a place in your project.clj where you can place those jvm arguments

21:19 bob2: java-opts

21:19 qbg: Are you running out of memory benkay?

21:19 bob2: at some point you've made the heap too big, though

21:19 benkay: yeah i'm familiar with java opts, just not en-honk-ifying a jvm

21:20 qbg: are you having perf issues?

21:20 benkay: nah, big job

21:20 bob2: you can't just set it to a high random value

21:20 benkay: scripted it up in clojure for the heckofit

21:20 pmap being a useful thing in the context

21:20 bob2: gc pauses are a real thing

21:20 qbg: how big of a heap are you going to want?

21:21 benkay: heap isn't so much of a concern - it's running on an 8 core box and i'd like to utilize as many as possible

21:22 bob2: that just happens, without configuration

21:22 qbg: how much work does the function you pass to pmap do?

21:22 benkay: squeeeee clojure

21:22 none

21:22 qbg: if it isn't enough, the overhead is going to kill the gains

21:22 benkay: it's like "try to s3 cp this object from bukkit a to bukkit b"

21:22 there's just a mess of things to get copied and there's no reason to do it serially.

21:23 Cr8: benkay: used reducers yet?

21:23 wouldn't be appropriate in this case

21:23 benkay: ah only to do dumb dumb stuff like ,(reduce [1 2 3])

21:23 Cr8: but they are a neat thing

21:23 qbg: benkay: you're code is I/O bound rather than CPU bound?

21:23 benkay: ah only to do dumb dumb stuff like ,(reduce + [1 2 3])

21:23 yeah, very much io bound

21:23 Cr8: benkay: clojure.core.reducers I mean

21:23 bob2: if you want to do it fast, you'd want async network io, not more cpus or threads

21:23 qbg: pmap probably isn't what you want then

21:24 (inc bob2)

21:24 lazybot: ⇒ 1

21:25 benkay: thing is that i'm working with weavejester's s3 library and this bit of code is a one-off

21:25 (famous words before one-off script becomes central to biz processes)

21:26 Cr8: (my current weekend is fixing up some "one-off" scripts I wrote last week so that they can become productionized)

21:26 luckily they're currently -so- "one-off" that they only run on my machine

21:27 benkay: if we copy any more gigantic s3 buckets i'll have to have some words with business people about costs incurred that could be avoided with a bit of time.

21:28 qbg: what is roughly the upper limit on the size of the sequence you're sending to pmap currently?

21:29 aphyr: yeah, suggest not using pmap for any more than, say, 1000 items.

21:29 benkay: interesting

21:29 aphyr: JVM doesn't deal so well with infinite threads.

21:29 benkay: i figured something like that'd be the case, so i wrote it to perform things batch-ed-ly

21:29 qbg: aphyr: pmap doesn't send everything to its own thread

21:30 the number of computations in flight is limited

21:30 benkay: what are the constraints on length of lists over which to pmap?

21:30 bob2: depends on what your function does

21:31 benkay: it's a mystery!

21:31 jokes aside as i dig through the s3 client source what should i be aware of

21:32 aphyr: Oh shit, pmap changed!

21:32 Didn't realize.

21:32 qbg: http://stackoverflow.com/questions/5021788/how-many-threads-does-clojures-pmap-function-spawn-for-url-fetching-operations

21:35 bob2: ugh threads for url fetching

21:35 benkay: hey man i'm just a mechanical engineer trying to make his way in this over complex world of computer you people have munged together over the past twenty years. tell me how to do it right!

21:36 qbg: I think it is a bit more than 20 :p

21:36 benkay: well 20 years ago we had symbolics machines iirc

21:37 jokes its 2014

21:37 so 29 years

21:37 qbg: Why not go all the way back to the IBM 704?

21:38 benkay: did it run lisp?

21:38 bob2: yes

21:38 in like 61

21:38 benkay: well then sure :)

21:38 bob2: for your thing, pmap is probably fine as a balance between effort and performance

21:39 benkay: 's what i thought too. glad to have someone with experience (assumption!) confirm.

21:39 echosa: Who needs the Turing test. It's all about the Lisp test: does it run lisp? :)

21:39 bob2: for something non-one-off, something like http://martintrojer.github.io/clojure/2013/07/07/coreasync-and-blocking-io/ is going to be a lot faster

21:39 disclaimer, I have only a little clojure experience

21:40 benkay: bob2: i think i'm actually going to go down the nio rabbit hole next time i come around to this problem

21:40 bob2: oh, aleph is apparently a thing to loko at

21:40 benkay: which is particularly amusing because i have zero java experience beyond the interop that's been forced on my from time to time

21:40 i'm aware of aleph yeah

21:40 what do you think of: https://github.com/pjstadig/nio

21:41 bob2: really I just want Twisted for clojure

21:41 nio looks very far below the 'do lots of http requests' level you were talking about earlier

21:42 benkay: ah well you see the next networky thing i have on my plate is lots of binary over tcp

21:43 bob2: aleph apparently does tcp stuff too

21:46 benkay: hm yeah

21:46 quizdr: are circular references a problem in clojure as they are in some languages? can I have 2 source files that each refer each other?

21:46 qbg: that is going to be difficult

21:47 benkay: but all this framework of expectations and data flow is a bit much cognitive overhead for my tastes.

21:47 qbg: See if you can clean up your design

21:52 beamso: quizdr: while i've never experienced that i believe it can be a problem

21:52 qbg: Clojure effectively enforces good design here

22:05 quizdr: ,(println (str (take 3 "abcdef")))

22:05 clojurebot: clojure.lang.LazySeq@1ecc1\n

22:05 quizdr: shouldn't println force the output of above?

22:06 beamso: ,(apply str (take 3 "abcdef"))

22:06 clojurebot: "abc"

22:06 quizdr: gotcha

22:07 beamso: the docs for str don't say that it returns a lazy sequence :/

22:07 qbg: take returns a lazy seq

22:07 and you're turning that lazy seq into a string with str

22:08 (in your original code)

22:08 beamso: yeah

22:08 the take returns a lazy seq

22:08 the str' With more than

22:08 one arg, returns the concatenation of the str values of the args.'

22:17 qbg: println also uses a different code path than str

22:19 amalloy: qbg: println just calls str

22:20 t0m`: hi

22:20 qbg: there is a bit more magic though than that

22:20 t0m`: hey i'm dealing with deeply nested maps, is there something like xpath but for nested maps?

22:21 qbg: amalloy: println can handle unbounded output

22:22 amalloy: what does "unbounded output" even mean?

22:22 qbg: infinite seq for example

22:23 amalloy: &(println (range))

22:23 lazybot: java.lang.OutOfMemoryError: Java heap space

22:23 amalloy: that's not handling it super-impressively

22:23 qbg: lazybot has to capture the output

22:24 if you're writing to the console, then everything is fine

22:24 amalloy: i mean, yes, you can (println (range)) in a repl, and it probably writes forever. i'm not sure that's much of a feature

22:24 at any rate, i was definitely wrong that println just calls str

22:25 qbg: println doesn't also need to generate an entire string before printing

22:27 ambrosebs: bbloom: I haven't been able to get if-pred out of my head all morning

22:28 bbloom: really helped pinpoint the problems with if-let

22:31 bbloom: ambrosebs: you're the types guy, you should have been all over that one :-)

22:33 ambrosebs: bbloom: I have much to learn

22:35 bbloom: ambrosebs: besides typed racket and now core.typed, do you know of any languages that have a sensible type system with union types instead of sum types?

22:36 amalloy: bbloom: if-pred?

22:36 bbloom: amalloy: long story. discussion about if-some, see logs

22:39 ambrosebs: bbloom: hmm there is SML CIDRE which is a refinement type checker for SML. The way I look at it, it looks like you're defining sum types (called data "sorts") but you don't actually "construct" data sorts; they are refinements on existing SML types.

22:39 http://www.cs.cmu.edu/afs/cs/user/rowan/www/src/red-black.sml

22:40 the equivalent types in cor.etyped https://github.com/clojure/core.typed/blob/master/src/test/clojure/clojure/core/typed/test/rbt_types.clj

22:40 bbloom: ambrosebs: so is "refinement types" the magic phrase for this sort of thing in the literature?

22:41 ambrosebs: and how does that relate to "occurrence typing" ?

22:42 ambrosebs: bbloom: often when general unions and intersections are discussed in the context of ML-like type systems, it's related to refinement types

22:45 killerswan: so, do any of you have tips on parsing XML from within ClojureScript?

22:45 ambrosebs: bbloom: I haven't looked too much into this, but here's an example http://www.cs.cmu.edu/~joshuad/papers/tridirectional-typechecking/Dunfield04_tridirectional.pdf

22:45 bbloom: if you're from CMU, it's "type refinements"

22:45 bbloom: and a "refinement type" checker :)

22:46 my honours supervisor wrote CIDRE for his phd http://www.cs.cmu.edu/~rwh/theses/davies.pdf

22:47 bbloom: and if you're the racket people (is that northeastern or something?) then it's occurrence typing?

22:48 dnolen_: killerswan: use an existing JS XML lib?

22:48 ambrosebs: bbloom: hmm

22:49 bbloom: ambrosebs: or utah? i don't know anything about CS graduate programs :-P

22:49 ambrosebs: bbloom: occurrence typing is an approach to eliminating union types are programs progress

22:49 bbloom: ok so they are different? i guess i'll need to study them at some point

22:49 killerswan: dnolen_: any recommended tutorial on how to set up externs for that? (jay's tutorial links to some externs from MANY versions ago of jQuery...)

22:49 s/jay/jayq/

22:49 ambrosebs: bbloom: essentially occurrence typing eliminates unions as it gets further into the program

22:50 bbloom: as I understand it, refinement type checkers are intended to check each possible combination of types, which might mean checking a program many times with different types

22:50 bbloom: so two approaches to a similar goal

22:51 dnolen_: killerswan: http://docs.closure-library.googlecode.com/git/closure_goog_dom_xml.js.html

22:51 bbloom: ambrosebs: hm ok, i'll dig in to it all eventually

22:56 killerswan: dnolen_: OK, thanks

23:45 TravisD: in case forms, is it standard to use "true" as the catch-all case? Or is there some syntactic sugar for that?

23:46 qbg_: case, or cond?

23:46 :else seems to be idiomatic for cond

23:46 TravisD: oh, sorry, cond

23:47 :else is considered true in cond?

23:47 mischov: I believe catchall for case is a last statement without a condition.

23:47 :else for cond

23:47 bbloom: TravisD: it's just an idiom, any logically true value would suffice

23:47 ,(cond :false "omg")

23:47 &(cond :false "omg")

23:47 lazybot: ⇒ "omg"

23:47 bbloom: damn bots :-P

23:48 TravisD: Hehe, is there a simple characterization of logically true values?

23:48 clojurebot: "omg"

23:48 bbloom: TravisD: false and nil are the *only* logically false values. everything else is true

23:48 TravisD: oh, alright :)

Logging service provided by n01se.net