#clojure log - Dec 09 2012

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

0:00 seangrove: I'm trying to build something around it, and it's alright, but there's going to have to be a somewhat substantial wrapper around it to make it fit what I want

0:00 Raynes: Was this seangrove's paste?

0:00 seangrove: Yeah

0:00 Raynes: Damn all of you who don't have user accounts.

0:01 seangrove: You're famous now. I tweeted it and everything.

0:01 seangrove: The embedded javascript for refheap looks great Raynes

0:02 Raynes: Also, let this be a lesson for everyone: if your paste is public, I will one day use it for some demonstration somewhere. It's only a matter of time.

0:02 seangrove: but tomoj, when you get a chance, would love to hear your thoughts

0:02 tomoj: I guess branch is OK

0:02 and when

0:03 seangrove: Hmmm, so bad compared to what, then?

0:04 tomoj: trying to get them in my repl so I can confirm they are broken :)

0:14 right

0:15 seangrove: https://www.refheap.com/paste/cf279b53c2f6168fa30ce1e0b

0:16 if you do (.addCallback (.branch d) ...) instead, you get the, uh, correct results

0:19 seangrove: Sure, but isn't that expected behavior?

0:20 tomoj: in what sense? I expected it of Deferred, because I expected Deferred to be wrong :)

0:21 seangrove: Heh, in that the result is cascaded through callbacks sequentially

0:21 Do you expect all callbacks to be called with the same value?

0:21 tomoj: yes

0:21 Deferred seems like a deferred mutable value

0:21 I want a deferred immutable value, naturally

0:22 seangrove: I see, I kind of saw it as analagous to ->

0:22 tomoj: if it's restricted to a lexical scope, maybe

0:23 but the burden is on you to be careful not to expose the wrong Deferred and let others mutate it

0:24 like (-> x inc inc inc) might be analogous to (-> d (.addCallback inc) (.addCallback inc) (.addCallback inc) .branch) ?

0:24 seangrove: Ah, as in someone else could attach a callback somewhere and potentially mess up any later callbacks you add?

0:25 Or (doto (.branch d) (.addCallback inc) (.addCallback inc) (.addCallback inc))

0:26 tomoj: even after you branch, that branched thing is still a Deferred, so it's still broken :)

0:27 seangrove: hmm, interesting

0:27 If you could *only* apply callbacks to a branched deferred unless you created it in a local scope, would that be better?

0:28 Obviously not possible, but hypothetically

0:28 tomoj: unbranched, you mean?

0:29 I think it's safe to do (.addCallback (.branch d) inc) no matter where d came from

0:29 seangrove: no, branched, so that you couldn't affect the original deferred from the pov of whoever gave it to you

0:29 tomoj: if you created d and are caring for it, then you might not need to call branch

0:29 seangrove: Yeah, that's right

0:29 And if you hand it to someone else, they wouldn't be able to add a callback to it that would affect any of yours

0:30 Effectively, they would have to call .branch on it first, and could then add callbacks on the newly-returned deferred

0:30 tomoj: yeah

0:30 seangrove: I suppose that's what you meant by immutable deferreds though ;)

0:30 tomoj: I think this is very relevant though I've only skimmed it https://gist.github.com/3889970

0:30 if you're wrapping Deferred maybe you can make your wrapper safe

0:31 personally I'm ignoring Deferred and implementing, uh, correct promises directly in cljs, then someday I'll provide some wrapper that converts a Deferred into a correct promise

0:32 seangrove: The problem I have is you can't implement deferred from the outside of functions

0:32 For example, I can't pass an xhr request to a deferred and expect them to work together, unless I've built my own wrapper around both of them

0:33 And then that wrapper won't work for any other library or code that doesn't conform to my specific patterns

0:33 For example, I think you could probably implement something close to it by building something on deferreds, xhr, and goog.events, but it'd be more code for less effect than I'd like

0:34 tomoj: surprised XhrIo doesn't return a Deferred of a response

0:35 seangrove: Doesn't return anything :P

0:35 tomoj: yeah :(

0:36 seangrove: Presumably you could make a module that copied the innards of xhrio and returned deferreds... it'd be much nicer if it were included as a standard though

0:37 tomoj: what do you mean by 'pass an xhr request to a deferred'?

0:38 seangrove: (.callback my-deferred (my-xhr-fn))

0:40 I have to have to something similar to: (defn my-xhr-fn [...] (if (success) (.callback my-deferred)))

0:40 Like you said, if XhrIo returns a deferred, I think that'd work well

0:44 tomoj: well, dunno. but protocols may help with the "won't work for any other library or code" problem

0:44 of course, only for other cljs libraries or code..

0:53 gaze__: yo! I can't find anything definining the behavior of carats in the documentation, just references (def ^:dynamic, for instance

0:53 what do they do?

0:56 p_l: reader macro to set metadata stuff

0:57 tomoj: &(meta (read-string "^:dynamic []"))

0:57 lazybot: ⇒ {:dynamic true}

0:57 tomoj: &(meta (read-string "^{:foo :bar} []"))

0:57 lazybot: ⇒ {:foo :bar}

1:22 seangrove: tomoj: Yeah, I think protocols might be the way to go about it eventually, but just frustrating how much basic infrastructure will need to be built out

1:53 gaze__: say I have some macro that defines a symbol, and I want stuff inside the macro to be able to manipulate that symbol, without explicitly making reference to it

1:54 using name# I guess assigns a special name

1:55 and if I just remove the hash, it complains that it's not making reference to a qualified name

1:59 or... is there a better way to do implicit arguments?

2:02 amalloy: $google clojure anaphora macro symbol

2:02 lazybot: [Unhygienic ("anaphoric") Clojure macros for fun and profit] http://amalloy.hubpages.com/hub/Unhygenic-anaphoric-Clojure-macros-for-fun-and-profit

2:02 amalloy: hey, that's me! anyway, gaze__, that's the name of the thing you're talking about, if i understand you

2:03 gaze__: YES

2:03 thanks :D

2:13 tpope: bbloom: do you have a proposed solution? eval top level form?

2:19 gaze__: amalloy: I should actually just ask the question I mean to ask... let's say I want to have a macro called defx, where any time (go a) is called within it, a is appended to a list. The result of a definition of defx is to be the list.

2:20 (defx foo (let [x 5] (go x) (go (+ 5 x))))

2:20 then (foo) should be '(5 10)

2:22 in my version I'm both defining an unhygenic symbol and trying to make a mutable bound variable... is there a more sensible way to do this?

2:27 amalloy: this is unpleasant, but there's nothing obviously better unless you're willing to really dive off the deep end and use continuations, which i suspect would do it

4:14 adxp: I'm getting a "Could not locate clojure/instant__init.class or clojure/instant.clj on classpath" error when trying to use fetch with cljsbuild. As far as I can tell, others have fixed this by upgrading to clojure 1.4 or cljsbuild 0.2.9. I'm using those already, though. Anyone have any ideas as to what else I could try?

4:15 tomoj: *clojure-version* is 1.4.0?

4:17 adxp: that's what's in my project.clj, and what's reported by manually running clj, yep. I'm still pretty new to clojure, so I'm not sure if there's anything else I should check...

4:17 * Sgeo|web ponders if there's already a letrec for Clojure

4:17 tomoj: adxp: you have a new-ish version of leiningen?

4:18 adxp: running with --version reports "Leiningen 1.7.1 on Java 1.7.0_09 Java HotSpot(TM) 64-Bit Server VM"

4:18 tomoj: Sgeo|web: could you write (letrec [a [b] b [a]] [a b]) with it?

4:18 that's pretty old

4:18 Sgeo|web: This exists https://gist.github.com/486880

4:18 tomoj: adxp: but, since it's old, check to see which clojure jar is in lib/

4:18 Sgeo|web: tomoj: I assume that some things would infinite loop

4:19 adxp: tomoj: clojure-1.4.0.jar is in lib/, but I can look at upgrading leiningen if that might help

4:19 tomoj: doubt it should help..

4:19 but it would be a good idea in general

4:19 probably..

4:20 adxp: ok, will do; thanks

4:20 tomoj: so the only other question I have is, if you upgraded from something older than clojure 1.4, did you restart the jvm since upgrading?

4:21 adxp: what do you mean by restart?

4:21 tomoj: well, where are you getting that error?

4:21 adxp: when I run "lein cljsbuild [auto / once]"

4:21 tomoj: oh

4:21 adxp: I did upgrade my JDK earlier, but I doubt that's related...

4:22 tomoj: that doesn't make any sense to me, sorry

4:22 adxp: the error?

4:22 tomoj: I mean I can't think of any explanation

4:22 clojure/instant.clj is in my 1.4.0 jar

4:23 adxp: yeah, ditto

4:23 jar tf lib/clojure-1.4.0.jar | grep instant | head

4:23 clojure/instant/

4:23 hum.

4:23 tomoj: well, further down you should see clojure/instant.clj

4:23 adxp: yeah, that's there too

4:23 tomoj: `lein classpath` shows a dir with that jar in it?

4:24 presumably..

4:24 adxp: yup

4:24 tomoj: maybe you just need to upgrade lein

4:24 I could imagine that cljsbuild assumes lein 2

4:24 not sure though

4:25 not sure how that would cause your error, either

4:25 adxp: trying that now

4:26 huh, worked. thanks!

4:28 gaze__: how do I inject an array of stuff into the arguments of something? like... I have (defn x [a & b] ...) and I want b to take the values ['p 'q]

4:28 Sgeo|web: Ugh, I think to do what I really want would require writing my own sort of container

4:28 tomoj: container like an IDeref?

4:29 Sgeo|web: Yes

4:29 Although come to think of it, maybe I'm imagining a lazy letrec when that's not what letrec typically is

4:29 amalloy: $findfn list 'a 'b ['p 'q] '(a b p q)

4:30 lazybot: []

4:30 amalloy: what the hell, findfn. the answer is apply

4:30 Sgeo|web: ,(+ 1 2)

4:30 clojurebot: 3

4:30 Sgeo|web: ,(apply + [1 2])

4:30 clojurebot: 3

4:30 gaze__: sweeeet. Thanks :D

4:30 Sgeo|web: ,(apply + 1 2 [3 4])

4:30 clojurebot: 10

4:33 Sgeo|web: What special forms besides quote take lists as arguments that are not treated like code?

4:35 tomoj: I've been pondering letrec for asynchronous IDerefs, like maybe (letrec [a (merge (periodic 1) (postpone Math/PI a))] a)

4:39 borkdude: someone asked me: what are the new features for clojure 1.5. I told him: reducers and a lot of new threading operators… am I right and what else?

4:40 tomoj: (which has occurrences at 0,1,2,3,pi,4,pi+1,5,pi+2,6,pi+3,2pi,7,pi+7,2pi+1.. I think?)

4:41 borkdude: http://dev.clojure.org/jira/secure/attachment/11744/changes-draft-v11.md

4:42 borkdude: tomoj many tnx

4:45 Sgeo|web: as->'s doc seems inconsistent

4:45 It sounsd like it does do threading, although it claims it does not

4:56 tomoj: as->^

4:56 ?

4:56 oh, sweet

4:56 I didn't like 'test->

4:58 Sgeo|web: the doc is inconsistent with the name?

4:59 Sgeo|web: "then binds name to that result, repeating for each successive form"

4:59 So the name doesn't stay the expr throughout the as->, it changes, as a sort of threading

5:00 Which, while possibly useful in some circumstances, is inconsistent with the stated goal "Instead it allows the user to assign a name and lexical context to a value created by a parent threading form."

5:00 In order to do that goal, you'd have to do something like (as-> some-name (do ...))

5:00 If you want to use multiple forms

5:01 amalloy: Sgeo|web: (-> foo inc blah whatever (as-> bar (for [x bar] ...)))

5:01 Sgeo|web: amalloy: the issue pops up when there's more than 2 forms (the name and a form) in the as->

5:01 tomoj: you could say that is a kind of threading

5:02 Sgeo|web: I would

5:02 amalloy: that's not an issue, man. if you want more threading, you didn't need as-> in the first place

5:02 tomoj: I think the changes md means that it is not the syntactic threading of ->

5:02 amalloy: i'm showing you the intended usage of as->, and why it doesn't make sense to continue threading the form

5:03 Sgeo|web: amalloy: my point is that the documentation says that it continues threading (kind of, just in a different way)

5:03 Suppose you want to do side-effects in the as->

5:06 borkdude: aren't all these extra threading macro's adding extra "syntax" to clojure, I wonder if it's worth it?

5:07 but then again, I don't really mind

5:08 gaze__: how do I get a defmacro to put multiple things at the toplevel?

5:08 borkdude: gaze__ use multiple defns in it?

5:09 gaze__ generally a bad thing, unless you are writing a framework or smth

5:09 tomoj: generally a bad thing then too :P

5:10 borkdude: hehe

5:10 Sgeo|web: gaze__: do

5:10 tomoj: why does clj-http parse the url, never look at it, then just convert it back to a url when doing the request?

5:10 gaze__: yeah it feels kinda dirty. But... I need after each definition to push the name of the function and the actual symbol into a table

5:10 tomoj: "for ring compliance" I think, but.. really? :/

5:10 gaze__: and it looks like defmacro is variadic and everything it sees it just pushes

5:11 so... cool :D

5:11 Sgeo|web: demacro is variadic because it takes in code, just like defn does

5:11 Code which can consist of multiple forms

5:11 Outputting multiple forms is impossible, but wrapping it in do works fine

5:11 ,(do (println "A") (println "B")) ; one form

5:12 clojurebot: A

5:12 B

5:12 tomoj: oh, actually, I see some reason for it

5:12 e.g. :query-params -> :query-string conversion

5:15 gaze__: http://pastebin.com/pdzUSBvv

5:15 here's what I'm doing

5:15 does all this seem reasonable?

5:16 lotta mutable stuff... would like to have less mutable stuff

5:16 but I don't see much way out of it

5:17 Sgeo|web: a) You're not going to be outputting the defn

5:17 b) caller and trxn will be visible from the body. Do you really want that?

5:18 gaze__: a) Ah... I'll wrap it in a do

5:18 b) caller, yes. trxn, no

5:18 but I don't see a way around having trxn visible to go

5:50 zamaterian: Is it possible to get syntax highlightning in lein repl ?

5:53 tomoj: it's probably possible, but there is no support for it now, and it seems like it would be a lot of work. it would probably be much easier to get syntax highlighting at a repl embedded inside an editor that can already do clojure syntax highlighting

5:54 zamaterian: tomoj, thx (i

5:55 tomoj, i'm using vim+vimclojure+foreplay - but uses lein repl for all my prototyping..

5:57 rodnaph: hi - i've copied some java source files into my leiningen project src directory (with namespace folders) then set the :java-source-path, but leiningen doesn't seem to be doing anything with them (the classes are not available if i start a repl) - can anyone help?

6:00 andrewmcveigh: rodnaph: I think you have to compile them first, but I've never worked with java & lein together.

6:03 tomoj: `lein javac` maybe?

6:04 dnolen: would you be interested in a patch which copies cond-> and friends from 1.5 into cljs/core.clj (to be pulled only after 1.5 is out, I suppose)?

6:06 rodnaph: ah - got it! the property has changed in lein 2.0 :E https://github.com/technomancy/leiningen/blob/master/sample.project.clj#L210

6:07 thanks both

6:14 Sgeo|web: I wonder, if it's possible to take a threading macro and pass it in and convert it to a let-like thingy

6:15 Threading macros are really just cheap hacks around the lack of nice monad syntax

6:15 Or, alternatively, they are in a sense a nice monad syntax

6:16 (bind mv f) == (-?> mv (f))

6:16 I think?

6:17 Can I go the other direction, from a bind into a threading macro? Kind of, but wouldn't be a perfect implementation of a threading macro

6:18 I think

6:19 (-?> mv (a b c)) == (bind mv #(a % b c))

6:19 People might be more willing to use monads if they took the form of threading macros

6:19 To me, both do syntax and threading feels "intuitive"

6:21 clojure.algo.monads has monads be first-class values, which is generally useful. My big objection to it is with one of the monad implementations, not with the core concept behind it itself

6:21 Although I do dislike needing to use defmonadfn

6:22 If I were to write my own monads library, I would just use dynamically-scoped variables

6:24 tomoj: so you could write a (defn foo [x] (m-> x f)) and then use it in different monads?

6:24 (I'm not familiar with defmonadfn)

6:24 Sgeo|web: defmonadfn is the macro you need to use to use bind and return in your own functions with clojure.algo.monads

6:25 (

6:25 (iirc)

6:26 clojure.algo.monads uses a bunch of macros to try to have bind and return effectively be lexically scoped

6:27 ambrosebs: if anyone's bored, I recorded some experiments with Typed Clojure https://vimeo.com/55196903

6:28 Obviously rough, but feedback welcome.

6:28 Sgeo|web: ambrosebs: will Typed Clojure allow for polymorphism on the return type of a function?

6:29 ambrosebs: Haskell type class style? no

6:29 Sgeo|web: Will Typed Clojure allow for the semantics of a program to rely on being run with Typed Clojure?

6:29 Oh, ok, darn.

6:29 Thank you

6:29 ambrosebs: I'm definitely interested in this area though.

6:30 It seems like TC is a starting point for such a thing.

6:32 Sgeo|web: I wonder what sort of things one can do with bind but no return

6:32 tomoj: while you're here, why not put the annotations in metadata? because you want to be able to annotate things which can't have metadata, I guess?

6:33 Raynes: ambrosebs: What's the problem with return type polymorphism?

6:33 ambrosebs: tomoj: I thought about it, but I don't really want to rely on runtime behaviour much. eg. what if the var doesn't exist yet?

6:34 Raynes: Firstly, Typed Clojure doesn't affect runtime behaviour at all atm

6:35 Raynes: Further than that, I'm not sure of the details, but I assume something like Haskell's inference + type classes is needed.

6:35 The most practical issue is how to best affect runtime behaviour: how to communicate with the compiler.

6:36 Sgeo|web: Pass the type to a function that somehow indicates that it wants access to the type that it should be outputting

6:36 As in, make it be an argument

6:36 Or maybe dynamic variable?

6:37 ambrosebs: It's a hard problem. But my trail of though was operating directly on the AST before it gets compiled.

6:38 Raynes: ambrosebs: Call it cheeky a few times and I bet it'll get easier.

6:39 ambrosebs: Raynes: just run it backwards.

6:40 Sgeo|web: Would there be any significant problems to just having a dynamic variable *return*

6:40 And *bind* I guess

6:40 ambrosebs: Sgeo|web: You might be on the right track.

6:41 tomoj: if all you're trying to do is monads, maybe?

6:41 Sgeo|web: clojure.algo.monads's macrology scares me

6:41 I'm not particularly thinking in terms of TC

6:42 But I also want to have Functor and Applicative stuff, and those don't rely on re... Functor doesn't rely on return type polymorphism

6:43 ambrosebs: Sgeo|web: so who binds the dyn vars?

6:44 Sgeo|web: The user. In, say, a with-monad macro, and some macros that might take a first-class monad

6:44 Such as domonad

6:46 ambrosebs: Interesting.

6:46 Are you thinking more like protocol-monads than algo.monads?

6:47 Sgeo|web: Actually, I think it's more like algo.monads than protocol-monads, because I'm not looking at the types of the arguments, just using functions in a structure passed in from a higher-up-the-call-stack caller

6:49 ambrosebs: also, you missed my musings about threading macros and monads

6:49 ambrosebs: I'll have a look

6:49 tomoj: domonad is like let?

6:49 (syntactically)

6:50 Sgeo|web: tomoj: similar, yes

6:50 ambrosebs: Sgeo|web: I think I'm missing something. Is there any inference going on, or have we pushed the work to the user?

6:50 Sgeo|web: ambrosebs: pushed the work to the user

6:51 ambrosebs: ok

6:51 Sgeo|web: ,(-> nil (and 1 2 (do (println "Side-effect") true)))

6:51 clojurebot: nil

6:51 Sgeo|web: ,(-> true (and 1 2 (do (println "Side-effect") true)))

6:51 clojurebot: Side-effect

6:51 true

6:51 Sgeo|web: Wait, and still operates on values, not on code, it just expands into code that operates on values

6:52 ,(macroexpand '(and a b c))

6:52 clojurebot: (let* [and__2241__auto__ a] (if and__2241__auto__ (clojure.core/and b c) and__2241__auto__))

6:52 Sgeo|web: ,(macroexpand '(and a b))

6:52 clojurebot: (let* [and__2241__auto__ a] (if and__2241__auto__ (clojure.core/and b) and__2241__auto__))

6:52 Sgeo|web: ,(macroexpand '(and a))

6:52 clojurebot: a

6:56 ambrosebs: Sgeo|web: wouldn't dynamic vars be a perf issue vs. algo.monads local bindings?

6:57 sounds slower

6:57 tomoj: (also, no bound-fn in cljs :/)

6:57 Sgeo|web: perf issues ... I guess people really care about that sort of thing :/

6:59 ambrosebs: Sgeo|web: I thought Clojure was supposed to be fast :)

6:59 Sgeo|web: <elliott> so you can only use one monad at once

6:59 Not entirely sure what he means

6:59 ambrosebs: I'd suspect protocol monads would be the fastest.

7:00 tomoj: is that conal?

7:00 Sgeo|web: tomoj: no

7:06 ambrosebs: Sgeo|web: what exactly do we need to know to be able to statically generate the required code?

7:06 Sgeo|web: ?

7:07 Need to know the expected type of the result of return

7:08 And/or have the code somehow know a function to use when return is called

7:08 ambrosebs: I assume langs like Haskell would have some sort of implicit arg?

7:09 (sorry, forgot exactly the issue, makes sense now)

7:10 Raynes: ambrosebs: You should learn Haskell.

7:10 ambrosebs: Raynes: agreed.

7:11 Sgeo|web: ambrosebs: you could say that return has an implicit arg, passed to it from the type checker

7:11 (return is just an ordinary function, btw, if that wasn't clear)

7:12 ambrosebs: Got it. return is polymorphic and the type checker infers and instantiates the correct types, *which then affect runtime*

7:13 Sgeo|web: Right

7:13 ambrosebs: Yes, I have scratched my head for awhile as how to achieve this in TC.

7:14 Could we possible make a new kind of function?

7:14 *possibly

7:15 Does everything here basically occur in a domonad?

7:17 Sgeo|web: No. domonad is basically clojure.algo.monads's macro for Haskell's do syntax

7:17 My idea is that with-monad would supply the information that the type-checker would normally supply. But you can use bind and return outside of any special syntax (at least, you could if the type-checker were supplying what it needed to to the runtime)

7:18 borkdude: I'm experimenting a bit with linuxes on a vps… when I use Arch on a 256 I see the memory is almost all used (with free), but when I try Debian on a 512 MB it's also almost used.. does debian really use twice as much when doing nothing, or does linux have a weird way of using memory that's not allocated?

7:18 (this is off-topic, but I do want to host a clojure app on it ;))

7:19 ambrosebs: Sgeo|web: Ok. Sounds like a lot of extra work.

7:19 Raynes: borkdude: Arch for a server is kinda like jumping off a bridge, or so I hear.

7:19 It feels good on the way down, but eventually you hit bottom and die.

7:19 borkdude: Raynes yes, I heared this

7:20 Raynes that's why I'm trying debian now

7:21 alex_baranosky: what's the best place to report a bug with the new reducers?

7:23 tomoj: curious, what's the bug?

7:24 ambrosebs: Sgeo|web: perhaps if we wrap each position that needs dyn vars provided with some macro, Typed Clojure can generate the right bindings for you.

7:24 Sgeo|web: dyn vars are just a substitute for having something like TC generate bindings

7:25 ambrosebs: oh right.

7:25 That was an optimistic suggestion :)

7:25 You should implement your idea.

7:26 I'd love to see it in action.

7:26 Sgeo|web: What would make sense is for all uses of return to accept an extra argument and TC fills it in

7:27 ambrosebs: Sgeo|web: yes.

7:28 Sgeo|web: I have Javascript stuff I was supposed to be writing tonight

7:28 Ugh

7:33 wei_: what happened to the s3 utils in noir?

8:05 borkdude: isn't this a bit weird, why memory usage increases after openjdk install?

8:05 https://www.refheap.com/paste/7439

8:10 I guess the +/- buffers cache is most important after reading up a bit on this

8:16 bonega: If I have a def-style macro, what are my options for getting doc-tools to pickup my docstrings?

8:16 I basically have something that evaluates to a defn-form

8:17 (doc thesymbol) works

8:17 clojurebot: excusez-moi

8:17 bonega: but the tools for generating documentation of course fails

9:16 borkdude: any advice on how to start and stop "java -jar someleinuberjar.jar" in a a script in /etc/init.d in debian?

9:17 yerinle: is there a way to import multiply java classes in one command (import '(java.util *)) ?

9:18 or do I have to import each class separately?

9:28 gfredericks: separately, though you can save space with (import '[java.util List Map ...])

9:33 borkdude: I guess this is kind of how people do it?

9:33 http://www.shayanderson.com/linux/add-startup-script-or-service-with-linux-on-bootup.htm

9:33 killall -v java… hmm

9:33 cmn: this is what pid files are for

9:34 borkdude: cmn tnx for the pointer, will read about it

9:34 cmn: just look under /var/run

9:36 borkdude: cmn yeah, it looks like I have to create my pid file manually for a .jar running?

9:37 cmn: your distribution may have helpers

9:38 borkdude: cmn I could also use this, what do you think? lsof -t /home/borkdude/twitter-service-0.1.0-SNAPSHOT-standalone.jar

9:38 cmn: on Debian and derivatives, start-stop-daemon(8) can do this for you

9:38 borkdude: cmn I'm using Debian

9:39 cmn: that would bind your startup script to a specific version of the service

9:41 borkdude: cmn yes, I could resolve that with a symbolic link, or isn't that your point?

9:42 cmn whatever, start-stop-daemon looks better

9:42 cmn: it would not let your script upgrade

9:42 as you'd be searching for something that's not running

9:57 jonasen: dnolen: I couldn't find any examples of (usage of) core.logic/cvar. I tried https://www.refheap.com/paste/7336 but that didn't work as I expected.

10:23 dnolen: looking at https://github.com/clojure/core.logic/blob/master/src/main/clojure/clojure/core/logic.clj#L4026 I also tried https://www.refheap.com/paste/7449 without success

11:08 yedi: does anyone have examples of people using clojure to do ML/AI?

11:19 mpenet: yedi: prismatic

11:20 yedi: right

11:20 i wish they would write more about their experiences with it

11:20 mpenet: yeah, they used to be more open. They removed all their repo from github

11:22 yedi: really?

11:22 whackkk

11:22 mpenet: they used to publish under getwoven (or woven) and then clj-sys orgs

11:22 there are some forks left here and there, but it's > 2yo

11:23 ex: https://github.com/seancron/work

11:25 arcatan: zenrobotics uses clojure to do ML/AI. they haven't written about their experiences either, though.

11:31 gfredericks: is joda the best way for doing math on dates (without time)?

11:34 mpenet: gfredericks: less painfull yes (using clj-time), when it's trivial stuff I just convert to long and do it manually, depending on the context

11:42 gfredericks: a long representing a day?

11:42 mpenet: a java.util.Date instance

11:42 but as I said, for trivial stuff

11:43 ,(.getTime (java.util.Date.))

11:43 clojurebot: 1355070867468

11:43 gfredericks: okay, so representing milliseconds

11:43 mpenet: yes

11:43 gfredericks: I'd rather avoid the redundant information

11:45 joda has LocalDate, which seems to be the closest to what I want

11:45 otherwise I'd just roll my own. local date math is a lot simpler than time.

11:51 borkdude: gfredericks wasn't there a library for this, clj-time?

11:52 it just wraps joda

11:56 gfredericks: right of course

11:56 * gfredericks herp derps

11:57 * gfredericks presents lein-cljsbuild with an award for "easiest library name to pronounce out loud"

11:57 gfredericks: borkdude: the readme doesn't suggest it handles bare dates explicitely

11:58 borkdude: gfredericks don't know how well it's maintained either, never really used it

12:02 gfredericks: woah; the clj-time project.clj uses numeric keywords (e.g., :1.2)

12:02 I think I saw an issue on jira complaining that the reader accepts those

12:46 devn: gfredericks: i think the documentation for edn makes that complaint null

12:55 solussd: does anybody know how to tell the clojurescript compiler to minify?

12:58 nevermind, looks like setting :pretty-print to false does it

13:07 bsteuber: solussd: you might want advanced mode

13:08 solussd: yup, i set it to pretty-print false when compiling advanced mode (compiling clojurescript code via noir-cljs)

13:08 devn: bsteuber: if you're not using external javascript libraries definitely use :optimizations :advanced

13:08 seangrove: Jesus, there are too many videos to watch from the clojure eXchange

13:08 devn: lol

13:09 solussd: using advanced + pretty-print took a 780KB clojurescript file down to 149KB. I think that's noticable to clients. :)

13:09 bsteuber: :)

13:09 solussd: (+pretty-print false)

13:15 gfredericks: solussd: I bet it gzips quite well as well

13:15 solussd: no doubt

13:15 gfredericks: I gzipped an advanced CLJS file that was about 3x the size of jquery, but when they were both gzipped they were almost the same

13:16 solussd: clojurescript is a godsend.. I *hate* writing javascript- totally breaks my flow. Clojurescript + the fetch XHR library makes it almost fun. :)

13:23 gfredericks: my `lein repl` keeps timing out while it compiles

13:24 bsteuber: sometimes happens to me, too

13:24 I just do lein compile first then

13:32 ivan: someone on the mailing list needs to know which Closure Library jar actually contains third_party

13:32 or perhaps he must make his own or something

13:50 dnolen: tomoj: yes about the patch for the new threading operators

13:51 jonasen: you need to look at how cvars are used in the simple unifier - I don't really want to explain any high level interfaces much because they are bound to change soon.

13:54 * gfredericks fights with data readers

13:56 gfredericks: I feel like I've had this issue before. I enter a data-reader literal at the repl, and it prints a runtime exception. But then *1 is bound to the correctly read form.

13:57 (the exception claiming that it doesn't know about the tag I used)

13:58 * gfredericks tries a later version of 1.5

13:59 jonasen: dnolen: I'll take a look, thanks

14:02 dnolen: jonasen: basically cvars aren't really meant to be anywhere except to support the simple unifier - if you're using run* they are completely unnecessary.

14:02 "meant to be used", I mean.

14:03 amalloy: gfredericks: i wouldn't be too surprised to hear it's a problem of nrepl (or whatever repl frontent) having a different set of data readers than your app

14:03 gfredericks: amalloy: yeah I started thinking that, because anything not involving the repl seems to work fine

14:03 dnolen: jonasen: because of that I don't believe I've done any work to guarantee they are actually run in the general case - if you look at the simple unifier you'll see there is some extra code to ensure they are actually run.

14:06 jonasen: dnolen: ok, so when using run* i should drop down to 'project' instead

14:06 dnolen: jonasen: no

14:07 jonasen: you don't need project if you have constraints

14:07 jonasen: what I'm saying is that cvar is not a part of the API at all

14:07 jonasen: it's an implementation detail for the simple unifier

14:08 jonasen: it sounds like your use case is simple and you're already using run* in kibit right?

14:11 jonasen: if that's the case try defc which is likely to become something people can actually use, (defc numberc [x] (number? x)), (run* [q] (numberc q)), (run* [q] (numberc q) (== q "foo"))

14:22 jonasen: dnolen: what's the difference between constraints and core.logic/pred?

14:23 dnolen: jonasen: do you mean predc?

14:23 jonasen: no, I mean https://github.com/jonase/core.logic/blob/master/src/main/clojure/clojure/core/logic.clj#L2005

14:23 It's the "non-relational", right?

14:24 dnolen: jonasen: yes that's non-relational, clause order matters.

14:25 jonasen: constraints basically defer their execution until some or all arguments have become ground. so they allow you to work relationally.

14:26 jonasen: now that we have constriants any usage of project is pretty much discouraged.

14:27 jonasen: I see. Could you give a minimal example of using constraints with the unifier?

14:27 rodnaph: interop question - how do i call a java method with no args? (.getMessages folder) is giving me the error that no property getMessages exists...) have read the docs and it seems this should work?

14:28 gfredericks: yep, should work

14:29 rodnaph: gfredericks: ok thanks, must be something else i'm doing then. will keep trying.

14:30 dnolen: jonasen: I don't have a minimal example because I haven't decided how that is going to work.

14:30 jonasen: Kevin and I wrote something up that I think could work but I need to implement it.

14:31 samflores: I believe that it was asked millions of times, but what's the most idiomatic way to load libs/namespaces: require or use?

14:32 gfredericks: require

14:33 jonasen: dnolen: are you considering (? x number?), or some other syntax? Can I read what you have written, link?

14:33 zilti: gfredericks: Why that? When using :as, aren't they pretty much the same?

14:34 gfredericks: zilti: the use functionality has been added to require, so I think use is quasi-deprecated

14:34 samflores: gfredericks: thanks.

14:35 zilti: gfredericks: Thanks.

14:35 I have a library here that's not in a repository. I placed it in projectroot/lib, how do I tell Leiningen to use it?

14:36 gfredericks: leiningen really really wants that library in a maven repo

14:36 zilti: But I really really don't want to create a repo just for that jar file

14:37 gfredericks: you have to argue with leiningen about it for twenty minutes first

14:37 dnolen: jonasen: 90% sure it'll work by passing a map of lvars or sets of lvars -> constraints

14:37 gfredericks: zilti: maven has a local repo on your computer

14:38 dnolen: jonasen: http://gist.github.com/4156747

14:38 zilti: gfredericks: Ah, yes, the .m2 dir..

14:39 gfredericks: zilti: there are maven commands for adding jarfiles there

14:39 I think install-file is the main one

14:39 you'll need a pom

14:43 jonasen: dnolen: thanks for your help. I was confused about A) what cvars were meant to be used for (I thought you could use them interchangeably with lvars) and B) that I could use constraints (today) with the unifier. Things are clearer now.

14:43 dnolen: I'll take a look at the unifier proposal

14:45 dnolen: jonasen: sorry for the confusion. yet constraints work great today when working directly w/ the run* interface. the high level interface is still getting sorted out.

14:45 yet -> yes

14:46 jonasen: and if I want to use constraint with (run* ...) I should pre-define my constraints with (defc ..)

14:54 zilti: lein-localrepo plugin looks POMising.

14:57 * gfredericks guffaws silently

15:03 jonasen: dnolen: Is this the correct usage of predc (It seems to work): (run* [q] (== 3 q) (predc q number?))? And should predc be used instead of the old pred?

15:06 bordatoue: in clojure how do i implement a queue where insertion at the rear and deletion at the head

15:06 gfredericks: there's a queue data structure

15:06 ,(into clojure.lang.PersistentQueue/EMPTY [2 3 4])

15:06 clojurebot: #<PersistentQueue clojure.lang.PersistentQueue@6b58c280>

15:06 bordatoue: gfredericks: can you make use of list to attain this behaviour

15:07 gfredericks: bordatoue: if you're interested in implementing one you could google the baker's queue

15:07 otherwise the PersistentQueue type should work fine

15:07 lists will not naively work, as you probably suspect

15:08 bordatoue: thanks gfredericks

15:09 jonasen: dnolen: What is the difference between (defc numc [x] (number? x)) and (defn numc [x] (predc x number?))?

15:11 bordatoue: gfredericks: i couldn't find information on persistentQueue, i have been searching clojure datastructure,http://clojure.org/data_structures is this a part of clojure data structure

15:11 gfredericks: it's built in, just not well documented

15:11 mthvedt: does clojure/lein support remote debuggers?

15:11 gfredericks: ,(-> clojure.lang.PersistentQueue/EMPTY (conj 7) (conj 3) (conj 4) (pop))

15:11 clojurebot: #<PersistentQueue clojure.lang.PersistentQueue@8d94be90>

15:11 gfredericks: ,(-> clojure.lang.PersistentQueue/EMPTY (conj 7) (conj 3) (conj 4) (pop) seq)

15:11 clojurebot: (3 4)

15:12 gfredericks: bordatoue: you can get the empty queue as per above, and use conj/pop/peek as necessary

15:13 bordatoue: gfredericks: is there any way to know what interfaces this type inherits and the methods inherited by the interfaces

15:13 gfredericks: ,(ancestors clojure.lang.PersistentQueue)

15:13 clojurebot: #{clojure.lang.Seqable java.lang.Iterable clojure.lang.IPersistentStack java.util.Collection clojure.lang.Obj ...}

15:14 gfredericks: bordatoue: the clojure source is always available as well

15:14 bordatoue: cool, is this the only datastructure that inherits IPersistanceStack

15:14 gfredericks: it'll be in there with the java code

15:15 no vectors do as well

15:15 in fact it is odd to me that a queue would want to be considered a stack

15:15 oh and lists are stacks

15:16 bordatoue: gfredericks: so a pop on queue pops from head whereas pop on a vector from the rear

15:16 gfredericks: yep

15:17 it pops from whence it is efficient to pop

15:17 bordatoue: cool, thanks for the information. Its been helpful

15:17 gfredericks: no probalo

15:24 dnolen: jonasen: I haven't made any promises about anything in 0.8.0

15:24 jonasen: but predc is a little bit more flexible then using defc.

15:26 jonasen: defc is more likely to survive - and yes you should prefer a constraint based solution like predc / defc over pred

15:33 mpenet: bordatoue: you can also use this fn https://gist.github.com/2053633 to get an overview of the ancestors. ex: https://gist.github.com/4121044

16:04 thorwil: is there a way to take a var as argument to a function and to use the varname to build a keyword in the function?

16:05 gfredericks: like you want to turn #'first into :first?

16:06 Bronsa: , (keyword (.sym #'+))

16:06 clojurebot: :+

16:07 bbloom: Bronsa: or with metadata rather than interop:

16:07 ,(-> #'+ meta :name keyword)

16:07 clojurebot: :+

16:07 Bronsa: oh, that's better

16:08 thorwil: Bronsa: that does not work within a fn

16:09 gfredericks: here is the worst way I can think of to do it on short notice:

16:09 ,(-> #'first str (clojure.string/split #"/") last clojure.string/reverse (str ":") clojure.string/reverse read-string)

16:09 clojurebot: :first

16:09 Bronsa: thorwil: are you trying to do eg (fn [x] (-> x var .sym keyword))?

16:10 gfredericks: presumably worse methods could be developed if it was important

16:10 thorwil: Bronsa: yes

16:10 Bronsa: you can't do that

16:10 gfredericks: oh oh are we about to learn about macros?

16:11 hyPiRion: gfredericks: an interesting method, indeed.

16:11 thorwil: gfredericks: what i want is trivial with macros

16:11 gfredericks: thorwil: oh is that why you were asking about functions specifically?

16:11 thorwil: i just thought for a moment there might be a more flexible fn based approach

16:12 yes

16:12 gfredericks: either the function has to accept a var instead of a symbol, or you need to use resolve to turn a symbol into a var -- but know that the latter is namespace-relative

16:14 hyPiRion: ,((fn [foo] (-> foo meta :name keyword)) #'+)

16:14 clojurebot: :+

16:14 hyPiRion: With the name itself (e.g. +) it's impossible.

16:14 As a function, that is

16:16 thorwil: hmm, that might do it

16:16 thanks folks, gotta get back to this tomorrow. and likely read up on smybols/var/resolve :)

16:38 tgoossens: how can i do this: (defn add [& args] (+ ?????)) (i know i can use reduce for such things but that's not the point

16:39 ssideris: tgoossens: what are you trying to achieve?

16:39 tgoossens: (defn create [class* & args]

16:39 (new class* args))

16:40 how can i get the args right?

16:40 concrete example

16:40 ssideris: I think you may be looking for (defn add [& args] (apply + args))

16:40 yeah apply should work

16:40 ToxicFrog: This may be a stupid question but couldn't you just do: (def create new) ?

16:41 kmicu: , (doc apply)

16:41 clojurebot: "([f args] [f x args] [f x y args] [f x y z args] [f a b c d ...]); Applies fn f to the argument list formed by prepending intervening arguments to args."

16:41 kmicu: tgoossens: ok?

16:41 tgoossens: hmm myes

16:41 i think i get it

16:41 kmicu: , (+ 1 2 3 4)

16:41 clojurebot: 10

16:41 kmicu: , (apply + [1 2 3 4])

16:41 clojurebot: 10

16:42 Raynes: Yikes https://github.com/cgrand/enlive/pulls

16:42 :\

16:42 Guess that's where all pull requests go to die.

16:42 kmicu: submitted to cgrand/enlive 2 years ago...

16:43 tgoossens: ,(apply new String)

16:43 clojurebot: #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: new in this context, compiling:(NO_SOURCE_PATH:0)>

16:43 tgoossens: why doesn't that work but

16:43 mpenet: apply wont work with new

16:43 tgoossens: (new String "a")

16:43 ,(new String "a")

16:43 clojurebot: "a"

16:43 tgoossens: why?

16:43 clojurebot: why is the ram gone is <reply>I blame UTF-16. http://www.tumblr.com/tagged/but-why-is-the-ram-gone

16:43 kmicu: why new? :/

16:43 tgoossens: i'm making a tool in clojure for manipulating java objects to study them

16:44 don't be afraid i'm not trying to do OO in clojure :-)

16:44 ToxicFrog: tgoossens: "new" is a special form, not a function or macro

16:44 mpenet: special form for java interop, I think you at least need to know the number of args, and then use a lambda to wrap the calls

16:44 or use some java magic I don't know about

16:44 ToxicFrog: ,(doc new

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

16:44 ToxicFrog: ,(doc new)

16:44 clojurebot: Huh?

16:44 ToxicFrog: Dammit clojurebot

16:44 tgoossens: lol

16:45 tardis.core=> ,(doc new)

16:45 -------------------------

16:45 new

16:45 (Classname. args*)

16:45 (new Classname args*)

16:45 Special Form

16:45 The args, if any, are evaluated from left to right, and

16:45 passed to the constructor of the class named by Classname. The

16:45 constructed object is returned.

16:45 Please see http://clojure.org/java_interop#new

16:45 nil

16:45 ToxicFrog: Yes, I know, I was trying to get clojurebot to display that for your benefit.

16:45 Raynes: dsantiago: tinsel is still faster than enlive and capable of the same things, right?

16:45 tgoossens: i know

16:45 and thats why i posted it

16:45 because mr clojurebut didn't want to :p

16:45 kmicu: tardis x])

16:46 dsantiago: Raynes: I don't know, has enlive been extensively rewritten? I haven't heard otherwise.

16:46 Raynes: Nope.

16:46 tgoossens: i don't have any idea on how to achieve what i want atm :p

16:46 Raynes: dsantiago: You still maintain tinsel, right? I mean, when it needs maintained of course.

16:46 dsantiago: Raynes: It's capable of doing many of the same things, but not all.

16:46 I do consider it maintained. Don't know of any problems, can't think of anything to add. Works for me.

16:47 kmicu: tgoossens: can you describe what do you want?

16:47 Raynes: dsantiago: I need to use *something* to transform some markdown code that has been transformed to HTML before storing it in the db.

16:47 * ToxicFrog fiddles with macros

16:47 kmicu: , (map #(new String %) ["a" "b" "c"])

16:47 clojurebot: ("a" "b" "c")

16:47 dsantiago: Raynes: I think tinsel is probably not a good match for that.

16:48 Raynes: That's sad.

16:48 tgoossens: kmicu: i want a function (create classname & parameters)

16:48 dsantiago: tinsel is for pre-parsed templates. Things that aren't going to change. It actually invokes the compiler on each template to make it go fast.

16:48 Raynes: Enlive has 11 open pull requests and a version range.

16:48 dsantiago: That is going to be much slower than just parsing and interpreting the template.

16:48 For a one-shot, I mean. It's a pay-up-front to go fast a million times type model.

16:50 tgoossens: i'll just experiment until i have something that works

16:50 probably have to write a macro

16:50 a nice challenge for me :p

16:50 :)

16:53 Raynes: dsantiago: I'm gonna see if I can do a little work on a fork of enlive. Also, hickory is cool. Thank heavens for jsoup, amirite?

16:54 sshack: Are there any decent split testing libraries for clojure?

16:54 dsantiago: Raynes: I was going to suggest you pull a bultitude on it, if that's the case.

16:54 And yes, jsoup is fantastic.

16:54 Raynes: dsantiago: I have this nasty habit of deciding to maintain projects and rewriting half of them and stuff and then hating myself in the morning.

16:55 dsantiago: Raynes: I have a very similar problem.

16:57 ghengis: where do clojure programmers usually publish release announcements?

16:57 mpenet: ghengis: on the mailing list

16:57 ghengis: cool, thanks

16:59 tomoj: where did "ANN: foo" come from?

16:59 ToxicFrog: tgoossens: does this work?

17:00 tomoj: oh, just.. usenet, says wikipedia

17:00 ToxicFrog: ,(defmacro create [class* & args] `(new ~class* ~@args)) (macroexpand '(create String "a" "b" "c"))

17:00 clojurebot: #<Exception java.lang.Exception: SANBOX DENIED>

17:00 tgoossens: wow

17:00 ToxicFrog: ,(printf "eat me clojurebot")

17:00 clojurebot: eat me clojurebot

17:00 tgoossens: cool

17:01 ToxicFrog: Anyways that appears to work for me locally

17:01 tgoossens: what does the ~@ exactly?

17:01 mpenet: tgoossens: unsplices the sequence [a b c] becomes a b c

17:01 tgoossens: interesting

17:01 ToxicFrog: That's an "unquote-splice", replaces the symbol with its sequence-contents.

17:02 user=> (macroexpand '(create String "a" "b" "c"))

17:02 (new String "a" "b" "c")

17:02 Plain "~" would cause it to expand to (new String ["a" "b" "c"])

17:02 tomoj: you can't apply that macro, though..

17:03 tgoossens: hmmm

17:03 i get what it does

17:03 ToxicFrog: Hmm, point.

17:03 tgoossens: i don't get how it does it

17:06 amalloy: &'`(new ~class ~@args) ;; maybe instructive?

17:06 lazybot: ⇒ (clojure.core/seq (clojure.core/concat (clojure.core/list (quote new)) (clojure.core/list class) args))

17:07 amalloy: i mean, that is literally how ~@ works. `(new ~class ~@args) is identical to (concat (list 'new) (list class) args), or to (list* 'new class args), if you like

17:09 tomoj: (defn document [] js/document)

17:10 compiles to: function document() { return document }

17:10 expected?

17:10 ToxicFrog: tgoossens: can you expand on what you don't get about it? Did amalloy's explanation help?

17:11 tgoossens: toxicfrog: oh. Its just i have no experience at all with macro's so i was a bit confused

17:11 (and still am)

17:11 ToxicFrog: tgoossens: aah.

17:12 tgoossens: but i should just read the documentation

17:12 ToxicFrog: So, (defmacro create [class* & args] `(...)) is saying "when expanding macros, replace (create ...) with the `(...)"

17:13 Within that `(...), ~foo means "in the generated code, insert the value of foo" and ~@foo means "insert the contents of foo, which should be a list"

17:13 p_l: definitely better than syntax-rules :)

17:14 ToxicFrog: So, (create String "a" "b" "c") results in macro expansion with class* being String and args being ["a" "b" "c"]

17:14 tgoossens: mmmyes

17:14 ToxicFrog: `(new ~class* ~args) would expand into (new String ["a" "b" "c"]); using ~@args instead "unpacks" args, so you get (new String "a" "b" "c")

17:15 tgoossens: cool

17:16 ToxicFrog: (I think the fundamental thing to "get" here is that a macro is a function that takes some arguments and returns a code fragment - an abstract syntax tree - based on those. The `(...) is the AST to return; ~ and ~@ let you "fill in" parts of that with values at macro expansion time, rather than when the result of the expansion is actually executed)

17:17 tgoossens: i think i start to get it :)

17:17 *i'm starting

17:18 ToxicFrog: <3 macros

17:18 tgoossens: yeah its really amazing

17:18 once you start learning them

17:18 in java for example

17:19 when something was not possible

17:19 you had to think long time how you can "patch" / workaround that problem

17:19 here

17:19 ToxicFrog: And the fact that in lisp you're basically writing everything in ASTs already makes them go down much smoother than the equivalent in something like metalu.

17:19 *metalua.

17:19 tgoossens: "lets add a new feature!"

17:21 g2g

17:21 so long and thanks for all the fish ;)

18:23 jweiss: can the ns macro just create an alias to a ns without :require'ing it? (just for using namespaced keywords)

18:30 cemerick: jweiss: doesn't look like it. refer itself doesn't accept vectors (necessary for :as) anyway.

18:38 tomoj: into-kv: https://www.refheap.com/paste/f83eb49d4520e7522014c7395

18:38 bblöom: ^

18:38 but, seqs of pairs are not reduce-kv

18:38 should they be, somehow?

18:39 i.e. seq implements IKVReduce by assuming the values are pairs?

18:40 tpope: cemerick: do you have time to discuss this issue we've been going back and forth about in the channel?

18:41 cemerick: tpope: About 5 minutes. Hadn't been following the channel tho; do you mean the github issue?

18:41 tpope: yes the github issue

18:41 bbloom: ^

18:41 bbloom: tpope: yeah, i just saw the email

18:42 tomoj: bblöom: nvm, since you wanted (into {} (partition 2 kvs)), this is irrelevant

18:42 Raynes: !last

18:42 Wrong channel.

18:42 tpope: cemerick, bbloom: the session business I demonstrated is weird, but since clone works, it's not really a big deal

18:43 the main issue is where is out and err disappearing to

18:43 bbloom: cemerick: i was surprised to see string keys rather than keywords. i dunno anything about nrepl, but i was about to warn tpope and his fledging clojure skills that keywords and strings aren't interchangable, but then i saw your example used them, so maybe they are interchangeable for nrepl :-)

18:43 cemerick: tpope: the sid in your example is nil, which is bizarre

18:44 bbloom: they're turned into keywords by the time middleware/handlers see them

18:44 bbloom: cemerick: makes sense

18:44 cemerick: they're strings if you're using the default bencode transport

18:44 tpope: cemerick: err, it wasn't when I was playing with it interactively

18:44 cemerick: s/strings/strings on the wire

18:44 tomoj: though (into-kv {} (partition 2 kvs)) would work if (partition 2 kvs) were IKVReduce.. hmm

18:44 cemerick: tpope: spooky

18:44 bbloom: cemerick: gotcha.

18:45 tpope: cemerick: in fact, I

18:45 cemerick: tpope: re: "parsing"; you really need to consume things in terms of messages, not e.g. grepping for "done", etc.

18:45 dunno how that percolates into vimscript, etc

18:45 tpope: just added a println on sid and it's set for me

18:45 the error that comes back mentions the same sid

18:46 cemerick: very spooky

18:46 tpope: what rev of nREPL?

18:46 tpope: 0.2.0 beta 9

18:46 cemerick: hrm

18:46 tpope: try 0.2.0-RC1

18:47 I quashed some wonkiness between b9 and b10/RC1

18:48 tpope: cemerick: same

18:48 cemerick: hrmph

18:48 tpope: I'll sink into it tomorrow morning

18:48 tpope: cemerick: so nrepl/client just slurps up everything available within 100ms, correct?

18:48 tomoj: ";;aseqs are iterable, masking internal-reducers" in clojure/core/protocols.clj. so this impl for ASeq relies on the undefined choice of that over the Iterable impl? interesting...

18:48 tpope: or whatever timeout you pass in

18:48 cemerick: tpope: right

18:49 though, it's not slurping; it's a seq of responses

18:49 tpope: okay

18:49 so what happens when something takes longer than 100ms to eval?

18:49 I guess what I'm getting at is how does a client know when to print a prompt again?

18:50 cemerick: you'll get an empty seq

18:50 For interactive usage, most clients just wait indefinitely

18:50 though I understand you can't do that

18:50 tpope: well my client isn't in clojure, so I'm not sure how "empty seq" translates

18:50 cemerick: oh, no data, EOF

18:51 tpope: my socket should actually eof?

18:51 cemerick: The timeout is critical for noninteractive use cases, where you don't want a tool blocking on getting e.g. code completion data

18:51 tpope: sorry, being fast and loose with terminology

18:52 there will be no data

18:52 tpope: I'm trying to find the difference between "no data" and "no data *yet*"

18:52 cemerick: Always the latter

18:52 This is related to the (tricky) semantics of "done"

18:53 e.g. if you've sent an eval message with a given ID, and it spins up a future that prints stuff, when do you send a "done" message?

18:54 tpope: well, I kind of have to give up on that case. which is why I keep going back to a "when does a client print its prompt"

18:54 cemerick: right now, nREPL's eval middleware prints "done" when all forms sent in the code have evaluated, but messages with the same ID may be seen later with :out and :err entries

18:54 tpope: okay

18:54 stuff that happens after that "done" I'm going to have to give up on

18:54 bbloom: cemerick: done-ness is tricky in general, then cancel-ing is even more tricky… clojure's futures lack a notion of a process tree

18:55 cemerick: bbloom: right; for exactly that reason, nREPL's interrupt won't touch futures, threads, queued agent sends, etc.

18:56 tpope: all this aside, the blocking issue is out and err. If I send an eval request on a new request with an existing session, I don't get out and err back

18:56 new connection*

18:57 bbloom: at the risk of venturing off onto a tangent, there's some work going on surrounding listenable futures and future seqs. i'm pushing for process trees :-)

18:58 cemerick: tpope: well, something's wonky there.

18:58 First, I'm going to figure out why I'm seeing something different than you with the code you posted.

18:58 tpope: got to run; I'll be back tomorrow morning.

18:59 tpope: okay cheers

19:00 bbloom: tpope: a simple @cemerick spurred him to help. maybe i'll @kotarak and we can get the VimClojure runtime files "decomplected" too :-)

19:00 tpope: yeah I've been meaning to reach out :

19:00 what with my snarky README and all

19:00 bbloom: tpope: i can just open a ticket to eliminate dependency on VimClojure, this way i'm the bad guy :-P

19:01 tpope: :)

19:03 bbloom: I'd love for the static versions to ship with vim

19:03 it's weird that he started them separate, but then complected them

19:03 bbloom: tpope: i'll mention that in the ticket. i don't know enough about the vim distro processes to help there

19:04 tpope: bbloom: you email bram and say "hey I wrote these runtime files I think should be included" and he replies like "k"

19:04 bbloom: tpope: heh, simple enough

19:04 tpope: https://github.com/tpope/vim-foreplay/issues/12

19:05 tpope: oh wow, you weren't kidding

19:07 bbloom: tpope: i've inadvertently been the guy who writes the inflammatory email so many times, that i've learned when to intentionally apply to quasi-inflammatory email

19:07 it's a curse.

19:12 tpope: time to play good cop I guess

19:17 okay guys! so I'm actually trying to learn clojure myself

19:17 bbloom: tpope: happy to help. if you have any questions, fire away

19:18 tpope: I thought a good first task might be "parse a netrc". it basically looks like machine foo.bar login baz password quux over and over

19:18 simple enough, right?

19:18 so here's my first stab: https://www.refheap.com/paste/7456

19:19 bbloom: (doc into)

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

19:19 bbloom: ,(seq {:x 1 :y 2})

19:19 clojurebot: ([:y 2] [:x 1])

19:20 bbloom: ,(into {} [[:x 1] [:y 2]])

19:20 clojurebot: {:x 1, :y 2}

19:20 bbloom: tpope: ^^ that should help you clean up your reduce block

19:20 tpope: let me try!

19:21 okay, that was simple. no more outer reduce

19:21 bbloom: tpope: new pastie?

19:22 tpope: bbloom: https://www.refheap.com/paste/7457

19:22 bbloom: (doc ->>)

19:22 clojurebot: "([x form] [x form & more]); Threads the expr through the forms. Inserts x as the last item in the first form, making a list of it if it is not a list already. If there are more forms, inserts the first form as the last item in second form, etc."

19:22 bbloom: (doc ->)

19:22 clojurebot: "([x] [x form] [x form & more]); Threads the expr through the forms. Inserts x as the second item in the first form, making a list of it if it is not a list already. If there are more forms, inserts the first form as the second item in second form, etc."

19:23 bbloom: those are useful for flattening the nesting of multistep proceedures

19:23 so you can have netrc-tokenize, reduce, and into all at the same level and appear in the order that they are evaluated

19:23 tpope: okay, I know the threading macros. I'm missing how to apply them here

19:24 that's enough for me to take a stab

19:26 ToxicFrog: tpope: rather than going (into (reduce (netrc-tokenize ...))), you can (->> ... netrc-tokenize reduce into) or similar.

19:29 bbloom: we'll just keep providing one hint at a time until it's pretty!

19:31 tpope: okay I think I got it: https://www.refheap.com/paste/7459

19:33 the peek and pop business was what felt particularly ugly

19:34 bbloom: tpope: yup

19:34 peek and pop aren't that common to use

19:34 let me see…. hm

19:36 tpope: I should add that I have additional requirements that may well render this moot :)

19:36 bbloom: tpope: eh, the learning won't be moot

19:36 tpope: yeah I agree

19:36 which is why I didn't lead with "help me bolt more crap onto this"

19:36 bbloom: so i'm not familiar with netrc files

19:37 tpope: if you've ever used heroku, you have one

19:37 bbloom: heh ok

19:37 tpope: all they are is login/passwords for hostnames

19:37 bbloom: the goal is to get a map of machine name to login credentials?

19:37 amalloy: i think you want to partition your input, tpope. instead of trying to do everything in the reduce step on a single k/v, split it up into chunks between each instance of "machine"

19:37 tpope: yes

19:38 bbloom: the goal is to get something like {"mylaptop" {:username "brandon" :password "abc123"}}

19:38 ?

19:38 tpope: bbloom: yeah

19:38 I have tests actually, let me paste them

19:38 bbloom: tpope: amalloy is right, netrc-parse should be broken down into a part that parses individual records, and one that parses the whole thing

19:39 tpope: I agree

19:39 bbloom: each individual record should be [machine-name credentials]

19:39 and then it's trivially to map that over a file and into {}

19:42 tpope: tests: https://www.refheap.com/paste/7461

19:42 first two pass, third is a new requirement: a "default" machine

19:43 I bring up the default machine now because this two pass thing seems like a good time to introduce it

19:44 okay, so how would I split it into machines?

19:45 bbloom: ,(clojure.string/split "machine foo login bar machine baz login quux" #" +")

19:45 clojurebot: ["machine" "foo" "login" "bar" "machine" ...]

19:45 tpope: got that. my re-seq was basically the same thing

19:45 bbloom: oh dur, yeah

19:46 (doc partition-by)

19:46 clojurebot: "([f coll]); Applies f to each value in coll, splitting it each time f returns a new value. Returns a lazy seq of partitions."

19:46 bbloom: you can use sets as a predicate:

19:46 ,(#{:foo} :bar)

19:46 clojurebot: nil

19:46 bbloom: ,(#{:foo} :foo)

19:46 clojurebot: :foo

19:46 tpope: hmm

19:47 bbloom: ,(partition-by #{"machine"} ["machine" "foo" "bar" "machine" "baz"])

19:47 clojurebot: (("machine") ("foo" "bar") ("machine") ("baz"))

19:47 bbloom: (doc take-nth)

19:47 clojurebot: "([n coll]); Returns a lazy seq of every nth item in coll."

19:47 tpope: bbloom: what if someone's login or password *is* machine?

19:47 bbloom: tpope: heh, good point....

19:47 amalloy: tpope: do you have a sample input somewhere? i haven't really been following but this isn't a hard problem if i know the inputs

19:48 tpope: amalloy: I can make one, sec

19:48 bbloom: i don't know enough about the format, i would have to read the man page to see how machines are actually parsed...

19:49 amalloy: i'm trying to avoid giving him a solution, he's trying to learn :-)

19:50 tpope: oh, i didn't realize that each field is labeled

19:50 (parition 2 ["machine" "foo" "login" "bar" "password" "baz" "account" "quux"])

19:51 (parition 2 ["machine" "foo" "login" "bar" "password" "baz" "account" "quux"])

19:51 ,(parition 2 ["machine" "foo" "login" "bar" "password" "baz" "account" "quux"])

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

19:51 bbloom: er, typing is hard.

19:51 ,(partition 2 ["machine" "foo" "login" "bar" "password" "baz" "account" "quux"])

19:51 clojurebot: (("machine" "foo") ("login" "bar") ("password" "baz") ("account" "quux"))

19:51 bbloom: then you can use partition-by and your predicate can be on the first element

19:51 or split-with and a loop

19:52 tpope: amalloy, bbloom: https://gist.github.com/4247721

19:53 the macdef stuff is gross. you can omit it if it's simpler

19:54 bbloom: okay, that's pretty reasonable, although it breaks down at the "default" cases

19:54 case*

19:54 bear with me, ssh has gone to lag city

19:57 amalloy: yeah, if you want to support "default" rather than "machine default" or something, i don't think anything pretty works well. possibly the best you can do is a reduce over each token, where the reduce is running a miniature little state machine that reminds you what to do with the next token

19:58 tpope: well, it's strangely reassuring to hear that the elegant solution I couldn't find probably doesn't exist

19:59 bbloom: #{"default" "machine"} is a reasonable predicate to split by

19:59 tpope: is it easy to show me what that state machine might look like?

20:00 bbloom: true, and even/odd sorts out which it is. but you're back to the "what if their login is machine?" problem

20:00 bbloom: oh, dur, again… default doesn't take an argument

20:01 tpope: it's such a simple yet infuriating format

20:01 bbloom: heh, yeah, b/c you can just imagine that the underlying original implementation is a manual C loop :-)

20:01 anyway, ignoring "real" parsing strategies

20:01 tpope: btw, curl and wget both read this file, which is what makes it handy for api credentials

20:02 bbloom: a simple loop is the way to go

20:02 tpope: does this mean I have to use recur?

20:02 bbloom: maybe? :-P

20:02 so imagine a simple recursive decent parser for a moment

20:03 you have some token stream and some AST accumulator

20:03 but here, you don't want to mutate the token stream

20:03 so each parse production function should return two values: the AST as transformed, and the new token stream

20:04 so if you have ["machine" "foo" "machine" "bar"] and you parse-machine on that, you should get back [{"foo" {}} ("machine" "bar")]

20:05 if you use that calling convention, you can write a simple recursive solution

20:06 tpope: okay

20:06 bbloom: then you can loop/recur at the top level until your input token stream is empty

20:07 tpope: sounds totally possible

20:07 do you have any thoughts about macdef?

20:08 bbloom: tpope: what's it do exactly?

20:08 tpope: bbloom: slurps up till the next double newline as a string

20:09 bbloom: so in that example, you'd get {"ftp.server" {... :macdefs {"somemacro" "cd somewhere\n..."}}}

20:09 bbloom: ah, i see… hm

20:09 you need double-newline in your token stream :-/

20:10 tpope: I mean, I bet virtually nobody needs this

20:10 but if I was to, say, package it up and release it, it'd be nice if it implemented the full spec

20:10 bbloom: so #"\S+" probably isn't sufficient for re-split

20:10 tpope: yeah

20:10 I'd think you'd need to switch to some sort of reader api

20:11 bbloom: significant whitespace is annoying for parsers :-P

20:12 amalloy: tpope: https://www.refheap.com/paste/7462 is a state-machine impl, which doesn't handle macdef at all

20:13 jonasac: am i insane for thinking that always aliasing imports and always qualify imported functions with the alias ?

20:13 is a good idea

20:13 bbloom: jonasac: nope

20:14 use is mainly for interactive work and some DSL-ish libraries

20:14 tpope: amalloy: awesome man

20:15 amalloy: and it's just splitting on whitespace, so if there's some significance to newlines vs spaces you probably need to toss the whole thing in the trash

20:15 tpope: amalloy: I see you raising plain old Exception. is that common for this sort of miscellaneous stuff?

20:15 amalloy: no significance except macdef :/

20:15 bbloom: tpope: unfortunately, yes :-/ (it's annoying for CLJS portability)

20:15 amalloy: oh, i dunno. something else might be better, but i rarely bother with anything more than Illegal(State|Argument)Exception

20:16 jonasac: bbloom: good, seen alot of code that don't do that tho, makes it harder to read

20:16 amalloy: and it wasn't clear which of those this is

20:17 tpope: amalloy: thanks for this. it may take me a bit to grok it

20:20 amalloy: you're welcome. keep bringing the light of clojure to the vim savages

20:21 tpope: :)

20:23 bbloom: parsing always winds up harder than you expect

20:23 i don't even bother with hacky parser attempts any more, i go straight to formal grammars :-)

20:24 * Hodapp <3 parser combinators

20:25 bbloom: tpope: although it's arc instead of clojure, there is a good example of parser combinators that Hodapp mentioned here: http://awwx.ws/combinator/toc

20:26 but i haven't found a parsing library for clojure that i really like yet… i've tried a few

20:27 tpope: neat

20:28 bbloom: combinators are fun

20:29 a long time ago i made a trivial bullet hell game out of combinators: http://code.google.com/p/bulletcombinators/

20:29 powerful technique

20:29 tpope: so long ago that google code was in fashion!

20:30 bbloom: nov 2009

20:30 :-P

20:30 tpope: okay, maybe not in fashion :P

20:30 bbloom: heh

20:31 i was still working for msft then…. git was practically unusable on windows still

20:31 so glad that period of my life is over....

20:34 brehaut: bbloom: the biggest problem with clojure parsing libraries is they all eventually fade into disrepair

20:40 bbloom: we've got max, max-key, but no max-comparer or similar?

20:45 amalloy: bbloom: i think that function is called sort

20:46 bbloom: well it's (first (sort …))

20:46 but sort is less efficient really, since max can be implemented O(N)

20:46 even if sort is lazy, i don't think first sort gives you linear time

21:00 stuartsierra: `sort` is not lazy.

21:01 You can implement "max-comparer" with reduce.

21:07 jonathanwallace: i'm attempting to use rich hickey's cartesian product with a couple of ranges which is giving me a lazy sequence like ((1 0) (1 -1)...)

21:07 i'd like to then use the first element in that sequence apply a function to it but i believe first element is being evaluated which is generating an error

21:12 i'd like to apply(map?) a function onto each element returned by cartesian-production function (found here https://github.com/richhickey/clojure-contrib/blob/2ede388a9267d175bfaa7781ee9d57532eb4f20f/src/main/clojure/clojure/contrib/combinatorics.clj#L107)

21:12 cmeiklejohn: it was good sharing a cab with you at rubyconf!

21:13 Apage43: (map somefn (cartesian-product …)) ?

21:15 cmeiklejohn: jonathanwallace: Oh, totally!

21:16 Small world :)

21:17 Apage43: jonathanwallace: depending on what you're trying to do you may just want for

21:17 ,(for [x [1 2 3] y [4 5 6]] (str x "," y))

21:17 clojurebot: ("1,4" "1,5" "1,6" "2,4" "2,5" ...)

21:26 jonathanwallace: cmeiklejohn: heh, yep

21:28 Apage43: when i try (map + (cartesian-product ..)) i get an error :(

21:28 ,(map + (cartesian-product (range -1 2) (range -1 2)))

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

21:29 jonathanwallace: but not that error :)

21:29 Apage43: ,(map (partial apply +) [[1 1] [1 2] [1 3]])

21:29 clojurebot: (2 3 4)

21:31 Apage43: cartesian-product returns a seq of seqs, so map + was calling + on seqs, instead of numbers

21:31 bbloom: stuartsierra: that's precisely what i did, i called it max-by: https://www.refheap.com/paste/7463

21:32 Apage43: I've needed that several times

21:32 jonathanwallace: Apage43: thank you so much

21:32 i'm only one month (maybe 4 hours total) and was ignorant of partial

21:33 s/only one month/only one month into learning clojure/

21:33 tomoj: there is also https://github.com/chrismgray/clojure-heap-sort

21:33 unfortunately not published anywhere

21:34 useful when you want a lazy seq instead of just the biggest element

21:34 Apage43: or perhaps a top-N, I'd guess

21:36 tomoj: I'd guess a strict top-N could be done more quickly directly than with a heap sort, dunno though

21:36 amalloy: wow, he's using a single vector to simulate a tree instead of just using an actual tree? really dedicated to performance, or slavishly transliterating from C, i wonder

21:37 tomoj: rewrite it and publish it, please :)

21:38 Apage43: there's a lot of existing writing on doing heaps that way, I expect it's not a perf thing.

21:39 amalloy: tomoj: i wrote lazy-shuffle; lazy-sort is someone else's problem :P

21:46 tomoj: (take-shuffled n coll) is statistically equivalent to (take n (shuffle coll)) ?

21:48 amalloy: tomoj: indeed, provided (<= n (count coll))

21:49 i don't really remember why i wrote it as take-shuffled instead of just lazy-shuffle

21:51 aaelony: On large data, I've found it faster to do something like (def random-int [upper-bound] (.nextInt (Random.) upper-bound))

21:51 if i remember correctly...

21:51 tomoj: so you can either have the output lazy (lazy-shuffle), or the input lazy (reservoir sampling). but not both, I assume?

21:52 I think you really don't want to create a new Random every time

21:52 aaelony: fine.

21:52 but rand-nth I've found to be really slow

21:53 tomoj: maybe because it counts the coll every time?

21:53 ..plus the nth every time

21:54 aaelony: yeah, unless there's a nice way to memoize it. but even so, sometimes i'd rather not count something very very large

21:54 tomoj: in that case, I think you want reservoir sampling?

21:54 but then it seems you have to decide ahead of time how many you want to pick..

21:55 aaelony: i'm content with picking a random number like above

21:55 tomoj: where do you get the upper bound if you don't count?

21:55 aaelony: I may know it already

21:55 or something large enough to suffice, that i know exists

21:56 amalloy: rand-nth is, as expected, egregiously slow for anything that is not both counted and indexed, but is pretty reasonable if you have that condition

21:57 aaelony: that's my experience too

21:57 tomoj: random-int seems a tiny bit faster than rand-int if you don't recreate the Random every time

21:57 s/a tiny bit/moderately/

21:58 aaelony: for me just separating the getting of the random int and then using it to get an nth has been faster

21:59 ideally there's an even faster way

21:59 amalloy: tomoj: you could probably have the input and output both lazy, if you can (a) count the input, and (b) produce the nth input item on demand without needing any other inputs

21:59 aaelony: perhaps best is to compute a set of random ints and then asking for the nth

21:59 when needed

22:00 tomoj: if you count the input, you don't have the input lazy (or you don't have what I meant when I said "input lazy")

22:01 amalloy: certainly you can't work on an input that is a lazy-seq

22:01 tomoj: assuming you want lazy output, right?

22:02 amalloy: i guess what i'm imagining is really just equivalent to (map f (lazy-shuffle (range n-items))

22:02 ie, a function to produce the nth item, and knowledge of the upper limit

22:03 aaelony: but, isn't (range n-items) wasteful and slow if n-items is large?

22:03 tomoj: would be interesting if (range n) were IIndexed

22:04 gfredericks: tomoj: so it'd have to be a special seq type, no?

22:04 tomoj: right

22:05 which means you have to go add it to all your protocols.. :(

22:05 gfredericks: it certainly could be, but if you're ever in a situation where you need that then you're doing it weird :)

22:05 amalloy: my patch to make range foldable is similar to making it indexed

22:05 gfredericks: not at all

22:05 gfredericks: amalloy: what? you disagree with something I said about clojure?

22:06 amalloy: clojurebot: note the date and time

22:06 clojurebot: multimethods are http://clojure.org/multimethods

22:06 tomoj: amalloy: how? there's no r/nth, and r/drop will still be O(n), yes?

22:06 gfredericks: amalloy: so anyhow I'm curious

22:06 amalloy: tomoj: but the same steps are involved. to fold it in chunks, you have to be able to ask for the nth through mth items

22:07 tomoj: I see, but that functionality is not exposed in a way that lets you skip in O(1)

22:07 since there's no IDrop or whatever

22:07 Sgeo|web: How many threading macros are there out there? As in, Enlive's do-> for example

22:08 amalloy: yeah

22:08 Sgeo|web: How many macros are there that are like threading macros except treating some values specially

22:08 gfredericks: Sgeo|web: well if you count libraries then it's difficult to give an exhaustive answer

22:08 Sgeo|web: Are there likely to be a lot

22:09 nightfly_: Probably

22:09 Sgeo|web: :o)

22:09 Given such a macro, it's easy to write bind...

22:12 The other direction is probably a very good idea too, a nice easy to understand way to use monads

22:15 brehaut: type annotations for conj are crazy

22:15 tomoj: the special treatment is that if the last step returned an m v, the next step is automatically bind instead of normal invoke?

22:18 does that cause trouble related to m (m a)?

22:28 frozenlock: Raynes: A little Noir question. On the top of your head, any ideas why when I use (flash-get :some-key), it returns something for two retrievals, instead of one like mentioned in the docs?

22:29 Raynes: No idea. It shouldn't.

22:29 I never saw that behavior.

22:30 frozenlock: Hmm... so it's _very_ probably in code.

22:30 Thanks

22:36 Raynes: frozenlock: If you can't figure it out, try to get a small reproduce case and create an issue on the lib-noir project.

22:41 Sgeo|web: tomoj: hmm?

22:42 Which direction are we talking? Making a threading macro from a monad? Each step in the threading is automatically bind

22:42 Hmm, although I guess that might be inconvenient in some cases?

22:43 For the maybe monad, can treat nil as nothing, everything else as Just whatever

22:43 For the Just Nothing case, we make a special type called Escape

22:43 (Escape. nil) corresponds to Just Nothing

22:44 Instead of Just (Escape. nil)

22:44 And you can escape escape, etc.

22:45 frozenlock: Raynes: Before I do, could you tell me if I'm missing something important here? Is there a need to be on a different page or something? https://www.refheap.com/paste/7465

22:46 Raynes: Oh. OH.

22:46 frozenlock: oh?

22:46 Raynes: frozenlock: Are you expecting that after the first call to flash-get, it'll vanish?

22:47 frozenlock: Well.. yes

22:47 Raynes: Yeah, that's how it used to work. Now it works for one *request*. Meaning, you can get the value multiple times, but it goes away after that request.

22:47 frozenlock: Oooooh :)

22:47 Raynes: frozenlock: I'll fix the dcos.

22:47 docs*

22:49 Sgeo|web: What special forms besides quote take lists and don't treat them like code?

22:49 frozenlock: I will just make my own with the session/swap! then. Thank you for the explanation!

22:50 Raynes: frozenlock: I released 1.3.0 tonight and Chris will be pushing the updated website… soon.

22:51 frozenlock: wait--- you mean 1.3.0 NOT beta4? :P

22:51 * frozenlock hugs Raynes

22:51 Raynes: I do.

22:51 <3

22:51 Nothing has changed from the last beta though.

22:52 It needed to be a final release so we could update all the documentation.

23:00 Sgeo|web: Hmm, auto-return like I envisioned could really suck in some circumstances

23:01 tomoj: I've been struggling with auto-return too

23:01 I think it could sometimes require satisfies? checks?

23:01 ..which are slow

23:16 sshack: Raynes any major changes in 1.3.0?

23:18 Sgeo|web: tomoj: my concern isn't performance

23:18 tomoj: my concern is, what happens when you give it whatever, and suddenly you accidentally give it a list (say, if you're in the list monad), and instead of acting like you expect it to, it treats it specially

23:19 Why should your code need to check "Oh, and if it's a list, do this extra thing"

Logging service provided by n01se.net