#clojure log - Jan 27 2012

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

0:00 dnolen: bbloom: that won't work

0:00 bbloom: the callback's execution is deferred until the event loop gets pumped

0:00 i discovered that :-)

0:00 dnolen: bbloom: same issue applies to bindings + lazy sequences

0:01 bbloom: :-/ bummer

0:01 has this been discussed before? i couldn't find it in the google group

0:02 b/c the current cljs behavior for "binding" seems kinda useless :-/

0:02 dnolen: bbloom: it comes up in Clojure - but that's the behavior there's nothing much to fix.

0:02 bbloom: think some more about what dynamic binding is good for before making any judgements :)

0:03 sritchie: alexbaranosky: Is it possible to mock out the binding of a particular symbol in midje, not just as a function call?

0:03 dnolen: bbloom: closures solve the problem just fine just like they do in JS

0:03 bbloom: well lexical binding is clearly preferable in most cases, but that doesn't mean a well-placed dynamic variable can't be super useful

0:03 sritchie: (fact (+ 1 1) => 1 (provided + => *)), or something like that

0:04 alexbaranosky: it could work w/ symbol-macrolet, but would probably cause problems w/ lexical binding scope

0:04 alexbaranosky: sritchie, I don't think so... but let me peruse the source a little and get back to you

0:04 dnolen: bbloom: dynamic variables are super useful, but in this case I don't see how closures don't perfectly solve your problem

0:04 bbloom: it's a minimal repo case ;-)

0:05 sritchie: alexbaranosky: my next step w/ midje-cascalog will be mocking out the return values of operations within the hadoop flow

0:05 dnolen: bbloom: in JS you have an issue since "this"" is special, no such problem in CLJS since this is not a keyword in JS

0:05 not a keyword as it is in JS I mean

0:06 bbloom: dnolen: "this" is your best bet to emulate dynamic binding in JS, but it is very cumbersome

0:07 sritchie: alexbaranosky: actually, before I do that I need to come up with a few compelling examples of why you wouldn't just use a let binding

0:07 alexbaranosky: sritchie, so, no you cannot currently mock out particular vars... I'd have to get back to you on what it might take to change that though

0:08 sritchie, when in doubt keep it simple, right?

0:08 sritchie: alexbaranosky: yup, agreed

0:08 alexbaranosky: one guy mentioning an idea in IRC probably doesn't equate to great demand

0:09 I was working on this a number of months ago, but it really is just too magical

0:09 https://github.com/pallet/thread-expr/blob/develop/src/pallet/thread_expr.clj#L361

0:10 especially because you can't bind a special form (like if) to anything

0:10 alexbaranosky: sritchie, mocking vars that aren't functions might be doable with some thought, but mocking just any old symbol is another ballgame I think

0:10 sritchie: functions vars I like, I don't see any need to go beyond that

0:11 alexbaranosky: sritchie, I don't really see a need for -->

0:11 sritchie: pallet's built around these threading forms --

0:11 I was trying to build a dsl that would let you write something that looked liked defn with internal control structures,

0:12 hiding what was going on

0:12 bbloom: dnolen: so what is the story for cljs with respect to dynamic variables. I see it listed as a difference from clj proper. Is it simply a TODO?

0:13 sritchie: alexbaranosky: this is a macro,which absolutely should have been a monad: https://github.com/pallet/pallet-apache-crates/blob/master/hadoop/src/pallet/extensions.clj#L81

0:13 dnolen: bbloom: there is no difference from Clojure

0:13 w/ the exception that there's no thread-local story

0:13 alexbaranosky: sritchie, I saw a gist of yours about monads in clojure

0:15 bbloom: dnolen: so what do I do if I want a stack-like behavior for bound symbols which work across async callbacks?

0:16 i don't even need different values per thread

0:17 (well obviously, it's a single threaded event loop)

0:19 dnolen: bbloom: perhaps you could write an async-bind macro that does what you want? haven't thought about it much.

0:19 clojurebot: Cool story bro.

0:19 dnolen: bbloom: personally I think it would be more interesting if someone fixed delimc for CLJS instead ;)

0:20 bbloom: https://github.com/swannodette/delimc

0:20 delimited continuations

0:21 bbloom: heh

0:21 phil: dnolen: i like em a lot :)

0:24 bbloom: anyway: what's the community norms on irc vs goog groups? I'd like to raise this issue on the mailing list so that others may find it easier in the future :-)

0:26 muhoo: wow. i feel like a complete idiot coming to this language without a MS CS degree.

0:27 dnolen: bbloom: bring it up the list. dev list is also good but you need to submit a CA (which is easy).

0:28 bbloom: k

0:29 dnolen: that said, a tricky change like that probably needs justification, possibly reconciliation w/ Clojure's current behavior, and a good solution.

0:29 bbloom: but please join the fray, we need more people hacking on the CLJS compiler.

0:30 Raynes: muhoo: Why is that?

0:32 muhoo: Raynes: sentences like this: "Composable continuations are a means of inverting control by reification of continuation segments"

0:32 Raynes: Delimited continuations, monads, logic programming, etc, all have nothing to do with Clojure itself. Those are all separate tools that you aren't expected to automatically know about and aren't required for you to use and enjoy Clojure.

0:33 dnolen: muhoo: what Raynes said

0:33 Raynes: People are using Clojure for complex and sometimes computer sciency things. Doesn't mean you have to understand them.

0:33 muhoo: i know that, and i do enjoy closure, and i see how i can use it for mundane stuff like web servers and js guis without having to know all this insane stuff

0:33 Raynes: Of course, they are fun to learn about. But you can learn about them with Clojure and only if you want to.

0:34 muhoo: still, i see this stuff float by, and i go, "wow, brain exploding". and it *is* fun to read this stuff even if i don't understand a fraction of it!

0:34 dnolen: muhoo: all in good time ... or even never! :)

0:34 Raynes: I certainly don't have a computer science degree -- I haven't even finished high school yet.

0:34 muhoo: !

0:36 phil: haha, require-macro monads blows up cljs, output file is 0 bytes

0:37 removing require-macro and its back up to 50kb or smth

0:39 k9quaint: ugh...clojure 1.3.0 :(

0:39 muhoo: what's wrong with clojure 1.3.0?

0:39 Raynes: Anything in particular that's uggy?

0:40 k9quaint: moving from 1.2.1 to 1.3.0 is all

0:40 grumpy plugins, lein is pouting in the corner, etc ;)

0:42 Raynes: Is there anything in particular that you're having trouble with?

0:43 k9quaint: at the moment appengine-magic refuses to play nice with lein 1.6.2 & 1.3.0

0:43 Raynes: Yikes. Way to find something I know nothing about.

0:44 k9quaint: its a bad sign when I google for it, and get myself asking about it in #clojure ;P

0:46 muhoo: is there a way to get a complete trace of what gets called by what, in, for example, a noir request?

0:47 phil: macro files should be in the src directory have a clj extension for cljs to find them, right?

0:47 muhoo: i'm trying to understand the flow of execution, which is a LOT easier in clojure than in most things, but there's still lots of stuff, layers of things, middleware, etc., all firing off

0:48 k9quaint: did anything change with leiningen tasks between and 1.6.2?

0:49 Raynes: I don't think so. We don't like breaking changes for patch versions.

0:49 (so we never do them).

0:50 muhoo: My solution so far has been to write bugfree code.

0:50 ;)

0:50 muhoo: Also, did you ever get refheap.el working? Or anything for that matter.

0:50 I see some pastes from you.

0:51 muhoo: Raynes: yes, i did, thank you, it works great

0:51 a bit slow, but it does what i wanted

0:51 Raynes: Yeah, I can't figure out why it's so slow.

0:51 muhoo: there's like a 15-second delay between when it posts and when i get the *Message* with the url

0:51 Raynes: It's like it is just sitting there for a full minute before giving me something.

0:51 Yeah, it's even longer for me.

0:52 muhoo: where's the delay? in url-* on emacs, or at the server?

0:52 Raynes: Definitely not on the server.

0:52 My other tools are fast.

0:52 muhoo: damned single-threaded editor :-)

0:52 Raynes: Heh.

0:53 It really might be better to just shell out from elisp to refh or something.

0:53 The elisp http client stuff is pretty primitive.

0:54 muhoo: i might do that. could use curl even.

0:54 Raynes: Yeah, even curl would work.

0:54 muhoo: the response comes back in json, but i can hit it with sed and awk and it will submit

0:54 Raynes: Given how completely stupid I am with elisp and the fact that nobody who knows it better than me cares enough to help out with refheap.el (understandably), I think I'd accept a patch that used curl.

0:56 muhoo: ok fair enough. might be good to take a break from stuff i don't understand to slap somethign together that i *do* understand.

0:56 Raynes: muhoo: Well, actually, the json elisp package is very tame. You could just keep that part and just use curl for the http part. You'd know for sure if it was the url-* stuff causing the delay.

0:56 muhoo: though this answers a lot of questions about the former: http://brehaut.net/blog/2011/ring_introduction

0:56 Raynes: brehaut is a beast.

0:56 A mighty one.

0:56 muhoo: indeed.

0:57 k9quaint: hmmm, the stable release of lein 1.6.2 can't seem to see the appengine-magic plugins

0:57 lein deals with them fine

1:06 muhoo: Raynes: https maybe?

1:07 JanxSpirit: what's the best emacs Clojure approach?

1:09 muhoo: Raynes: aha. i am currently experiencing the exact same hangup/lockup with curl that i see with emacs!

1:09 the response comes back, but then it just waits a minute for the connection to timeout

1:09 Raynes: try this: curl -D - -o - --trace-ascii - -d "private=true&language=clojure-mode&contents=foo%20bar%20baz" https://refheap.com/api/paste

1:09 tensorpudding: JanxSpirit, get emacs-starter-kit and swank-clojure

1:09 using packages

1:10 muhoo: if the client is waiting for the connection to close before returning, it's going to be waiting a long time.

1:10 tensorpudding: it'll get you clojure-mode and you can hook into it with slime through swank-clojure to get a REPL

1:10 muhoo: maybe some of the other clients read a stream, and return as soon as they get a valid json {} to parse

1:11 JanxSpirit: nice thanks tensorpudding

1:13 Raynes: muhoo: Huh. So this would be a server problem then.

1:13 muhoo: i suspect nginx, yes

1:13 Raynes: I'll look into this tomorrow. Taking off for the night.

1:13 Thanks for finding this out.

1:13 muhoo: np. glad to help in whatever way i can.

1:13 Raynes: I'll ping you when I have more info. :)

1:14 muhoo: please. have a great night!

1:14 Raynes: You too!

1:17 devn: technomancy: still following the comments? lol

1:17 "Yes and no. In the other kinds of languages, you can certainly create modules of code that can be reused - macros, subroutines, libraries, and other structures. But they don't have as flexibility as functions do in LISP. I can't really explain it as I don't really understand it, but it might be something like this: Functions in LISP are like mathematical functions; what they do to their inputs is highly knowable and predictable. Because of this, ...

1:17 ... functions of functions of functions, etc., are similarly knowable and predictable, and that makes for more power to the programmer, right on!

1:17 heh.

1:18 phil: what is let*?

1:19 i.e. let star

1:21 devn: phil: what context?

1:22 phil: a macro (domad) expands to (let* ...) and i suspect that may be the reason why the clojurescript compiler blows up

1:22 among other things

1:22 domonad*

1:23 muhoo: let* is a scheme-ism IIRC

1:24 k9quaint: ok, all hail the grand file .lein-classpath ;)

1:24 devn: phil: static final Symbol LET = Symbol.intern("let*");

1:25 phil: src/jvm/clojure/lang/Compiler.java

1:25 phil: devn: i wont be able to deduce what it is, i have never looked at the clojure compiler source

1:26 but i found this comment: "Handle let* and loop* forms. The symbols defined in them are protected

1:26 from symbol macro expansion, the definitions and the body expressions

1:26 are expanded recursively."

1:27 muhoo: bootstrap stuff? java versions he had to do in java, then covered them up asap in clojure once the language was bootstrapped?

1:28 i see loop*, let*, letfn*, fn*, import*, deftype*,, case*, and reify* ... and that's it in terms of *'s.

1:29 devn: it's all bootstrap

1:29 k9quaint: wewt...now using clojure 1.3.0 :)

1:29 devn: ";during bootstrap we don't have destructuring let, loop or fn, will redefine later

1:29 * k9quaint crosses fingers

1:29 phil: muhoo: but why would a macro expand to (let* instead of let

1:30 muhoo: because let* is the java primitive

1:30 devn: ,(source let)

1:30 clojurebot: Source not found

1:30 phil: oh so macroexpand shows you the primitives?

1:30 devn: &(source let)

1:30 lazybot: java.lang.RuntimeException: Unable to resolve symbol: source in this context

1:30 muhoo: it's right there, in Compiler.java

1:30 devn: &(use 'clojure.repl)

1:30 lazybot: ⇒ nil

1:30 devn: &(source let)

1:30 lazybot: ⇒ Source not found nil

1:31 muhoo: it's a macro

1:31 let is a macro, let* is a java primitive, looks like.

1:31 phil: ahaa

1:31 and since a macro has to expand to something in the end which isnt a macro

1:31 muhoo: exactly

1:32 phil: thats what those stars are for

1:32 muhoo: what is it going to expand to? some java

1:32 yeah, stars like __do_not_use_this

1:32 :--)

1:32 devn: ; # __seriously_dont_useThis

1:32 phil: well i would have said it expands to clojure functions, but let* is a valid clojure function anyway

1:33 i mean you can use it

1:33 but yea, dont :)

1:34 devn: "A few special_forms are actually implemented as macros, primarily to provide destructuring: fn let loop"

1:34 see: http://clojure.org/macros

1:34 see: http://clojure.org/special_forms#special forms

1:35 muhoo: which reminds me

1:35 where could i find a good description of what destructuring *is* and what it's used for?

1:35 devn: muhoo: lots of places -- i can dig some up if you'd like

1:36 muhoo: devn: that'd be great, or just some tips on where to look

1:36 devn: muhoo: https://gist.github.com/438897

1:37 muhoo: devn: thanks. i found some stuff on google in my notes, fogus article, i should read that one

1:37 devn: muhoo: it's a way for naming items in a coll, retaining the inital value, etc. etc. -- there are many reasons, but ultimately it's just a way to extract relevant elements from a structure

1:38 it's like regex for assignment

1:38 muhoo: nice, thanks

1:38 the gist examples help too

1:38 devn: muhoo: they get a little crazy

1:38 muhoo: it's a decent list of what you can do though

1:38 even if it's pretty abstract

1:40 muhoo: usually i find myself using either [[foo bar] [1 2 3]] or [{:keys [a b]} {:a 1 :b 2}]

1:41 muhoo: i've seen the latter, and wondered what it did

1:41 devn: &(let [[foo bar & baz] [1 2 3 4 5]] [foo bar baz])

1:41 lazybot: ⇒ [1 2 (3 4 5)]

1:42 devn: &(let [{:keys [a b]} {:a 1 :b 2}] [a b])

1:42 lazybot: ⇒ [1 2]

1:43 devn: the latter is "destructuring a map"

1:43 muhoo: oh, nifty. the first one looks like varargs kind of stuff

1:43 devn: muhoo: *nod*, but you can do a bit more

1:44 &(let [[foo bar _ _ & baz] [1 2 3 4 5 6 7 8 9 10]] [foo bar baz])

1:44 lazybot: ⇒ [1 2 (5 6 7 8 9 10)]

1:44 devn: &(let [[foo bar _ _ & baz :as orig] [1 2 3 4 5 6 7 8 9 10]] {:new [foo bar baz] :orig orig})

1:44 lazybot: ⇒ {:new [1 2 (5 6 7 8 9 10)], :orig [1 2 3 4 5 6 7 8 9 10]}

1:45 muhoo: what's with the _ _ 's though

1:46 oh i see, ignore those two

1:46 devn: muhoo: just empty spaces

1:46 *nod*

1:46 it's like if i had a function which needed to take 2 args for some reason, but i only use one

1:46 I might write a definition:

1:48 &(let [do-something (fn [arg1 _] arg1)] (do-something 3))

1:48 lazybot: clojure.lang.ArityException: Wrong number of args (1) passed to: sandbox12685$eval15702$do-something

1:48 devn: ^expected

1:48 &(let [do-something (fn [arg1 _] arg1)] (do-something 3 300))

1:48 lazybot: ⇒ 3

1:48 muhoo: right

1:49 devn: muhoo: you mentioned fogus -- he has a nice review of destructuring as one of clojure's "mini languages IIRC"

1:49 muhoo: cool, thanks. i've seen the _ used for (fn [ _ ] ...)

1:49 devn: that's the article i bookmarked yes

1:49 devn: muhoo: my best advice is to peek at people who are using let in their projects

1:50 muhoo: i'm familiar with let from scheme, but this destructuring thing was new to me

1:50 devn: muhoo: you can do an incredible amount with destructuring, but the common use cases are what you're interested in IMO

1:50 muhoo: it seems a fantastic way to transform data

1:50 devn: muhoo: it's really nice to have what you want to produce a new value by the time you're in your function body

1:50 it just feels nice and clean

1:51 it's like an implicit guard or something

1:51 an implicit sentinel? *shrug*

1:51 i like it. :)

1:51 muhoo: indeed. very powerful. thanks for explaining it!

1:51 that :orig is very cool too

1:52 sorry :as orig

1:52 devn: muhoo: ah, the :as keyword, yeah

1:52 :or is interesting also

1:52 you can also use & baz in destructuing

1:52 destructuring

1:53 muhoo: is the :as part of let? where is it documented?

1:54 devn: http://clojure.org/special_forms#Special Forms--(let [bindings* ] exprs*)

1:54 muhoo: :or, :as, i wonder where they are defined/documented

1:54 devn: muhoo: ^

1:54 muhoo: oh cool

1:54 devn: muhoo: i know it's dry, but it explains it all

1:55 phil: i have the feeling that cljs blows up whenever the (ns...) macro is incorrect... however, wth is wrong with (ns x.y.z (:require) (:require-macros [a.b.c :as a]))

1:55 devn: "Also optionally, an :or key in the binding form followed by another map may be used to supply default values for some or all of the keys if they are not found in the init-expr:"

1:55 muhoo: oh i see. default values

1:55 devn: phil: why the naked (:require) ?

1:56 phil: devn: it actually has arguments, forgot to add "..."

1:56 muhoo: devn: yep, it's there, i see it now. the reference is terse, as references are, but it's all there.

1:56 devn: phil: what does it blow up on?

1:56 muhoo: i shy away from it sometimes, but in the end i usually just end up reading those docs. they describe usage AND *intent*

1:56 phil: devn: it doesnt produce an error message, just an empty js file... when i remove the (:require-macros) directive the js file is produces correctly

1:56 devn: muhoo: the intent is very important IMO

1:57 phil: and the referenced macro clj file is empty save for a (ns ...) spec

1:57 i really have no idea what could be wrong

1:58 devn: phil: sorry to be so formal about it but: could you please say what you're trying to run from the CL, what your source looks like, the problem and intended output?

1:59 like: I run script/foo. Source is here: pastebin.com/something. The problem is I want to implement algo.monads in cljs. The aim is to use a specific aspect of this library in clojurescript.

2:01 phil: the more specific the problem statement and succinct the solution, the easier the tree of possible solutions is pruned and all of that...

2:05 phil: devn: sure, im using cljs-watch to cross-compile into both normal java and cljs, i have a src-generic directory where i put all of my generic files that are then being copied into src-generated... then the cljs compiler is invoked by the cljs-watch script, which works wonderfully (for both clj and cljs), producing class files and js files... until i try to do the following: https://gist.github.com/1687592, in which case the generated

2:05 view.js file equals to 0 bytes, with no error message produced by the cljs compiler - whenever i remove the (:required-macros ...) directive the js file is generated as expected

2:05 (sorry if im not expressing myself very precisely, been up all night)

2:09 devn: phil: speaking of which, im really sorry to leave you hanging but i desperately need some sleep

2:09 phil: devn: np, good night :)

2:09 devn: phil: if you'd like a swift answer i'd suggest sending that off to the clojure google group

2:09 phil: will do, thx for the suggestion

2:10 devn: sorry i need to duck out :\ -- best of luck and happy clojuring :)

2:10 clgv: oh. there are still US people around here? ;)

2:13 phil: clgv: worse, eu :) when i say all night i mean literally :D

2:13 clgv: phil: hey, good morning to you then ;) I didnt read your "all night"

2:13 what did you do?

2:14 phil: good morning to you too, but for me its still yesterday :) been messing with cljs macro madness the last few hours

2:15 its strange to go to sleep when other people wake up :D

2:17 muhoo: it's only 11:20PM here in california. that's early :-)

2:19 though i think i'm going to call it an early night tonight.

2:24 phil: muhoo: 11:20pm is like early afternoon for me :D

2:34 clgv: $time +1

2:34 lazybot: clgv: The time is now 2012-01-27T08:37:12Z

2:34 clgv: phil: well, I guess you can kill much time with alpha software like cljs ;)

2:35 phil: clgv: more than i would like to admit :/

2:36 theres a whole world out there, bird chirping etc, and im trying to make macros work in cljs :D

2:36 clgv: phil: are you developing with cljs for a production environment?

2:36 phil: clgv: not yet but i hope i will

2:36 clgv: phil: ah, so thats a hobby project right now?

2:37 phil: depends on how unstable it is, but i really would like to use it

2:37 well, not exactly, its more like investigating new tech for the next project

2:38 clgv: have you been using it extensively?

2:39 clgv: phil: no. I just downloaded the ClojureScript One and had a brief look at it and its documentation

2:40 phil: I have it in mind to make a hobby webproject of mine "dynamic" on client side ;)

2:41 phil: yea, my previous project was in gwt and i wasnt ready to give up type safety, refactoring, debugging and tool support for a language like js but with clojure now the game has changed :) especially with cljs web dev is awesome (if it works :D)

2:41 clgv: so i guess youll have fun

2:42 clgv: phil: gwt looked nice but I liked Vaadin even more, which uses GWT soley as a renderer...

2:43 phil: yea but vaadin is server side

2:43 with a thin semi-dynamic client layer

2:44 which is cool for many use cases but when you need something completely dynamic it cant do much

2:48 clgv: phil: yeah thats true. you would have to fallback to GWT if you need something custom they are not offering

2:49 phil: clgv: or even if you want your logic completely on the client with the server just acting as a data store

2:49 and not a html template generator etc

2:50 clgv: phil: ah, thats the kind of things you do?

2:51 phil: clgv: yea for example

3:36 unlink: What's the idiomatic clojure equivalent of "map (x:) . drop 1" from Haskell? My clunky approximation reads #(map (partial list %1) (next %2))

3:39 Chousuke: I think it might be clearer to just write the function explicitly

3:39 that seems like a weird operation

3:41 raek: unlink: the point-free style is not as ideomatic in Clojure as it is in Haskell

3:41 unlink: raek: Right. %1 and %2 are points, though, correct?

3:41 raek: yes

3:43 for example, (partial foo x) is even longer than #(foo x %)

3:43 unlink: raek: that's true, but it's disallowed here.

3:43 raek: (but of course you cannot nest the shortcut syntax for anonymous functions)

3:43 unlink: as you just noted.

3:45 raek: I would translate that function to (defn f [ys] (for [y (rest ys)] (cons x y)9)

3:45 *)))

3:45 unlink: The full containing example was: f xs = concat $ zipWith g xs $ tails xs where g x xs = map ((,) x) $ drop 1 xs

3:45 (With functions renamed to protect the innocent.)

3:46 snamellit: is (apply hash-map some-seq) the best (idiomatic) way to turn a list of key val key val ... into a map?

3:46 raek: snamellit: yeah

3:47 snamellit: is this for keyword arguments?

3:50 unlink: does it produce the cartesian product of the list with itself, but with pairs where both parts are the same excluded?

3:51 unlink: raek: almost, like that except drawing the diagonal through it and discarding half (so no dups and not fst > snd))

3:51 *no dups and no fst > snd)

4:01 raek: So you would do something like: (defn f [xs] (letfn [(pair-with [x ys] (for [y (rest ys)] [x y]))] (mapcat pair-with xs (tails xs))))

4:02 raek: I have something in my repl which I think works

4:02 and it looks just like that :)

4:02 had to define tails, too

4:04 unlink: raek: yeah, no Data.List in clojure.

4:04 raek: That's 50% longer than (defn f [xs] (mapcat #(map (partial list %1) (next %2)) xs (tails xs))) though.

4:04 raek: https://gist.github.com/1687882

4:05 yeah...

4:05 unlink: (defn tails [xs] (take-while identity (iterate next xs)))

4:12 raek: it's funny. I never thought to convert "map" to "for". Going all list monad style on me!

4:12 snamellit: raek: thanks. Not specifically for keyword args. I guess you can run them through keywordize-keys for that?

4:13 raek: snamellit: I was just curious why you had a map in that form from the beginning

4:14 the only case I'm aware of is when you want to have keyword arguments to a function, like (f :a 1 :b 2)

4:15 but then you can do (defn f [& {:keys [a b]}] ...)

4:18 unlink: raek: hah. clojure.math.combinatorics/combinations actually does exactly what I want.

4:19 fancy that.

4:53 clj_newb: great wizards of clojure: is there anyw ay for mere mortals like me to get z-order support in java graphics 2d?

5:05 judofyr: CLOJURE!

5:49 LoganLK: Is there a preferred way to instantiate java objects or call static properties of java objects? (new JFrame) vs (JFrame.) or (Math/cos 3) vs (. Math cos 3)

5:52 hoeck1: LoganLK: the short forms are preferred over new and dot in written code

5:53 LoganLK: thank you

5:54 hoeck1: LoganLK: but you still need new and dot when writing macros which expand to a method or ctor call

7:34 smokecfh: am i mistaken in that using leiningen and clojars are serious security threats?

7:35 Chousuke: smokecfh: how so?

7:36 clgv: smokecfh: if you are doing a closed source projects and pushing source jars to clojars one could call it that :P

7:37 Chousuke: that's not a security threat, that's just being stupid :P

7:37 clgv: " one *could* call it that" ;)

7:38 Chousuke: I'd call the person a security threat in that case.

7:38 smokecfh: i mean, nearly anyone could upload a library (including a trojan) there

7:38 Chousuke: sure, but it's not like they can overwrite what others have uploaded

7:39 they'll have to use their own identifier

7:39 smokecfh: true. so i just should be careful what libraries i use

7:39 Chousuke: yeah. just like with anything else that you download.

7:40 smokecfh: well, in the case of leiningen it's extremely easy to download and use it :)

7:41 clgv: yeah there was some discussion about mandatory signing of libs that would prevent the hacking part of that topic

7:42 talios: clgv - oss.sonatype.org and maven-central now require GPG signed artifacts

7:43 for auto-synched projecs anyway I believe

7:44 https://docs.sonatype.org/display/Repository/Sonatype+OSS+Maven+Repository+Usage+Guide#SonatypeOSSMavenRepositoryUsageGuide-6.CentralSyncRequirement

7:45 clgv: ah ok

7:46 talios: doesn't really prevent anyway injecting poisoned artifacts, but you could at least trace who BUILT said poisoned artifact

7:47 unless I stole your keys and just signed my things with yours

7:47 clgv: talios: doesnt theprocedure allow organizing the maintainers public key in advance?

7:48 * talios heads to bed. *GONE*

7:51 PaulIIIIIIII: what do yo think when in the forest meets mans grownup triplets width man who have one testicle

7:52 what do yo think when in the forest meets mans grownup triplets width man who have one testicle

7:54 smokecfh: i take this as a hint to actually be worried about security threats

9:03 TimMc: Perhaps PaulIIIIIIII's comment was the result of a terrible accident in a translation factory, and he was simply trying to ask about how to retrieve a single resource from a triple-store.

9:10 gtrak``: TimMc: triple stores?

9:10 lucian: gtrak``: i'm assuming something that stores graphs as subject-predicate-object tuples

9:12 gtrak``: ah, yea, lucian, know what they are, just curious about the context, it seems TimMc was trying to be nice to a crass thing

9:30 lucian: gtrak``: i see

10:05 TimMc: gtrak``: Basically.

10:44 jcrossley3: hiredman: i thought about what you said. you're right. i found a better, less surprising way.

10:46 aidanf: Is there a print method that returns a non-nil value? E.g. I want a print into an and form...

10:47 Currently I'm just doing (do (println "message") true)

10:47 Is there a nicer way?

10:49 TimMc: aidanf: You want (and ... (print ...) ...) ?

10:49 gfredericks: is this a debugging thing?

10:51 aidanf: Not debugging, just more printing updates to the console when a series of conditions are met and then continuing with testing some more conditions.

10:52 So don't want the (print ...) to cause the (and ...) to exit

10:52 TimMc, yeah, basically that.

10:52 TimMc: aidanf: (or (print ...) 1) if you insist on having everything in that and..

10:55 lynaghk: If I want to throw a collection of some DOM nodes into a set (in ClojureScript), all I need to do is make sure they implement IHash and then call (into #{} my-nodes), right? It doesn't seem to work; getting "undefined" back from the statement.

11:02 jeremyheiler: aidanf: You could just create a do-print function that does exactly what you want. Maybe have an optional second arg that will be returned? Something like ##((fn do-print ([obj] (do-print obj obj)) ([obj ret] (do (println obj) ret))) :foo)

11:02 lazybot: ⇒ :foo :foo

11:05 lynaghk: ohh, nevermind. Scope problem.

11:05 aidanf: Thanks, I'll make a small utility fn to do what I want. Was just checking if I was missing a builtin function that already does what I want.

11:06 Still early in my clojure development so I often find I do something and later discover that there already a builtin way to do it.

11:06 :)

11:07 jeremyheiler: You're definitely not alone in that regard.

11:07 clgv: aidanf: no the print-and-return function is missing ^^

11:07 gfredericks: what we need is a new version of all eight print functions

11:08 clgv: I doubt that ;)

11:08 gfredericks: I guess the -str ones wouldn't be amenable to it

11:08 jeremyheiler: gfredericks: I feel like I agree, but cold you elaborate?

11:09 could*

11:09 gfredericks: jeremyheiler: about the first thing or the second?

11:09 jeremyheiler: new print functions

11:09 gfredericks: jeremyheiler: I was speaking ironically; pointing out how many print functions there already are

11:09 so making new versions of each would take it from 8 to 12 or 16

11:10 jeremyheiler: haha ok. i was sorta thinking that their names kind of suck

11:10 gfredericks: how so?

11:11 clgv: &(apropos "pr")

11:11 lazybot: ⇒ (project clojure.tools.logging.proxy$java.io.ByteArrayOutputStream$0 *print-radix* get-pretty-writer *print-miser-width* *print-pprint-dispatch* print-table print-length-loop pprint-indent pprint *print-suppress-namespaces* *print-right-margin* *print-pretty* with-pp... https://refheap.com/paste/448

11:12 pdk: needs the classic

11:12 *print-cycle*

11:12 oh wait

11:12 jeremyheiler: well, print and println map well to java, but im still unsure what pr and prn do.

11:12 TimMc: jeremyheiler: "Print Readably"

11:12 clgv: jeremyheiler: printing datatypes to read them back in

11:12 pdk: they're basically just for pickling data

11:12 clgv: &(doc project)

11:12 lazybot: ⇒ nil

11:12 gfredericks: ,((juxt print-str pr-str) [2 3 4])

11:13 clojurebot: ["[2 3 4]" "[2 3 4]"]

11:13 gfredericks: ooh bad example

11:13 clgv: &(resolve 'project)

11:13 lazybot: java.lang.SecurityException: You tripped the alarm! resolve is bad!

11:13 TimMc: yep

11:13 jeremyheiler: so it basically serializes objects in a printable form?

11:13 clgv: right

11:13 TimMc: jeremyheiler: In a *readable* form.

11:13 gfredericks: ,((juxt print-str pr-str) "foo")

11:13 clojurebot: ["foo" "\"foo\""]

11:13 TimMc: Something that 'read can take.

11:13 Well, read-string

11:14 jeremyheiler: yeah, readable, sorry

11:14 gfredericks: jeremyheiler: I think it parallels ruby's inspect, if you're familiar with that

11:14 clgv: &(let [s (pr-str {:a 1 :b 2})] (println s) (read-string s))

11:14 lazybot: ⇒ {:a 1, :b 2} {:a 1, :b 2}

11:15 clgv: &(let [s (pr-str {:a 1 :b 2})] (println (type s) (type (read-string s))) )

11:15 lazybot: ⇒ java.lang.String clojure.lang.PersistentArrayMap nil

11:20 jeremyheiler: Could someone give an example where the output of pr is different than the output of print? (using the same input, unless I am missunderstanding)

11:20 pdk: ,(print '(hello))

11:20 clojurebot: (hello)

11:20 pdk: ,(pr '(hello))

11:20 clojurebot: (hello)

11:20 pdk: welp that was a good example

11:21 gfredericks: (print "hello")

11:21 clgv: jeremyheiler: defrecords

11:21 gfredericks: ,(print "hello")

11:21 clojurebot: hello

11:21 gfredericks: ,(pr "hello")

11:21 clojurebot: "hello"

11:21 jeremyheiler: ah! got it

11:21 thank you

11:21 gfredericks: ,(print (range 1 10))

11:21 clojurebot: (1 2 3 4 5 ...)

11:21 gfredericks: dangit

11:21 clgv: &(pr (range 1 10))

11:21 lazybot: ⇒ (1 2 3 4 5 6 7 8 9)nil

11:22 gfredericks: &(print-str (range 1 10))

11:22 lazybot: ⇒ "(1 2 3 4 5 6 7 8 9)"

11:22 gfredericks: alc

11:22 s/alc/arg

11:22 TimMc: I believe lazybot uses pr-str for its own output, by the way.

11:23 ,(binding [*read-eval* true] (read-string "#=(+ 1 2)"))

11:23 clojurebot: 3

11:24 TimMc: Oh my god clojurebot, you are such a dunce!

11:24 or perhaps a pushover

11:24 gfredericks: ,(binding [*read-eval* true] (read-string "#=(def foo 12")) foo)

11:24 clojurebot: #<RuntimeException java.lang.RuntimeException: EOF while reading>

11:24 * gfredericks sucks

11:25 clgv: ,(binding [*read-eval* true] (read-string "#=(def foo 12)")) foo)

11:25 clojurebot: #<RuntimeException java.lang.RuntimeException: Can't resolve def>

11:26 clgv: ,(binding [*read-eval* true] (read-string "#=(clojure.core/def foo 12)")) foo)

11:26 clojurebot: #<RuntimeException java.lang.RuntimeException: Can't resolve clojure.core/def>

11:26 TimMc: It does have *some* additional protections against def, but you can screw with vars in other ways.

11:26 And it restarts every 10 minutes. :-P

11:27 gfredericks: just like life

11:27 TimMc: And there are some other protections at the JVM level.

11:27 * gfredericks is loving the hell out of xmonad

11:28 TimMc: ,(let [evil (resolve (symbol "eval"))] (evil `(java.lang.System/exit 0)))

11:28 clojurebot: #<AccessControlException java.security.AccessControlException: access denied (java.lang.RuntimePermission exitVM.0)>

11:28 TimMc: gfredericks: I have to get around to trying that.

11:28 gfredericks: TimMc: so worth it

11:30 TimMc: Much config required?

11:30 gfredericks: TimMc: what're you currently using?

11:31 TimMc: GNOME :-/

11:31 on Ubuntu v.Previous

11:32 gfredericks: TimMc: I'm running it on top of both of those

11:35 TimMc: did my pm get through?

11:36 TimMc: Hmm, on *top* of? Got it, it's not a full DE.

11:36 mattmitchell: how can i get a range of values in a vector?

11:37 gfredericks: mattmitchell: ##(vec (range 4))?

11:37 lazybot: ⇒ [0 1 2 3]

11:37 TimMc: mattmitchell: You mean, like substring?

11:37 gfredericks: oh maybe subvec

11:37 mattmitchell: gfredericks TimMc yes exactly, like substring

11:37 subvec ok i'll try that

11:37 TimMc: mattmitchell: subvec will do it, but it is just a window onto the original

11:38 so the original is not GC'd until the subvec can be.

11:38 gfredericks: eeeeew

11:38 * gfredericks did not know that

11:38 TimMc: just like substring and split, IIRC

11:38 gfredericks: is that because of base-32 alignment issues?

11:39 TimMc: Nope, just the downside of O(1) range operators

11:39 gfredericks: hmmmm...you'd think there ought to be a way...

11:39 not for strings, but at least for vectors

11:39 TimMc: It might be smart enough to only hold into the parts of the tree that it needs.

11:39 mattmitchell: is there a better way than subvec?

11:40 TimMc: (into [] (subvec ...)) :-P

11:40 mattmitchell: ok :)

11:42 TimMc: &(class (subvec [1 2 3 4 5] 1 3))

11:42 lazybot: ⇒ clojure.lang.APersistentVector$SubVector

11:43 TimMc: And checking the 1.3.x source... no trimming at all. I was hoping it would descend the tree and find the lowest node, but it is truly O(1).

11:44 gfredericks: that is baffling

11:44 TimMc: A subvec on a subvec points to the original, though -- they are GC-independent.

11:44 gfredericks: :/

11:45 katratxo: hi all, quick newbie question, what's the difference between the available ways to import an external library? http://clojuredocs.org/clojure_core/clojure.core/import

11:45 TimMc: $google 8thlight require use import

11:45 lazybot: [Clojure Libs and Namespaces: require, use, import, and ns | 8th Light] http://blog.8thlight.com/articles/2010/12/6/clojure-libs-and-namespaces-require-use-import-and-ns/

11:45 TimMc: katratxo: ^

11:46 katratxo: TimMc: thanks, i'll check it out

11:46 jsabeaudry: ,(String/format "0x%x" 44)

11:46 clojurebot: #<ClassCastException java.lang.ClassCastException: java.lang.Long cannot be cast to [Ljava.lang.Object;>

11:46 gfredericks: ,(format "0x%x" 44)

11:46 clojurebot: "0x2c"

11:47 jsabeaudry: Hmmm, interesting

11:47 TimMc: jsabeaudry: varargs strioke again

11:48 [Ljava.lang.Object; is an Object[] in Java

11:48 ,(String/format "0x%x" (to-array [44]))

11:48 clojurebot: "0x2c"

11:48 TimMc: But yeah, use format.

11:48 cemerick: (vec (subvec …)) probably is within spitting distance of the work that'd have to be done to prune the source vector's tree.

11:49 TimMc: The windowing property of .split bit us here at work. I really wish this stuff were made more explicit in docs.

11:52 gfredericks: ,(let [foo (subvec [1 2 3] 1 2)] (identical? foo (vec foo)))

11:52 clojurebot: false

11:56 TimMc: &(class (vec (subvec [1 2 3] 1 2)))

11:56 lazybot: ⇒ clojure.lang.PersistentVector

11:57 TimMc: In (source vec) I see clojure.lang.LazilyPersistentVector -- what.

11:57 muhoo: TimMc: what do you mean by windowing property? how did it break stuff?

11:59 jsabeaudry: Suggestions for a pretty way of doing parameter validation in the context of a web noir application?

12:00 TimMc: muhoo: We were using split or substring or something to get a ton of tokens out of documents, then using them as keys in a global hash table in a long-running process. Boom, OOM! All the document test strings were still around in their entirety.

12:00 muhoo: jsabeaudry: i think there's a couple starter validation functions in noir.validation

12:00 TimMc: it broke the GC?

12:01 TimMc: No, we just got an OutOfMemory error.

12:01 (OOM)

12:01 jsabeaudry: muhoo, Oh wow, thanks I had seen that before but completely forgot about it.

12:01 TimMc: It prevented GC, if that's what you meant.

12:01 muhoo: yes, that's what i was asking.

12:03 i'm curious how you got around that.

12:04 how does one force GC to happen in situations like that?

12:04 * muhoo does not know many JVM tricks

12:05 jeremyheiler: muhoo: use weak references

12:06 muhoo: at least thats one of the first thoughts, might not have been an option in TimMc's case. We'll have to wait and see *oms on popcorn*

12:06 gfredericks: could copy the strings somehow or another

12:07 * gfredericks realizes he isn't even sure if we're talking about strings

12:08 muhoo: i think he said it was strings.

12:08 "All the document test strings were still around"...

12:09 jsabeaudry: wow, validation.clj contains one of the hairier regexes i've seen in a while:

12:09 (re-matches #"[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?" v)

12:10 jeremyheiler: muhoo: what does it do?

12:10 muhoo: maybe he's checking for UUCP-style email addresses.

12:10 jsabeaudry: hehehe email validation

12:10 muhoo: jeremyheiler: verifies email address

12:10 jeremyheiler: good times

12:10 muhoo: (defn is-email? ...)

12:14 oh cool, i think i finally get wrap-foo in ring/noir ... it's like hooks in emacs

12:20 TimMc: muhoo: Yeah, the solution is to copy the little substrings into new Strings so they don't share teh char[]

12:21 jeremyheiler: Weak references only help when it is possible to recompute the value as needed.

12:22 muhoo: good to know, thanks.

12:23 phil___: when i reply to a topic on the clojure maillist, does the reply have to be reviewed by an admin as well? i just wrote like 2 pages worth of text and it wasnt posted :/

12:25 tavisrudd: jsabeaudry: I'm curious how you ended up proxying that stream from c.

12:26 muhoo: maybe google groups has a TL;DR filter?

12:26 tavisrudd: phil___: there's a mod queue

12:27 dnolen: this is a very cool if somewhat advanced series on core.logic http://clojurelx.blogspot.com/2012/01/lx-in-corelogic-2-jumps-flexible.html

12:38 noidi: is it possible to upgrade the closure library from what clojurescript's bootstrap downloads?

12:40 dnolen: noidi: tweak the script/bootstrap

12:42 muhoo: TimMc: did you see that problem using java .split or the clojure.string/split ?

12:42 TimMc: muhoo: String/split

12:42 This was a Java app.

12:42 muhoo: oh

12:42 noidi: dnolen, okay, so it won't break the cljs compiler? :)

12:44 TimMc: muhoo: Although both String/split and clojure.string/split use Pattern/split, which calls String/substring, which is where the problem is anyway.

12:44 noidi: it's a bit strange that the distributed version is almost a year old

12:45 muhoo: TimMc: it looks to me like the clojure version converts the results to a LazilyPersistentVector, whatever that is

12:45 i have to wonder if it has the same problem or not

12:45 TimMc: muhoo: That's just the result container.

12:45 gfredericks: I wonder what happens when you conj onto a subvec

12:45 TimMc: (.split re s) is the Pattern/split call.

12:46 &(class (conj (subvec [1 2 3] 0 1) 5))

12:46 lazybot: ⇒ clojure.lang.APersistentVector$SubVector

12:46 gfredericks: &(class (pop (subvec [1 2 3] 0 1 )))

12:46 lazybot: ⇒ clojure.lang.PersistentVector

12:47 TimMc: gfredericks: that's an edge case

12:47 &(class (pop (subvec [1 2 3 4 5] 0 3)))

12:47 lazybot: ⇒ clojure.lang.APersistentVector$SubVector

12:47 seancorfield: dcjackson: you pinged me off-channel about a java.jdbc question? not sure if you're still around?

12:47 TimMc: You ended up with the empty vector.

12:47 gfredericks: ah ha

12:48 good catch

12:48 TimMc: &(identical? [] (pop (subvec [0 1 2] 0 1)))

12:48 lazybot: ⇒ true

12:48 gfredericks: _the_ empty vector

12:48 TimMc: yes

12:50 muhoo: ,(class (clojure.string/split "foo bar baz" #" "))

12:50 clojurebot: #<ExecutionException java.util.concurrent.ExecutionException: java.lang.RuntimeException: java.lang.ClassNotFoundException: clojure.string>

12:51 muhoo: &(require 'clojure.string)

12:51 lazybot: ⇒ nil

12:51 muhoo: &(class (clojure.string/split "foo bar baz" #" "))

12:51 lazybot: ⇒ clojure.lang.PersistentVector

12:51 muhoo: &(class (.split " " "foo bar baz"))

12:51 lazybot: ⇒ [Ljava.lang.String;

12:52 * jondot2 80 pages into the joy of clojure and loving it!

12:54 muhoo: jondot2: does it cover clojure 1.3?

12:54 jondot2: no, 1.2

12:55 is there much of a difference?

12:56 TimMc: Numerics and dynamic vars, mostly.

12:56 Bronsa: protocols too

12:56 *records

12:57 TheSeparateFirst: j #scala

12:57 TimMc: *gasp*

12:57 ~guards

12:57 TheSeparateFirst: Bah, my lack of config ruins me again

12:57 clojurebot: SEIZE HIM!

12:57 jondot2: haha

12:57 TimMc: (That will never, ever get old.)

12:58 jeremyheiler: (never)

12:58 TheSeparateFirst: But hey. In my defense, I did come here first.

12:58 TimMc: It's all good.

13:00 muhoo: whenever i hear "seize him!" i see dom delouise saying it: http://www.youtube.com/watch?v=kt3745NRxpo

13:04 * gfredericks has not seen this movie

13:04 TimMc: you should

13:04 muhoo: Roughly what timestamp?

13:07 muhoo: TimMc: towards the end

13:08 right before they chase his ass out of there

13:08 TimMc: Don't have time to watch it now. :-(

13:08 muhoo: np, it's part of the cultural lexicon.

13:09 jeremyheiler: TimMc: 7:14

13:12 TimMc: thanks

13:12 haha, "KILLLLLL himmmm"

13:12 jeremyheiler: It's better after watching why the ceaser says it.

13:12 TimMc: yep, I watched the 30 seconds prior as well

13:43 llasram: technomancy: You around?

13:48 technomancy: llasram: sure

13:50 llasram: I figured out the Ant-related problem I mentioned having with the Debian package, but I don't know lein well enough to know if it's a bug and if so in what

13:50 The project I'd tested it on had a dev dep on a package which has a dep on an ancient (1.6.5) version of ant

13:51 THis never seems to bother the lein self-install, but sometimes the Debian package picks it up

13:52 Adding an exclusion fixes things, so there's a workaround

13:52 technomancy: regular dep or dev dep?

13:52 llasram: dev dep

13:53 Hadoop actually

13:53 technomancy: I'd actually expect that to screw up the non-deb version as well; have definitely had bug reports to that effect

13:54 llasram: Hmm. Weird. I'm not sure exactly what circumstances it occurs in. I setup up the package on our CI system and tested it w/ this project manually, and it worked fine, then exploded when the CI user tried it

13:55 technomancy: dev-deps are messy and ever since implementing profiles for lein2 I have started to hate them.

13:55 llasram: Ah. I'll just wait for lein2 then :-)

13:55 TimMc: It's pretty much ready, right?

13:55 technomancy: weeeeeeeeeeeeelllllllllllllllllll

13:55 maybe

13:57 TimMc: Trying decide what can be put off and what has to be put in now?

13:58 technomancy: I actually don't know how ready it is.

13:59 it feels pretty ready, but I've literally only run it a handful of times on projects other than itself

14:05 jsabeaudry: tavisrud`, It's still not done as the driver for the device that I need to take the stream from is not ready yet

14:06 technomancy: anyway, if you're curious about lein2 or how awesome profiles are, feel free to give it a try and complain in #leiningen if anything breaks

14:07 stuff that's broken: javac, trampoline, shell-wrappers, and cleaning of transitively-compiled .class files

14:08 oh, and native-deps. if you don't need any of those features, check it out.

14:08 TimMc: Oh good, all the stuff I don't need. :_P

14:09 technomancy: I know, right?

14:12 TimMc: All the hard stuff that gets implemented last because it isn't as fun and isn't needed for most beginner use-cases.

14:12 technomancy: feels good, man

14:12 TimMc: haha

14:18 devinus: has anybody played around with running Clojure of openjdk 1.8 ?

14:20 jedahu: anyone come across cljs.closure/build treating a ns form as if it were a function call?

14:20 http://paste.lisp.org/display/127347

14:23 TimMc: devinus: Is that even out yet?

14:23 dnolen: hmm checked arithmetic could be interesting in ClojureScript ...

14:24 devinus: TimMc: they have public tests builds outs

14:24 TimMc: alpha?

14:24 devinus: TimMc: http://code.google.com/p/openjdk-osx-build/wiki/OpenJDK8MLVM

14:25 TimMc: beta, looks like

14:30 tavisrud`: here's a handy elisp function for inserting, toggling and moving the #_ ignore-next-form reader macro: https://gist.github.com/1690495 If you call it repeatedly, it moves the #_ up the syntax tree.

14:31 edw: fogus?

14:34 hiredman: neat

14:42 tmciver: tavisrud`: looks awesome, but I can't seem to make the 'move up a syntax level' work by repeating the command.

14:45 tavisrud`: tmciver: what happens? It has to be called in succession, btw, with no other commands / movements in between.

14:46 TimMc: blacksmiths and lispers, makin' their own tools

14:46 tmciver: tring again

14:46 trying

14:46 Yeah, doesn't seem to work when two successive commands given.

14:47 ckirkendall`: Quick question on clojurescript one. Does anyone know how to specify a :libs directive.

14:47 tavisrud`: tmciver: anything show up with toggle-debug-on-error enabled? Also, what Emacs version?

14:48 tmciver: tavisrud`: I haven't bound the function to a key, so I M-x <command>; not sure if that matters somehow. Don't know elisp very well.

14:48 tavisrud`: hmm, that might be it

14:49 nope, works with or without the keybinding

14:50 tmciver: tavisrud`: works for you? It's quite possibly I have an eff'd up emacs config somewhere.

14:50 tavisrud`: yep, at least on Emacs 24

14:51 tmciver: I'm on emacs 23. Perhaps it's time for an upgrade.

14:51 tavisrud`: TimMc: http://feelerdealer.com/blacksmithSilhouette.jpg

14:51 read the text on the anvil

14:52 TimMc: heh

14:52 ekoontz: what's the last line? $> HT?

14:52 tmciver: It never ceases to amaze me how quickly people here can come up with an esoteric yet relevant link!

14:53 tavisrud`: ekoontz: must be old English for C-x C-c

14:53 TimMc: Yeah, I expected that was technomancy when I saw that link.

14:53 ekoontz: tavisrud`: hmm

14:53 tmciver: I know! That guy.

14:54 TimMc: By the way, the sparks coming off that anvil... I think he overheated that metal. Probably burned whatever he was working on.

14:54 Or maybe when you're an expert you can get away with it.

14:55 Now I want an anvil with eval/apply on it.

14:56 tmciver: Who doesn't? But I'll probably just take the easy route and print it out and stick it on my laptop.

15:23 dnolen: https://github.com/clojure/clojurescript/compare/master...checked-arithmetic

15:23 in this CLJS branch (+ 1 2 "3") is an error

15:23 with flag to switch to unsafe arithmetic

15:24 gfredericks: dnolen: compiler flag?

15:24 dustinside: hello

15:24 xcgfbcf

15:25 dnolen: gfredericks: basically, not a real one tho, just via an atom, real ones require changes to Clojure far as I know.

15:26 gfredericks: dnolen: so that means it has the same performance sacrifices as built in numerics would?

15:27 dnolen: gfredericks: I did some tests, it's a 3X perf drop, which I think is fine for the kind of arithmetic most JS apps require.

15:27 gfredericks: for performance sensitive apps set/unset the flag around the critical code

15:28 gfredericks: if it's via an atom doesn't that still require a runtime check of the atom at each execution of +?

15:28 I thought + was inlined which prohibited that kind of stuff

15:28 dnolen: gfredericks: atom in Clojure, not ClojureScript

15:28 gfredericks: remember there no such thing as compilation environment in ClojureScript

15:29 gfredericks: ah yes -- so it compiles differently in different parts of the app

15:29 dnolen: gfredericks: exactly, you can't just set this stuff at runtime, it's for controlling compmilation

15:30 gfredericks: that's cool; so that tactic could be used for numerics as well

15:30 dnolen: gfredericks: what do you mean?

15:30 gfredericks: well hmmm...

15:30 never mind :)

15:31 I mean I guess it could. I mean arithmetic with other numeric types without using separate arithmetic functions

15:31 I'm not sure how useful that would be.

15:33 dnolen: gfredericks: perhaps. I know there's a ticket open for ratios - tho not sure how that would work w/o killing regular arithmetic perf.

15:34 gfredericks: dnolen: yeah; we discussed that a while back.

15:35 dnolen: gfredericks: oh yeah.

15:35 gfredericks: it made me a little sad

15:35 tavisrud`: dnolen: how about ClojureScript:cljs.user> (+ (.join (js/Array 5) (- "wat" 1)) " Batman!") ? inspired by https://www.destroyallsoftware.com/talks/wat

15:36 gfredericks: that wat talk has some insane stuff in it

15:36 particularly [] + [] vs [] + {} vs {} + [] vs {} + {}; I didn't know any of that.

15:36 dnolen: tavisrud`: yeah you wouldn't be able to do that anymore

15:36 I have a new blog post brewing: ClojureScript <3 (JavaScript - WAT)

15:39 gfredericks: dnolen: would the checked-arithmetic branch allow you to subtract WAT from JavaScript?

15:40 (<3 ClojureScript (- JavaScript WAT))

15:40 tavisrud`: ClojureScript:cljs.user> (- js wat)

15:40 NaN

15:40 * gfredericks wants there to be a useful and intuitive interpretation/implementation of <3

15:40 dnolen: gfredericks: i hope so, not entirely sure, just started working on this today.

15:40 depends on how we treat NaN and Infinity ...

15:41 llasram: gfredericks: Why define <3 when you can just go ahead and define ♥?

15:41 dakrone: (= Double/NaN Double/NaN)

15:41 ,(= Double/NaN Double/NaN)

15:41 gfredericks: llasram: easier to type

15:41 clojurebot: false

15:41 dakrone: :(

15:41 llasram: gfredericks: Ok, fair enough :-)

15:42 tavisrud`: I'm surprised that last snippet didn't raise something like 'unable to resolve symbol'

15:47 amalloy: dakrone: a required part of the IEEE floating-point spec, so not much you can do about it

15:47 dakrone: amalloy: that sucks

15:48 amalloy: any comparison that involves NaN has to return false

15:48 &((juxt = not= < <= > >=) Double/NaN 4)

15:48 lazybot: ⇒ [false true false true false true]

15:48 dnolen: actually hmm is NaN even if issue if we checked arithmetic in CLJS

15:49 we can avoid producing Infinity by preventing div by zero

15:49 amalloy: hm, the trues surprise me. i guess >= is implemented as (complement <) or something similar?

15:49 ~def >=

15:51 yeah, gte(x, y) is !lt(x, y)

16:03 m0smith__: ,(+ 1 2)

16:03 clojurebot: 3

16:22 unlink: What is the clojure idiom for representing application-global configuration (which would be loaded at application start time)?

16:23 In almost any other language, I'd just use globals here and set them from a function called early from main().

16:24 AimHere: I dunno. Global config variables seem awfully stateful to me! I'm trying to unlearn that shit!

16:24 unlink: Not to me. They seem like constants that happen to get set at runtime to me.

16:25 m0smith__: Where would you get the config data from?\

16:25 AimHere: One config to rule them all ...

16:25 m0smith__: Are you talking about "private static final"s or property files or what?

16:25 AimHere: Hey, if it's against your programming methodology to change stuff like that, just hardcode the settings ;)

16:27 unlink: Hmm, that's true, I could just use properties.

16:27 joegallo: unlink: i've seen it done with clojure maps in .clj files

16:27 why use properties files when you have a more powerful syntax already available from the reader?

16:27 just slurp the clj file and read-string it

16:27 unlink: I don't want to hardcode it, though, since it's machine/environment-specific configuration.

16:28 joegallo: how would you avoid doing that hardcoding with properties files, and why would that not work exactly the same way with clj files?

16:28 unlink: Because I want a configuration DSL. More flexible isn't always better.

16:28 joegallo: okay, good luck to you.

16:29 unlink: In my case, I can get away with parameterizing the name of the properties file, and just load the right one.

16:29 m0smith__: unlink: so you would do the same as you would in a Java program and read in the properties/clj file

16:29 unlink: Yeah. I am also curious where people do store values passed on the command line (having been parsed), though.

16:30 And it would be nice to put the properties somewhere rather than using the clunky Java API for accessing them when I care, though.

16:32 fleetdb for example is able to get away with passing everything from configuration around functionally. I am not so lucky in this case.

16:32 joegallo: given that constraint then, i would probably slam it in a global atom, and call it a day ;)

16:33 maybe hide that atom behind a function that will access it on your behalf, so that you could change the implementation pretty easily if you come up with something better

16:34 the-kenny-w: Is this what clojurebot announced a new swank-clojure release? :)

16:35 technomancy: still a snapshot, the stable release is just around the corner

16:35 m0smith__: With configuration you want to create a state for your program to run in

16:35 That state can be represented by a combination of global data, bindings and higher order functions

16:43 the-kenny-w: technomancy: Awesome :)

16:51 technomancy: The next release will include nicer stack traces, do I remember that correctly?

16:52 technomancy: the-kenny-w: it's already in 1.3.4 IIRC

16:52 though maybe not the coloring, which is rad

16:53 pjstadig: soo...

16:53 how about those reader literals?

16:53 * Raynes loads his pistol.

16:53 ibdknox: lol

16:54 stuartsierra: If you hate them you just haven't been enlightened yet.

16:54 hiredman: boy did they save my butt that one time, when, well I dunno

16:55 Raynes: stuartsierra: I don't care about them one way or the other. I'm just strongly against bitchfests, which reader literals seem to invoke.

16:55 stuartsierra: everything invokes a bitchfest these days

16:55 pjstadig: guys...

16:55 stuartsierra: 5000+ people

16:55 Raynes: Are you calling me a bitch?

16:55 ;)

16:55 pjstadig: stop bitchfesting about bitchfests

16:55 ibdknox: lol

16:56 stuartsierra: Let it be know that on January 27, 2012, the neologism "bitchfesting" entered the world

16:56 Raynes: ibdknox: What the hell man. You need to set up an autocommand to ping me when you come online. I never notice you're around until you say something here.

16:56 technomancy: ibdknox needs a bouncer

16:56 ibdknox: Raynes: ping ;)

16:56 Raynes: I'd give him an account on mine if he asked.

16:57 hiredman: and my entered the world you mean "I said it, and since I am the only real person, it doesn't matter if anyone else said it, it wasn't really said until today"

16:57 * ibdknox doesn't even know what that is.

16:57 hiredman: by

16:57 ibdknox: I never used IRC before this really

16:57 lol

16:57 hiredman: ~google bitchfesting

16:57 clojurebot: First, out of 1550 results is:

16:57 bitchfest - definition and meaning

16:57 http://www.wordnik.com/words/bitchfest

16:57 Raynes: $google "bitchfesting"

16:57 lazybot: [Woke Up Knowing — Dyana Valentine] http://dyanavalentine.com/category/woke-up-knowing-2/

16:57 Raynes: Aw, no result count.

16:58 technomancy: curse you, stemming

16:58 stuartsierra: 23,000

17:03 later

17:06 TimMc: /join #bitchfest

17:07 I don't even know what y'all are on about.

17:16 Raynes: technomancy: Currently working on convincing ibdknox to use my bouncer.

17:17 technomancy: ibdknox: bouncers are great.

17:19 TimMc: I just use irssi in a screen session somewhere.

17:20 technomancy: that's a bouncer in spirit

17:20 TimMc: I tried using irssi's internal bouncer with Pidgin, but every time I closed a chat window it would close the channel in irssi.

17:20 Maybe that's not really a bouncer, though -- just a fancy proxy.

17:21 Raynes: Pidgin. Hah.

17:21 You people are insane.

17:21 TimMc: I use it for everything else, though.

17:21 technomancy: pidgin is great for voip

17:21 assuming you don't need to have more than two participants

17:23 emezeske: irssi is the shiznit

17:23 * jeremyheiler just switched from pidgin to xchat today--what a difference.

17:23 emezeske: The nice thing about console IRC clients is that, if you use screen or tmux, you can copy+paste code in and out of IRC with no mouse

17:27 * Raynes rolls his eyes.

17:38 technomancy: oh man, almost forgot it's open source friday

17:38 time to make noise on jira

17:38 hiredman: :)

17:39 the-kenny-w: open source friday?

17:40 technomancy: the-kenny-w: supposedly the day of the week in which it's possible to get core members to look at patches.

17:40 * TimMc bangs some pots together

17:40 the-kenny-w: technomancy: Ah

17:41 hiredman: relevence aka clojure/core

17:52 llasram: If you're doing Java/Clojure cross-development, is there a way to force a running Clojure REPL to load the new version of a .class file?

17:54 technomancy: llasram: you need a new classloader IIRC. afaik there's no way to automate adding one.

17:54 llasram: Ok. I thought I remembered swank doing some class-loader magic, so that each top-level form was getting a new class loader

17:55 technomancy: it could be; I meant that I'm not aware of an existing way to automate one. that doesn't mean it doesn't exist, even in swank. =)

17:55 llasram: haha

17:56 Oh well. I fixed my Java bug, so it has academic for the moment. Perhaps next time...

17:56 s,has,has become,

18:06 unlink: Oh no! I spent an hour trying to figure out why read-line in leiningen doesn't work!

18:06 technomancy: =(

18:19 unlink: Is there a more idiomatic way to write to stderr than (binding [*out* *err*] (println ...)) ?

18:25 Raynes: unlink: That's pretty idiomatic.

18:28 unlink: Raynes: Perhaps unidiomatic is my use of cond, then. (cond (nil? (some-check)) (binding [*out* *err*] (print error-message)) (nil? another-check) ... :else (proceed-normally))

19:37 LeNsTR: Hello guys! I'm a beginner in Clojure. Can you say something about my solution? http://stackoverflow.com/questions/9033678/changing-map-behaviour-in-clojure/9041816#9041816

19:41 jeremyheiler: LeNsTR: Your solution doesn't return a seq if the function is called with out any colls.

19:42 LeNsTR: user> (map + [])

19:42 ()

19:42 right?

19:42 user>

19:42 ops

19:42 user> (map-ext + [])

19:42 ()

19:42 same

19:43 jeremyheiler: &((fn [& c] (if (empty? c) [] :reallymap))

19:43 lazybot: java.lang.RuntimeException: EOF while reading, starting at line 1

19:43 jeremyheiler: &((fn [& c] (if (empty? c) [] :reallymap)))

19:43 lazybot: ⇒ []

19:44 jeremyheiler: I see a vector being returned in your code on SO.

19:44 Nanakhiel: ,(length "I Worship His Shadow")

19:44 clojurebot: #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: length in this context, compiling:(NO_SOURCE_PATH:0)>

19:44 jeremyheiler: (doc size)

19:44 clojurebot: It's greek to me.

19:44 Nanakhiel: ,(len "I Worship His Shadow")

19:44 clojurebot: #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: len in this context, compiling:(NO_SOURCE_PATH:0)>

19:44 Nanakhiel: Waargh

19:44 jeremyheiler: ,(doc size)

19:44 clojurebot: Gabh mo leithscéal?

19:44 TimMc: chouser: Please ban Nanakhiel

19:44 Nanakhiel: ,(size "I Worship His Shadow")

19:44 clojurebot: #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: size in this context, compiling:(NO_SOURCE_PATH:0)>

19:44 TimMc: I's lajla again

19:44 Nanakhiel: Baaargh

19:44 TimMc, not only that

19:44 TimMc: Nanakhiel: Seriously, stop it. Play with teh bot in privmsg.

19:44 jeremyheiler: duh, count lol

19:45 Nanakhiel: but also the best programmer in the world except only the microsoft chief software architect

19:45 * jeremyheiler needs a drink

19:45 Nanakhiel: jeremyheiler, I'll share one with you.

19:45 A fine sip of þe 12 year old scotch

19:45 LeNsTR: ")

19:47 jeremyheiler: &(map +)

19:47 lazybot: clojure.lang.ArityException: Wrong number of args (1) passed to: core$map

19:47 jeremyheiler: LeNsTR: If you want to stick with how map works, returning an empty vector would be incorrect

19:48 that's all im saying

19:48 Nanakhiel: I concur.

19:48 Or ehh

19:48 LeNsTR: ah

19:48 Nanakhiel: Do I

19:48 No

19:48 I do not

19:48 LeNsTR: user> (map-ext +)

19:48 []

19:48 rly

19:48 :)

19:48 Nanakhiel: I refrain from concurring

19:48 I withdraw my support for this dangerous proposition.

19:48 I have carefully reviewed evidence and come to the conclusion that my former assesment was indeed in error.

19:49 LeNsTR: jeremyheiler, thanks, I try to fix it

19:49 I will*

20:11 https://gist.github.com/1691934

20:11 jeremyheiler, ^^

20:13 jeremyheiler: LeNsTR: two things.

20:13 &((fn [& c] (empty? c)) [])

20:13 lazybot: ⇒ false

20:13 jeremyheiler: the varargs are wrapped into a vector, so if you pass in an empty vector, it will be: [[]]

20:14 sorry, they'r enot wrapped in a vector, but in a seq)

20:14 still, an empty vector has a paramter is still considered an element in the vararg seq.

20:14 as a*

20:15 &((fn [& c] (empty? c)))

20:15 lazybot: ⇒ true

20:16 jeremyheiler: The second thing, I would probably throw an ArityException, like map, just to be consistent.

20:38 phil___: is (merge-with conj m {:key element}) a good way do conj a value onto a collection in a map?

20:39 or is (update-in :key #(conj % element)) better?

20:39 jeremyheiler: no

20:39 &(conj {:foo :bar} [:a :b])

20:39 lazybot: ⇒ {:a :b, :foo :bar}

20:39 jeremyheiler: tuple vectoris are considered key/val pairs

20:39 hiredman: jeremyheiler: I think you are misreading the question

20:40 jeremyheiler: probably

20:40 hiredman: ,(update-in {:foo nil} [:foo] conj :x)

20:40 clojurebot: {:foo (:x)}

20:40 hiredman: is the way to do it, no anonymous function required

20:41 phil___: ah perfect, thx a lot

20:41 jeremyheiler: sorry phil. thanks hiredman for cleaning tha tup

20:41 clearing that up*

20:42 phil___: jeremyheiler: np, my way of asking wasnt very precise either :)

20:43 TimMc: phil___, jeremyheiler: Also look at 'fnil for use with update-in

20:44 phil___: i have to say, looking at update-in's design it is perfectly suited for just passing some function that takes a collection + a vararg, like conj

20:45 i was wondering if there were some "rules" for arranging arguments in such a way that functions are easily composable with partial varargs and the such

20:47 for example, if conjs parameters were flipped it wouldnt be possible to "place" it into update-in in such an easy ways

20:47 jeremyheiler: TimMc: that's looks so simple, yet extremly useful.

20:47 hiredman: there are some useful conventions, operations on collections take the collection first, operations on seqs take the seq last

20:47 phil___: from what i gather, it is alwasy a good idea for collections to go first, then the rest of the arguments

20:48 hiredman: ah, exactly what im looking for

20:48 hiredman: seqs go last because you can do things like (-> s (foo 1 2) bar (w 3 4))

20:48 er

20:48 make that ->>

20:48 bobhope: is there a function that checks if there are duplicates in a seq?

20:48 TimMc: phil___: And seqs are a type of collection, just to clarify.

20:49 phil___: but with -> you could compose functions that would take them as a first argument, right?

20:49 bobhope: I could do (= s (distinct s)), but I'm not sure if there's an idiom

20:49 hiredman: ,(->> (repeat 10) (map inc) (filter even?))

20:49 TimMc: bobhope: Throw a 'count onto each argument of that and it's more efficient, at least.

20:49 clojurebot: Execution Timed Out

20:49 hiredman: oh

20:50 ,(->> (range 10) (map inc) (filter even?))

20:50 clojurebot: (2 4 6 8 10)

20:50 TimMc: $findarg map % [[1 2 3] [1 2 2 3]] [true false]

20:50 lazybot: []

20:50 TimMc: $findarg map % [[1 2 3] [1 2 2 3]] [false true]

20:50 lazybot: []

20:51 phil___: ,(-> (range 3) (conj 5))

20:51 clojurebot: (5 0 1 2)

20:51 TimMc: bobhope: Looks like you'll just want to define it yourself as a little helper fn.

20:51 bobhope: TimMc, would it be better to do (every #(= 1 (val %) (frequencies s))

20:51 (except ((parenthesized) properly))

20:51 TimMc: That's pretty slick, but I have no idea whether the performance is any better.

20:51 bobhope: I don't give a damn about perf at the moment

20:52 :)

20:52 TimMc: Ha, OK!

20:52 bobhope: I'm writing a compiler, so i'm more concerned with correctness this time around

20:52 plus, this is just a simple semantic check

20:52 jeremyheiler: bobhope: curious, what are you compiling?

20:52 TimMc: Well, there's nothing more readable than (no-dups? ...), implemented however you feel is appropriate.

20:53 bobhope: jeremyheiler, i'm writing an HDL

20:53 TimMc: and I place a premium on readability.

20:53 Cool!

20:53 jeremyheiler: good stuff

20:53 bobhope: I'm hoping to get an initial release with basic functionality w/in the month

20:53 just the type system + synthesis to verilog

20:53 * gfredericks can only assume that stands for homain dpecific language

20:54 bobhope: and support for some basic math, and maybe structures or vectors

20:54 jeremyheiler: hah

20:54 bobhope: hardware description language

20:54 it's for writing computer chips

20:54 gfredericks: somehow that seems more plausible than mine

20:55 bobhope: lol

20:56 TimMc: bobhope: You may be interested in my behavioral circuit simulator, which is basically a way to attach functions together into a wires-and-registers arrangement: https://github.com/timmc/feedback (and needs to be completely rewritten)

20:56 LeNsTR: jeremyheiler, Yay, seems it's work pretty well ^_^ https://gist.github.com/1691934

20:56 bobhope: TimMc, that's really exciting

20:56 is it single-threaded or multithreaded?

20:57 I wrote a simple multi-threaded cycle-based simulator

20:57 TimMc: Don't get too excited, it's not as cool as it sounds. But I almost used it to write a cycle-accurate MIPS simulator for my comp arch final project.

20:57 jeremyheiler: LeNsTR: nice!

20:58 bobhope: TimMc, if you like cycle-accurate mips simulation, you should follow my progress on github (github.com/dgrnbrg/piplin)

20:58 LeNsTR: thank you for the suggestions!

20:58 bobhope: my first major target is implemting a cycle-accurate mips processor

20:58 TimMc: bobhope: It's a cycle-based simulator that carries arbitrary values on wires, not just numbers or bits.

20:58 bobhope: that's what i'm implementing

20:58 but the wires are unnamed

20:59 TimMc: Except you're doing it with descriptions of real hardware, right?

20:59 bobhope: i spent a long time designing a representation that is amenable to simulation and synthesis, and avoids putting any cycles in the graph

20:59 TimMc: As in, something that could compile down to components, given the right compiler.

20:59 bobhope: it could be real hardware, if you use the type system I wrote

20:59 which lets you say things like (instance (uintm 8) 3), which is 8 bits, unsigned, modulo on overflow, with value 3

21:00 but you could also use any clojure types

21:00 and use pli to link to a verilog simulator, or just run the clojure cycle simulator

21:00 to give you a lot more flexibility when defining tests

21:01 i use a hybrid approach to the compiler, where it gives you the full power of clojure during elaboration

21:02 if you've ever used myhdl, it's kind of like that

21:02 but designed to avoid the limitations their author got themselves stuck in

21:02 TimMc: I haven't worked with any HDL to any degree.

21:03 The closest I've gotten is visual component-and-wire editors and simulators.

21:03 bobhope: The goal of my system is that you won't need to understand as much about the FPGA architecture

21:03 so that you can write at a higher level to describe the algorithms, and the compiler can take care of the details

21:03 it's closest to this, i'd say

21:03 http://people.csail.mit.edu/jrb/Projects/gel.pdf

21:04 but I found gel confusing in some places

21:04 phil___: is (-> :x :y :z m) an accepted replacement for (get-in ...)

21:04 ?

21:04 gfredericks: I think you need the m at the front

21:05 phil___: gfredericks: yes, sry

21:05 gfredericks: maybe not though...

21:05 * gfredericks stares

21:05 TimMc: you do

21:05 phil___: you do

21:05 gfredericks: ,(-> :x :y :z {:z {:y {:x 5}}})

21:05 clojurebot: nil

21:06 phil___: :z :y :x

21:06 jeremyheiler: &(:x :y)

21:06 lazybot: ⇒ nil

21:06 TimMc: phil___: It gave me pause because (:x {:x 5}) and ({:x 5} :x) both give 5. :-)

21:06 bobhope: is lazybot haskell?

21:06 * gfredericks is finally convinced

21:06 phil___: ,(-> :z :y :x {:z {:y {:x 5}}})

21:06 clojurebot: nil

21:06 TimMc: bobhope: It has a haskell evaluator.

21:06 gfredericks: phil___: in any case yeah I think that's fine.

21:07 TimMc: but it is written in Clojure

21:07 bobhope: interesting...does it evaluate other languages?

21:07 TimMc: $he 1 + 1

21:07 lazybot: ⇒ 2

21:07 TimMc: \o/

21:07 phil___: TimMc: yea, i gotta get accustomed to the fact that maps and keys both represent functions :)

21:07 gfredericks: phil___: I think I use -> a lot more often than get-in. get-in is more capable since you don't have to have a fixed keyset at compile time.

21:07 TimMc: That's all the Haskell I know.

21:08 phil___: gfredericks: yea, thats true

21:08 TimMc: gfredericks: Not precisely... ##(let [sel :x] (-> {:x 5} sel (* 2)))

21:08 lazybot: ⇒ 10

21:08 phil___: gfredericks: so for trees etc youll have to use get-in anyway, but for more or let fixed data structures (-> ...) seems to be clearer

21:09 gfredericks: TimMc: fixed-size at least

21:09 TimMc: yeah

21:09 gfredericks: I can't say for sure I meant that :/

21:09 phil___: gfredericks: so get-in is preferred?

21:09 TimMc: depends

21:10 bobhope: :( I just realized the function i'm writing could be done in 1/10 the code w/ core.logic

21:10 phil___: when you have some data and you know its structure at compile time, for example

21:10 bobhope: but i've only got 4 or 5 more lines ot go

21:11 phil___: bobhope: and then youll debug it 3h :)

21:11 go with the 1/10 cod

21:11 code*

21:11 bobhope: phil___, I've debugged everything so far

21:11 phil___: bobhope: good :)

21:11 bobhope: it's the very hairy datastructure munging that could've been declarative

21:11 TimMc: phil___: I prefer to reserve -> for doing processing on something. 'get-in instantly signals to the reader that you're not munging anything.

21:11 bobhope: but I've got them all munged now

21:12 phil___: TimMc: but if you have something like (-> tree :node :person :name) i think thats clear enough?

21:13 compared to (get-in tree [:node :person :name])

21:13 yea i can see both sides :/

21:14 amalloy: i strongly prefer get-in for that

21:14 bobhope: I like get-in for traversing trees

21:14 TimMc: phil___: When you say -> I have to think about what each operator is doing.

21:14 bobhope: and -> is evil and to be avoided ;p

21:14 amalloy: i would be willing to defend using -> to get that result, but not the way you did

21:14 phil___: amalloy: how then?

21:15 TimMc: ((comp :name :person :node) tree) :-P

21:15 phil___: is -> really considered evil?

21:15 amalloy: (:name (-> (:node tree) :person)), for example, if you want to emphasize the name and the node, but deemphasize the person

21:15 TimMc: phil___: For simple getting-in, yeah, it's kind of weird.

21:16 bobhope: -> isn't strictly evil, but often using a (let ) is clearer, since you can name your temporaries

21:16 amalloy: -> isn't evil at all, i love ->

21:16 TimMc: amalloy: Oh, like when you cross data structure borders?

21:16 amalloy: TimMc: sure, or whatever you think makes it clearer what you're doing

21:16 clojurebot: Excuse me?

21:16 TimMc: Yup, that's always a good metric.

21:16 well, litmus test

21:16 amalloy: the magic of -> is that it lets you write your operations in any order you like, so put the ones you consider "important" first

21:17 eg, it makes with-meta much more palatable: (-> (some foo bar) (with-meta {:x true}))

21:18 phil___: oh god so many ways to do a single thing

21:19 amalloy: there are a lot of ways you could have composed an equivalent sentence. you chose a phrasing that makes you sound overwhelmed

21:19 phil___: my tricks.txt is growing fast :)

21:19 amalloy: well overwhelmed by choice, lets say that

21:20 when youve worked for some time with a language you begin to develop best practices etc

21:20 amalloy: i'm not making a value judgment about your sounding overwhelmed. my point is, you had a bunch of choice in how to write that sentence, which makes the language expressive

21:20 phil___: but when youre starting out and there are 10 ways of doing the same thing, then its kinda hard to decide what is best

21:20 amalloy: ah i see your point

21:21 TimMc: phil___: Half the battle is learning the idioms.

21:21 phil___: im not sayng expressivity is a bad thing, on the contrary

21:21 TimMc: yea, exactly

21:21 amalloy: TimMc: how meta

21:21 TimMc: haha!

21:22 bobhope: So, I often want to write a function that calls many functions internally, some of which can fail. Their failures are returned as errors, and if any of them fail, I want to return a seq of the errors, but since this is pattern I don't like cluttering my logic with lots of "if errror return error else do stuf"

21:22 Is there a good way to do this?

21:22 TimMc: phil___: e.g., if you do "for (int i=0; i<foo.length; i++) { ... }" in Java, any programmer with any experience will *instantly* understand what is going on, without having to think about the comparison or the ++ or anything.

21:23 Clojure has some similar things, of course.

21:23 bobhope: I made a let-safe macro that checks for errors on each binding, and bails out if any are errors. I could make map-safe and reduce-safe, etc, but I'd rather use something that already exists

21:23 phil___: bobhope: id say monads :)

21:23 bobhope: that is what seems to be calling for me

21:23 but I don't really understand them

21:24 phil___: bobhope: but this is *exactly* the kind of problems monads are perfectly suited for

21:24 bobhope: is clojure.contrib.monads up to date?

21:24 phil___: clojure.algo.monads

21:24 bobhope: I know I've written my own crappy monad system...

21:24 phil___: there is even an error monad there but idk if it accumulates the errors the way you want it to

21:25 TimMc: bobhope: clojure.contrib.* iss not up to date :-/

21:25 bobhope: Have you looked at slingshot?

21:25 phil___: TimMc: yea, but there arent 30 ways of writing a loop in java or c

21:25 :)

21:25 jimduey: clojure.algo.monads is pretty good

21:25 bobhope: TimMc, I have, but I need a bit more power, since I need to return multiple erros

21:25 since a compiler really wants to say "Here's all the errors I found this time!"

21:26 TimMc: Ah, *all* the errors, right.

21:26 jimduey: And https://github.com/clojure/algo.monads has some links to some tutorials.

21:26 bobhope: jimduey, i'm currently reading them :)

21:26 phil___: maybe sequence-m error-m

21:26 jimduey: Well then, I'd say you're all set. :)

21:27 phil___: sequence-m is a monad whose monadic values are non-deterministic (i.e. lists)

21:27 jimduey: and if you don't mind listening to me. http://www.infoq.com/presentations/Monads-Made-Easy

21:27 bobhope: I just need to figure out whether it'll take me longer to learn the monads or hack my implementation

21:27 jimduey, can I show you some code I have now that I believe is the monad?

21:28 and maybe you could say "Yes, that's a monad"

21:28 or "no, monads won't really help"

21:28 phil___: bobhope: id say learn em even if it takes longer

21:28 bobhope: I have a lot of code to write, and I only get to work on this on nights and weekends

21:28 jimduey: learning monads will pay dividends beyond your current project.

21:28 phil___: yes

21:29 bobhope: I have a lot of learning-based projects

21:29 jimduey: sure. post a link or something. or send me an email if you want to keep it private.

21:29 bobhope: I like the "doing" part a bit more

21:29 jimduey, https://github.com/dgrnbrg/piplin/blob/master/src/piplin/types.clj#L42

21:30 that function and the following macro are currently what I do that I think is monadic

21:30 amalloy: i never thought i'd hear "non-deterministic; that is, lists". how are those two synonyms?

21:30 phil___: amalloy: very oversimplified ofc, they are in no way synonymous

21:31 LeNsTR: why this doesn't work? (defn foo [x & xs :as e])

21:31 in let bindings :as work pretty well

21:32 phil___: bobhope: yea thats a monad

21:32 bobhope: does it exist yet?

21:33 amalloy: :as only works if there was a single data structure already

21:33 &((fn [x y :as args] args) 1 2 3 4) ;; what is args here? it can't be [1 2 3 4], since that object was never created

21:33 lazybot: java.lang.Exception: Unsupported binding form: :as

21:33 phil___: do you want to break execution when an error is encountered or continue?

21:34 LeNsTR: ah I understood

21:34 amalloy: &(let [[x y :as args] [1 2 3 4]] args) ;; but here, there's an object to use

21:34 lazybot: ⇒ [1 2 3 4]

21:34 jimduey: bobhope: that's not a monad, but I'm pretty sure you could accomplish what you're attempting with one.

21:34 bobhope: phil___, the computation is structured as a tree, so whenever a branch of the tree fails, it should propagate the error back up. But at each node in the tree, all the children can be executed independently, and if any were errors, then they should all get combined into an errors object and that gets propagated up

21:35 So every computation results in an answer or an error object, and if anything gets an error object as its input, it must return all the error objects it got

21:36 jimduey, i'll be watching you sometime in the next few days

21:36 phil___: so essentially you wanna either thread a list of errors through your functions or the computed value, right?

21:36 bobhope: yeah

21:37 any function can "abort" its subtree, and if anyone aborts, the abortion goes up to the root, joining other abortions on the way

21:37 jimduey: bobhope: feel free to shoot me an email if you have any questions. No reason to beat your head against a wall.

21:37 bobhope: that doesn't read like it sounded in my head :)

21:37 TimMc: yeah

21:38 I'm gonna quote you on that last clause.

21:38 amalloy: how is this different from exceptions?

21:38 TimMc: amalloy: pokemon exceptions

21:38 collect 'em all

21:38 bobhope: jimduey, thanks--I might take you up on that

21:38 is your email easily googable?

21:39 phil___: bobhope: look at this: http://brehaut.net/blog/2011/error_monads

21:39 amalloy: augh. plz don't ruin jokes like that, TimMc. it's cruel

21:39 jimduey: should be.

21:39 bobhope: it's true, though--I want to get as many errors as possible per run

21:39 phil___: it returns the first error, but you can extend it easily to return a list of errors

21:41 bobhope: phil___, I actually already implemented that, but I called it (error msg) and safe-let

21:41 But I also need it to work on map, and fn

21:41 really, i'd like to take any function and make a safe version

21:41 phil___: i.e. you wanna "lift" it

21:42 bobhope: I don't know what lifting is, but yes.

21:42 phil___: to work in the error-list monad

21:42 bobhope: i think so

21:42 phil___: yea, it would be best to read up on monads of you have a spare day or two

21:42 bobhope: :/

21:43 I'm not going to have a whole free day for at least a week

21:43 phil___: its not a topic that can be explained in 10mins anyway, and im not the biggest expert either

21:43 bobhope: Well, I've studied them on and off for a while

21:43 so i'm familiar with the concepts

21:43 phil___: bobhope: well it doesnt have to be in one setting ofc

21:43 bobhope: it just hasn't "clicked" yet

21:44 but I feel close, since I had thought that my error handling functions were already close to monads

21:45 phil___: it is just a way to compose functions but you can modify the "compose" part, i.e. you can take the result of one function, do something with it, and feed it to the next, or dont feed it at all (in which case you abort the computation, i.e. maybe monad)

21:46 its just a way to formalize and extend the usual function composition

21:48 like (comp a b) always takes the result of a and feeds it into b, but with monads you could say, "hm, a is returning an error, so im gonna add it to this list and feed it to b"

21:49 but really, im not the best person to explain monads :)

21:50 xeqi: b

22:01 jeremyheiler: how do you search google from lazybot?

22:03 nevermind, $google

23:19 phil___: lets say we have this function: (fn [] (let [x (+ 1 2)] ...)) - is x gonna be recomputed every time the function is called, assuming (+ 1 2) is a constant expression?

23:20 unlink: phil___: yse.

23:21 phil___: unlink: so it is then better to move (def x (+ 1 2)) out of the function and just use x instead?

23:21 Raynes: unlink: In this unbelievably simple case? My answer is omgdudeworryaboutrealproblems.

23:21 Er, phil___ ^

23:23 In general, yes.

23:23 phil___: Raynes: well no, x is a rather large-ish map of functions, and it is used in a recursively called function that may be called many times per second, so if this map is recreated on every call thats GOTTA be slow

23:23 Raynes: If it is a constant expression, especially if you need it in more than one place, it is better to put it in the top level.

23:23 Right, if it is expensive computation, it can be important to put it in the top level so that it only has to be computed once.

23:24 technomancy: measure twice, cut once

23:24 profile, don't guess

23:24 phil___: technomancy: youre right of course

23:25 Raynes: Well, this isn't really a matter of how bad performance would be -- it only makes sense to put a constant expression, especially an expensive one, in a place where it doesn't have to be computed more than necessary.

23:26 * emezeske thinks readability should always be Priority #1, until profiling says otherwise.

23:26 phil___: Raynes: well in this case it would be better to put it inside the function, because those functions inside the map close over the main functions arguments... if i put them at the top level, ill have to explicitly pass em those arguments

23:26 and thinking about it, the map HAS to be recomputed every time, since the innter functions close over the main funcrions arguments

23:26 gawd

23:27 Raynes: There there.

23:46 phil___: are pre- and postconditions working in clojurescript?

23:49 dnolen: phil___: hmm doesn't look like there are, feel free to add a ticket if you don't see one open already.

23:49 phil___: dnolen: allright, will do

Logging service provided by n01se.net