#clojure log - Dec 15 2012

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

1:19 mdeboard: Anyone know if it's possible to run cascalog jobs via nrepl? iow not compiling the jar and running it that way?

1:21 sw2wolf: ,(sqrt 100)

1:21 clojurebot: #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: sqrt in this context, compiling:(NO_SOURCE_PATH:0)>

1:21 sw2wolf: ,(sin 1)

1:21 clojurebot: #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: sin in this context, compiling:(NO_SOURCE_PATH:0)>

1:25 ivan: isn't it kind of weird to invade someone's namespace as clj-http-lite does with clj-http.lite?

1:26 sw2wolf: i cannot visit http://www.khanacademy.org/, then how to use clojurebot ?

1:27 ivan: do the two have anything to do with each other?

1:27 technomancy: ivan: namespaces actually are not hierarchical

1:28 so there's no invading going on; it's just an illusion

1:28 ivan: sw2wolf: perhaps https://www.wolframalpha.com/input/?i=sqrt%28100%29 would interest you

1:28 technomancy: yeah but what if clj-http wants its own .lite

1:28 that's what I meant by invasion

1:29 sw2wolf: ivan: it is using clojure ?

1:29 ivan: heh, no

1:29 sw2wolf: oh

1:29 ivan: &(Math/sqrt 100)

1:29 lazybot: ⇒ 10.0

1:29 technomancy: yeah, you'd have to communicate

1:29 ivan: in this case both libs are written by co-workers

1:30 sw2wolf: thx

1:30 ivan: well, that solves the problem

1:30 sw2wolf: &(range 10)

1:30 lazybot: ⇒ (0 1 2 3 4 5 6 7 8 9)

1:32 sw2wolf: "/msg clojurebot &(range 10)" returns strange thing ?!

1:33 ivan: & is for lazybot

1:33 lazybot: java.lang.RuntimeException: Unable to resolve symbol: is in this context

1:33 ivan: try a ,

1:34 sw2wolf: lazybot works but "/msg clojurebot ,(range 10)" return nothing

1:35 amalloy: ~help

1:35 clojurebot: Nobody can help with "X doesn't work". Please provide context: what you did, what you hoped would happen, and what happened instead. A stack trace is especially helpful, if applicable.

1:35 amalloy: technomancy: that used to return "help is http://www.khanacademy.org/&quot;; thus the connection

1:40 technomancy: heh

1:41 sw2wolf: ,(make-vector {:a 1, :b 2, :c 3})

1:41 clojurebot: #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: make-vector in this context, compiling:(NO_SOURCE_PATH:0)>

1:42 sw2wolf: &(make-vector {:a 1, :b 2, :c 3})

1:42 lazybot: java.lang.RuntimeException: Unable to resolve symbol: make-vector in this context

1:43 sw2wolf: ,(doc into)

1:43 clojurebot: "([to from]); Returns a new coll consisting of to-coll with all of the items of from-coll conjoined."

1:43 ivan: &(seq {:a 1, :b 2, :c 3})

1:43 lazybot: ⇒ ([:a 1] [:c 3] [:b 2])

1:43 sw2wolf: ivan: thx

1:44 ivan: sw2wolf: btw, lein repl

1:44 amalloy: or /msg lazybot, or...

1:44 sw2wolf: ivan: i know. but this is freebsd box without JRE installed

1:45 amalloy: sorry! i will use /msg later.

1:56 ghengis_: is clojure/java.jdbc pretty much the standard sql interface or are there other significant choices?

1:59 ioexception: ghengis_: I don't know or "do any clojure", but clojureql looks also nice http://clojureql.org/

2:01 ghengis_: ioexception: thanks, this looks nice too

2:04 amalloy: yikes, clojureql. if you want to do sql, use https://github.com/clojure/java.jdbc

2:17 sw2wolf: which emacs mode is for clojure ?

2:17 ivan: clojure-mode

2:17 sw2wolf: thx

2:17 ivan: you also want nrepl.el

2:17 and perhaps paredit

2:21 dabd: since clojure vectors have O(log32n) access if I want O(1) access i should use java arrays?

2:21 alex_baranosky: hey guys, is there a way to get equivalent behavior to 'realized?' for promises in 1.2.1?

2:24 ivan: dabd: only if you hate values

2:24 is log32n too slow for you?

2:25 dabd: yes I would like the fastest possible access

2:26 amalloy: dabd: so why are you using java? or virtual memory? or an operating system? it would be faster to connect wires straight to the RAM sticks

2:26 the point is everything's a tradeoff, and the performance cost of using vectors rather than arrays is minimal

2:28 alex_baranosky: has anyone used promises in 1.2?

2:28 is there no way to ask it if it has been yet delivered to?

2:29 dabd: amalloy: actually Java may not be the right tool for the job. Perhaps I should use C and jni to call it from Clojure

2:31 ivan: RAM sticks are way too slow, man

2:31 you've got that DDR3 protocol in your way

2:41 alex_baranosky: I'm afraid the lack of response about 1.2.1 promises is not a good sign for me

2:43 amalloy: alex_baranosky: it's a great sign! you have an excuse to stop using 1.2

2:53 alex_baranosky: amalloy: I've got a lot of excuses to stop. IF you can fathom it, we just moved to leiningen a month ago on the project I want the promises for

2:54 amalloy: this just means I need to prioritize moving to 1.3 before I can make this change., I guess

2:54 amalloy: hah, amazing

2:54 alex_baranosky: or 1.4 preferrably :)

2:55 amalloy: alex_baranosky: iirc in 1.2.x, (promise x) is just (reify IDeref (...) IFn (...)), so anything that's not exposed in that reify can't be gotten/done

2:55 alex_baranosky: yeah I just took a look at the history of core.clj, and you are correct

2:55 amalloy: yeah, 1.3 is terrible. upgrading to 1.4 is easier than upgrading to 1.3

3:22 vsync: if I have a PHP (ugh) server which I need to serve a bit of data to a ClojureScript client, what's the laziest and most trouble-free way? XML, JSON, or Clojure s-exprs?

3:23 and especially that for this iteration it will be a static file that i will later serve dynamically

3:32 tomoj: suppose you change #'binding and you double the time of a performance test that calls binding over and over in a loop. is that really bad?

5:53 squidz_: what would be the simplest way to read in a password from the cmd-line, and save it with clojure? Is it possible without a database?

6:06 squidz: What's the easiest way to save a passsword passed in the commandline without a Database?

6:13 pepijndevos_: Is nrepl specific to Clojure, or can it be used with any server?

6:18 Raynes: squidz: Hi.

6:18 squidz: Sit still and I will answer you. :p

6:18 squidz: So, is your question "How do I get a password on the command line" or "How do I store a password without a database"?

6:19 Or both?

6:22 squidz: how to store it

6:22 sorry if I asked my question twice, I was having problems with my irc client

6:23 mindbender1: `lein classpath` is not picking `:source-paths` in project.clj. is this normal

6:23 as a result lein ring server returns classnotfound

6:30 Raynes: squidz: How would you like to store it?

6:30 squidz: In a file somewhere?

6:30 squidz: i just dont want that somebody can see it as plaintext

6:31 borkdude: squidz hash it?

6:31 Raynes: squidz: You can hash it.

6:31 borkdude: GTFO

6:31 ;)

6:32 borkdude: Raynes I looked up what that means. You want me to get the fuck out?

6:32 Raynes: Well, that makes it sound mean.

6:32 squidz: how do I hash it? then store it in a file?

6:32 borkdude: =)

6:33 Raynes: squidz: jbcrypt for hashing, spit for storing.

6:34 https://github.com/noir-clojure/lib-noir/blob/master/src/noir/util/crypt.clj

6:34 borkdude: I would like to express my appreciation of the read-line support in CCW now… but nobody is here to receive it. So I won't.

6:34 squidz: thanks

6:46 borkdude: hmm, I sometimes get this exception in CCW, but I don't know how to reproduce it https://www.refheap.com/paste/7601

6:47 ah well, I do know now! using an atom and applying swap! to it from the repl will

6:47 hyPiRion: as in (apply swap! ...) ?

6:47 or (swap! ...)

6:47 borkdude: hyPiRion just (swap! ...)

6:48 hyPiRion: Huh, IOExceptin

6:48 borkdude: not immediately though, only sometimes

6:49 hyPiRion: Doesn't really sound like an error with swap! and atoms though.

6:50 But it seems like it's activating the error somehow

6:50 borkdude: hyPiRion yeah, I'm trying to reproduce now, but no luck

6:56 hmm, never mind

6:56 can'r reproduce it anymore :-s

6:59 mindbender1: technomancy: lein classpath is not reflecting my :source-paths entry, is there a way of tracing the problem?

7:02 lein trace

7:03 hyPiRion: classpath != source path

7:03 classes are the java binaries, source is the source code

7:06 mindbender1: hyPiRion: but I thought source-paths get influence classpaths with lein

7:07 hyPiRion: hm

7:07 mindbender1: :)

7:08 hyPiRion: right, I see both target/classes and my src-folders here

7:08 what version are you running?

7:08 `lein version`

7:08 mindbender1: I think the problem is with my silly head I actually forgot that I changed lein script to point to lein2

7:08 I found out with lein version

7:09 hyPiRion: heh

7:09 mindbender1: :)

7:09 hyPiRion: I make lein point to lein 2.0, and lein1 to lein 1.7

7:09 I use lein 2.0 so much now that lein1 is essentially only for building lein2.

10:43 ravster: hello everyone

10:49 borkdude: hello ravster

11:02 gauravag: is there any parallel implementation of filter?

11:12 hyPiRion: gauravag: not afaik, the concatenation of lists/vectors would kill the performance

11:13 ravster: What does the ',,,' mean when used in a thread? It doesn't look like it gets parsed at all, but its not a comment either.

11:13 lantiga: gauravag: look into the reducers library http://clojure.com/blog/2012/05/08/reducers-a-library-and-model-for-collection-processing.html

11:13 gauravag: hyPiRion, lantiga: thank you

11:14 Bronsa: ravster: , is treated as a whitespice by the clojure reader

11:14 lantiga: if the filtering function is heavy, you could also gain some speed with (filter identity (pmap f coll))

11:14 ravster: Bronsa: I see. my lead dev uses 3 (so ',,,'), but it can even be a ',' and it'll still be unprocessed?

11:15 Bronsa: yes

11:15 ',,,' is usually used in threading macros as -> and ->> to indicate the position where the variable will be threaded

11:16 gauravag: the filtering function is not really heavy, but the seq is long enough

11:16 ivaraasen: so, the most hilarious thing ever happened today. they handed out our exam with the solution stapled to it.

11:16 multiple choice exam as well.

11:17 gauravag: ivaraasen: wrong window?

11:18 ivaraasen: gauravag: yeah, sorry for that. still pretty hilarious though

11:18 gauravag: :D

11:19 ravster: cool, thanks Bronsa

11:19 gauravag: https://gist.github.com/4296706

11:19 Is there any way to optimize it?

11:20 ravster: is there a preferred way of doing docstrings in clojure? I've got a CL background, and all thats done there is a string after the def. But clojure also has some '^' meta thing going on.

11:26 joegallo: ravster: don't worry about that. just do (def foo "some docstring blah blah blah" 4) and (defn bar "some docstring" [arg list] ...). that'll get you through 95% of situations.

11:27 ravster: [arg list]?

11:27 oh, right, defn.

11:27 nvm.

11:27 oh, so the docstring comes before the [arg list]

11:28 joegallo: thanks

11:29 joegallo: gauravag: you don't need to compare numbers, you can just keep them as strings, OR, you can just compare seqs

11:29 ,(defn palindromic? [s] (let [s (str s)] (= (seq s) (reverse s))))

11:29 clojurebot: #<Exception java.lang.Exception: SANBOX DENIED>

11:29 joegallo: ~(defn palindromic? [s] (let [s (str s)] (= (seq s) (reverse s))))

11:29 clojurebot: ,(let [testar (fn [x y] (if (= (reduce + (filter odd? (range 0 x))) y) (str y " is an")) )] (testar 10 25))

11:30 joegallo: (palindromic? 101)

11:30 (palindromic? 101) would work the same as (palindromic? "101"), which is somewhat nice...

11:30 gauravag: oh yeah..

11:31 that is a nice to have.. but I still have the performance problem! :(

11:31 joegallo: ravster: yes, see https://github.com/dakrone/clj-http/blob/master/src/clj_http/core.clj#L28 for an example.

11:32 the defn and name on one line, then a line or paragraph of docstring, and then arguments vector on the line after. that's pretty much standard.

11:33 gauravag: you are checking more number than you need to.

11:33 100*101 = 101*100, so you can modify your number generator to do a better job of avoiding the duplicate multiplications.

11:34 and then that would have you checking fewer results to see if they're palindromic.

11:35 hyPiRion: Reverse the problem.

11:35 gauravag: I understand that.. but the logic would become complex if am trying to avoid 15*8 and 40*3

11:35 joegallo: yeah, worry about that later.

11:36 gauravag: hyPirion: explain?

11:37 joegallo: gauravag: takes 1.5 seconds on my machine -- how fast do you need this to be?

11:37 gauravag: joegallo: I was looking to leverage the multi-core architecture for this problem

11:38 If the number increases it really makes no sense even if I am able to filter out only some of the numbers.

11:39 4-digit * 4-digit, or going higher than that would be very difficult!

11:39 hyPiRion: gauravag: First off, what do you know about a number which is a product of two three-digit numbers?

11:39 joegallo: right, but by adding a :when (=< x y) you can cut the size of the problem in half...

11:40 hyPiRion: ,(* 999 999)

11:40 clojurebot: 998001

11:41 hyPiRion: So the highest possible palindrome is on the form abccba.

11:41 where a is nonzero.

11:42 gauravag: oh yes..

11:43 you are looking towards a different solution?

11:50 hyPiRion: iterate over the abc's descending instead, and check if it's possible to split in two.

11:54 like this

11:54 ,(let [cands (set (range 100 1000)) good? (fn [n] (some cands (map (partial / n) cands)))] (first (filter good? (for [a (range 9 0 -1) b (range 9 -1 -1) c (range 9 -1 -1)] (Long. (str a b c c b a))))))

11:54 clojurebot: 906609

12:00 gauravag: (let [cands (set (range 100 1000)) good? (fn [n] (some cands (map (partial / n) cands)))] (first (filter good? (for [a (range 9 0 -1) b (range 9 -1 -1) c (range 9 -1 -1)] (Long. (str a b c c b a))))))

12:00 hyPiRion: have you really optimized for tried optimizing for time?

12:01 brainproxy: anyone else found themselved using datomic and its db functions feature to achieve polymorphism, i.e. along lines of multimethods and protocols, but more meta-data driven?

12:03 i've flipped flopped a few times now on that approach, fearing it would be hard to maintain, but the lure is very strong

12:04 hyPiRion: gauravag: not completely, but it's running on roughly 150 msec here.

12:04 You could do some more mathy tricks to get it even further down

12:06 gauravag: (source partial)

12:08 brainproxy: Guest18246: what you sticking the range into a set?

12:08 whoops

12:08 gauravag: ^

12:08 *why are

12:09 sorry, just woke up

12:09 gauravag: was just wondering the same thing!

12:10 brainproxy: i mean, it will work, but I don't see that it changes anything, you're still leveraging it as a collection

12:10 so might as well stick with the LazySeq coming back from range

12:55 gauravag: Bronsa: , are basically white spaces in clojure

12:55 Bronsa: yeah

13:32 antoineB: hello, does exist a macro that transform (my-or = a [c d]) to (or (= a c) (= a d)) ?

13:44 borkdude: antoineB the closest would be (#{c d} a) probably

13:44 mattmoss: antoine left

13:45 I was thinking: (some (partial = a) [c d])

13:46 borkdude: mattmoss or just (or (= a c) (= a d)), what's the big deal anyway ;)

13:46 ChongLi: if your [c d] vector happens to have thousands of elements

13:46 mattmoss: borkdude: No biggie... context is everything. However, antoineB left.

13:47 ChongLi: kinda silly to ask a questin and leave so quickly

13:47 jeremyheiler: yeah... i mean at least 4 of us where thinking about it

13:47 mattmoss: Bets on him coming back and asking again?

13:48 ChongLi: I've seen him here in the past

13:48 so he'll probably be back

13:48 maybe not today though

13:58 jeremyheiler: (defmacro my-or [f a vs] (cons 'or (for [v vs] `(= ~a ~v))))

13:58 meh?

14:00 jaimef: java stack traces always ruin such a great lang

14:05 firesofmay: Hi, is it possible to include a library inside repl? or is it possible to have a library which is always available without adding it to all repos project.clj? Like clojure-docs api for example? : https://github.com/dakrone/clojuredocs-client

14:05 ivan: jaimef: ask chouser to release longbottom

14:05 alexakarpov: hm? I have just started with Clojure, but I find it's stack traces really puzzling... or are you saying it's Java's fault?

14:05 dakrone: firesofmay: if you are talking about the clojuredocs-client in particular, lein2 already includes it in the repl

14:05 firesofmay: dakrone, ah okay.

14:06 AimHere: The stack traces appear to be raw Java stacktraces, which are very definitely annoying to work with

14:06 dakrone: fire up a lein2 repl and do (cdoc map)

14:06 AimHere: Whose fault it is is left as an exercise for the lynch mob

14:07 alexakarpov: oh I see; so Clojure doesn't have it's own mechanism for producing stack traces, then?

14:07 firesofmay: dakrone, How to I run it? (cdoc map) is giving me error. Unable to include also : (use 'cd.client.core) > error.

14:07 dakrone: firesofmay: are you using lein version 2?

14:07 firesofmay: dakrone, i mean (use 'cd-client.core)

14:07 dakrone, yes

14:07 dakrone, I am running this inside emacs btw using slime.

14:07 dakrone: ahh, so that REPL is a little different

14:08 cd-client gets added to the vanilla `lein repl` repl

14:08 firesofmay: dakrone, okay. so is there a way around this?

14:08 dakrone: firesofmay: you could add it as a dev dependency to your project, so it'll be available while you're at your dev REPL

14:09 firesofmay: dakrone, But Is there a way to add this like a global library?

14:09 dakrone, without me adding it to every project.clj

14:09 dakrone: firesofmay: you could add it to your ~/.lein/profiles.clj :user profile, I'm not sure if that one gets added to each project for a slime connection (or you could put it in the :dev profile in ~/.lein/profiles.clj, but that's not a great repeatability practice)

14:10 ChongLi: I'm very interested in longbottom

14:10 it seems to remain shrouded in mystery though

14:10 apart from some slides

14:10 firesofmay: dakrone, I thought its only for lein plugins ~/.lein/profiles.clj no?

14:11 dakrone: firesofmay: depends on where you add it, you could add {:user {:dependencies [[cd-client ...]]}}

14:11 firesofmay: dakrone, I see.

14:12 dakrone: firesofmay: not sure if this is an approved way, I would recommend looking into nrepl.el and using middleware for it

14:12 firesofmay: dakrone, okay

14:14 berdario: dakrone: do you know about nrepl.el?

14:14 technomancy: yeah :dev in ~/.lein/profiles.clj will be likely to conflict

14:14 dakrone: berdario: yes? that is an ambiguous question

14:15 yes I know about it, I use it

14:16 berdario: dakrone: I was just wondering if you could help me debug a problem with launching it

14:16 that is, it fails when M-x nrepl-jack-in

14:16 dakrone: with what error?

14:17 berdario: it's an error related with $SHELL, function or variable

14:17 (it says that variables may not be used as commands... and indeed, I'm not using a standard bash shell)

14:18 dakrone: not really familiar with that error, have you tried opening an issue on the github repo?

14:19 berdario: dakrone: I usually avoid to report problems if I'm not able to pin down exactly what's going wrong

14:19 btw, it just dawned upon me, that... even if I installed nrepl.el from marmalade, I can just try to modify the .el file, and...

14:20 (I just realized that I don't know where it's stored...)

14:20 jaimef: I am saying the java stacktrace wakes me up from my lisp fantasy :P

14:20 ttvd: lol

14:21 jaimef: want a ":1 to continue :2 <abort>"

14:21 dakrone: berdario: ~/.emacs.d/elpa/nrepl*

14:21 berdario: ok, elpa/nrepl

14:21 dakrone: thanks :)

14:22 dakrone: since you're probably more emacs-knowledgeable than me... do you suggest to erase the .elc or to use a command to recompile them?

14:23 jaimef: berdario: did you install manually? or through package-install?

14:23 berdario: jaimef: package-install

14:23 jaimef: what problem are you getting?

14:23 is this win32?

14:24 berdario: which OS are you using?

14:24 berdario: jaimef: Linux (Ubuntu 12.10), emacs 24

14:24 jaimef: odd. what is your $SHELL?

14:25 technomancy: berdario: you can always find where something is defined in Emacs with C-h f

14:26 berdario: jaimef: fish, and fish indeed doesn't let to use variables as commands... I was expecting to find a shebang or a way to configure the shell in which to execute the command inside nrepl.el, but I'm at a loss for the moment

14:26 technomancy: though I recommend the elisp-slime-nav package for even better navigation

14:27 berdario: if you clone from git you can use M-x package-install-from-buffer to apply your changes and get the byte-compilation/autoloads set up

14:27 berdario: technomancy: thanks, I'll look into elisp-slime-nav (uh, I have tons of things to install and configure, already)

14:27 technomancy: thanks again :)

14:27 technomancy: that one is pretty simple; just install it and suddenly M-. works in elisp like you'd expect

15:05 berdario: dakrone: I got it to work... opened the issue on github :) https://github.com/kingtim/nrepl.el/pull/192/files

15:43 tgoossens: I noticed when solving problems on 4clojure I very frequently end up using loop, recur. Is it the nature of the problems on 4clojure or is it just me trying to use tail recursion to bring back my familiar loops of imperative programming.

15:43 bbloom: tgoossens: maybe a mix of both :-)

15:44 tgoossens: probably :)

15:44 bbloom: in generally, i'm a big believer in loop/recur while working through the problem

15:44 it forces you to consider the base case and the general case

15:44 you need to think about termination conditions, what changes on each iteration, etc

15:44 tgoossens: it has worked great for me. yes indeed

15:44 bbloom: i often write the loop/recur version, and then go back and extract it into a multi-step process

15:44 and then find the builtin for each step

15:45 tgoossens: just wrote a function for infix caluclations (infix 1 + 2 / 3) :)

15:45 i was hoping to find a solution with reduce

15:45 but so far i haven't

15:45 i did it with loop,recur

15:46 and some curry

15:46 bbloom: paste your solution on refheap

15:48 tgoossens: ok

15:51 bbloom: https://www.refheap.com/paste/7608

15:51 bbloom: tgoossens: random nitpick… seems like 2 spaces are preferred over tabs in most clj i see :-)

15:52 tgoossens: just coming from java :p

15:52 and lol, you are not the first one to say that to me :p

15:52 bbloom: (doc empty?)

15:52 clojurebot: "([coll]); Returns true if coll has no items - same as (not (seq coll)). Please use the idiom (seq x) rather than (not (empty? x))"

15:53 tgoossens: mm

15:54 bbloom: ok so reduce in core is really a foldl, which is defined in terms of a binary operator, an initial accumulator value, and a sequence

15:54 here, your base case of "(empty? expr)" basically says "exhaust the input sequence"

15:55 tgoossens: correct

15:55 bbloom: and you are combining expr and value in some way (two operands) on each non base case loop

15:55 so yeah, definitely a reduce opportunity! :-)

15:55 try this: move the if form inside the second argument to recur

15:55 tgoossens: i've been thinking about partitioning first

15:55 bbloom: that's basically your binary operator

15:55 tgoossens: (partition 2 ... ) or something and then use reduce

15:56 bbloom: it's simpler than that :-)

15:56 tgoossens: which of the ifs?

15:56 bbloom: the number? check

15:56 tgoossens: hmm

15:56 bbloom: notice that the first argument to recur is always the same

15:56 so you can use the if inside the expression for the second argument

15:57 tgoossens: mmyes

15:57 bbloom: minimize the scope of any particular expression (where it doesn't hurt readability)

15:57 and that will get you closer to abstracting out the binary operator you need for reduce!

15:57 tgoossens: let me try that

15:57 bbloom: brb

15:57 epitron: do you clojure people find yourself parsing english sentences with parens as clojure code? :)

15:59 tgoossens: epitron: kind of :p

16:00 epitron: (if that makes sense)

16:00 AimHere: I find myself writing the left parens in front of the function name in C-like languages and Excel spreadsheets

16:00 tgoossens: aimhere: same "problem" here

16:00 it happens a lot that i write

16:00 (if

16:04 dimovich: hey ppl

16:04 tpope: hi

16:05 dimovich: can someone enlighten me regarding the web crawler example from Clojure programming book?

16:05 the agent action uses a (try ... (finally)) form...

16:06 we return the new state in the try body, but we use this new state in the finally form...

16:06 clojurebot: anybody is anyone

16:07 dimovich: so... is the finally form evaluated after we return from the function... or how does it work?

16:07 tpope: dimovich: the finally is evaluated before returning

16:08 AimHere: Even if there's an exception in the try block

16:09 dimovich: https://gist.github.com/4299179

16:09 get-url returns the new state... but we need this new state in the run function which is called in the finally block

16:11 how is the new state assign to the agent before returning?

16:11 *assigned

16:11 tgoossens: bbloom: i did it

16:11 tpope: dimovich: the body of the try is evaluated before the finally. but both run before the function returns

16:11 I'm not sure if that answers your question

16:11 bbloom: tgoossens: post it :-)

16:11 tgoossens: bbloom: i think its magical now :D

16:13 bbloom: https://www.refheap.com/paste/7609

16:13 still checking how i'm going to make it even cleaner

16:13 but i think its already pretty clean

16:15 apparently when copying it doesn't preserve my 2 space intendation, bah!

16:16 tpope: tgoossens: if you're using hard tabs defined as 2 spaces, then no, it won't copy

16:17 tgoossens: ah

16:17 ok that explains it

16:17 tpope: better to just use spaces. "soft tabs"

16:17 tgoossens: i'll remember that

16:17 ravster: hello everyone

16:17 tgoossens: ravster: hi

16:17 tpope: hi

16:19 bbloom: tgoossens: usually, when you split up arguments on to multiple lines, you line them up one argument per line, so that people don't need to count parens

16:19 tgoossens: i was confused by the "identity expr"

16:20 tgoossens: ok

16:20 bbloom: tgoossens: here's your exact code reformatted https://www.refheap.com/paste/7612

16:20 now you can clearly see the arguments t reduce

16:21 solussd: looks like this is solved in clojurescript, but in clojure I cannot use clojure.walk functions with records b/c records don't implement the empty function of IPersistentCollection. Looks like there is an open, unresolved bug for it (CLJ-1105), but it's in the backlog. Does that mean no chance we'll see a fix in Clojure 1.5? :)

16:21 tgoossens: ah cool

16:21 much clearer indeed

16:22 i'm so proud of myself now :p

16:22 bbloom: :-)

16:22 that's a pretty reasonable solution

16:22 tgoossens: clojure is a language where you really can get complete satisfaction from a piece of code :p

16:22 bbloom: yup

16:23 tgoossens: next semester after my exams i should find myself some projects in clojure instead of playing around with 4clojure :p

16:24 borkdude: tgoossens I see you're getting really addicted.. nice ;)

16:25 I wonder what language is more addicting, clojure or Haskell -- I think clojure, but I don't know why really

16:25 tgoossens: borkdude: never worked with haskell before.

16:25 next year i'll be seeing it in a course "declarative languages"

16:25 so now i'm focusing on other languages

16:26 borkdude: tgoossens in my first year at university we were taught Miranda - it was kind of a predecessor of Haskell

16:27 ravster: is anyone having issues with ring.middleware,

16:27 a

16:27 tgoossens: the problem with a language like haskell (i think) is that - like rich hickey state in his talks - is that we need to be able to model "processes"

16:27 ravster: bah

16:27 basic-authentication

16:27 borkdude: tgoossens haven't seen a hickey talk in a while, so explain

16:27 xeqi: ~anyone

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

16:28 ravster: xeqi: :O

16:28 thanks

16:28 I'm now

16:28 I'm not sure that its modifying the request object

16:29 xeqi: can you make a paste showing how you're using it?

16:29 borkdude: ravster maybe it helps when you post your handler.clj to refheap

16:30 tgoossens: there are "processes" in your software that produce new values. There is the identity car. you can perceive that car in a certain state. The next time you perceive (look at it) it can may be in a different state.

16:30 ivan: "You cannot vote for an issue you have reported" what is this, metafilter? ;)

16:31 tgoossens: It is the process that makes transitions possible and takes in account external events

16:31 its not the car that is *behaving* but rather

16:31 borkdude: tgoossens yeah, identity vs state

16:31 tgoossens: the proces that brings the car into a new state

16:32 bbloom: tgoossens: clojure's notion of value, identity, and state is super interesting and enlightening, but i don't think that haskell is in anyway incapable of that approach

16:32 tgoossens: no it is capable

16:32 (monads i suppose)

16:32 bbloom: tgoossens: well haskell would utilize monads to implement it, but monads are an orthogonal issue

16:32 tgoossens: oh well, i think i should first learn the language

16:32 before i make such statements :p

16:32 borkdude: bbloom tgoossens isn't this more about persistent datastructures than anything else?

16:33 bbloom: borkdude: it's a bit deeper than that. it's about this idea that identity and value are two components of state

16:33 tgoossens: the key thing is

16:33 what rich tried (and how i interpret it)

16:33 is to make a clear separation of

16:34 the pure and the impure (process) part of the software

16:34 rather than trying to make eveything pure

16:34 Chousuke: a state is the value of an indentity at a given point in time.

16:34 that's how they relate to each other.

16:34 borkdude: Chousuke right

16:34 bbloom: tgoossens: haskell excels at separating pure and impure :-P

16:35 tgoossens: bbloom: i'll let you know how i think of that next year then :

16:35 :)

16:35 i've seen people bringing monads (i have only a very very little understanding of the concept btw) to clojrue

16:35 clojurebot: I don't understand.

16:36 Chousuke: bbloom: as far as I know, technically there is no such thing as "impure" in haskell :P

16:36 tgoossens: so maybe it'll become popular in the future

16:36 (more)

16:36 bbloom: Chousuke: well of course there is

16:36 Chousuke: bbloom: even IO is pure

16:36 borkdude: the IO Monad.....

16:36 Chousuke: since from haskell point of view IO actions are pure values

16:36 bbloom: Chousuke: if you're program doesn't explicitly do something impure, then the only thing it is doing is heating up your desk :-P

16:37 tgoossens: haskell offer's clojure's notion of identity and state in several packages

16:37 devn: core.logic is so cool

16:37 bbloom: for example http://www.haskell.org/ghc/docs/latest/html/libraries/base/Control-Concurrent-MVar.html

16:38 you'll notice a similar API: readMVar is like deref, swapMVar is like swap!, etc

16:38 Raynes: borkdude: A popular misconception is that IO is impure. In reality, IO functions return IO actions that are instructions on how to perform an IO action and not the result of an actual IO action being performed right there at that moment.

16:38 tgoossens: bbloom: i wonderd. was clojure state / identity separation a new and unique idea introduced in clojure.

16:38 Chousuke: bbloom: yeah, but that's outside the language :P

16:38 Raynes: borkdude: And then a little dude comes out and goes and performs those actions when you run the program.

16:39 Chousuke: bbloom: from haskell point of view, IO actions are pretty much just like any other value

16:39 bbloom: tgoossens: i don't think that rich hickey claims novelty for any part of clojure :-P

16:39 borkdude: Raynes yeh ok

16:39 xeqi: that unsafePerformIO is sneaky

16:39 bbloom: clojure is about pragmatism and clarity of mission

16:40 Chousuke: xeqi: that's an extension

16:40 it's not actually haskell

16:40 xeqi: haha

16:40 Raynes: It's amusing, but completely true.

16:40 bbloom: "let's take all the good new ideas and use them with all the good old ideas"

16:40 where good ideas are very carefully defined

16:40 tgoossens: mmyes i can follow you on that

16:45 * devn is watching david nolen's talk: http://skillsmatter.com/podcast/home/the-refined-clojurist

16:45 devn: i like the idea of saying that clojure is about "what" and less about "how"

16:45 RE: bbloom

16:45 borkdude: http://stackoverflow.com/questions/4063778/in-what-sense-is-the-io-monad-pure

16:46 bbloom: devn: it's certainly evolving that way

16:46 however, haskell & friends did a lot of deep research into separating the pure from the impure

16:46 i think we need a language to deeply study the separation from how and what

16:46 then we can back port those good ideas into a lisp :-)

16:47 because, fundamentally, clojure dictates "how" at a very deep level: (f (g x) (h y)) says that g, h, and then f will be evaluated… in that order!

16:55 Siphonblast: Can someone help me setup clojure-mode within emacs? adding to my ~/emacs.d/init.el doesn't make the package-install [RET] clojure-mode visible.

16:55 I'm new to emacs and none of this really makes any sense at all, really.

16:55 http://dev.clojure.org/display/doc/Getting+Started+with+Emacs

16:57 devn: bbloom: reducers, though, as dnolen points out, fixes some of this

16:57 bbloom: "should I use foldl or folr?" -- reducers don't care

16:57 foldr*

16:58 declarative programming, not order complected.

17:02 bbloom: of course, but like i said: declarative programming is the new frontier

17:02 immutible objects weren't a new idea in haskell

17:02 but that community deeply explored functional programming

17:02 prolog started to explore logic programming, but didn't really get into constraint programming

17:03 oz/motzart has explored constraint programming more and dnolen et al are starting to import some of those good ideas

17:03 devn: violent agreement complete!

17:04 bbloom: :-)

17:04 devn: bbloom: like most things, you need to take something to its extreme to discover where it is most useful

17:04 bbloom: devn: yeah, i love "one issue languages" as learning experiments

17:05 devn: what i like about clojure is the idea of a la carte paradigms

17:05 so we can have some (f (g x) (h y)) here and there, and then take all of that how, and use it in our what

17:05 which sounds dirty

17:06 bbloom: devn: i've been considering creating an experimental new language that has a strict separation of what and how

17:06 just to see what happens :-)

17:06 (and how it happens :-P)

17:08 TimMc: bbloom: "Bah, your language is no good -- you're still complecting 'what I want to do' with 'the source code I write'."

17:08 gfredericks: (run 5 [r a b x] (== r [a b]) (infd a b (domain 1 2)) (<fd a b) (firsto r x))

17:08 ^ errors o_O

17:09 bbloom: TimMc: i assume you're making a joke, but i'm not sure i get it and am curious for an elaboration :-)

17:09 borkdude: I guess there is a function that gets the current date in Haskell? How on earth can that be a pure function?

17:09 SegFaultAX: I'm so happy that complect has made it into the daily vernacular of this channel. :)

17:09 gfredericks: borkdude: it wouldn't be; it'd return an IO Date or something like that

17:09 devn: SegFaultAX: it's spread pretty far and wide

17:09 bbloom: SegFaultAX: i was just saying yesterday: complect and reify are my two new favorite works :-)

17:09 devn: i hear it a lot at work from people who are primarily ruby programmers

17:09 SegFaultAX: bbloom: Well, reify isn't new.

17:09 devn: (and quite often, since they're ruby programmers)

17:09 ;)

17:09 bbloom: SegFaultAX: yeah, but damn if it isn't a good word

17:10 TimMc: bbloom: Just a throwaway joke about source code being "too related" to what a program does. Clearly you need to separate those concerns better!

17:10 SegFaultAX: bbloom: Hah, you got me there.

17:10 borkdude: gfredericks I think we just established that IO of something was considered pure, because it was only a recepy of how an IO action would be performed

17:10 devn: TimMc: ha! i was thinking the same thing...

17:10 bbloom: borkdude: http://www.haskell.org/haskellwiki/Getting_the_current_date

17:10 ivan: Siphonblast: are you typing it into the minibuffer that pops up when you hit M-x

17:10 SegFaultAX: bbloom: But reification is a pretty general term.

17:10 gfredericks: borkdude: okay; well that's how it's pure then

17:10 bbloom: TimMc: i think the bigger challenege in separating "what" from "how" is that often the "what" *is* the "how"

17:10 ie with business processes

17:11 borkdude: gfredericks but a pure function always returns the same output with the same input…. getCurrentTime of course doesn't

17:11 TimMc: Yeah, that's the ha-ha-only-serious side of my joke.

17:11 I think you could go a long way before that's your biggest design problem, though!

17:12 SegFaultAX: borkdude: I think you mean a referentially transparent function.

17:12 gfredericks: borkdude: sure it does; it always returns you the same IO Date

17:14 ravster: in compojure routes, does using [] in the argslist of the GET call just pass on the whole request?

17:15 gfredericks: ravster: probably does nothing. you could either replace [] with req or {:as req}; I expect at least one of those would do that

17:20 borkdude: gfredericks you mean, it always returns the same "recepy for getting the current date" or smth? I think I'm too tired to understand this, but is there no way to create an impure function in Haskell?

17:21 SegFaultAX: borkdude: That's correct.

17:21 gfredericks: well there is performUnsafeIO

17:21 but pretend that there isn't

17:22 borkdude: that's what makes haskell interesting; the compiler forces the IO stuff to propogate all the way to the top. You can't "reach into" the IO yourself, you have to either let ghci do that, or the main function of a program.

17:22 so you can't hide side effects

17:22 * gfredericks created LOGIC-77

17:24 borkdude: gfredericks well yeah, hmm, so… but you can get the current date inside a do block right? but it will always be wrapped inside an IO smth when you want to return it, so it will in fact always be a recepy of how you will get the current time and use that… or smth - I will look into this later, I'm really too tired :P

17:25 SegFaultAX: borkdude: We can help you in #haskell.

17:25 borkdude: SegFaultAX so the only impure function in Haskell can be main?

17:25 SegFaultAX: borkdude: Impure function isn't a thing in Haskell.

17:26 gfredericks: borkdude: if the type of main is an IO Thing, then the IO will actually get performed

17:27 same thing in ghci, which can be rather misleading

17:38 borkdude: gtg, bye

17:40 Siphonblast: ivan: Thanks for the help, but I solved it just now. The solution was to install Emacs24 rather than wank around with the init.el of 23 like a noob :D

17:40 ivan: heh

17:40 you might also want to take a look at what emacs-starter-kit does and copy things from it

17:43 Siphonblast: okay.

17:44 hallski: *qiot

17:50 Siphonblast: oh wow, this starter-kit-mode has confused the hell out of me, ironically.

17:50 heh.

17:50 The GUI button at the top went away and were replaced with a scratch buffer or something. Oh gosh I have so much to learn.

17:50 ivan: M-x menu-bar-mode to turn the menu back on

17:51 the toolbar that got turned off is pretty darn useless

17:51 sshack: Okay, A question and a riddle.

17:52 Firs the question. What's the current reasonable choice for CSV parsing libraries that support fieldnames in clojure?

17:56 SegFaultAX: sshack: What does it mean to support field names?

17:56 sshack: Well, in many CSV files, the first row contains the names of the columns. Like "name", "account", "balance", "address", etc.

17:57 SegFaultAX: sshack: Right, but what behavior do you need with those names, exactly?

17:57 sshack: Ideally I'd like to refer to the fields by name. Rather than field 3, field 4, etc.

17:58 tgoossens: equals equals equals

17:58 ,(= = =)

17:58 clojurebot: true

17:59 SegFaultAX: sshack: But you could do that yourself, no?

17:59 sshack: No, I couldn't.

17:59 SegFaultAX: Like, (def headers [:one :two :three]) (into {} (map vector headers row))

18:00 sshack: At that point I might as well be programming in assembler, writing my own pmode routines.

18:01 SegFaultAX: sshack: Hah. Anyway, I've used data.csv and clojure-csv, and they both worked fine.

18:01 sshack: I'll look at data.csv

18:03 clojure-csv doesn't do field names.. I'm dealing with CSV files that had missing/added fields and fields are frequently reordered.

18:03 Having to do the mapping myself would leak that complexity into my app.

18:04 Siphonblast: O.O

18:04 This autocompletion and beginner mode is amazing.

18:04 I feel like I've just had sex with software for the first time.

18:05 pandeiro: Siphonblast: well how was it?

18:05 Octopus: Does anybody know the library quil?

18:05 SegFaultAX: sshack: That's like... 60 characters or something. Is it really as bad as all that?

18:06 sshack: SegFaultAX: It's a slippery slope. One I've fallen (or been shoved) down before.

18:06 SegFaultAX: sshack: That must have been awful for you... having to map your own headers.

18:06 Siphonblast: pandeiro: I don't know. I am still trying to interpret my experience.

18:08 SegFaultAX: sshack: If it means anything to you, the same pattern is common when using Python's csv module. [dict(zip(headers, row)) for row in mycsv] etc.

18:08 sshack: Actually python's csv supports headers now too.

18:08 SegFaultAX: sshack: Oh? How recent is that?

18:08 sshack: headers/fields/columnnames whatever you'd want to call them.

18:09 SegFaultAX: I was using python 2.7. so whenever.

18:09 SegFaultAX: Oh, dictreader, yea.

18:09 But that's just a wrapper for the above logic.

18:11 sshack: That's fine. It still doesn't leak the complexity off to me.

18:12 SegFaultAX: sshack: Who hurt you?

18:12 sshack: I want you to know, I'm here for you.

18:12 sshack: SegFaultAX: sendmail.

18:12 and his friends autoconf and autotools

18:13 * SegFaultAX sheds a tear for sshack

18:13 sshack: I appreciate it.

18:13 Okay, next the riddle.

18:14 ravster: hello everyone

18:14 SegFaultAX: sshack: gogogogo

18:14 ravster: Herro.

18:14 sshack: I've got a core dataset, say customers with name, account, balance, age, address, and postalcode

18:15 I'm splitting the customers into some number of groups (the whales, the average customers, cheapskates, etc).

18:15 Then I'm doing some aggregate statistics on the whales, normals, cheapskates, etc). Say average, stddev, etc.

18:16 But I have proxy data for my customers too, based on zip code. So for example, average income, urban vs rural area, crime rate, etc.

18:16 I want to calculate the same statistics for those different groups on my proxy data as well.

18:17 Thoughts on approaches?

18:17 btw, this data isn't cheap to calculate, so I'm storing it in a table.

18:17 SegFaultAX: sshack: Sounds relational. Database?

18:17 sshack: I thought that part was a given.

18:18 SegFaultAX: sshack: Then what's the question? You have some reports you need to generate, go write some queries.

18:18 sshack: Right now the only approaches I can think of are quite complex. huge number of joins, etc.

18:19 SegFaultAX: sshack: Reporting is like that.

18:20 sshack: Sometimes it's useful to spin up a read replica specifically to serve your report generation.

18:20 sshack: That won't be necessary here. It's a very low volume app.

18:22 SegFaultAX: sshack: Another option might be to use a datastore that's good at this sort of thing.

18:23 sshack: Eg a mapreduce datastore (couchbase, for example)

18:24 Express your reports as designs documents and let the datastore figure out how to efficiently parallelize that over your dataset.

18:24 sshack: It isn't a large data problem, it's a modelling one.

18:24 The actual processing isn't an issue here. Just the modelling.

18:24 SegFaultAX: Like, your data model is bad and you should feel bad?

18:26 sshack: Well, perhaps.

18:26 SegFaultAX: sshack: That's the nice thing about pulling your data out and putting it into something like couch. I'm assuming that your current dataset is highly normalized which would lead to a lot of joining across loads of tables...

18:27 sshack: But that's REALLY expensive when you're trying to build lots of aggregates. If you load it into couch or something, your first step is to figure out a reasonable way to denormalize the data into core collections.

18:28 sshack: Well, my dataset fits into $500 worth of RAM. So the database isn't changing.

18:28 SegFaultAX: sshack: For example, your current user information + proxy exists as several tables (from your description) but you might join that information together into a much larger "user" document.

18:28 sshack: I was thinking about views. Which would work nicely. But I'm not sure how to make adding/removing proxy data reasonably easy.

18:30 SegFaultAX: Well views won't really help you here. Materialized views might, though.

18:32 sshack: I think there's multiple ways to go about this.

18:32 views is the obvious first choice. But I'm not sure that'd be flexible.

18:34 craigbro: I don't understand the aversion to joins here

18:34 SegFaultAX: craigbro: Just the slowness I'm assuming.

18:34 craigbro: joins across alot of tables is not epensive if you have your indexes built right

18:34 especially if, as you said, it all fits in ram

18:37 it WILL gen expensive if you start doing alot of OR or NOT conditions, or aggregates, and then sorting

18:37 OR/NOT can mess up your query planners use of indexes and stop you from just index scans and instead do a table scan

18:37 SegFaultAX: craigbro: But that's the thing, he's building reports. So yea, probably lots of aggregates, complex constraints and lots of derived tables.

18:37 craigbro: and aggregate and sortings on big big data usually ends up CPU bound

18:38 if it fits in ram, tho none of this is gonna amount to much

18:38 on my 3tb+ database it is only if I'm doing aggregates on the biggest tables 150million plus rows, that I notice DB time at all

18:38 SegFaultAX: sshack: Ultimately, I think you should just pick the simplest possible solution and measure. Improve after you have real data.

18:39 craigbro: and that's with a horrid IO constraint due to a hardware problem on that server right now

18:39 sshack: SegFaultAX: I agree. I'm taking baby steps out from there now.

18:40 craigbro: I'm wanting to do aggregates for each of the columns, for the multiple classes.

18:40 ravster: how do I cleanly exit from an nrepl.el session?

18:40 (quit) and (exit) and C-d don't work.

18:41 craigbro: sshack: how many rows in your core set (customers) and in your annotation data (demographics etc..?)

18:41 the slowness of aggregates here I mentioned is prolly not an issue if your DB fits in memory

18:41 sshack: 170, Probably a few hundred in my proxy data in the end.

18:41 craigbro: what?

18:41 clojurebot: What is 2d6

18:41 craigbro: that's all

18:41 fuck, just put it into a DB and write your SQL

18:42 leave it in whatever DB it's in

18:42 any concern about the performance of an sql database on that dataset is, well, misplaced 8)

18:42 sshack: craigbro: I know. I was trying to get that point across to segfault. It's a modelling problem, not a DB problem.

18:42 craigbro: yah

18:42 sorry, that's what I get for jumping in late 8^)

18:42 sshack: Any concern about performance can be cured by money in this case.

18:42 SegFaultAX: sshack: 170? Really? Wow.

18:42 craigbro: I acually find highly normalized tables easy to deal with

18:43 sshack, you want some fun?

18:43 load ALL the ata up into a bunch of core.logic defrel/facts

18:43 and then write your reports that way

18:43 SegFaultAX: sshack: I thought we were talking about actual data.

18:43 craigbro: that's what we do for generate reports on our malware analysis runs (which are a bouple megs of JSON each, and quite complex)

18:44 sshack, of hell, just load each table up intoa couple of refs

18:44 /sof/or

18:44 s/of/or even!

18:44 sshack: craigbro: Actually, I don't want fun. I want someone to say "Well that's obvious, lets move on".

18:44 SegFaultAX: Let's move on.

18:44 craigbro: what? no fun? 8^(

18:44 I want fun

18:44 i never get any fun anymore

18:44 sshack: craigbro: The fun part is looking at your bank account if you've done things right.

18:45 craigbro: nothing for ugluk, nothing for ghishnak

18:46 ok, gotta go

18:46 sshack: So my current idea is to have a separate table storing table, column and class along with the aggregate result.

18:47 and then another table which has details of what proxy data to join in.

18:47 SegFaultAX: sshack: Your current dataset probably fits in a few megs /at most/. It literally doesn't matter.

18:48 sshack: SegFaultAX: It's about 9gig currently.

18:48 a few million rows.

18:48 SegFaultAX: You said 170.

18:48 sshack: 170 columns

18:48 SegFaultAX: Ohhh, 170 columns.

18:48 sshack: oops.

18:49 170columns+few hundred proxy columns. A few million rows. Still nothing though.

18:49 SegFaultAX: He asked how many rows.

18:49 Not columns.

18:50 sshack: Yeah, I'm sorry. I misread.

18:50 SegFaultAX: Well that changes everything.

18:51 sshack: Regardless, it's still a modelling problem. Not a data problem. The data will all still fit in memory.

18:53 A view would be brittle (couldn't easily add/change things on a dime.

19:05 ravster: when we use datomic sessions through ring.middleware.sessions, do the keys in the :session have to match the key-names in the DB schema?

19:11 Where can I find information on the SessionStore protocol that ring.middleware.sessions is using?

19:11 erwagasore: Moustache vs Compojure? What is the best choice?

19:12 NonInc: Good evening! I've got this list with a single string in it. This string is a decimal number. Now i want to create a symbol to give me its value so i can do calculations with it. In the example https://gist.github.com/4301198 I need to replace stragedef with something i do not know. Can you please help me?

19:13 scottj: erwagasore: compojure is much more popular and I think has more features. other than that I think it's personal preference.

19:16 NonInc: I'm sorry, just learning. I read about sequences and found out i can 'decapsule' a single element with (first list). Nevermind

19:34 bbloom: NonInc: your problem is not clear, what are you trying to accomplish?

19:35 ravster: which rabbitmq client do people here prefer using?

19:39 SegFaultAX: Decapsule?

20:23 bbloom: seangrove: the more i work on this cps transform, the less i think it will actually be useful

20:23 seangrove: bbloom: Would be cool to share your thoughts and rationale

20:23 Quick post on the current state?

20:23 I'd love to try to understand it myself

20:24 bbloom: thoughts still forming on the usefulness of it

20:24 but in the meantime, i've scoped it down a tad

20:24 at first, i wanted to do basically what scala did: provide automatic continuations throughout the system

20:25 but i think some kind of type system is necessary to have that work in a sane way....

20:25 any higher order function that accepts a continuation passing function needs to be implemented differently

20:26 scala gets static polymorphic dispatch based on types, you can overload a function such that (reduce f coll) is different depending on if f accepts a continuation or not

20:26 as it stands, i'd need to do like the reducers library does with r/map etc

20:26 i'd basically need k/map and k/reduce and all that jazz for continuation passing style higher order functions

20:27 unless you add some "type hints" that says this function is or isn't CPS

20:27 and then compile two version of every higher order function :-/

20:30 seangrove: does that make sense?

20:31 seangrove: hmm, yes

20:31 Presumably you could do it if the signature of the function matched some contract?

20:32 bbloom: seangrove: so the calling convention i'm using is that any CPS function takes as it's first argument an IContinuation object

20:33 seangrove: So then any function could be made to work with a tailored wrapping function then?

20:33 bbloom: maybe? it needs more exploration

20:34 so like i said, i reduced down the scope a bit: i'll no longer recurse into function bodies when doing the transform

20:34 so you need to opt into a cps transform with a macro and any nested functions will be protected from transformation

20:34 seangrove: Sounds reasonable, that's what I've been with the libraries I've been trying to use - organize wrappers for them so they all use the same calling convention, so I can macro away some of the tedium

20:34 bbloom: you'll have to explicitly use call-cc, just like you would explicitly async/await in C#

20:35 seangrove: Yeah, that sounds right

20:35 bbloom: my goal is to get to there

20:35 and if any more useful macros or libraries can be built on top, that'd be good news

20:35 Sgeo: ooh, someone's implementing call/cc?

20:36 seangrove: call-cc makes me smile though, I haven't worked with anyone who both 1.) understood it and 2.) thought it was a good idea to expose by itself

20:36 bbloom: Sgeo: https://github.com/brandonbloom/cljs-cps/

20:36 Sgeo: bbloom, here's one: Delimited continuations allow for a very pretty interface for using monads

20:36 bbloom: Sgeo: eh, i'm not super interested in monad libraries

20:36 :-P

20:36 Sgeo: Oh

20:36 bbloom: but if you think you can built one on my cps lib, i'd love to see it

20:36 :-)

20:37 but i decided to implement call-cc as the basis, rather than start w/ delimited continuations b/c of the nature of the top level being a non-cps form

20:37 Sgeo: I'm currently rather interested in Factor. It has threads that "block" etc. etc., with 1 "real" thread and co-operative multithreading based on call/cc

20:37 bbloom: shift/reset can be implemented with call-cc, an atom, and some macros

20:37 Sgeo: Interesting stuff

20:37 Although sucks when you accidentally write an infinite loop

20:38 bbloom: Sgeo: yeah, co-operative multithreading use cases would be interesting too

20:38 i'm trying to get the simplest bits to work reliably

20:38 hence some macro (tenatively called spawn, needs to be renamed) which transforms it's lexically enclosed form

20:38 seangrove: bbloom: Sounds like a good idae, I think it's a very interesting area to explore and build on

20:39 bbloom: any uses of (call-cc f x y z) inside that macro then get transformed into (f K x y z)

20:39 (would also be an apply-cc too

20:39 )

20:39 Sgeo: bbloom, can a function in the macro call another function that itself calls call-cc?

20:39 bbloom: Sgeo: should be able to

20:39 Sgeo: Ok, good

20:39 Because without that, it would be difficult to build useful abstractions on top of it

20:41 bbloom: yeah, well that would of course work :-)

20:41 so i think i'll "ship it" when this thing is basically equivilant to the async/await keywords in C#

20:41 will be a tiny bit different

20:41 but i think libs can be built on top of that

20:42 i'm not sure what those libs will be yet

20:51 dnolen: gfredericks: ping

20:58 aphyr: Uh, what's a good way to tell prn not to recurse indefinitely and run out of stack?

21:03 amalloy: &(doc *print-depth*)

21:03 lazybot: ⇒ nil

21:03 amalloy: &(doc *print-level*)

21:03 lazybot: ⇒ ------------------------- clojure.core/*print-level* *print-level* controls how many levels deep the printer will print nested objects. If it is bound to logical false, there is no limit. Otherwise, it must be bound to an integer indicating the maximum l... https://www.refheap.com/paste/7619

21:03 aphyr: Aha! Thanks amalloy!

21:04 Weird, why is that not in core.clj...

21:04 tpope: core_print.clj

21:05 I discovered this just today!

21:21 some projects are like foo.bar-test and others are like foo.test.bar. Is there a backstory there?

21:22 aphyr: tpope: bar-test is the new style.

21:23 I expect it changed so that projects could use myproject.test namespaces without colliding.

21:23 tpope: ah, makes sense

21:28 caecusum: Hi. I'm trying to figure out how to use (eval) in the context of a simple client/server application that lets the user type in expressions. I've borrowed some Clojurescript code from the Sierra/VanderHart book, and have it all working for the most part. The problem is, any time I try to eval my own functions, they aren't in scope. The code looks like this: http://pastebin.com/W00BkmeU

21:29 So if I send a request with an expression like (+ 2 2) it works, but if I do (k) then it doesn't

21:46 aphyr: caecusum: my guess is you're not evaluating the code in the context of cljs-d3.server

21:46 Try this: (binding [*ns* (find-ns 'cljs-d3.server)] (eval expr))

21:47 ... and make sure your host is server is firewalled, haha. ;)

21:47 caecusum: I know it's unsafe, I'm just doing it through localhost as an experiment :)

21:50 binding the namespace worked great! thanks

22:00 wingy: what's the easiest way to convert all string keys in a map to keyword keys?

22:01 eg. {":foo" 1} to {:foo 1}

22:01 aphyr: On clojure 1.4?

22:01 wingy: yeah

22:01 hmm btw

22:01 let me reprahse

22:01 rephrase

22:02 i wanna eval all keys/values in a map

22:02 eg. {":foo" "2"} -> {:foo 2}

22:02 aphyr: Gotcha.

22:03 (into {} (map (fn [[k v] [(read k) (read v)]) coll))

22:03 er, think I forgot to close the fn args

22:04 use (eval (read)) if you actually want to evaluate them as code

22:05 wingy: can't i use read-string if i made that map to a string

22:06 aphyr: Ah, yes, read-string

22:06 wingy: im actually using ring's form-params

22:06 wanna eval all form-param's key/value pair

22:06 s

22:07 ivan: depends on how hard you want to get owned by #= in a key

22:07 wingy: what is that?

22:07 ivan: user> (read-string "#=(+ 2 3)")

22:07 5

22:08 aphyr: wingy: if you're writing a web application, I strongly suggest using a more restrictive parsing

22:08 wingy: yeah

22:09 i should

22:09 but luckily me im just doing a prototype

22:09 i need something fast

22:09 aphyr: If all you want is to convert keys to keywords, that's pretty straightforward

22:09 (though again, you have to worry about the possibility of someone exhausting your keyword space!)

22:09 wingy: i need to convert values as well to clojure data

22:10 aphyr: Is there a strict EDN parser out there yet?

22:13 seangrove: Is there a reason why (swap! my-atom #({})) wouldn't swap the value of my-atom?

22:13 aphyr: well anyway this will read string forms: http://cljbin.com/paste/50cd3abbe4b0b37878b7565d

22:14 seangrove: #({}) becomes (fn [] ({}))

22:14 seangrove: which means it's executing a map as a function

22:14 seangrove: Ah, jesus

22:14 aphyr: If you want to change the value of my-atom without respect to its current value, use reset!

22:14 seangrove: Thank you

22:14 aphyr: If you want a function that returns {}, use (constantly {})

22:15 seangrove: yeah that bit me for about six months haha

22:15 seangrove: aphyr: I'm using dissoc, but that's not having any affect as well, so I was experimenting with just straight #{}

22:15 wingy: aphyr: great solution!

22:15 aphyr: Dissoc should work...

22:16 `(let [x (atom {:foo 1 :bar 2})] (swap! x dissoc :foo) @x

22:16 ,(let [x (atom {:foo 1 :bar 2})] (swap! x dissoc :foo) @x

22:16 clojurebot: #<ExecutionException java.util.concurrent.ExecutionException: java.lang.RuntimeException: EOF while reading>

22:16 aphyr: ,(let [x (atom {:foo 1 :bar 2})] (swap! x dissoc :foo) @x)

22:16 clojurebot: {:bar 2}

22:16 wingy: aphyr: i should make a middleware out of it

22:16 aphyr: wingy: I really wouldn't encourage this, haha ;-)

22:16 seangrove: Oh yes, I'm sure it's something I was doing

22:16 wingy: haha

22:17 seangrove: Or am, rather

22:17 wingy: aphyr: RAP ftw!

22:17 meaning zero security

22:17 i meant RAD :P

22:18 aphyr: wingy: https://clojars.org/fogus/ring-edn

22:19 what the what, that just uses read-string internally

22:19 Ughhhhhh

22:20 seangrove: Is that bad?

22:21 aphyr: seangrove: oh, this is for wingy's problem

22:21 it means the web application using it is subject to arbitrary code execution

22:22 madsy: What are you guys talking about? Does ring have an evil/read-string flaw?

22:22 aphyr: No, but ring-edn does!

22:22 madsy: s/evil/eval

22:23 Oh, okay. I'm not using that, phew

22:23 aphyr: https://github.com/fogus/ring-edn/blob/master/src/ring/middleware/edn.clj#L14

22:25 wingy: aphyr: so it evals the form posted to ring? so if someone types (println "hello world") in a form field i get that evaled in the server?

22:25 aphyr: Checking.

22:26 I've never delved that deep into #= before

22:27 (read-string "#=(map inc [1 2 3])")

22:27 (nil nil nil)

22:29 ambrosebs: dnolen: what's nominal unification?

22:32 dnolen: I think you'll enjoy this as a musician and a programmer. Overtone + core.logic by an AFAICT non-musician https://vimeo.com/55677313

22:34 aphyr: OK so this is... AFAIK undocumented, but binding *read-eval* false will close the #= hole

22:35 Aha, and wrap-edn-params does this. Terrific.

22:35 ivan: ,(doc *read-eval*)

22:35 clojurebot: "; When set to logical false, the EvalReader (#=(...)) is disabled in the read/load in the thread-local binding. Example: (binding [*read-eval* false] (read-string \"#=(eval (def x 3))\")) Defaults to true"

22:36 aphyr: Yeah, just never found #= in the reader docs before

22:36 didn't know it existed til today

22:36 dabd: I have a seq with some indices and I want to initialize each index (taken from the list) of a vector with some value. What is the functional way?

22:36 ivan: ,(read-string "#=(eval (map inc [1 2 3]))")

22:36 clojurebot: #<RuntimeException java.lang.RuntimeException: EvalReader not allowed when *read-eval* is false.>

22:38 dnolen: ambrosebs: yes I just watched that a little while ago - so cool!

22:41 aphyr: ,(let [indices [1 6 2]] (reduce #(assoc %1 %2 true) (vec (repeat (apply max indices) false)) indices))

22:41 clojurebot: [false true true false false ...]

22:41 aphyr: ^-- dabd

22:42 dabd: aphyr: i used recursion but this seems nicer. thanks

22:43 ivan: I think this is going on inside the #= weirdness with map

22:43 ,(map 'inc [1 2 3 4])

22:43 clojurebot: (nil nil nil nil)

22:44 ivan: only the first symbol is resolved

22:45 dnolen: ambrosebs: nominal unification is a part of alphaKanren, it's to support nominal logic programming

22:46 ambrosebs: alphaKanren from Byrd's thesis allows for this. Basically it a logic programming approach that supports reasoning about scope. I'm sure there's much more to it than that but I haven't had time to look into beyond that Byrd describes.

22:47 ambrosebs: Byrd was skeptical that we could make it work w/ the constraint system we currently have - but I was pretty sure we could. It looks like Nada Amin thought so as well :D

22:48 amalloy: Raynes: http://www.reddit.com/r/gaming/comments/npdrt/a_very_portal_christmas_tree/

22:48 er, wrong channel. but hey, maybe y'all will enjoy it too

22:48 Raynes: amalloy: Wrong channel

22:48 Oh man, that's awesome.

22:49 ambrosebs: dnolen: nice. I remember Will explaining nominal logic programming at Conj 2011, I didn't really understand it.

22:50 dnolen: what does this test mean:

22:50 (is (= (run* [q] (nom-fresh [a] (== q a))) '(a_0)))

22:50 What is a_0?

22:52 dnolen: ambrosebs: a term

22:53 ambrosebs: it gets interesting tho when you express that terms are free or bound in some other term.

22:54 wingy: aphyr: it was actually better to convert it myself using your code

22:54 than using edn middleware

22:55 no magic and i can add security

22:55 ambrosebs: ambrose: what is a_0 vs _0? Is the former bound, latter free?

22:56 dnolen: ambrosebs: oh sorry, nom-fresh creates fresh noms, which are different from logic vars

22:56 ambrosebs: oh got it

22:57 dnolen: ambrosebs: thus they reify differently - a_0 vs _0

22:57 ambrosebs: http://arxiv.org/pdf/cs/0609062v2.pdf

22:57 ambrosebs: the first couple of pages sum up what's cool about it.

22:59 ambrosebs: thx!

23:12 n_b: You declare a var as dynamic by defining it like this: (def ^:dynamic foo "bar"), right?

23:13 ohhh, I see

23:14 I've misunderstood how this function, I think. If I within a REPL do (def *auth* new-val) I'm not rebinding, *auth* but overwriting it, and so would have to include the metadata again, correct?

23:20 and the proper way to actually handle it is using binding so any changes to auth are thread-local?

Logging service provided by n01se.net