#clojure log - Oct 09 2012

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

0:02 technomancy: TimMc: unfortunately if you need something to work in the presence of profile operations you have to express it in terms of profiles

0:02 akhudek: callen: "If the LEIN_NO_DEV environment variable is not set, the server will monitor your source directory for file modifications, and any altered files will automatically be reloaded."

0:02 https://github.com/weavejester/lein-ring

0:03 technomancy: TimMc: so if you can use leiningen.core.project/add-profiles then it'll get preserved properly

0:03 callen: akhudek: hrm.

0:03 technomancy: the problem is that there's no way to reverse an operation like merging a profile, so we have to just save the pristine copy and operate on that

0:03 callen: now I just have to figure out how to start the jetty server.

0:03 akhudek: callen: lein ring server

0:04 it starts a jetty server

0:04 technomancy: I really don't get the point of keeping your dev jetty in a different process from your repl

0:04 callen: 'ring' is not a task. See 'lein help'.

0:04 akhudek: ^^

0:04 frio: callen: get lein2 :)

0:04 callen: frio: I am in lein2, that's why it broke

0:04 frio: oh? that works for me...

0:04 technomancy: callen: just start jetty from your repl

0:05 it's easy

0:05 callen: technomancy: that's what I've resorted to.

0:05 akhudek: technomancy: I like starting from the repl myself, though I haven't been abel to convince many others of this

0:05 technomancy: callen: it's so much simpler

0:06 keeping it in a separate process maybe makes sense if you use textmate or notepad or something, but if you have editor integration you should use it.

0:06 callen: oh you start it from your nrepl-jack-in

0:06 technomancy: yup

0:06 * callen fires his up instead of the terminal

0:06 technomancy: (start-jetty #'app {:port 8080 :join? false}) or whatever

0:07 callen: technomancy: do you use 'raw' ring, Noir, or something else?

0:08 well that was a fail, I edited code and it didn't reload.

0:08 so going back to my question, how do I make it auto-reload?

0:08 akhudek: callen: if you are doing the repl route, you can reload most functions in the standard way

0:08 callen: C-x C-e on my handler failed.

0:09 akhudek: but routes and enlive templates area bit different

0:09 callen: clojure.lang.Compiler$CompilerException: java.lang.IllegalStateException: index already refers to: #'reminders.core/index in namespace

0:09 ...not helpful.

0:09 so how do I auto-reload my code...routed handlers included?

0:10 akhudek: callen: could try wrap-reload, though I have not managed to get it to reload routes for some reason

0:10 * callen blinks

0:10 akhudek: oddly enough the lein-ring plugin does seem to work

0:10 http://clojuredocs.org/ring/ring.middleware.reload/wrap-reload

0:10 sorry, that's outdated

0:10 hold on

0:11 callen: if it doesn't reload the routes, it's not incredibly useful to me.

0:11 akhudek: see the bottom here: https://github.com/ring-clojure/ring/wiki/Interactive-Development

0:13 then be sure to reload you entire namespace

0:13 TimMc: technomancy: Thanks, that gives me a good start. I guess I can't reasonably make something that's compatible with both 1.x and 2.x, so I'll branch lein-otf.

0:13 akhudek: as to your question about noir vs ring, I prefer ring + compojure to noir myself.

0:14 tomoj: are fn* and loop* the only recur points?

0:15 callen: okay, I got it to do what I want now

0:15 I got lein ring server to work.

0:15 it seemed to auto-reload my code so that seems kosher now.

0:15 akhudek: thank you.

0:22 zackzackzack: How do I make it so I can define what happens when I call nth on a datatype or record?

0:25 trevor`: How do people do JDBC CallableStatements in Clojure?

0:26 tomoj: this feels somewhat wrong https://gist.github.com/9f89e03eb42bef6ddeab ?

0:31 callen: well. lobos seems nice enough.

0:31 is lobos what most people use for migrations?

0:32 zackzackzack: tomoj: Which walk is walk?

0:32 w/walk I maen

0:32 *mean

0:33 tomoj: w is clojure.walk

0:33 well it's definitely wrong because I don't deref the Reduced

0:33 but seems kinda weird to use Reduced

0:39 zackzackzack: Why not this? https://gist.github.com/1d4e89438b8c2bb4d210

0:39 Hmm

0:39 It doesn't stop though

0:39 Nevermind

1:02 callen: how do I get trailing slashes to work in ring?

1:08 tomoj: zackzackzack: I felt like there should be a simpler way to write it, too

1:11 I don't have w/walk at the top because f should be able to stop on the root form too

1:12 xeqi: callen: the slashes should show up in the :uri

1:12 if you want to act the same as the non slash, you could use a middleware to change it

1:12 or redirect

1:14 https://github.com/noir-clojure/lib-noir/blob/master/src/noir/util/middleware.clj#L28 is one example

1:14 tomoj: shoot, I wish if were a macro for if*

1:15 oh, no I don't

1:21 is it an acceptable use of with-redefs to redefine macroexpand-1 to cljs.analyzer/macroexpand-1?

1:22 zackzackzack: tomoj: maybe realize it as a list and then do a search through it with a take while or something?

1:23 tomoj: for the stoppable walk?

1:23 "stop" there means "don't descend into the form f returned"

1:25 e.g. in my impl, if (reduced? (f form)), then the walk will not descend into (f form), but all the siblings of (f form) are still walked

1:40 zackzackzack: Any particular reason why protocols don't support variadic (& rest) arguments?

1:49 SegFaultAX|work: When looping and destructuring a list, what is the most idiomatic way to stop when you've reached the end of the list? I usually use something like (loop [[h & t :as c] (if (empty? c) ... (recur ...)))

1:52 Somehow that feels more verbose than it needs to be.

1:53 Frozenlock: SegFaultAX|work: Isn't there 'while'?

1:55 If it can help: http://clojuredocs.org/clojure_core/clojure.core/take-while

2:01 SegFaultAX|work: Frozenlock: That doesn't really address my question at all.

2:05 tomoj: &(loop [[h & t] [1 2 3]] (if t (recur t) h))

2:05 lazybot: ⇒ 3

2:22 wingy: how do i interact with XML responses?

2:23 some services only provide XML :/

2:42 zoldar|away: wingy: define "interact"

2:42 wingy: zoldar|away: working with xml like i can do with json responses

2:42 reading elements, attributes .. setting values etc

2:42 save data to db

2:43 creating new attributes and elements as well

2:43 reminds me about DOM manipulation but I have never worked with XML responses

2:44 how does everyone handle XML resonses in clj/java land

2:44 zoldar: wingy: my bet would be on this: https://github.com/clojure/data.xml

2:45 wingy: cool

2:46 tomoj: "Wrong number of args (-1) passed to: core$map"

2:46 interesting

2:47 (defmacro foo [] `(~@(map)))

2:47 (that one has -2 args)

3:00 wingy: zoldar: clj has basic ops built in http://clojuredocs.org/clojure_core/clojure.xml

3:01 i might just use that one

3:03 tomoj: there is also clojure.zip/xml-zip and clojure.data.zip.xml

3:03 wingy: i wonder why clojure has different projects for xml though

3:04 they have those you mentioned but also https://github.com/clojure/data.xml

3:04 its in the clojure github project

3:04 does anyone here know why?

3:06 tomoj: clojure.xml uses SAX, clojure.data.xml uses StAX

3:24 wingy: tomoj: i c

4:05 gtuckerkellogg: ,(doc repl)

4:05 clojurebot: I don't understand.

4:05 gtuckerkellogg: ,(doc doc)

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

4:21 bairui: has anyone here used both clojure and newlisp? have you written serious apps in both? any constructive observations / criticisms / comparisons?

4:22 (no, i'm not trying to start a war - i happen to like both)

4:25 mucker: bairui: what type of app ? newlisp is a scripting language. clojure from the start is a general language that lets take adv of jvm

4:26 bairui: mucker: no limits on type of app; only that both should be... suitable to the language/platform and be of reasonable size - not just tutorials / toys.

4:27 mucker: i concede that clojure has the awesome power of all those jvm libs behind it - that is certainly something newlisp has much less of (exhaustive set of libs)

4:30 michaelr525: hello\

4:31 bairui: i saw a presentation on seesaw a few days ago - it looks very pretty. Is seesaw THE recommended way to do GUIs in clojure now?

4:35 mucker: bairui: in my experience, no matter what the recommended way, there is some struggle ;)

4:36 bairui: :-( ain't it always so

4:37 clgv: Is it right that setting *unchecked-math* to true has no effect when I use primitives and type hints anyway?

4:38 bairui: i dabbled with haskell a while back and noticed they were trying to forge a new path in functional guis... what was that called again? reactive? is there a clojure attempt at this? is it mature/operational?

4:38 i infer from your previous answer that even if there is one... it's no silver bullet :)

4:40 tomoj: incidentally I am working on a library (not published yet) inspired by reactive, but a very long time till I get to swing, probably never. dom and canvas are early targets

4:40 mucker: bairui: :) don't be afraid to port haskell ideas to clojure

4:41 bairui: lol; my haskell skills are akin to that of a child with large coloured blocks; and that is being disingenuous to the child.

4:41 tomoj: swing would be interesting though.. or maybe android someday

4:42 I bet with some synchrony there reactive's behaviors are nicer than in cljs

4:42 clgv: bairui: seesaw is awesome if you want to build a Swing GUI - but I only used it for some smal GUIs yet

4:42 bairui: as i understand it, there already are several swing interfaces - seesaw being one, no?

4:42 clgv: cool; the presentation i saw on it made it look quite cool. I haven't yet built a gui with seesaw, but i am itching to do so. I have a newlisp app that i will port to clojure/seesaw.

4:43 clgv: are you implying there are alternatives to wanting a 'swing' gui?

4:43 * bairui is NOT a java coder

4:45 mucker: bairui: you can use java classes in clojure, so that's one way ... donno alternatives to seesaw

4:45 clgv: bairui: swing is the easiest way since its built-in. there is SWT which is used by eclipse

4:45 bairui: mucker: actually, i was wondering about alternatives to swing - does anybody still write guis in awt directly?!

4:45 i hadn't heard of swt

4:46 clgv: now you have ;)

4:46 mucker: bairui: awt is a big NO

4:46 bairui: heh :) good

4:46 clgv: I think java world is either swing or swt

4:49 michaelr525: re

4:50 bairui: ok, thanks, clgv. I'll make a note to look at swt, but i'll try seesaw first.

4:52 clgv: bairui: yeah try seesaw first. I don't know if there is any clojure lib that provides an interface for swt

4:52 bairui: cool

5:21 wingy: how can i convert a string with base64?

5:27 tomoj: https://github.com/clojure/data.codec

5:27 (String. (encode (.getBytes "foo"))) for example

5:31 wingy: tomoj: ah

5:31 (ring.util.codec/base64-encode (.getBytes "adasd")) this worked great as well

6:45 augustl: when I build with "lein ring uberwar", everything in {:profile {:dev {:resource-paths [...]}}} gets added to the war

6:45 how do I build a "production war"?

6:48 it also contains my dev dependencies, so "lein ring uberwar" seems to assume I want to use the dev profile

6:48 tomoj: try `lein with-profile production ring uberwar`

6:49 augustl: tomoj: "'ring' is not a task. See 'lein help'." hehe

6:51 tomoj: hmm

6:51 clgv: is ring also a :dev dependency? ;)

6:51 tomoj: I found `lein with-profile production lein ring uberwar` somewhere

6:52 augustl: no, it's a plugin - :plugins [[lein-ring "0.7.1"]]

6:52 clgv: ^^

6:52 clgv: outside of :dev?

6:52 augustl: yes

6:52 tomoj: same thing, "lein is not a task"

6:52 tomoj: that one makes sense

6:53 augustl: agreed :)

6:53 clgv: what does `lein with-profile production help` list you?

6:54 augustl: clgv: https://www.refheap.com/paste/5616

6:54 clgv: lein-ring should be listed there, right?

6:55 augustl: no idea :)

6:55 it's not listed with just "lein help"

6:55 sec :P

6:56 tomoj: works for me

6:56 augustl: works for me too

6:56 goodie!

6:57 is it possible to default to the production for just "lein ring uberwar" so we don't make the mistake to build with the dev env?

6:58 clgv: I think that is an error in the plugin implementation - lein uberjar for example excludes the :dev profile

6:58 augustl: I think you can define an alias that automatically uses the production profile

6:59 augustl: clgv: I'll look that up, thanks

7:06 resource-paths in leiningen just adds those folders to the classpath, right?

7:23 clgv: augustl: no, it also includes thos folders in the jar

7:41 djpowell: anyone know how to dynamically construct a bunch of OR'd together clauses in Korma?

7:42 i can easily take my clauses and reduce over the query applying k/where to it

7:42 but i'm not sure how to do something similar with OR

7:52 clgv: djpowell: you could generate a list of your or-clauses using the symbol 'or and where* instead of where

8:00 djpowell: clgv: hmm, not quite figured out how to use where*

8:20 ok, got it sorted. just about.

8:22 clgv: djpowell: with where*?

8:38 nkoza: where I can report a clojurescript documentation bug? The issues tab in the github page seems disabled

8:38 gfredericks: dev.clojure.org/jira

8:41 nkoza: thanks

8:48 augustl: would be nice if the issues tab in github could be enabled, but link to an external issue tracker instead, since so many people seem to default to look up issue trackers on github repos

9:01 djpowell: clgv: yeah, with where*; i pretty much did a macroexpand on where, and duplicated the result. bit ugly cause it uses stiff in engine and fns

10:01 edward_: Hi guys, I'm just wondering, in case statement, how can I do nothing for one case?

10:01 clgv: edward_: do not add the statement

10:02 cshell: do nothing or return nothing?

10:02 edward_: hmmm sorry I'm new to clojure so I guess return nothing since clojure is functional :D

10:03 cshell: exclude the statement or return nil

10:04 antares_: edward_: return nil

10:05 edward_: hmm like (nil)?

10:05 and how can I exclude the statement?

10:05 antares_: edward_: nil is not a function, just nil

10:05 cshell: just nil

10:05 clgv: (case v 10 11, 11 nil, 12 13, 42)

10:06 edward_: oh haha forgot () is calling function

10:18 pandeiro: how do i view the dep tree with lein?

10:20 cshell: you can generate the pom then run mvn dependency:tree

10:20 but lein probably has an easier way

10:22 jsabeaudry: pandeiro, https://github.com/the-kenny/lein-deps-tree

10:24 nkoza: pandeiro: lein deps :tree (at least with lein 2)

10:26 augustl: https://www.refheap.com/paste/5620 weird stack trace.. If anyone has got some suggestions I'm all ears

10:27 pandeiro: jsabeaudry: nkoza: thanks

10:29 augustl: is there a way to get column info in stack traces? servlet.clj file that seems to cause the error has only one long line in it (it's a generated file)

10:30 antares_: augustl: you are replacing clojure.core/list with myapp.views.attendants/list. This probably confuses the compiler (which relies on parts of clojure.core for some bits)

10:30 jsabeaudry: augustl, I beleive that is coming in 1.5

10:31 antares_: augustl: add (:refer-clojure :exclude [list]). Column numbers are coming in the next release.

10:32 WokenFury: has anyone used Noir validations with enlive? if I try to access noir.validation/errors? in a defsnippet it turns out that noir.validation/*errors* is unbound, outside of a defsnippet it's bound.

10:32 augustl: yay for column numbers :)

10:33 antares_: the redefine of clojure.core/list wasn't the problem

10:33 still getting the same error after adding (:refer-clojure :exclude [list]), the warning is no longer there so it was picked up

10:34 clgv: WokenFury: usually the problem is that those variables are not bound outside a request

10:34 augustl: antares_: oh I was getting another error from another file. Fixed them all, now it works, thanks.

10:35 WokenFury: clgv: my defsnippet is called from within a noir/defpage though, so the request is definitely active and *errors* is bound in the defpage

10:38 clgv: WokenFury: maybe defsnippet tries to use *errors* on macro expansion time?

10:39 I dont know how defsnippet works ;)

10:40 antares_: WokenFury: you can also try http://clojurevalidations.info, it is a completely standalone library, no implicit use of vars (otherwise noir.validation is just as good)

10:43 WokenFury: looks like someone else ran into this. let me test snippets outside of deftemplate https://github.com/cgrand/enlive/issues/30

10:45 edward_: hmm, is there any other way of "do nothing" instead of returning nil in clojure?

10:47 augustl: edward_: depends on what you're working with I guess

10:47 jsabeaudry: edward_, removing the statement

10:47 augustl: edward_: + returns 0 with no arguments, which will cause it to "do nothing"

10:47 jsabeaudry: augustl, taking note of that for 4clojure :)

10:47 antares_: edward_: in Clojure, you primarily work with returned values. Everything is an expression. So returning nil, 0 or any other sensible value is typically how you do it.

10:48 augustl: jsabeaudry: :D

10:49 edward_: ya but the problem is, I'm working with enlive, and I have this case statement. For one case I can't return nil cuz that would literally render nil in the frontpage

10:49 antares_: edward_: if you want a function that "does nothing", there is clojure.core/identity that takes something and returns exactly what it is given.

10:49 edward_: oh nice !

10:49 antares_: edward_: use an empty string

10:50 edward_: hmm it gives me indexoutofbounds if i use empty string, but let me try identity first

10:50 nice it worked just the way I wanted :D

10:50 Thanks guys

10:53 pandeiro: drewr: can i ask you a postal/javax.mail question? do you know why MimeMultipart parts are sometimes encoded as base64 and sometimes as 7bit?

10:57 WokenFury: grrrr. having major regrets about rewriting this hiccup code in enlive. less code in enlive, but more random explosions

11:01 drewr: pandeiro: I don't know off the top of my head; can you give me an example of the two?

11:02 pandeiro: drewr: so i'm looking through postal/message.clj... when it calls (.attachFile msg "foo.png"), the result MimeBodyPart ends up yielding an instance of com.sun.mail.util.BASE64DecoderStream

11:03 but at the repl, when I manually do the same, the MimeBodyPart.getContent() yields a regular InputStream

11:03 i am trying to debug some problems with using BASE64DecoderStream in another lib, and I am baffled at the seemingly random results

11:05 it seems like with postal, and with mail clients like Alpine too, plaintext files end up encoded as 7bit (SharedByteArrayInputStream instances), while binaries like pdfs and pngs end up as BASE64DecoderStream

11:06 yet if you do (.getContent (doto (javax.mail.internet.MimeBodyPart.) (.attachFile "foo.pdf"))), you get an instance of FileInputStream

11:07 drewr: that all sounds right to me

11:07 pandeiro: how is it determining which to encode as which, and why the different behavior at the REPL and in message.clj?

11:09 is there somewhere postal 'hints' to javax.mail.internet.MimeBodyPart that it should encode those binaries as base64 instead of FileInputStream? or does FileInputStream get converted magically when you do Transport/send or something?

11:09 drewr: no, that's all javamail

11:11 pandeiro: damn i am stumped by this... anyway sorry for bothering ya

11:13 arrdem: ,(= identity (fn [x] x))

11:13 clojurebot: false

11:27 Kototama: hi, how can I make th equivalent JS call "new Backbone.View({})" in clojurescript?

11:30 ohpauleez: Kototama: If you can require the Backbone namespace (if it's setup like a Closure lib), you would require it and then do: (Backbone.View. {})

11:32 If it's a singleton and you're using a function call, you might end up with something like (.View Backbone {})

11:34 Kototama: don't I need prefix Backbone with js/Backbone?

11:34 and how can I specify that the call is a 'new' ?

11:34 .View will just invoke the function no?

11:37 nDuff: Kototama: (View.) constructs a new object.

11:37 Kototama: ...as opposed to .View

11:37 ohpauleez: Kototama: Right, like my first example

11:37 nDuff: ahh.

11:37 Kototama: ok but if I don't required the lib but used a dynamically loaded library

11:37 nDuff: ...so, ohpauleez's answer looks right.

11:38 the "." being on the end specifies that it's a new.

11:38 Kototama: (js/Backbone/View.) won't work

11:39 ohpauleez: Kototama: If you're using it that way: (js/Backbone.View. {})

11:39 nDuff: ...well, that's a Clojure {}, not a JS {}, no?

11:39 ohpauleez: but that's not advised - you're going to have to externs that stuff

11:39 Kototama: yeah okk I'm just playing with existing code to see what I could do with clojurescript

11:39 * nDuff shrugs, and wanders off -- it's been a few months since he last did cljs, and he seems to have forgotten everything he knew.

11:40 Kototama: because JS makes me cry everytime I forget that the context of 'this' has changed :-s

11:41 ah! js/Backbone.View works but if I remember correctly this is some new syntax, not clojure comptible

11:42 ohpauleez: Kototama: That's regular Clojure code, JVM interop works very similarly, with the exception of the js/ piece

11:43 Kototama: nDuff: you'right {} is passed as a cljs.core.ObjMap

11:43 ohpauleez: the reason for periods and not slashes happens because you're using js/ and you're accessing a constructor, not hitting an aliased namespace

11:43 Kototama: ohpauleez: ok i need to relook at that because I didn't write any niterop code since a long time

11:43 clojurebot: primetime |is| <lowlycoder> i'm not convined clojure is ready for primetime until i see facebook apps in clojure

11:44 ohpauleez: Kototama: (js-obj) I believe is the form, but you're probably better off extending appropriate protocols to Backbone stuff

11:44 Kototama: well you're right java.lang.Integer just uses plain dot and is clojure

11:44 yep

11:45 not sure how to do that in clojurescript

11:45 ohpauleez: Kototama: The same way you do it in Clojure

11:46 let me get you an example

11:46 Kototama: http://shoreleave.github.com/shoreleave-browser/#shoreleave.browser.cookies

11:47 drewr: pandeiro: sry, I would look into it more but I can't atm

11:47 ohpauleez: Here I extend Closure's Cookies support, so I can use map-like lookups

11:48 SegFaultAX|work: Has anyone else seen Brendan Eich's talk at Strange Loop about JavaScript?

11:48 Kototama: wow it looks really easy

11:49 ohpauleez: very easy

11:50 Kototama: but this would not really create new Backbone.Views / Models but only add clojurescript methods to the backbone types right?

11:50 so that I call count or whatever on the models

11:51 +could

11:51 ohpauleez: Kototama: You would do something like: (def cookies (goog.net.Cookies. js/document))

11:51 or wrap the constructor call

11:51 SegFaultAX|work: It seems like they've just taken a random smattering of features from Python and Ruby and added them to JavaScript haphazardly.

11:52 ohpauleez: and then with the protocols extended to the object in Backbone, you can use standard Clojure functions on them

11:52 treating views like maps, vectors, whatever you want

11:52 SegFaultAX|work: Who has? Backbone?

11:53 SegFaultAX|work: ohpauleez: The ECMAScript team.

11:53 Kototama: ok but the render function for instance for views should be dispatched on instances; not on the type

11:53 ohpauleez: ahh yes, the new specs are adopting a lot of things that are prevalent in other circles and patching up some oddities in the spec

11:53 Kototama: it's like the method of an object basically

11:54 SegFaultAX|work: ohpauleez: Check it - http://brendaneich.github.com/Strange-Loop-2012/#/

11:54 ohpauleez: Slides on his talk at Strange Loop about features coming in ES6 and ES7.

11:54 ohpauleez: nutty, I definitely will

11:54 SegFaultAX|work: ohpauleez: Don't get me wrong, I'm glad they're doing it. It might actually make JS a sensible language to some degree. But the selection of features is pretty random. Maybe that's a good thing?

11:55 duck1123: there are protocol extensions to backbone?

11:55 Kototama: for instance you can't do that with extend-type http://paste2.org/p/2316251 right?

11:56 I need to call the extend function first to create instances of views and only then I would be able to user the generic function defined by extend-type for it

11:56 antoineB: ,(nth 2 [:a :b :c])

11:56 clojurebot: #<ClassCastException java.lang.ClassCastException: clojure.lang.PersistentVector cannot be cast to java.lang.Number>

11:57 Kototama: but the specific render function needs to be passed in the hash of the extend call, right?

11:57 antoineB: ,(nth [:a :b :c] 2)

11:57 clojurebot: :c

11:57 duck1123: Kototama: Here's how I've been using Backbone w/ cljs https://github.com/duck1123/jiksnu/blob/pending/src-cljs/jiksnu/model.cljs

11:59 Kototama: duck1123: really helpfull thank you

11:59 duck1123: I made my own backbone ns so I could easily reference those classes

12:00 next step will be a macro to make those model defs really pretty

12:00 TimMc: clojurebot: Why so sad?

12:00 clojurebot: No entiendo

12:01 Kototama: duck1123: and then do a lib that I can import ;-)

12:01 jconnolly: ,(nth [:a :b :c] 2)

12:01 clojurebot: :c

12:01 duck1123: Kototama: That'll be the idea

12:01 in the mean time, feel free to steal any of that you find useful

12:02 Kototama: thank you I'll have a look at that

12:04 duck1123: if you hold on, I have new stuff to push

12:04 antoineB: do you know any big application done in clojurescript?

12:07 Kototama: duck1123: i'm not in the hurry, I will have a look at it tomorrow

12:07 fckw: Hi there.

12:07 Got a FP question:

12:07 I have a map with key-value pairs.

12:07 Kototama: I need to see If I stick to JS until the end of the project or switch to ClojureScript to preserve my calm :-)

12:07 duck1123: Kototama: well, it's all there on the pending branch now. you can see it in action at http://renfer.name/

12:08 fckw: I want to apply some function (e.g. inc) to all the values of the elements and then return the new map.

12:08 There must be an easy way to do this, but I don't get it right now.

12:08 Using the val function returns only a seq of values - not what I want.

12:08 Sorry, I meant: Using the vals function.

12:09 Kototama: something like (map inc (vals coll)) ?

12:09 fckw: Yes, something like this.

12:09 lynaghk: Has anyone gotten tagged literals working within a REPL (i.e., not using the data_readers.clj file)?

12:09 fckw: But then returning the whole map, not only a seq of (changed) values.

12:10 lynaghk: I'm binding *data-readers* as instructed in the docs but my tags don't get picked up.

12:11 Kototama: look at reduce-kv I guess

12:11 jkkramer: lynaghk: are you using lein repl (reply)?

12:11 fckw: The background to my question is, that I want to html-escape all values in the params-map I get through a ring post requrest.

12:11 lynaghk: jkkramer: I'm using swank

12:11 jkkramer: lynaghk: got a paste-able snippet?

12:11 lynaghk: jkkramer: sure, give me a sec.

12:13 Kototama: (reduce-kv (fn [acc k v] (assoc acc k (inc v))) {} {:one 1 :two 2})

12:14 lynaghk: jkkramer: https://www.refheap.com/paste/5622

12:14 fckw: @Kototama: I have to try this out, thanks for your suggestion.

12:15 lynaghk: jkkramer: passing the var (e.g., #'map->A) doesn't make a difference either.

12:15 fckw: @Kototama: Thanks! I did not know about reduce-kv until now.

12:15 lynaghk: jkkramer: nor does namespacing the tag

12:15 Kototama: it's relatively new it was introduce in 1.4

12:15 hiredman: lynaghk: I have

12:16 lynaghk: I set! *data-readers*

12:17 lynaghk: https://gist.github.com/3859794

12:17 fckw: I believe it could be done even shorter somehow, but I cannot see a solution right now.

12:17 lynaghk: hiredman: that works, thanks! Shouldn't the binding form work as well, though?

12:17 hiredman: lynaghk: no idea

12:17 jkkramer: lynaghk: tagged literals can't be used that way. the binding happens after the code has been read. this will work but doesn't necessarily solve your problem: (with-bindings {#'*data-readers* {'A map->A}} (read-string "#A {:foo 1}"))

12:17 yeah, see hireman's thing

12:18 lynaghk: jkkramer: okay, that makes sense.

12:18 jkkramer, hireman: thanks.

12:31 fckw: Ah, here we go, there is an update-in function.

12:31 This might be handy.

12:41 Can anyone explain me why this code does not work: (def my-map {:one 1 :two 2 :three 3})

12:42 (update-in my-map (keys my-map) inc)

12:42 I get a NullPointerException.

12:42 clgv: fckw: you misunderstood update-in

12:42 hiredman: the keys you pass to update-in are expected to describe a path through a nested structure of maps

12:42 clgv: fckw: update-in is for nested maps

12:43 fckw: Oh gosh. So is there really no simple "update" function?

12:43 clgv: &(update-in {:a {:b 1} :c {:d 0}} [:a :b] inc)

12:43 lazybot: ⇒ {:a {:b 2}, :c {:d 0}}

12:43 fckw: Updating all values in a map?

12:44 clgv: you can use reduce-kv like: ##(reduce-kv (fn [m, k, v] (assoc m k (inc v))) {} {:a 0 :b 2})

12:44 lazybot: ⇒ {:b 3, :a 1}

12:44 fckw: As it seems I really have to unpack each value of a key-value pair and then associate the changed values with a new map.

12:44 Yes, I already was told so. Is this the standard way of doing updates to all values in a map?

12:45 Creating a new, empty map and re-associating the changed key-value-pairs?

12:45 clgv: fckw: from a structure-sharing point of view: you cant share structure if you update every value

12:45 fckw: Hm, that's true.

12:45 duck1123: no matter how you slice it, sooner or later, the code is going to loop every key and perform the operation in turn

12:45 fckw: Ok, thanks for your answer.

12:46 clgv: you can build a function from the above reduce-kv snippet for convenience

12:46 technomancy: ,((comp inc {:a 0 :b 2}) :b)

12:46 clojurebot: 3

12:46 technomancy: but then it's not a map anymore

12:46 dnolen: fckw: even if you were doing this in an imperative language you'd still have to loop over all the keys and mutate each entry.

12:48 fckw: But why can I do a map or apply on a list, but not something similar on a map?

12:48 Would be nice: Applying a change to each element (e.g. its value) in a map using the map function.

12:48 SegFaultAX|work: fckw: Sounds like you want fmap.

12:49 technomancy: fckw: part of the point of map is that it's lazy

12:49 arrdem: ,(let [m {:a 1 :b 2 :c 3}] (zip-map (keys m) (map inc (vals m))))

12:49 clojurebot: #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: zip-map in this context, compiling:(NO_SOURCE_PATH:0)>

12:49 arrdem: ,(let [m {:a 1 :b 2 :c 3}] (zipmap (keys m) (map inc (vals m))))

12:49 clojurebot: {:b 3, :c 4, :a 2}

12:49 clgv: fckw: (defn update-map [m f] (reduce-kv (fn [m, k, v] (assoc m k (f v))) {} m) voila! but maybe you should add transients

12:49 duck1123: performing an op on every vaule in a map isn't as common of a need IMO

12:49 technomancy: anyway, I agree that map-keys and map-vals would be nice, but at that point it's different from clojure.core/map

12:50 fckw: I cannot find a fmap function?

12:50 dnolen: fckw: you can map over a map - but map always returns lazy seqs - so you'll have to do some of the things shown above to get back to a map.

12:52 fckw: I wrote above that the background of my question is that I have a ring POST request giving me a parameters map and I want to html-escape all values in the parameters map.

12:52 But anyway, reduce-kv seems the way to go.

12:52 clgv: fckw: yeah, I think thats the reason why it was added in 1.4 ^^

12:57 SegFaultAX|work: fckw: Clojure has a Functor library that provides fmap.

12:57 fckw: Clojure contrib, rather.

12:58 fckw: Here is my new function that escapes html:

12:58 (defn- with-html-escaped [params]

12:58 @SeqFaultAX: I'll have a look, thanks.

13:00 clgv: ~contrib ;)

13:00 clojurebot: latest contrib is 947

13:00 clgv: oops

13:00 ~contrib

13:00 clojurebot: Monolithic clojure.contrib has been split up in favor of smaller, actually-maintained libs. Transition notes here: http://dev.clojure.org/display/design/Where+Did+Clojure.Contrib+Go

13:00 TimMc: clojurebot: forget latest contrib |is| 947

13:00 clojurebot: I forgot that latest contrib is 947

13:00 fckw: There is the fmap function: http://richhickey.github.com/clojure-contrib/generic.functor-api.html

13:00 lazybot: Nooooo, that's so out of date! Please see instead http://clojure.github.com/clojure-contrib/generic.functor-api.html and try to stop linking to rich's repo.

13:01 clgv: fckw: better use the update-map I gave you above ^^

13:04 fckw: @clgv: Yes, I'll use the reduce-kv as you suggested because prefer not to rely on clojure-contrib. But for the future a fmap functor would be really nice.

13:06 SegFaultAX|work: fckw: Functors are just things that can be mapped over. fmap is the generic map function for this mappable things. Eg fmap :: (Functor f) => (a -> b) -> f a -> f b

13:06 zerokarmaleft: fckw: as clgv said, you might want to add transients, frequencies in core is a good example of how to do that

13:07 SegFaultAX|work: fckw: In the case of clojure, "mappable things" applies broadly to all sequence/collection/container types.

13:10 fckw: Yes, using transient maps seems like a good idea when html-escaping parameter maps that are being sent from the client.

13:11 I'll have to read up the corresponding topics.

13:22 ppppaul: hey

13:22 anyone here use clutch?

13:28 pandeiro: ppppaul: yeah

13:28 ppppaul: pandeiro, have you done anything with attachments?

13:28 pandeiro: ppppaul: ha, yeah been debugging something involving attachments for almost 2 weeks

13:28 ppppaul: hmmm

13:29 pandeiro: my problem is with a particular input stream type, usually it has worked fine in the past

13:30 ppppaul: ok. i am pushing 23k attachments at 250megs into a doc (this is not an issue for me with couchdb). my issue is that i'm using node.couchapp, and it's a toy and breaks. it is keeping too much useless data in memory and i'm debugging it now. i've used clutch a bit (when it was young), and i'm wondering if i would have a lot of pain in trying to emulate couchapp with it, or is someone has already done the dirty work...

13:33 pandeiro: ppppaul: i haven't done the dirty work but tbh i'd do it with bash+curl

13:34 clutch can probably handle it, and would be infinitely more malleable i imagine

13:34 ah i meant to say bash + curl + underscore-cli (vital ingredient)

13:34 for slicing through the json etc

13:37 ppppaul: bash/curl... how would that handle pusing 23k docs?

13:37 i mean files

13:37 duck1123: pandeiro: thanks for pointing out underscore-cli

13:37 nDuff: ppaul: ...eh, that's not really a question that can be answered; depends on the specific requirements.

13:38 pppaul: the case where it _wouldn't_ be adequate is if you needed things like session keepalive.

13:38 ppppaul: hmmm... i guess i would have some commandline thing to base64 all the files?

13:38 nDuff: ppppaul: Huh? curl can manage encoding itself.

13:38 ...anyhow, #bash -> thataway.

13:38 ppppaul: nDuff i am bash noob :)

13:39 wow, i was really hoping to avoid bash scripts... but if you guys say this is the way to go, then i guess i'll do it...

13:39 jsabeaudry: pppaul, clojure is over-rated, use bash

13:40 * nDuff isn't really saying bash is "the" way to go, but that there's no obvious reason it wouldn't work given only the (limited) information thus far provided.

13:41 jweiss: is there a non-chunked lazy sequence? http://www.infoq.com/news/2009/12/clojure-11-rc1-transients "An interface to force single-item consumption of chunked seqs is still being designed."

13:41 ppppaul: well, i mainly need to push a dir into couchdb preserving relative paths

13:42 nDuff: jweiss: can be done using lazy-seq, yes.

13:42 duck1123: jweiss: I use this to unchunk my seqs https://github.com/duck1123/ciste/blob/master/src/ciste/routes.clj#L75

13:42 pandeiro: ppppaul: i am also bash-averse

13:43 but i will post my code, hold on

13:43 jweiss: nDuff: duck1123: so, does lazy-seq alone not do it then?

13:44 nDuff: jweiss: depends on what you mean by "lazy-seq alone".

13:44 jweiss: ...I mean, if you use lazy-seq to attach a new head to a chunked lazy sequence, then only that head will be unchunked.

13:45 pandeiro: ppppaul: http://sprunge.us/LWCg?bash

13:45 jweiss: nDuff: i have a long-running fn "lrf". if I call (take 5 (map lrf (iterate inc 1))) how can i make sure lrf only gets called 5 times

13:45 instead of 32

13:46 nDuff: jweiss: see what duck1123 gave you.

13:46 jweiss: ok thanks

13:47 nDuff: so it would be (take 5 (lazier (map ...)) ?

13:48 duck1123: jweiss: that should do it

13:48 jweiss: duck1123: great, thank you

13:48 amalloy: jweiss: iterate isn't chunked

13:48 nDuff: pandeiro: ...so, if I were doing my #bash curmudgeon thing, I'd have some quibbles about writing status information to stdout, using $(cat ...) in place of $(<...), and not indenting after using newline continuations, but that looks pretty good.

13:48 jweiss: amalloy: map doesn't do any extra chunking?

13:49 amalloy: nothing (afaik) ever makes a sequence become chunked

13:49 there are only chunked sequence-producers, and functions which retain chunkiness

13:49 jweiss: so i guess i would want to know if map does that :)

13:49 dnolen: jweiss: chunking is a property of the collection - range, vector etc

13:49 amalloy: it does, but you don't care

13:49 duck1123: amalloy: in my case, it was a map over a literal vector that makes it chunked

13:50 amalloy: well yep, that'll do it

13:50 jweiss: amalloy: i'm not sure why i don't care, but i'll take your word for it and try it without worrying about it and see if it happens

13:50 pandeiro: nDuff: thanks, i def _do_ need a bash mentor

13:50 amalloy: jweiss: because you're calling map on iterate

13:50 pandeiro: and #bash is scary

13:50 amalloy: if you were calling map on something else, you might care

13:51 btw there's https://github.com/flatland/useful/blob/develop/src/useful/seq.clj#L178 in useful

13:51 jweiss: amalloy: well, that was just an example, i'll really just be doing something more like (repeatedly 5 lrf)

13:51 amalloy: (unchunk coll) and (lazy (foo) (bar) (baz)) are both relevant

13:52 jweiss: amalloy: that looks the same as the earlier posted function 'lazier'

13:52 amalloy: it probably is

13:53 duck1123: there are some slight differences, which seems interesting

13:53 amalloy: duck1123: the version in ciste is not as good

13:53 because it forces realization of the first element unconditionally

13:53 duck1123: interesting. good to know

13:54 ppppaul: thanks pandeiro

13:54 amalloy: plus depending on useful seems like a better way to get a lazy-sequence operation than depending on ciste's routes lib

13:54 (from jweiss's point of view)

13:55 duck1123: very true. Thinking on depending on useful myself actually

13:55 pandeiro: ppppaul: ignore the debug statements and other bad forms nDuff mentioned ;)

13:55 duck1123: since I never have it required, I'm sure I'm missing out in several places

13:56 amalloy: duck1123: tbh the most-used thing in useful is probably ?, my debug macro

13:57 ppppaul: pandeiro, the .couchrc is a file with 1 line of text?

13:58 like, it wants localhost:5984/db_name ?

13:59 pandeiro: ppppaul: http://user:pass@host:port

13:59 ppppaul: i see

14:00 pandeiro: ppppaul: you could update it to automatically iterate over entire directories and stuff...

14:00 but for me that ended up being more useful than the whole couchapp/nodecouchapp chain for most of what i do

14:01 Licenser: ibdknox ping :)

14:02 jweiss: amalloy: is ? sort of like tracing functions but on the form level?

14:02 amalloy: jweiss: it's just a slightly less-awful version of debug printf

14:03 (? (foo bar)) evaluates the same as (foo bar), and also prints "(foo bar) is 10"

14:03 jweiss: amalloy: ah i see, you don't call it from the repl, you embed it in your code?

14:03 amalloy: yep

14:04 duck1123: how does it compare to clojure.tools.logging/spy (aside from the log vs. print)

14:06 amalloy: not much difference. it handles exceptions a little better, but for me the important gain is i don't have to figure out clojure.tools.logging

14:07 i suspect it also aligns a bit better for large expressions/values, but that's just based on reading the code for spy

14:08 duck1123: I had a similar macro that I used that put the output on the same line, but I abandoned it in favor of the logging version

14:08 pandeiro: nDuff: sorry for bash question, but i can't find anything on google about why u would use $(<cat...) instead of $(cat...)

14:09 nDuff: pandeiro: the latter requires exec'ing an external tool

14:09 pandeiro: if you run 'type cat', you'll see it's /bin/cat, not a bash built-in command.

14:09 pandeiro: ah sure ok

14:09 nDuff: oh, and it's not $(<cat file), it's $(<file)

14:10 jweiss: is there a suggested way to bind up functions with some args already fixed? eg, i have an http client but want to fix the username and password so they don't have to be specified each time. i know I can use a var and binding form, but that can get ugly with multithreaded apps. i guess i could generate a map with the functions in it. that seems awkward too.

14:10 nDuff: jweiss: sounds like you want partial?

14:10 jweiss: nDuff: yeah, partial will create the functions, but then how do i make them accessible

14:10 pandeiro: nDuff: but with non-internal stuff, $(cmd ...) would be an appropriate way to store cmd output into a variable?

14:11 nDuff: jweiss: One approach I've taken in the past is to have a top-level def of a future which retrieves the configuration on first use.

14:12 pandeiro: Yes.

14:12 jweiss: nDuff: i would want to support multiple configurations at the same time, but not necessarily on a per-thread basis

14:13 nDuff: jweiss: Ahh; that is indeed more interesting, then.

14:13 jweiss: that's why i shy away from using a var

14:13 i think maybe i'll just return a map like {:get <fn> :post <fn> ... {

14:13 }

14:20 jlewis: what's the idiomatic way to check if something is callable?

14:22 amalloy: &(doc ifn?)

14:22 lazybot: ⇒ "([x]); Returns true if x implements IFn. Note that many data structures (e.g. sets and maps) implement IFn"

14:22 jlewis: thanks!

14:26 Licenser: hmm if ifn? is the idiomatic way would (try () true (catch _ false)) the idiotic way?

14:33 zilti: When using lein-ring uberwar, the resources folder doesn't get included into the war file. Is that a known problem? How do I fix that?

14:39 Sometimes that stuff feels like it never gets used in production.

14:42 ulath: hi, i have a large text, and this text's parts are depends on some variables (conditions) and in the future these variables can increase and static part of the text will need to be conditional (dynamic). what is the best solution for problems like these?

14:44 pjstadig: ,(time (dotimes [_ 1000000] (object-array [1])))

14:44 clojurebot: "Elapsed time: 308.76889 msecs"

14:44 pjstadig: ,(time (dotimes [_ 1000000] (object-array (rseq [1]))))

14:44 clojurebot: "Elapsed time: 123.725152 msecs"

14:45 pjstadig: there's a riddle for you

14:45 to which i know the answer

14:45 technomancy: that is amazing

14:48 zilti: What does that underscore do?

14:48 scriptor: it means the variable is ignored

14:48 well, more specifically, you don't care about the binding

14:48 dnolen: zilti: it has no real special meaning - just convention

14:49 ppppaul: pandeiro, i'm working with your file, but i can't seem to get couch-put/couch-post working

14:51 scriptor: hmm, where's the rseq class defined?

14:51 amalloy: pjstadig: that's a curious riddle

14:52 scriptor: APersistentVector$RSeq

14:52 scriptor: yep, thanks

14:52 ppppaul: pandeiro, are you versioning the file? would you be interested in starting a repo or gist?

14:54 zilti: Is someone here working with lein-ring? Because of my problem with the inclusion of the resources directory

14:54 amalloy: oh. Vector$Seq doesn't implement Counted?!

14:55 pjstadig: correct!

14:55 well

14:55 PersistentVector$ChunkedSeq

14:55 ,(class (seq [1]))

14:55 clojurebot: clojure.lang.PersistentVector$ChunkedSeq

14:56 pjstadig: ,(instance? clojure.lang.Counted (seq [1]))

14:56 clojurebot: false

14:56 pjstadig: ,(instance? clojure.lang.Counted (rseq [1]))

14:56 clojurebot: true

14:56 devth: anyone know if there's a way to retrieve the source for an entire namespace, similar to clojure.repl/source for vars?

14:57 amalloy: hah. i didn't even look at ChunkedSeq, so it's lucky APersistentVector$Seq behaves similarly

14:57 pjstadig: going to submit a patch to fix that silliness?

14:58 pjstadig: actually APersistentVector$Seq implements IndexedSeq which implements Counted

14:58 amalloy: oh, so it does. i didn't expect that, given that APV$RSeq implements IndexedSeq and (explicitly) Counted

14:59 my detective skills are looking more and more like random luck

15:00 pandeiro: ppppaul: https://github.com/pandeiro/dotstar/blob/master/bash/bash_functions

15:00 pjstadig: i guess i should open a jira ticket for it

15:00 amalloy: wow, IndexedSeq is interesting. i didn't know that interface existed. and apparently neither did rich, because that index() method is never used anywhere in the clojure sources

15:01 dnolen: pjstadig: what would the fix be?

15:01 amalloy: well, i guess that's not true. someone could be using it indirectly via ArraySeq or some other implementing class

15:02 nope. lots of definitions of index(), and no uses of it. crazy

15:03 pjstadig: dnolen: i assume making PersistentVector$ChunkedSeq implement either Counted or IndexedSeq

15:05 tomoj: amalloy: it looks like it was ported from c#?

15:05 amalloy: whaaaaa?

15:05 pjstadig: hehe

15:06 dnolen: ,(counted (seq (range 32)))

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

15:06 dnolen: ,(counted? (seq (range 32)))

15:06 clojurebot: false

15:06 tomoj: amalloy: `git log` that file

15:06 dnolen: ^ probably also needs fixing as well then.

15:07 pjstadig: dnolen: you think?

15:08 tomoj: oh, well, not sure. but there is an almost identical c# file in the same commit that introduced IndexedSeq.java

15:08 amalloy: tomoj: i don't see it

15:08 ah

15:09 dnolen: ,(counted? (seq {:foo 1 :bar 2}))

15:09 clojurebot: true

15:09 pjstadig: dnolen: i see this as a regression, because before chunked seqs (object-array [1]) and (object-array (rseq [1])) would have taken roughly the same amount of time

15:09 amalloy: dnolen: agreed that's a good fix, and an implementation can be stolen from me via http://dev.clojure.org/jira/secure/attachment/11447/range-reducer.patch if anyone wants to do it

15:10 pjstadig: was range also counted before chunked seqs?

15:12 amalloy: pjstadig: probably not

15:13 since it's in clojure rather than java. unless you mean the super-old clojure.lang.Range, which is indeed Counted

15:14 Derylbat23: hello

15:14 list please ?

15:14 hiredman: ()

15:15 dnolen: pjstadig: I think the ticket should be general - return counted seqs if the information is available.

15:15 pjstadig: the CLJS persistent data structures exhibit this issue as well - since we just followed Clojure JVMs lead.

15:17 TimMc: (inc hiredman)

15:17 lazybot: ⇒ 14

15:18 hiredman: speaking of such things

15:19 ,(inc (Long/MAX_VALUE))

15:19 clojurebot: #<ArithmeticException java.lang.ArithmeticException: integer overflow>

15:19 hiredman: I guess that is technically correct, a long is a long integer, but :/

15:21 TimMc: As long as it doesn't say Integer overflow.

15:24 augustl: out of curiousity, why does leiningen have (defproject ...) instead of just a plain map?

15:24 pjstadig: ,(unchecked-add Long/MAX_VALUE 1)

15:24 clojurebot: -9223372036854775808

15:26 amalloy: pjstadig: i think he's just objecting to the message, not the exception

15:26 pjstadig: amalloy: yeah i was thinking of something else

15:28 ,(unchecked-add (Long. Long/MAX_VALUE) 1)

15:28 clojurebot: #<ArithmeticException java.lang.ArithmeticException: integer overflow>

15:28 pjstadig: ,(doc unchecked-add)

15:28 clojurebot: "([x y]); Returns the sum of x and y, both long. Note - uses a primitive operator subject to overflow."

15:29 pjstadig: which i guess is correct if you pay attention to the fact that the docstring says long with a lower case ell

15:30 i would almost perfer that unchecked-add throw an exception in that case instead of giving me the (slightly different) slow path in the code

15:30 or have the slow path check if it's a Long and call the overflowing version

15:37 dnolen: sorry i already created the story, i can see how maybe there should be a more general focus on implementing Counted where appropriate

15:37 i was also thinking it would be better to have smaller scope

15:37 callen: does anyone here use MongoDB with Clojure?

15:37 if so, is there a recommended library?

15:38 augustl: callen: I'm using monger, works fine

15:38 I built a small library on top of it though

15:38 callen: augustl: that's what I'd been looking at, thanks. Small library?

15:39 augustl: yeah, it adds stuff like (make-save "collection-name" validator processor)

15:39 a validator function can add validation errors and stop the save, a processor is pre-insert processing of the data

15:40 callen: that makes sense.

15:40 augustl: that's essentially it. That allows me to say (def save (make-save ...)) in user.clj, and later call (user/save ...), so I don't have to hardcode the collection everywhere

15:40 callen: also made my library take a db object as the first argument to all operations, to make it functional

15:40 rather than a hidden singleton somewhere storing the connection etc.

15:40 callen: I found the singleton in monger kinda problematic.

15:41 I tolerated a stateful connection object to MongoDB in Python, but in Clojure it raises my hackles a bit to have a stateful object floating through space like that.

15:41 augustl: callen: https://github.com/oiiku/oiiku-mongodb-clojure

15:41 just open sourced it, why not ;)

15:41 callen: augustl: very cool, thank you.

15:42 augustl: it's not documented at all though, will make it release quality later, just thought you'd might like to take a look at it

15:42 callen: augustl: I'm still less-than-proficient in Clojure, so it'll at least give me something to learn from. TYVM

15:42 augustl: np :)

15:43 the validation system should probably be stand-alone too, it's not really mongodb specific

15:43 callen: augustl: part of the reason I'm trying to move to clojure, is that I wanted to integrate and compose input/data validation across the frontend and the persistence layer

15:43 augustl: doing so in Python where every library is a fiefdom is a sisyphean task.

15:44 augustl: callen: using clojurescript for validation on the client side or something, you mean?

15:45 dnolen: callen: heh, i like that "where every library is fiefdom" ...

15:46 callen: dnolen: ahhh thank you. You're the one that did all that work on pred dispatch and logic right?

15:47 dnolen: callen: pred dispatch hasn't gotten very far, but yes I work on core.logic/match

15:47 callen: if so, awesome. Learned a lot from reading your posts about the subject.

15:52 does anyone else here use Lobos for migrations? it's not totally clear to me what refer-to does and I'm having a hard time finding it in the code.

15:53 augustl: callen: updated the README, at least it doesn't contain non-existing functions in it now ;)

15:56 callen: in fact, I can only find the refer-to function in the tests. how bizarre.

15:57 lobos...may not be production ready.

15:58 augustl: very cool, haha. Thank you.

16:02 TimMc: callen: There's also Ragtime and... drift?

16:02 callen: TimMc: what do you use?

16:02 TimMc: I don't. :-/

16:03 callen: TimMc: do you do anything with clojure that needs persistence?

16:03 TimMc: Last time I tried, I gave up. The things I found were not well documented in terms of their pragmatics, so I decided not to have migrations.

16:03 It was for a personal project, so I had the luxury of giving up.

16:04 callen: TimMc: what I'm eventually going to build is semi-serious, so there are tradeoffs to consider here. A half-baked migrations library might be worse than writing my own scripts.

16:07 technomancy: callen: I definitely support rolling your own; clojars has a simple implementation in two defns

16:08 https://github.com/ato/clojars-web/blob/master/src/clojars/db/migrate.clj

16:08 much easier than trying to comprehend lobos

16:08 callen: technomancy: I take it you've tried to go down the lobos rabbit-hole too?

16:09 in my case, it wouldn't even be in clojure, I'd just do it with sql scripts.

16:09 technomancy: callen: yeah, I think it's too ambitious among other things

16:09 callen: I agree. The refer-to functionality is *bizarre*

16:09 technomancy: there is no way you can abstract away the differences between schema languages of various DBs

16:10 callen: technomancy: thank you for the pragmatic note.

16:11 TimMc: That's why I tried using ragtime, since it isn't even specific to databases.

16:12 thorbjornDX: hi, I have a hundred or so lines of defmulti/multimethod statements that basically just does (defmulti somefunc :mykey) (defmethod somefunc :key1 [m] key1-ns/somefunc) ... Is there a macro that I can use to clean this up?

16:12 * Hodapp pours a leaky abstraction on technomancy.

16:12 technomancy: ragtime is pretty good, but it's more complicated because it supports down migrations. in my experience down migrations don't work in practice.

16:12 callen: I don't like the idea of an unsupervised "down" anyway.

16:13 I love automation, but it's unrealistic.

16:13 technomancy: I don't have an answer for migrations on long-lived branches other than "make sure they don't interfere with each other" unfortunately

16:15 callen: technomancy: it's case-specific, best to embrace that fact and realize that you have to know what you're doing.

16:16 technomancy: yeah, I guess beyond a certain complexity you just have to pick the lesser of N evils, which is highly specific to the codebase in question.

16:16 pandeiro: is it possible for cljs (clj) macros to reference cljs files?

16:17 dnolen: pandeiro: not as far as I know.

16:17 S11001001: pandeiro: functions, or macros, in said files?

16:17 neotyk: Hello Everyone!

16:18 when extending types in cljs, what is a difference between 'string' and 'js/String'?

16:18 dnolen: neotyk: if js/String appears in core.cljs probably an oversight, string is preferred

16:18 pandeiro: like if i wanted to write a specialized test macro that refers to a state atom in my client cljs files?

16:19 neotyk: dnolen: thanks

16:19 dnolen: pandeiro: then emit the fully qualified symbol to that atom.

16:32 ppppaul: pandeiro, hey. i realize that i don't know what couch-put or couch-post is supposed to do. would you be able to include some documentation or tests?

16:32 antares_: Second clojure-doc.org guide is good enough to recommend to people: http://clojure-doc.org/articles/language/polymorphism.html. If someone wants to help expand it, just submit a pull request :)

16:41 augustl: what's a good way to communicate success or error when both cases has data associated with it? For example, putting something in a database and returning the data, vs returning errors if it's wasn't put in the database for some reason

16:41 technomancy: augustl: do you know about ex-info?

16:42 augustl: technomancy: hmm no

16:43 technomancy: it's the best

16:44 augustl: it's not in the cheatsheet, how could I possibly know about it? :)

16:45 looks good, except it feels kind of wrong to use exceptions for control flow..

16:45 because I assume you mean raising an ex-info created exception instead of returning in the event of an error?

16:46 Apage43: also slingshot builds on that with some more advanced stuff you can catch on predicates or match on the associated data. For example, it was useful for me the other day, to only catch 404's from clj-http

16:46 augustl: the error in question is common since it's caused by erronous user input (form validation etc)

16:47 Apage43: augustl: that seems like a nice place to use it, because the error can be caught at where the response page would be rendered, and use the attached info the highlight the bad field, or something like that, and you don't have to bother with making it possible to thread the error case all the way back

16:49 augustl: aren't exceptions exceptionally bad for performance though?

16:49 pun intended

16:49 Apage43: that's really the point of exceptions, getting the relevant info about an error to the place in the code where they're going to be handled

16:49 technomancy: augustl: I really hope your users aren't submitting bad form values at a rate fast enough for that to be a problem.

16:49 if so you have more serious problems to deal with than exceptions =)

16:50 gtrak: is there a better way to do this? (read-string (str "::an-ns/" "failed")) -> :fully-qualified-ns/failed ?

16:51 augustl: I'm currently returning {:success true :data 123} or {:success false :errors "validation errors here.."}, I like that better than exceptions

16:51 you can multimethod over it ec.

16:51 etc*

16:51 loliveira: how do I access a recrd

16:51 augustl: loliveira: like a map

16:51 loliveira: (some-record :field)

16:51 technomancy: augustl: the problem there is that you could omit the check for the success field and proceed on faulty data. if you're convinced you will never make that mistake then it could work.

16:52 loliveira: how do I access a record method that was added using extend-type in other namespace?

16:52 augustl: true, an exception, if uncaught, makes it clear what went wrong

16:53 loliveira: more info: http://pastebin.com/RxJbj274

16:54 I am getting the folioing error: CompilerException java.lang.RuntimeException: Unable to resolve symbol: get-pos in this context

16:55 gtrak: this is slightly better: (keyword (namespace `an-na/dummy-symbol) "failed")

16:59 ppppaul: pandeiro, how do you use your functions? they are sooooooo buggy. i don't think couch-upload works with the latest version of underscore-cli...

17:01 Apage43: I've tended to do that sort of stuff with clojure

17:09 pandeiro: ppppaul: i never said i could write _software_

17:09 augustl: I have a map {:foo "bar" :baz 123}, how do I call a function that expects (myfunc "some other arg" :foo "bar" :baz 123) with that map?

17:09 ppppaul: pandeiro, lol

17:10 pandeiro: couch-put foo && couch-post foo '{"_id":"bar"}' && couch-upload foo/bar baz.png "image/png" && couch-get foo/bar | underscore pretty

17:10 the baz.png is on you :)

17:10 ppppaul: your couch-upload is buggy. i fixed it... but i also refactored your code a bit

17:11 augustl: I'm defining the function as (defn myfunc [some-arg & {:keys [foo baz]}] ...)

17:11 ppppaul: https://gist.github.com/3861438

17:11 pandeiro,

17:12 i got that working to upload a file...

17:12 so, now time to upload the other 28k files i have

17:12 augustl: (apply (partial myfunc "test") {:foo "bar" :baz 123}) does not work at least :)

17:13 Apage43: using couchdb as a file store, eh?

17:14 augustl: perhaps I should rewrite my function to just take a map as that's my only use case..

17:15 aperiodic: augustl: you need to use flatten, it's the worst

17:15 i recommend taking a map instead

17:15 augustl: aperiodic: doh, I guess that basically turns {:foo 123} into [:foo 123]?

17:16 aperiodic: augustl: exactly

17:16 Frozenlo`: OMG. Damnit I'm dumb. I just realized I can use [{:keys [...]}] instead of [&[{:keys [...]}]]

17:16 augustl: applying with [:foo 123] obviously works.. How silly

17:16 aperiodic: what's the easiest way to take a single map but still use destructuring? A let block in the body of the fn?

17:16 pandeiro: ppppaul: sorry i'm totally confused by how you renamed stuff

17:17 aperiodic: ,((fn [{:keys [foo]}] foo) {:foo "bar"})

17:17 clojurebot: "bar"

17:17 pandeiro: but i promise you if you take the versions from https://github.com/pandeiro/dotstar/blob/master/bash/bash_functions and run the line i wrote above, it works fine

17:18 augustl: aperiodic: ah of course

17:19 ppppaul: works fine on what system? what version of bash? what version of underscore-cli ? lol pandeiro

17:20 i'm on ubuntu, you may be on a mac (tends to be a much older version of bash)

17:20 thorbjornDX: what about 64-bit?

17:22 pandeiro: ppppaul: does ubuntu even use bash? i thought it was dash or something

17:22 pipeline: /bin/sh is probably ash/dash.

17:22 but bash is installed at /bin/bash usually

17:46 horofox: what function does the same of cons but take the parameters in the opposite way

17:46 or append to the end

17:46 of the list

17:46 ?

17:46 dnolen: conj

17:47 horofox: sorry I thought you meant arg order

17:47 casion: conj appends to the beginning of a list I thought?

17:47 dnolen: horofox: you can't append to end of list w/ traversing, Clojure doesn't really provide a operation that does that for lists.

17:47 horofox: use vectors

17:47 w/o traversing I meant

17:48 frio: does clojure have a reverse? (fn rcons [element list] (reverse (con element (reverse list)))) ?

17:48 (gross solution :))

17:48 dnolen: frio: yes, reverse

17:48 casion: you could use concat and (list) the asg

17:48 but that's a bit silly

17:49 horofox: dnolen: i have (cons 3 [1 2])

17:49 dnolen: but it turns [3 1 2]

17:49 dnolen: ,(conj [1 2] 3)

17:49 casion: ,(concat '(1 2) '(3))

17:49 clojurebot: [1 2 3]

17:49 horofox: i want [1 2 3]

17:49 clojurebot: (1 2 3)

17:49 dnolen: horofox: ^

17:49 lynaghk: dnolen: I got partial map matching added to core.logic the other day---Clojure protocols are so nice! Do you have any pref on a name for the type (PartialMap, PMap, SubMap)? Also, do you want me to inline everything in logic.clj or would you prefer the patch being a whole separate namespace that just calls extend-type a lot?

17:49 dnolen: ,(conj [1 2] 3)

17:49 clojurebot: [1 2 3]

17:50 dnolen: lynaghk: protocols rock, they are truly mind blowingly awesome - it's the kind of extensibility you want all of the time :)

17:50 and perf to boot

17:51 lynaghk: dnolen: yeah, though I was pretty confused for a hot minute as to what was getting unified with what. doesn't help that "u" and "v" are only a few px apart =P

17:51 dnolen: lynaghk: I'm not surea about the name, the actual name of the type actually concerns me less than a sensible ctor fn

17:51 lynaghk: dnolen: yeah, I've been thinking the same thing. Within my lib I was thinking about using tagged literals, though that might be too magical for inclusion in core.logic.

17:51 dnolen: lynaghk: so a better name for the underlying type matter less than - partial-map or sub map or something like that

17:52 horofox: YAY THANKS

17:52 just did my recursive fib implementation

17:52 it looks horrible

17:52 lynaghk: dnolen: well that and the semantics of whether partial map should apply to any map-like values it may have.

17:53 TimMc: horofox: I hope it isn't as horrible as this factorial implementation: https://gist.github.com/3036120

17:53 horofox: wtf

17:53 frio: HNNNNGH TimMc

17:53 I like it!

17:54 dnolen: lynaghk: I think it should unify with anything that implements IPersistentMap

17:54 horofox: https://gist.github.com/3861673

17:54 hahahaha

17:54 lynaghk: dnolen: yeah. But should the unification of the children be partial maps or complete maps? I.e., should the constructor walk the provided map and turn all map-like things into partial maps, or just the toplevel?

17:55 dnolen: lynaghk: just top level.

17:56 lynaghk: dnolen: okay. You want everything in the logic.clj or would a new file+namespace be okay?

17:56 dnolen: lynaghk: lynaghk new namespace is ok, actually preferred since there's going to be some churn soon.

17:57 lynaghk: but I'd like the partial map ctor fn to be in the core namespace of course.

17:57 lynaghk: dnolen: okay, sounds good to me. I'll get you a patch by the end of the week.

17:57 dnolen: lynaghk: awesome!

17:57 TimMc: horofox: How about (+ actual-n next-n) instead of (reduce + [actual-n next-n])?

18:01 horofox: TimMc: good

18:01 TimMc: I'm getting the hang of things... hehe, thanks!

18:04 TimMc: horofox: Some suggestions: https://gist.github.com/3861689

18:04 horofox: i will start doing a camping here in #clojure

18:04 TimMc: cool thanks

18:04 TimMc: I will do a better implementation now

18:14 TimMc: horofox: Also, you seem to be reversing actual-n and next-n in the recursive call, which introduces a bug that appears if you start the list at 2,3 instead of 0,1.

18:15 horofox: TimMc: oh, it should start in 0 1 always

18:16 TimMc: I'm going to try by passing only 2 parameters: the list and the amount of numbers to be generated

18:16 TimMc: Hmm, might be wrong about the exact nature of the bug, but you should be able to start from any point along the Fibonacci sequence.

18:19 hyPiRion: Hmm, is there any specific reason merge returns nil instead of {} when given zero arguments?

18:19 gtrak: what do you guys use to test agents?

18:20 hyPiRion: It sounds kind of counterintuitive.

18:21 gtrak: hyPiRion: maybe if you're doing (apply merge ..) it makes sense

18:21 nil's always used for seqs instead of an empty-seq too

18:22 hyPiRion: gtrak: hmm, how come?

18:22 gtrak: ,[(merge nil) (merge nil nil)]

18:22 clojurebot: [nil nil]

18:22 gtrak: ,[(merge {} nil) (merge nil {})]

18:22 clojurebot: [{} {}]

18:22 hyPiRion: ah.

18:22 gtrak: there's a semantic distinction there

18:23 hyPiRion: ,(doc merge)

18:23 clojurebot: "([& maps]); Returns a map that consists of the rest of the maps conj-ed onto the first. If a key occurs in more than one map, the mapping from the latter (left-to-right) will be the mapping in the result."

18:24 hyPiRion: I was more among the lines of why ##(merge) returns nil though.

18:24 lazybot: ⇒ nil

18:24 hyPiRion: s/I/It

18:24 gtrak: what else would it return?

18:24 hyPiRion: {}

18:24 gtrak: how about ##(apply merge [])

18:24 lazybot: ⇒ nil

18:25 dnolen: hyPiRion: are you running into a case where it matters?

18:25 hyPiRion: dnolen: If you want to use the new reducers library and use merge as a combine function, you have to modify it because of the zero-argument result.

18:26 gtrak: why?

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

18:27 hiredman: ,(doc fnil)

18:27 clojurebot: "([f x] [f x y] [f x y z]); Takes a function f, and returns a function that calls f, replacing a nil first argument to f with the supplied value x. Higher arity versions can replace arguments in the second and third positions (y, z). Note that the function f can take any number of arguments, not just the one(s) being nil-patched."

18:30 hyPiRion: Well, my real question is whether (merge) returns its identity element.

18:31 amalloy: hyPiRion: sure it does. (= (merge nil x) (merge x nil) x) for all x

18:32 hyPiRion: Yeah, nevermind. ##(assoc nil 1 2) does return a map.

18:32 lazybot: ⇒ {1 2}

18:32 wingy: wished datomic was schemaless

18:32 i cant know all of the attributes in advance

18:34 hyPiRion: I didn't knew (assoc nil x y) => {x y}. Is that something one should know?

18:35 TimMc: Pick a type, any type!

18:38 augustl: in a leiningen plugin, how do I load the project itself so that I can resolve it's dependencies etc?

18:40 technomancy: augustl: try leiningen.core.eval/eval-in-project

18:40 TimMc: augustl: Lein 1.x or 2.x? And do you mean the project.clj data?

18:41 augustl: TimMc: lein 2

18:42 TimMc: and I mean loading the actual library so I can access it

18:42 technomancy: hmm, I just did, and (resolve 'some-dep) returns nil

18:42 TimMc: augustl: Remember to require.

18:42 augustl: ah

18:42 horofox: hey TimMc

18:43 i did a beautiful implementation

18:43 WTF

18:43 TimMc: Share!

18:43 augustl: TimMc: hmm, require fails too

18:44 here's the full plugin https://www.refheap.com/paste/5639, and oiiku-closure-builder-client is a dependency of the project where the plugin is added

18:45 devth: so RH talks about the importance of values as facts but I just realized I've never seen anything on querying an atom/ref for its value at a given time. is that possible?

18:45 horofox: TimMc: https://gist.github.com/3861912

18:46 augustl: am I doing it the right way?

18:46 TimMc: augustl: I don't see anything terribly wrong, so here's some code I wrote that does work: https://github.com/timmc/lein-otf/blob/master/src/lein_otf/loader.clj#L33

18:46 rlb: devth: @some-atom

18:46 antares_: devth: that's what datomic can do, not Clojure. Clojure ref types only have "current" value (which you mutate by referencing a different immutable value)

18:47 TimMc: augustl: Wait, that's a single-segment namespace, which could be a problem. And you're trying to resolve the ns itself, and not a member.

18:47 rlb: devth: ohh -- you meant varying time...

18:47 hiredman: devth: when you get its value, you are getting its at a point in time (now) and because it is a value if you want to hang on to it for later comparison you can

18:47 augustl: TimMc: hmm, is that a problem? Many of my libs use lib-name instead of lib-name.core

18:47 devth: rlb: yeah

18:47 augustl: TimMc: works when running the code normally at lesat :)

18:48 devth: i thought clojure's persistent data structures would allow you to get past values

18:49 hiredman: devth: references provide identities over a series of values

18:49 augustl: devth: you need to do state manually, it's not a data structure revision tracking system :)

18:49 horofox: is there any way to pass a function by parameter(optional) in a function

18:49 mikerose357: anyone ever used clojure for android applications?

18:49 hiredman: if you want to compare the value of an identity now to the value of the identity 5 minutes ago, you have to have the value from 5 minutes ago

18:50 devth: augustl: that's reasonable but then my atom is just a "place" for place-oriented-programming

18:50 horofox: ?

18:50 devth: hiredman: i see

18:50 augustl: technomancy: can you see something glaringly wrong with https://www.refheap.com/paste/5639? Getting "Could not locate oiiku_closure_builder_client__init.class or oiiku_closure_builder_client.clj on classpath:"

18:50 devth: not sure what you mean

18:51 technomancy: augustl: eval-in-project is a function, not a macro

18:51 you need to quote the code you want evaluated inside the project. have you read the plugin guide?

18:51 TimMc: horofox: You can use multi-arity functions.

18:51 hiredman: devth: have you seen http://www.infoq.com/presentations/Are-We-There-Yet-Rich-Hickey ?

18:51 devth: in RH's talk of Value of Values he says something like "if you pass me the primary key for a record in a database, what have you conveyed? NOTHING, because the record that ID points to could be completely mutated between the time you sent it and when i read it"

18:51 so how is sending an Atom any better than sending a primary key?

18:52 augustl: technomancy: I have, but thanks :)

18:52 devth: hiredman: i haven't seen that, no

18:52 augustl: devth: indeed, an atom is very much now

18:52 devth: maybe the point is: don't send atoms, send the value at some point in time.

18:52 horofox: TimMc: will do some research about it, thanks!

18:52 devth: send the Fact instead of the Container

18:53 augustl: devth: you very rarely pass atoms around, I think, it's typically a singleton somewhere (def ...)

18:53 technomancy: augustl: eval-in-project is more like eval. you have to build up a self-contained form to send to the project.

18:53 TimMc: horofox: Looking better. What happens if you ask for only n = 1?

18:54 horofox: TimMc: I get an error :|

18:54 TimMc: augustl: Or they are kept in a local scope.

18:55 horofox: TimMc: I can do a if condition and deal with this 1 or 0 behavior

18:55 TimMc: inside fib function

18:55 TimMc: Yep.

18:55 horofox: TimMc: I'm actually trying to solve proj euler problem where it's different

18:56 augustl: technomancy: makes sense, thanks

18:56 horofox: TimMc: i need the sum of all even numbers of the fib sequence where the last fib number is 4 million

18:56 TimMc: but got hooked into how I can implement fib

18:59 (take-last 1 [0 1])

18:59 yields (1)

18:59 how do i take this item out of ()?

18:59 so it becomes 1

18:59 instead of (1)?

19:00 TimMc: You'd call last instead of take-last.

19:00 horofox: TimMc: oh yea... i feel so dumb hehe

19:01 TimMc: If you didn't have that, you could call first on the '(1).

19:02 If I were solving that Euler problem, I would probably write a Fibonacci lazy sequence and process it with take-while, filter, and reduce.

19:03 augustl: this updated lein plugin https://www.refheap.com/paste/5642 causes "Exception in thread "main" java.lang.ClassNotFoundException: leiningen.oiiku-closure-builder" O_o

19:03 any ideas..?

19:03 TimMc: Sorry, that was kind of spoiler-y. :-/

19:05 augustl: Probably has something to do with do-build not being available inside the project.

19:05 technomancy: TimMc is right; you need to build up a self-contained form that will evaluate inside the project

19:05 augustl: ah

19:06 horofox: TimMc: thanks man! I did the problem! I wouldn't do it if it weren't for you

19:07 TimMc: final solution: https://gist.github.com/3862014

19:08 TimMc: horofox: OK, *now* try making a version that produces and consumes a lazy-seq of Fibonacci numbers.

19:09 kirindave_: Ugh. Clojure, not a leading source of pretty fibbonaci impls.

19:09 Not without lazy seq, at least.

19:10 Guess my next blog post has gotta be, "The Most Epically Beautiful Fibbonacci"

19:12 amalloy: kirindave_: and you'll just steal the one from rosettacode, right?

19:15 augustl: so should I update the project for eval-in-project and add the leiningen plugin itself as a dependency in order to get it on the classpath?

19:15 TimMc: horofox: Here's a version that does what I describe, which you may wish to inspect: https://gist.github.com/3862052

19:16 augustl: adding it as a dependency sounds like a bad idea.. Just adding it to the classpath somehow would be nice

19:16 technomancy: augustl: not for a 3-line function; just send it as a form

19:16 kirindave_: amalloy: Haha, I can do it from memory

19:16 augustl: technomancy: it's more than 3 lines though :)

19:17 kirindave_: amalloy: It's like fibs = 0 : 1 : zipWith (+) fibs (tail fibs) -- DONE AND TAKE THAT

19:17 horofox: TimMc: very cool this take-while function

19:18 i have no idea what lazyseq means lol

19:18 kirindave_: amalloy: But I don't think any rosetta codes were harmed in the making of my fizzbuzz one. Umm… maybe the C one started there?

19:18 TimMc: horofox: It's a good one to know.

19:18 kirindave_: amalloy: I think nearly every C programmer will write it the wrong way in the same way.

19:18 horofox: in my country people don't even teach lisp :-(

19:18 augustl: anyone have an example of a leiningen plugin that adds its own utility functions to the project and uses eval-in-project to call them?

19:19 AtKaaZ: hi, how can I do something like this? ##(for [x (range 10) :let [y 1/x] ] y)

19:19 ,(for [x (range 10) :let [y 1/x] ] y)

19:19 clojurebot: #<ExecutionException java.util.concurrent.ExecutionException: java.lang.NumberFormatException: Invalid number: 1/x>

19:20 thorbjornDX: AtKaaZ: :let [y (/ 1 x)]

19:20 TimMc: AtKaaZ: 1/x is infix notation, which is not how Lisps work.

19:20 AtKaaZ: oh right, so obvious, thank you

19:20 ,(for [x (range 10) :let [y (/ 1 x)] ] y)

19:21 clojurebot: #<ExecutionException java.util.concurrent.ExecutionException: java.lang.ArithmeticException: Divide by zero>

19:21 amalloy: kirindave_: (map first (iterate (fn [[a b]] [b (+ a b)]) [0 1])) in clojure, though. the haskell/scala version translates very poorly to clojure

19:21 thorbjornDX: AtKaaZ: it's somewhat weird in this case because clojure supports ratio literals

19:21 augustl: only thing I can think of is grepping out the actual plugin entry in :plugins to get the correct version, and add that as a dependency to the project I eval-in-project

19:22 AtKaaZ: thorbjornDX, do you mean 1/2 works but not when 2 is a variable ?

19:22 kirindave_: amalloy: Did you enjoy my egregious fizzbuzz post?

19:22 AtKaaZ: ,(for [x (range 1 10) :let [y (/ 1 x)] ] y)

19:22 kirindave_: amalloy: I'm still suffering fallout from it.

19:22 clojurebot: (1 1/2 1/3 1/4 1/5 ...)

19:22 amalloy: i don't think i've read it

19:23 AtKaaZ: thorbjornDX, would it work inside a macro maybe?

19:23 augustl: seems lein-midje does this, except it hardcodes the dependency

19:23 horofox: TimMc: isn't this fib implementation slow? Like... (take 5 (fib 1 1))

19:23 calls fib 5 times?

19:23 augustl: s/dependency/dependency version/

19:24 kirindave_: amalloy: Ha.

19:24 TimMc: horofox: take doesn't call the second argument, it accepts the result of evaluating it.

19:25 thorbjornDX: AtKaaZ: yes, but I don't think that's a smart idea.

19:25 TimMc: AtKaaZ: No, because the reader is what's complaining.

19:25 kirindave_: horofox: That is the sort of stuff we trust the JIT to inline. :)

19:25 AtKaaZ: yeah I see it's not working

19:25 horofox: kirindave_: oh

19:26 AtKaaZ: but still, that (/ 1 x) is quite enough

19:26 TimMc: AtKaaZ: Just be aware that (/ 1 x) gives you a Clojure Ratio, which can be slow to do math with.

19:26 kirindave_: horofox: Seriously though. No one has any problem writing in Java: for(X x : xs) { x.thingABob() }

19:27 horofox: It's the price of admission. :)

19:27 horofox: kirindave_: i see

19:27 AtKaaZ: timmc, which one do you think would be slower (I know it's unrelated to what you said): 1/2 or (/ 1 2) where 1 and 2 could be any number

19:28 TimMc: "Slower"? To do what with?

19:28 AtKaaZ: like if I wanted to generate numbers like I did in the above for

19:29 I'm only trying to realize if 1/x (if it worked) would've been faster than (/ 1 x)

19:29 hmm, doesn't seem so

19:30 ,(prn 1/1 (/ 1 1))

19:30 clojurebot: 1 1

19:31 AtKaaZ: timmc, I'm merely experimenting, in my attempts to learn clojure, but it's good to know that math-ing with ratios is slower

19:36 TimMc: AtKaaZ: Use (/ 1.0 x).

19:37 You can't programmatically generate forms like 1/2 without using the Clojure reader, so don't.

19:37 AtKaaZ: but I wanted to keep them rational?

19:37 TimMc: (and you would still end up with a Ratio)

19:37 Oh, then use (/ 1 x).

19:38 AtKaaZ: but it's still good to know how to make them Double

19:38 thanks;)

19:42 ,(-> (for [x (range 1 11) :let [y (/ 1.0 x)] ] y) first class)

19:42 clojurebot: java.lang.Double

19:42 AtKaaZ: i like this ->

19:43 or this:

19:43 ,(->> (for [x (range 1 11) :let [y (/ 1 x)] ] y) (map class) )

19:43 clojurebot: (java.lang.Long clojure.lang.Ratio clojure.lang.Ratio clojure.lang.Ratio clojure.lang.Ratio ...)

19:43 AtKaaZ: it's freaking amazing

19:56 Roxxi: If you have a transient set, how can you treat it as a seq?

19:56 technomancy: IIRC transients are only for putting things in

19:57 augustl: Roxxi: you have to make it persistent

19:57 Roxxi: Right, but I'm looping over it, haha.

19:57 augustl: if by seq you mean persistent seq ;)

19:57 Roxxi: technomancy: If transients are only for putting things in, why is there disj! :)

19:59 amalloy: Roxxi: you can't treat a transient as a seq, because it can change at any time, invalidating the seq wrapped around it

20:00 ie, seqs require something persistent to work with

20:01 technomancy: erhm... not that's not quite right

20:01 you can seq an array

20:01 Roxxi: amalloy: Hmm, so it's ok to call persistent! on things, but continue using the operand to persistant as a transient later?

20:02 amalloy: technomancy: yes, and you get out a broken seq

20:02 technomancy: that is to say you can't treat a transient as a seq, but you could in theory wrap a seq around it

20:02 amalloy: fsvo of broken. the seq is still immutable, it just doesn't reflect the contents of what it wraps forever.

20:02 by the same logic line-seq is broken.

20:02 AtKaaZ: now that's clearler thanks

20:03 amalloy: &(let [a (into-array [1 2 3]), s (seq a)] (aset a 1 5) s) ;; technomancy, is this really what you mean?

20:03 lazybot: ⇒ (1 5 3)

20:04 technomancy: amalloy: sure?

20:04 amalloy: that seq is only immutable in the sense that once you realize an element it is fixed; but realizing it depends on mutable state

20:04 technomancy: of course.

20:05 that's what seqs are; a snapshot of a traversal of a thing.

20:05 amalloy: but it's not a snapshot of a traversal: the seq can represent a state that the array was never in

20:06 technomancy: that's why I said a snapshot of a traversal, not a snapshot of a state

20:07 if you have code that needs it to be otherwise, it's not the seq that's broken, it's the other code.

20:07 AtKaaZ: oh wait so you can still get the seq modified if you modify the original, ah that's not what I understood the first time then

20:10 ,(class (seq (into-array [1 2 3])))

20:10 clojurebot: clojure.lang.ArraySeq

20:14 AtKaaZ: how can I find all functions dealing with arrays? such as aset

20:15 aperiodic: AtKaaZ: http://clojure.org/cheatsheet

20:15 array stuff is in java interop at the bottom-right

20:15 AtKaaZ: yeah thanks a lot! great stuff

21:04 thmzlt: so is it a bad practice to define tests within source file using (with-test ...)?

21:31 xeqi: thmzlt: I haven't seen it done anywhere

21:31 thmzlt: xeqi: that's why I asked

21:31 xeqi: or setting *load-tests* to false, so I imagine doing that would run the tests for anyone using it (if its a library)

21:37 ynniv: is there no way to inherit defrecord fields?

21:37 and if not, can I at least specify them with a variable instead of a form?

21:39 tomoj: no

21:39 you could use a macro

22:01 ynniv: i guess that works

22:07 amalloy: it's a bit cruel of rich to tell us inheritance is so evil he can't include it in the language, but keep using it all over clojure.lang: it's occasionally a useful tool for avoiding duplication that's really hard to fake

22:09 ynniv: it would be nice to have inheritance in defrecord

22:09 AtKaaZ: what do you mean by "but keep using it all over clojure.lang" in the java code ?

22:09 ynniv: I'd really be okay if I didn't have to write my own macro to fake it

22:10 brehaut: yes the javacode

22:10 ynniv: it seems odd that you can't pass a list of fields to defrecord

22:10 AtKaaZ: you can't?

22:11 ynniv: it appears that the fields are taken as a form

22:12 i wrote this to expand the variable before defrecord is expanded: https://gist.github.com/3862734

22:12 * Sgeo suddenly thinks of Tcl

22:14 AtKaaZ: hmm there is no [org.clojure/clojure "1.5.0"] in project.clj with leiningen... only 1.4.0

22:15 tomoj: ynniv: why do you want inheritance?

22:15 ynniv: i have two record types that have a long list of fields that aren't exactly the same

22:15 and I'm trying to de-duplicate

22:15 AtKaaZ: I'd probably want the same thing

22:16 tomoj: but why do you have two record types with a long list of almost identical fields?

22:16 amalloy: ynniv: you probably just want plain old hashmaps

22:16 tomoj: er, you know what I mean

22:16 ynniv: to store data?

22:16 i mean, philosophically, there are are things that need to be stored which are very similar but not the same

22:17 do you think I should use pairs of records, one which is the shared fields, and one which is the remaining fields for that record?

22:18 i could use maps, but I would like better type checking

22:18 as in, i didn't type the wrong field name

22:18 records give me compile time sanity checking

22:18 brehaut: records dont give you type checking

22:19 ynniv: they create multimethods that won't exist if I type them wrong

22:19 which is a step up from keywords

22:19 thmzlt: brehaut: hey give you type-based polymorphism

22:19 *they

22:19 ynniv: they also do that

22:19 brehaut: thmzlt: thats wildly different than type checking

22:20 tomoj: also, (assoc a-record :a-typo foo) will still succeed

22:20 thmzlt: brehaut: agreed, but I think that's what ynniv meant

22:22 ynniv: does defrecord not provide field accessors?

22:22 i guess i'm carrying some common lisp baggage

22:23 brehaut: ynniv: you just use keywords

22:23 though there are field accessor methods thats not idiomatic

22:23 ynniv: hrm, not as helpful

22:23 brehaut: (and potentially slower)

22:23 thmzlt: ynniv: but defrecord doesn't work as function

22:23 ynniv: thmzlt: not sure what you mean

22:23 thmzlt: ynniv: (a-record :field) doesn't work

22:24 brehaut: thmzlt: (:field a-record)

22:24 ynniv: but (:field a-record) still does, correct?

22:24 thmzlt: ynniv: correct

22:25 ynniv: i suppose that I need to create vars for my field names to prevent typos?

22:25 brehaut: that would not be especially idiomatic code

22:25 but i guess it would work

22:26 ynniv: well, there's nothing to prevent someone else from calling my code with a keyword

22:26 but this would limit some of the madness

22:26 brehaut: yup

22:26 ynniv: or I could also generate accessors

22:26 hiredman: ynniv: you should also wear body armor all the time

22:26 brehaut: ideally though you create functions for manipulating your records, so that the implementation doesnt bleed out

22:27 hiredman: ynniv: you never know

22:27 ynniv: hiredman: sometimes a good idea!

22:27 brehaut: and look to a future where typed clojure is reasonable to deploy

22:30 ynniv: brehaut: i thought that defrecord generated field accessor/modifiers (like CLOS), which is how I ended up here

22:31 brehaut: ynniv: it does do that, but you generally dont want to use it

22:32 keywords use an inline cache at the callsite to optimize acccess, and the method form may go via reflection

22:32 ynniv: ah, it makes accessors in Java?

22:33 brehaut: yes, of course

22:41 AtKaaZ: is it PLOP when a ref changes? or is it too silly to ask? PLace Oriented Programming

22:46 amalloy: IMO it's not a very useful question to ask, but: a ref seems like a place. however, having a place doesn't mean you're doing place-oriented programming

22:47 gfredericks: you'd have to orient your code around the place?

22:52 AtKaaZ: watching this: https://www.youtube.com/watch?v=-6BsiVyC1kM&t=4m10s "anytime new information replaces old information you're doing PLOP"

22:52 gfredericks, not really understanding what you ask

22:53 gfredericks: I was just failing to be clever

22:53 AtKaaZ: lol I think I read that litterally once and I smiled:P

22:54 but there may be some truth in it

22:54 tomoj: what's the proposed alternative to PLOP again? VOP?

22:55 AtKaaZ: multiversion control:)

22:55 imutability ?

22:56 I have to be honest with you, I pretty much don't know what I'm talking about most of the time :) even though I might've gotten some things right

22:57 brehaut: AtKaaZ: sounds like 99% of every IRC channel ever

22:58 AtKaaZ: amalloy seems right, maybe unless that ref becomes data like I dno, a tree made of refs, refs to refs

22:58 gfredericks: AtKaaZ: so I think at least you can say that reference types, when not over-used, are a lot safer and simpler than traditional mutability

23:03 AtKaaZ: can anyone recommend a graph database in clojure ? maybe not a port like neo4j, something simple enough that would be good to hold graph nodes with directed edges between them, and no other data like properties attached to either nodes or edges. I'm currently going for datomic.

23:03 Sgeo: place oriented programming? Anything to do with Common Lisp places, setf etc?

23:03 AtKaaZ: Sgeo, like updating the same place in a database to replace the old info with new

23:04 so PLOP would be a relational database, and VOP(?) would be datomic

23:05 (not restricted to databases though, like PLOP is OO and VOP is clojure)

23:05 ynniv: it's only PLOP if you overwrite the old value

23:06 you can organize your db to only add new versions

23:06 AtKaaZ: so it would act like a mvcc database of sorts?

23:08 ynniv: not sure what that means

23:08 AtKaaZ: my problem would forever be how do I go back in time and see a consistent view of the database at any level, not sure yet if I can do it with datomic

23:09 ynniv, I got what you meant, not sure if it would indeed act like a mvcc multiversioned database as I said

23:09 ynniv: I'm not familiar with datomic yet, but I often think how nice it would be to use git as a database

23:09 scottj: AtKaaZ: not sure what you mean by "at any level", but with datomic you can to db.asOf(aDate) I believe

23:10 AtKaaZ: scottj, yes you can that, but the "at any level" would imply some sort of nested transactions, so that the top transaction would include multiple low level ones... I guess it would work if the low ones are only commited when the top one commits

23:14 ynniv, yeah I thought about that too, I definitely need some kind of git-like database esp. the branching then merging them

23:20 lancepantz: AtKaaZ: you still there?

23:20 AtKaaZ: yes

23:20 i was thinking of a question, in clojure how do you do two threads incrementing the same counter ?

23:20 lancepantz: AtKaaZ: https://github.com/flatland/jiraph

23:20 AtKaaZ: with dosync?

23:21 lancepantz thanks I'll check

23:21 lancepantz: we've been working on it for about 3 years and have it in production

23:21 it's very actively maintained

23:21 and faster than neo4j

23:21 AtKaaZ: sounds good!

23:26 gfredericks: AtKaaZ: two threads incrementing the same counter can be just an atom

23:26 TimMc: AtKaaZ: Just one counter? Try an atom.

23:26 * gfredericks wins

23:26 TimMc: bah

23:27 * gfredericks prances around

23:27 TimMc: You even won on my screen. I can't claim IRC relativity.

23:27 gfredericks: oh is it relative? that's good to know for future gloating

23:27 thmzlt: so I want to dispatch a method based on the first argument type (string vs. map), hints?

23:27 gfredericks: multimethods or protocols

23:28 TimMc: gfredericks: Larger IRC servers are distributed as a bunch of nodes connected by a spanning tree.

23:28 AtKaaZ: nice, atoms, STM of clojure good stuff

23:28 TimMc: hence netsplits

23:28 gfredericks: TimMc: yeah; it makes sense

23:28 there could be an eventual consistent ordering

23:29 but that would cause weird visual effects

23:29 TimMc: There could be, but there isn't.

23:29 Instead, each client just accepts the ordering of messages that it gets.

23:29 gfredericks: why aren't there git-based chat protocols yet?

23:29 TimMc: "Dude, I can't hear you -- accept my pull request first."

23:30 AtKaaZ: datomic might be like git but without the ability to do branches, I might be wrong, gotta learn datomic

23:30 gfredericks: AtKaaZ: you can do "local branches"

23:30 ynniv: thmzlt: (defmulti f-name type)?

23:30 gfredericks: but only one "master" I think

23:31 * gfredericks really doesn't know

23:31 ynniv: thmzlt: (defmethod asdf (type {}) [x] 'map)

23:31 gfredericks: AtKaaZ: where by "local" I mean like temporary in-memory sort of thing

23:31 AtKaaZ: gfredericks, yeah I was about to ask that, something like assume that the db has this data and the execute this query ? I think I saw that somewhere

23:32 gfredericks: ynniv: might want IPersistentMap instead of (type {})

23:32 AtKaaZ: this new/extra data

23:32 gfredericks: AtKaaZ: yep

23:32 ynniv: depends

23:32 thmzlt: I'm trying to figure out the multimethod syntax

23:32 ynniv: maybe there's a string that implements IPersistentMap :-)

23:32 gfredericks: ,(map type [{} (zipmap (range 1000) (range 1000))])

23:33 clojurebot: (clojure.lang.PersistentArrayMap clojure.lang.PersistentHashMap)

23:33 gfredericks: ynniv: ^ surprises there

23:33 ynniv: ah, good call

23:33 (type {}) isn't stable

23:34 that's why I wear my noob hat

23:34 hmm, it seems that I have forgotten to wear my noob hat. well, beware!

23:35 * gfredericks imagines a local news report about unlabeled noobs on the loose

23:36 scottj: ,(meta ynniv)

23:36 clojurebot: #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: ynniv in this context, compiling:(NO_SOURCE_PATH:0)>

23:37 AtKaaZ: if I ever want to use the value of the atom before modifying it, do I have to dosync instead ?

23:37 assuming 2 threads or so

23:38 gfredericks: AtKaaZ: no

23:38 if you want the new value based on the old one, then do it all inside your swap function

23:39 AtKaaZ: but if I want to use its value to compute something else, twice

23:39 and then increment it let's say

23:40 gfredericks: for tricksy things like that you can make a more complex atom, e.g. a map with :current-value and :last-value

23:40 AtKaaZ: say I do two calls where each takes 3 seconds, and each gets passed the value or the atom

23:40 gfredericks: make sure the swaps do the right thing, and then you can read the old value after the swap

23:41 AtKaaZ: I'm kind concerned if the other thread can increment the atom between those 2 calls which each takes 3 seconds :)

23:41 gfredericks: well only one of them will succeed and the other will retry

23:41 AtKaaZ: but if I use a dosync block around those 2 calls it will block right?

23:41 gfredericks: what is taking 3 seconds?

23:42 AtKaaZ: like if in one thread I do two calls and pass that atom, and when these are done then I increment the atom

23:42 gfredericks: I'm not sure what you mean by "calls" here

23:42 what are you storing in an atom?

23:42 AtKaaZ: but while thread1 is doing first call, which takes 3 second to compute, can another thread modify the atom so that it's different value for the thread1's second call

23:42 it's kinda hypothetical, but it's a counter

23:43 2 threads supposedly increment it by 1

23:43 but 1 thread is slow

23:44 TimMc: AtKaaZ: dosync doesn't know anything about atoms, and vice versa

23:44 it only coordinates refs, and delays sends to agents

23:44 AtKaaZ: timmc, I ref then?

23:44 gfredericks: AtKaaZ: generally you assume that reference types are being updated behind your back

23:44 AtKaaZ: timmc, I figure maybe in this case I'd have to use dosync, that's mainly what I'm asking

23:44 gfredericks: if there's some reason you don't want that to happen then I feel like you might be using them wrong

23:45 AtKaaZ: I do assume that that ref to counter would be updated behind my back between those two calls

23:45 gfredericks: so what's the problem?

23:45 AtKaaZ: but then if those 2 calls are within a dosync, they would always see the same counter value?

23:45 gfredericks: yes but you're holding up other threads

23:46 AtKaaZ: is there any way to maybe do that without the holding?

23:46 gfredericks: without getting more concrete I really don't understand the motivation

23:46 AtKaaZ: hmm... get the value before the calls?

23:46 yeah you're right

23:47 gfredericks: you can read the atom initially and pass that value in with the atom?

23:47 AtKaaZ: I guess in a way I really need to hold the other threads from modifying the counter, cause otherwise it would be like starting off a new branch in a git which is based on now obsolete commit since other thread already updated the counter

23:48 gfredericks: why do the two calls need to have the same basis?

23:48 AtKaaZ: I mean, if I want whatever those long calls are doing to be in sync with the counter

23:48 not sure, but I feel that I may want that hmm

23:49 like maybe they are doing some datomic transactions using that counter

23:49 wingy: since datomic only holds one level keys i thought that perhaps i wanna use keywords with namespace in my day to day maps in clj land instead of nested maps .. eg. {:name "foo" :address/street "maple street" :address/zip "12345"} instead of {:name "foo" :address {:street "maple street" :zip "12345"}} .. the latter one is compatible with datomic and also it feels like it is easier with one level rather than nested levels .. which one do you

23:49 prefer?

23:49 AtKaaZ: one level keys?

23:50 gfredericks: AtKaaZ: I give up

23:50 wingy: AtKaaZ: see the example

23:50 * gfredericks goes to bed

23:50 AtKaaZ: gfredericks, thank you though

23:51 wingy: any input?

23:52 AtKaaZ: wingy, I'd prefer the latter, because it seems extensible, tree-like; but that's just me

23:52 wingy: AtKaaZ: the former looks more treelike :)

23:53 AtKaaZ: maybe I'm missing something, but the latter :address seems to have an inner {}

23:53 wingy: oh yeah

23:53 i thought the latter was the former :)

23:53 AtKaaZ: so, in your OP the former is compatible ?

23:53 with datomic

23:54 wingy: OP?

23:54 clojurebot: optimizing is http://clojure.org/java_interop#optimization

23:54 AtKaaZ: original post=)

23:54 wingy: yeah the former is compatible

23:54 AtKaaZ: yeah it makes sense

23:54 wingy: since you have to declare the keys in advance in the schema

23:54 AtKaaZ: so you'd have to say that :address is a map ?

23:54 wingy: in a post they said they would make the latter work as well .. but it wont be indexable/searchable though

23:55 AtKaaZ: yeah I was afraid of that

23:55 wingy: there is no map type atm

23:55 but then why have namespaced keys if we dont use them :)

23:55 i kinda like flat struture in a way :)

23:56 AtKaaZ: wish it was more tree-like

23:56 wingy: yeah hope they will support it fully

23:56 AtKaaZ: maybe you can use db/ref entities and have :address be a db/ref and point to an entity which contains those :street :phone attributes

23:56 this way, you can have tree-like =)

23:57 didn't fully consider the implications of this though

23:57 wingy: great idea

23:57 why didn't i think about this :)

23:57 AtKaaZ: you got lost into details:) I always do that

23:58 wingy: yeah, nested vs namespaced keys :)

Logging service provided by n01se.net