#clojure log - May 05 2011

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

1:06 stirfoo: /quit


1:30 bhenry: before i write it, is there already a macro or function that will print and return the result of what's inside it? i.e. (prn-ret {:a 1}) will print {:a 1} but also return {:a 1} instead of nil like prn.

1:39 amalloy: bhenry: there are a few

1:39 one in cc.logging, but it logs instead of printing iirc

1:40 bhenry: https://github.com/amalloy/amalloy-utils/blob/master/src/amalloy/utils/debug.clj is mine

1:40 though if you want a super-simple one you can just ##(doto (inc 3) println)

1:40 sexpbot: ⟹ 4 4

2:17 thorwil: semperos: thanks for the mail, but i'm well aware of enlive'e substitute. the problem is extracting the content of the tag that is to be replaced ;)

2:17 semperos: thorwil: I figured

2:26 thorwil: I think you might find your answer by looking at the implementation of the content fn

2:26 as enlive deals with the HTML as maps, :content is just one of the keys

2:26 :tag is another

2:27 you can probably put together your own little fn in the same form, replacing the :tag instead of the :content for the target enlive node

2:27 thorwil: good point.

2:28 i saw mention of a let-select function on the enlive list, so i have a few things to try now. ty

3:09 given (def test-html (en/html-snippet "<p><span>Previous</span> <span>Next</span></p>"))

3:09 ((en/transformation [:span] ((fn [& values] #(assoc % :tag (en/flatten-nodes-coll values))) "a" )) test-html)

3:09 comes close, but i need a way to insert an :a

3:11 of course! ((en/transformation [:span] ((fn [& values] #(into % (en/flatten-nodes-coll values))) {:tag :a} )) test-html)

4:25 clgv: Are there any LISP conferences or deadlines for LISP related journals for the remaining year that one should know about?

4:37 fliebel: Is the clojure reader extensible?

4:37 ejackson: fliebel: no reader macros

4:38 fliebel: ejackson: Waiting for the new compiler, or by design?

4:38 clgv: fliebel: in a repl context you can wrap around it by passing an own function with :read to clojure.main/repl

4:38 ejackson: by design - Rich believes they lead to fragmentation and difficulties.

4:40 fliebel: clgv: What do you mean with :read?

4:41 clgv: fliebel: if you are shooting for reader macros like ejackson said then I guess it wont help you. didnt read that in time ;)

4:42 fliebel: clgv: But what *will* it help with?

4:44 clgv: fliebel: as far as I thought about it - you can define own commands for your repl that do not need to be clojure functions or macros. I used it for some stuff with the debug-repl

4:45 fliebel: Meh, it was a bad idea anyway probably… I'm thinking about templating languages.

4:45 clgv: that means?

4:46 fliebel: Well… scala has xml literal support ;)

4:47 clgv: you could build a clojure DSL though - it just has these additional parantheses ;)

4:48 fliebel: clgv: that'd be hiccup, but then uglier.

4:49 Are there any other exotic ones besides enlive? I mean, anything other than PHP style.

4:51 clgv: hmm is it really desirable to use literal xml in programs? I don't have an opinion on that myself atm...

4:51 fliebel: clgv: Not at all! Just a silly alternative to hiccup.

4:51 clgv: fliebel: ah your playing around and searching limits? ;)

4:52 fliebel: probably :) But the end goal is to find some really awesome templating

5:04 thorwil: from the outside, most templating engines seem to differ mainly in how/where to handle logic.

5:05 fliebel: thorwil: In that case, I'm in the no-logic camp. But that is only the start. I'm not all to happy with introducing a new mini language at all.

5:06 So I say, templates should be html and clojure, .-.-.- (full stop)

5:07 thorwil: that's why i really like enlive. no logic in templates, no new language (macros are on the edge, admittedly)

5:08 fliebel: thorwil: Yea, Enlive is great, but I was wondering if there was any competition in this space.

5:09 thorwil: if there's anything that might start to bug me, it will likely be the inroduction of javascript. especially in the "reverse-ajax/comet" (ain't those silly terms?) case

5:09 * fliebel keeps running into trouble with libraries that use macros heavily.

5:09 fliebel: thorwil: What?

5:10 thorwil: fliebel: the server triggers client code case

5:11 fliebel: thorwil: Yea, what about it? I haven't seen Enlive do that, which is what my confusion is about.

5:12 thorwil: fliebel: so far it only means that i have to insert tokens generated on the server into the JS

5:13 i do that with selecting the nth script tag and en/prepend to insert a single JS line

5:13 fliebel: oh, that :)

5:14 thorwil: a less explicit way to handle that would be nice. the Erlang web framework Nitrogen seems to be really great at that

5:14 (but has only very rudimentary templating)

5:15 fliebel: i think among other more interesting template engines are http://genshi.edgewall.org/ and http://beebole.com/pure/

5:16 fliebel: genshi is nice

5:27 andrewclegg: morning all... I'm trying to create a Date with no arguments like this: (def *now* (Date.))

5:27 but I get thisL

5:27 :

5:27 java.util.Date cannot be cast to clojure.lang.IFn

5:28 Am I losing the plot? :-)

5:29 Chousuke: that should work just fine

5:29 andrewclegg: it's not :-(

5:30 Chousuke: how are you using *now*? :/

5:30 also are you sure you didn't typo something

5:30 andrewclegg: I'm passing it to a function like this:

5:30 (crap-date-format *now*)

5:30 which isL

5:31 :

5:31 (defn crap-date-format [date]

5:31 "TODO: make this less crap."

5:31 (apply str (take 19 (.toString (date)))))

5:31 oh hang on

5:31 Chousuke: there's the problem

5:31 andrewclegg: I see it, sorry

5:31 * andrewclegg removes excess parens

5:31 Chousuke: btw, you can use subs to get a substring

5:31 andrewclegg: err, thanks :-)

5:31 oh, I hadn't seen that, thanks

5:32 still n00bing away

5:32 Chousuke: yeah, well subs is just a wrapper for the java method

5:32 andrewclegg: less typing is always good

5:40 sorry chousuke, another Date q. -- should this work? (def date (java.util.Date. 0)) for 1970-01-01 00:00:00:000

5:40 because I get No matching ctor found for class java.util.Date

5:42 Chousuke: andrewclegg: no idea, check the javadocs?

5:42 andrewclegg: public Date(long date): Allocates a Date object and initializes it to represent the specified number of milliseconds since the standard base time known as "the epoch", namely January 1, 1970, 00:00:00 GMT.

5:42 not casting to Long by default or something?

5:43 Chousuke: try doing (Date. (long 0)) then

5:44 andrewclegg: aha, thanks, didn't know you had to (or could) upcast ints to longs

5:44 cheers for your patience

7:45 manutter: I have an enlive question:

7:46 In PHP I might do something like this -- $banner = "<div class='welcome-banner'>Logged in as $user_id</div>"; echo $banner;

7:46 Is there an easy way to do that using enlive?

7:47 fliebel: manutter: yes

7:47 manutter: I get the impression enlive wants me to use a template something like <div class='welcome-banner'>Logged in as <span id="user_id"></span></div>

7:47 but I want to replace $user_id in the middle of the content (and possibly in more than one place

7:48 )

7:48 fliebel: manutter: Well, the idea is that you add just the banner div with the default content, and insert that whole message using enlive. I think the content/replace do what you want.

7:50 manutter: content/replace sounds promising, I'm not familiar with that

7:51 I don't want to build the whole message in clojure because I'd like to use the template itself for internationalization, so the surrounding text will be different depending on the locale

7:52 pareidolia: Hi all! Is it possible to loop through a sequence (doseq/for) in blocks, not taking just one element? Thanks!

7:53 fliebel: manutter: idk, the span seems like the way to go.

7:53 pareidolia: parition

7:53 *partition

7:53 manutter: I'm not overly averse to the idea, just want to explore the alternatives :)

7:53 tks much

7:56 pareidolia: fliebel: Nice! I haven't seen it suggested in my search results, but it's right there in the api. Thanks!

9:46 bulters: is it possible to create an anonmyous 'multimethod'o

9:46 ?

9:47 fliebel: bulters: Yes, with a lot of manual plumbing. Check the source for defmulti and defmethod. You just need to create the object yourself.

9:57 hyperboreean: what's the idiomatic way of storing paths to config/input files in clojure? I am using lein for building if this matters

10:06 jjido: hyperboreean: you can't use a Java File object?

10:06 raek: hyperboreean: if you want to read a resource file that is to be bundled with the program, you can put it in resources/ which is added to the classpath (and generated jar files) by lein

10:08 hyperboreean: to load a resource on the classpath, do something like (require '[clojure.java.io :as io]) (-> "foo/bar.txt" io/resource io/reader)

10:08 the file should be in resources/foo/bar.txt, relative to the project directory (which becomes foo/bar.txt relative to the class path)

10:09 for resource file paths, / should always be used as the delimiter

10:10 for ordinary file system paths in a platform independent way, construct the path with io/file by giving it the path segemts

10:10 (io/file returns a java File object, which represents a file path)

10:14 hyperboreean: the "resources" approach is typically used for things like icons and maybe config files for libraries the app uses.

10:20 pyr: hi

10:20 what is the accepted best way to deploy a ring/compojure app, in terms of performance ?

10:21 I'm using nginx in front of the jetty handler

10:21 AFAIK each request is mapped to a thread from a thread-pool, right ?

10:22 bulters: fliebel: thanks, will try it out :D

10:22 Belaf: Hello everybody.

10:23 cemerick: pyr: right; FWIW, there's not really any reason to proxy jetty or tomcat, unless you have other requirements that make that convenient.

10:24 pyr: cemerick: yep, i just don't wanna handle the rate limiting there

10:24 but point taken

10:24 cemerik: so this is basically the fastest way to deploy right now ?

10:25 cemerick: pyr: if by "fastest", you mean "least overhead", that's fine.

10:25 There's not a lot of variation in Java webapp servers, really.

10:26 Belaf: I made an attempt at using gen-class to extend java.awt.image.RGBImageFilter. Now everything seems to work fine, only I have some doubts on the performance I get calling the new object's methods: they seem some 100 times slower than a function doing the same job (in my case very little). Is this to be expected?

10:26 pyr: cemerick: sometimes i wish there was an async_ring

10:26 cemerick: pyr: which would do what?

10:26 manutter: Belaf: are you using type hints on your function parameters?

10:27 pyr: cemerick: run requests and replies in a single thread

10:27 Belaf: Uh, no... should I give it a try?

10:27 cemerick: pyr: Wouldn't be too hard, but you wouldn't be able to deploy it in a servlet container like jetty or tomcat.

10:28 manutter: Belaf: I'm not much good at interop stuff, but whenever I hear people talking about slowdowns, type hints seem to come up a lot

10:28 pyr: cemerick: yes, it'd be a matter of adding some sugar on top of netty from what i gather

10:29 cemerick: pyr: Sure. I don't see the point, but then I don't do high-volume web stuffs.

10:30 Belaf: You mean adding type hints to the method definitions, right? I can try adding them, but I'm puzzled, as the methods already have their signature declared in the :methods gen-class declaration...

10:31 manutter: Belaf: could be, like I said I don't know all that much about interop stuff

10:31 Perhaps someone else can chime in? :)

10:32 Belaf: allright, I'll try experimenting with type hints, I need to learn something about them, anyway :)

10:32 Thanks

10:32 clgv: Belaf: the first step should always be measuring to get to know where most of the time is spent and possibly lost ;)

10:32 pyr: cemerick: high volume is an application, websockets and bindings to/from QMS's are another

10:33 cemerick: i'll just shut up and code :)

10:33 cemerick: Belaf: FWIW, if you're only using your RGBImageFilter subclass from within Clojure, proxy is recommended over gen-class.

10:34 Belaf: clgv: I somehow measured it, actually:

10:34 user> (time (dotimes [n 1000000] (gdtest.core/filter0 0 0 0)))

10:34 "Elapsed time: 30.198033 msecs"

10:36 hyperboreean: raek: thanks

10:36 Belaf: cemerick: I think I couldn't use proxy, as I needed to access the protected canFilterIndexColorModel member in RGBImageFilter and proxy doesn't seem to allow it.

10:37 cemerick: Belaf: True enough. nm then :-)

10:39 Belaf: the sad point is that the filter works by calling a method once for each image pixel, so for big pictures it slows down a lot...

10:41 cemerick: Belaf: If there is any reflection going on, compiling with *warn-on-reflection* bound to true will emit useful warnings.

10:41 clgv: Belaf: you should measure inner and outer time to see if type hints might be really the reason

10:41 Belaf: cemerick: allright, I'm going to try that, thanks.

10:42 clgv: sorry, what do you mean by inner and outer time?

10:43 clgv: Belaf: you just measured the outer time. the inner one is within the function.

10:45 Belaf: clgv: do you have any suggestion on how to measure it? the code inside is really basic, actually:

10:45 (defn -filter1

10:45 [this x y rgb]

10:46 hv: Is there a Trie class (hopefully with collection inteface) in clojure?

10:46 clgv: Belaf: you tried the *warn-on-reflection* hint already? I'd do that before

10:47 Belaf: cemerick: is this what you were suggesting "(binding [*warn-on-reflection* true] (compile 'gdtest.aux))" I got no warnings from it.

10:47 clgv: Belaf: do (set! *warn-on-reflection* true) after your ns-statement

10:49 Belaf: clgv: I had some warnings, actually:

10:49 Reflection warning, gdtest/aux.clj:24 - call to setCanFilterIndexColorModel can't be resolved.

10:49 Reflection warning, gdtest/aux.clj:30 - reference to field filter can't be resolved.

10:49 clgv: time to fix them with type hints ;)

10:50 Belaf: Allright, going to try it... Thanks for your support!

10:55 fliebel: hv: http://stackoverflow.com/questions/1452680/clojure-how-to-generate-a-trie

10:55 Smart use of assoc-in :)

11:44 Belaf: Just in case it might be useful to somebody else: fixing the reflection warnings did the trick, now the (trivial) filter is 15 times faster. The only needed thing was to add a type hint to the class being defined to the 'this' parameter of method definitions.

11:44 Thanks so much for your help.

11:44 manutter: Thanks for the report :)

11:45 I'll have to add "reflection warnings" to the list of terms I mindlessly parrot whenever I hear about performance issues.

11:46 Belaf: Well, it seems a good tool to know.

11:47 clgv: but dont forget to comment them before compiling a jar ;)

11:47 manutter: I'd heard of it before, but was kind of hazy on the details

11:47 clgv: *warn-on-reflection*, I mean ;)

11:47 manutter: indeed

11:48 Belaf: I might try it, but... what would the result be?

11:49 oh, I think I know what you mean... I compiled one of my other files with it ... :-)

11:49 clgv: a compiler error

11:50 or wait. I think I get it when trying to run the jar

11:50 had it with *print-length* and *print-level* so I just used (binding [*print-length* 10, *print-level* 9] ...) in my main method

11:51 Belaf: compiling another of my files I got a number of such warnings, but I think I'm not going to add type hints for all of them, unless they are slowing things down... I like so much using things without knowing too much what they are... ;-)

11:52 clgv: seems you do a lot interop then ;)

11:52 manutter: what would be useful would be some kind of mechanism that would let you conditionally compile code based on whether you were executing lein repl or lein jar

11:54 zippy314: Hi folks, I'm trying to write a macro or function that defines a function in a particular namespace (by calling ns) and then then switches back to the current namespace, but this: (defn x [] (ns fish) (defn y [] 1) (ns user)) doesn't seem to work. Is this possible?

11:55 What I'm trying to do is to put functions into namespaces on the fly.

11:57 clgv: zippy314: binding *ns* to the namespace could work

11:58 technomancy: manutter: there's a :repl-init-script setting you could use

11:59 manutter: I was looking at that, hmmm

11:59 Just brainstorming, though, don't have an immediate use for it

12:00 we were just talking about (set! *warn-on-reflection* true) and the need not to compile that into the final jar.

12:00 technomancy: (when (System/getenv "LEIN_VERSION") (set! *warn-on-reflection* true))

12:01 manutter: aha, nice :)

12:08 zippy314: cigv: how do you do that?

12:39 Is there an opposite to refer? I.e. if you used (refer 'some-ns) and now you want to do something like (unrefer 'some-ns)

12:41 semperos: zippy314: :exclude can be used on individual fn's within a namespace

12:42 zippy314: hmm. It looks like ns-unmap actually does what I want.

12:43 But it looks like if you use refer and that overwrites a reference you can't get the old one back easily.

12:43 semperos: you can provide aliases and rename fn's using the ns macro, so if you see that you have a conflict, there are several ways to mitigate it

12:51 raek: zippy314: to get the old one: ns-unmap and then refer

12:52 or refer to it with it's fully qualified name

12:52 zippy314: I'm doing this because I'm defining functions on the fly and I want them to go into their own namespaces, so it gets kind of hairy...

12:54 raek: zippy314: maybe you could let them have a certain prefix (assuming they can have arbitrary names which might not "respect" clojure names)

12:55 zippy314: hmm that might work for starters...

12:56 amalloy: it seems to me like you're a zillion times better off not trying to define top-level functions at runtime in the first place. why do you feel you need to do this?

12:56 raek: or if their usage is determined "on the fly" too (i.e. you don't have hand-written code that uses the names), put them in one map

12:57 using a namespace as a map is not as ideomatic in Clojure as corresponding practices are in Ruby and Python

13:00 it's ok to have functions outside vars :)

13:02 manutter: ,(let [foo (fn [] (println "foo")), bar (fn [] (println "bar")), fly {:foo foo, :bar bar}] ((fly :foo)))

13:02 clojurebot: foo

13:02 dnolen: zippy314: what about your application requires these functions needs to be defined at runtime?

13:05 zippy314: What I'm writing is a system in which you can define grammars and semantics for those grammars as the running system. So for example I'd like to be able to do things like have lexically scoped grammatical constructs, just as we are used to lexically scoped variables.

13:06 In other words I'd like to define a grammar which includes positions of things, plus functions, and have them appear to be usable lexically, as opposed to in the context of an entire file.

13:06 dnolen: zippy314: then why not local functions?

13:07 zippy314: like how?

13:07 dnolen: ,(let [f (fn [a b] (+ a b))] (f 1 2))

13:07 clojurebot: 3

13:08 zippy314: hmm. That might work...

13:08 semperos: things like what clj-record does make sense for creating top-level fn's at runtime

13:09 but if you just need scoping, local fn's are probably a better bet

13:09 zippy314: I've read a little about clj-record, I need to dig into the source for that.

13:09 semperos: well, not at runtime perse, but dynamically

13:10 it's init-model macro dynamically generates CRUD fn's for a given database table

13:10 so that they're available elsewhere for CRUDdy activities

13:10 zippy314: But, the issue with local functions is that you can only use them once, wouldn't you have to re-declare them every time? The idea is to define the grammar for such functions, and then be able to use that grammar, lexically scoped.

13:11 semperos: zippy314: you might need to provide actual/pseudo code examples to get across exactly what you want

13:11 raek: zippy314: are you making a macro that will run once during initialization or an interpreter that will do this at run-time?

13:11 zippy314: the latter.

13:12 raek: then you should definitely not use defs for this

13:12 KirinDave: zippy314: If only we could pass functions around in a map :)

13:12 If only we could have... functions... without names. :)

13:12 zippy314: although the former might work too.

13:12 :-)

13:13 raek: if you will never write any source code that refers to the generated functions, there is no need for defs

13:14 defs are for programmers :)

13:37 * dnolen fails to understand the appeal of Go when there's OCaml for that sort of thing.

13:38 ejackson: dnolen: what kind of American are you - that's FRENCH !

13:39 dnolen: heh, I suppose I lack that level of nationalism.

13:39 manutter: Eh oui? Et qu'est-ce qu'ils ont, les francais? Hmm?

13:39 :)

13:39 ejackson: :)

13:42 fliebel: dnolen: What is the relation between OCaml and Go?

13:42 dnolen: fliebel: high performance systems programming languages w/ high-level features.

13:43 fliebel: dnolen: Oh, maybe I should check that out, I heard they have good pattern matching ;)

13:44 dnolen: fliebel: ;)

13:46 fliebel: dnolen: I have read some of the big paper by now, still not making much sense. I get the general idea, but when they start to bend equals signs ( ⊇ ), I get lost.

13:47 dnolen: fliebel: don't be confused, just means subset

13:47 fliebel: Wow, awesome, my unicode pallet has names for these things that make sense

13:48 Maybe I should read it again with the pallet at hand :)

13:50 dnolen: fliebel: you should, the math stuff is really about defining some things tersely. The only part that doesn't make sense to me is the operational semantics (?) notation. But that's not important to understand the paper anyhow.

13:52 fliebel: ah-ha!

13:56 dnolen: fliebel: it also turns out that using if + instance? checks is probably going to much faster for most predicate dispatch use cases. They put us in the 90ms territory versus 2000ms for multimethods.

13:58 i.e. when looking at 1e8 iterations on a 3 test dispatch.

13:58 subnetmax: hello - is there an elegant way to create a sequence with each item based on a function of all the previous items?

13:58 lazily would be nice

13:59 fliebel: subnetmax: iterate, kind of...

13:59 amalloy: subnetmax: reductions

14:00 &(reductions + (range 5))

14:00 sexpbot: ⟹ (0 1 3 6 10)

14:01 fliebel: dnolen: Wait, what are multimethods using internally? And are we talking a flat if, or some hand crafted DAG?

14:01 subnetmax: sorry, not able to get my head around how to use that.... i have a function next-item that takes a list of all previous items, could you show me how to use iterate or reductions to do that?

14:02 amalloy: subnetmax: all previous elements that you've output?

14:02 subnetmax: yeah

14:02 fliebel: (iterate #(conj % (next-item %)) the-items)

14:03 amalloy: fliebel: yeah, looks good

14:03 subnetmax: and the-items is [] for the first call of this?

14:03 amalloy: subnetmax: it depends what your input is

14:04 that is: imagine this function already existed. how would you call it?

14:04 subnetmax: i should say that i'm using rand to help generate each item, so my function is not referentially transparent

14:05 fliebel: subnetmax: well, the-items could be [], so then it'd invoke next-item with [] and conj that onto the empty vector.

14:05 subnetmax: ok, i'll see if i can make that work, thanks very much

14:05 amalloy: this all sounds too much like unfold

14:06 subnetmax: well everything sounds like some kind of fold if you think about it enough :)

14:06 fliebel: &(take 10 (iterate #(conj % (reduce + %)) [1]))

14:06 sexpbot: ⟹ ([1] [1 1] [1 1 2] [1 1 2 4] [1 1 2 4 8] [1 1 2 4 8 16] [1 1 2 4 8 16 32] [1 1 2 4 8 16 32 64] [1 1 2 4 8 16 32 64 128] [1 1 2 4 8 16 32 64 128 256])

14:06 fliebel: sweeet :)

14:06 amalloy: Time to mention amalloy-utils :)

14:07 amalloy: fliebel: why would i, when you're here to do it for me

14:07 fliebel: amalloy: Because I don;t know where unfold lives :O

14:07 amalloy: aww

14:07 it's in seq

14:07 https://github.com/amalloy/amalloy-utils/blob/master/src/amalloy/utils/seq.clj#L48

14:09 fliebel: amalloy: How would you solve this problem using unfold?

14:09 amalloy: note that if you actually depend on all the previous outputs, you can never generate an infinite sequence - you'll be holding onto the head of a large sequence forever

14:10 fliebel: i wouldn't, really, because unfold assumes you want to generate an infinite sequence

14:10 subnetmax: i'm only looking to generate max 30 items, and performance does not matter

14:10 fliebel: amalloy: You can never generate infinite sequences in a finite universe :)

14:10 amalloy: and the assumption that element x really depends on all previous elements is anathema to me

14:11 fliebel: subnetmax: What are you doing with all those ellements?

14:12 subnetmax: well for example, picking people for tasks, you need to know who has already been picked, along with other considerations

14:13 manutter: subnetmax: for that you could just generate a list of people, shuffle it, and pick them off in order

14:13 (which will be a random order after the shuffle)

14:14 subnetmax: imagine that as you pick each person, you need to look at who has already been picked to avoid personality clashes

14:14 but the issue is not important enough to start looking a large constraints solver

14:14 manutter: ah, ok

14:14 amalloy: subnetmax: don't generate a sequence of persons, imo

14:14 fliebel: subnetmax: Oh, I was just about to mention Logos.

14:14 amalloy: reduce from a sequence of tasks into a map of assignments

14:14 then you only depend on the one object: a map

14:15 subnetmax: why is depending on a map better than depending on a list

14:15 amalloy: it's not, really

14:15 but it's much easier to work with

14:17 fliebel: subnetmax: Have a look at the readme of core.logic, especially disequallity and defining facts. https://github.com/clojure/core.logic

14:26 dnolen: fliebel: multimethods use a couple of things, memoization, PersistentHashMap of dispatch values

14:27 fliebel: DAG -> if. but I want it to be flexible enough to goto case if we see that that'll be more efficient. shared parts of the tree are lifted into fns, like matchure.

14:28 fliebel: the coolest thing about the paper is the notion of necessity from lazy evaluation - that's what makes the smaller trees possible.

14:29 subnetmax: i can solve my problem like this http://pastebin.com/083aRBUe - i was just thinking that i seem to be doing something that other people do and so perhaps there is already a function for

14:32 fliebel: subnetmax: Well, iterate and unfold would work.

14:33 amalloy: iterate *or* unfold, i think is clearer

14:35 fliebel: dnolen: Okay, I did not understand that necessity part at all.

14:41 no_mind: If I define a record with two attributes lets say first_name and last_name. Can I define a protocol which will change the attributes of the record ?

14:41 fliebel: dnolen: The raging hordes are starting to respond to your question :)

14:42 no_mind: records are immutable

14:42 But you can say (assoc this :first_name "foo" :last_name "bar")

14:53 subnetmax: Is it right that (disj #{1 2 3} #{2}) evaluates to #{1 2 3}? I was expecting #{1 3}

14:56 manutter: ,(doc disj)

14:56 clojurebot: "([set] [set key] [set key & ks]); disj[oin]. Returns a new set of the same (hashed/sorted) type, that does not contain key(s)."

14:57 manutter: hmm

14:57 ,(disj #{1 2 3} #{2})

14:57 clojurebot: #{1 2 3}

14:57 subnetmax: user=> (disj #{1 2 3} #{2})

14:57 #{1 2 3}

14:58 manutter: ,(disj #{1 2 3} 2)

14:58 clojurebot: #{1 3}

14:58 manutter: ,(disj #{1 #{2} 3})

14:58 clojurebot: #{1 #{2} 3}

14:58 manutter: doh

14:59 ok, got it

14:59 ,(= #{2} #{2})

14:59 clojurebot: true

14:59 manutter: well, got most of it

15:00 subnetmax: sorry, what am i doing wrong?

15:00 manutter: #{2} != 2

15:01 subnetmax: oh i see, it's not two sets, it a set and a list of keys to remove

15:01 manutter: #{2} is not one of the values in #{1 2 3}

15:01 yeah

15:01 subnetmax: how can i do a disjunction between two sets?

15:02 dnolen: fliebel: heh, not getting much upvotes, but noone responding w/ an interesting answer either. Except "easier" maybe.

15:03 manutter: ,(remove #{2} #{1 2 3})

15:03 clojurebot: (1 3)

15:03 manutter: hrm, close

15:04 ,(into #{} (remove #{2} #{1 2 3}))

15:04 clojurebot: #{1 3}

15:04 manutter: ,(into #{} (remove #{1 4} #{1 2 3 4 5}))

15:04 clojurebot: #{2 3 5}

15:04 fliebel: dnolen: How do you know? (not= minutes upvotes) I wonder if anyone there knows both OCaml and Go ( and Rust?)

15:05 raek: subnetmax: check out the functions in clojure.set

15:05 manutter: subnetmax: "into #{}" plus "remove" seems to work

15:06 bartj: subnetmax, disjunction = union of two sets ?

15:06 manutter: I'd have thought there'd be a built-in for that, but...

15:06 bartj: there is

15:06 fliebel: manutter: there is, raek said it.

15:06 bartj: check out clojure.set

15:06 manutter: ,(disj #{1 2 3 4 5} (seq #{2 4}))

15:06 clojurebot: #{1 2 3 4 5}

15:06 subnetmax: ah, difference

15:07 manutter: sigh

15:07 raek: ,(clojure.set/difference #{1 2 3 4 5} #{2 4})

15:07 clojurebot: #{1 3 5}

15:07 manutter: I thought that one might have worked

15:07 subnetmax: it's just that difference and disjunction have exactly the same meaning, so why would i look for difference when i had found disj?

15:07 dnolen: fliebel: it doesn't look like it. But honest opinion if you know OCaml you'll think is a bad joke.

15:07 think Go

15:07 manutter: Oh, there it is, I was looking in clojure-contrib.set

15:08 raek: subnetmax: disjunction means "or", so that means the set of the elements that are in set a *or* set b

15:08 (inclusive or)

15:08 disj stands for disjoin

15:08 which means to separate

15:09 fliebel: dnolen: I'd say one needs some brains to write a language, so someone must have thought Go was a good idea. One of those people even said Rust was written in OCaml.

15:10 raek: hrm. but "disjoin" and "disjunction" do share a common root. I guess the meaning of "disjunction" has shifted in meaning over the history

15:15 dnolen: fliebel: Go is a classic example of Worse Is Better. That maybe a good or bad thing depending on your perspective.

15:39 fliebel: re: necessity. it's just about figuring which column *must* be tested. if it's going to be tested in every path, test it first, turns out this can usually produce smaller trees.

15:41 fliebel: dnolen: But how do you ever figure that out? I mean, okay, when you write (and (< x 3) (< x 4)) you could *maybe* figure out that the first one is redundant, how can you know?

15:41 Is this why the wiki said you had to define predicates and their relations?

15:42 dnolen: fliebel: logic programming remember.

15:42 fliebel: exactly, those kinds of issues are checked before we produce the dag.

15:43 fliebel: Subclassing and negation is the easiest to check probably.

15:45 bartj: what does ~ and ` mean while writing macros ?

15:45 *do

15:46 fliebel: &(let [x 5] `(+ 1 ~x))

15:46 sexpbot: ⟹ (clojure.core/+ 1 5)

15:47 bartj: oh, I was reading ` as a '

15:48 raek: bartj: syntax-quote ` is very similar to quote ' except that it resolves symbols and has a unquote feature

15:49 dnolen: fliebel: yeah the key bit is that you can't use just anything for a guard. You have declare the predicates you will use as guards, then we can reason about them.

15:53 bartj: ,(doc `)

15:53 clojurebot: Unmatched delimiter: )

15:53 fliebel: dnolen: So in the end you have kind of a trie of guards instead of words :)

15:54 raek: bartj: it's documented here http://clojure.org/reader

16:26 bartj: raek, thank you, as usual

16:45 lawrent: Does clojure support currying? If not, do you often find that you miss this feature?

16:46 opqdonut_: ,(doc partial)

16:46 clojurebot: "([f arg1] [f arg1 arg2] [f arg1 arg2 arg3] [f arg1 arg2 arg3 & more]); Takes a function f and fewer than the normal arguments to f, and returns a fn that takes a variable number of additional args. When called, the returned function calls f with args + additional args."

16:46 lawrent: That's a little clumsy, no?

16:46 opqdonut_: not really, no

16:46 lawrent: Seems to me that currying is one of the very basics of functional programming, along with referential transparency, and clojure does neither well

16:46 opqdonut_: I miss a real type system more than currying

16:47 and clojure does referential transparency better than any other lisp

16:47 or any other jvm language for that matter

16:47 lawrent: ...but not better than haskell

16:47 kephale: partial can be limiting due to ordering of arguments

16:47 lawrent: exactly!

16:47 opqdonut_: well so is ordinary currying

16:48 amalloy: kephale: define flip, then partial a flipped version

16:48 kephale: but you can get the same effect with the #( blah %1 %2 ) macro

16:48 opqdonut_: but yeah, there's no equivalent of flip/rcurry in the clojure standard lib

16:48 kephale: amalloy: i tend to just use the function reader macro

16:48 amalloy: so do i

16:49 but it's not hard to get partial to fill in something other than the first N arguments

16:49 kephale: noted

16:49 amalloy: i have a reodering library for juggling around function arguments in various ways if you need something more sophisticated than flip

16:50 dnolen: lawrent: given fns can have variable arity how do you see currying as useful in Clojure?

16:51 lawrent: a pure function in Clojure is just as referentially transparent as in any other lang, FP or not.

18:02 zippy314: how come (defn x.x [] 1) works, but you can't call (x.x)?

18:02 heh

18:02 (defn y.y [] 1)

18:03 hiredman: the code that resollves symbols to vars/classes assumes a symbol with a dot in it is a class

18:07 zippy314: hiredman: thanks. another q: why can't I do something like this: (def x "foo") (defn (symbol x) [] "bar")

18:09 amalloy: because (symbol x) isn't a symbol, it's a list

18:09 defn needs a literal symbol

18:09 &`(defn ~(symbol "test") [] "data")

18:09 sexpbot: ⟹ (clojure.core/defn test [] "data")

18:09 hiredman: zippy314: the defn special form doesn't evaluate the first arg

18:10 or any of it's args

18:13 amalloy: hey hiredman, does clojurebot have a trigger to make him process commands or eval forms mid-message? something like, "hey zippy314, check out ~~source defn"?

18:15 hiredman: no

18:21 semperos: writing a Clojure api around a Java lib; what do folks thing would be a good name for a namespace that only has defmethod's of print-method to make printing the Java original objects more meaningful?

18:26 amalloy: myapp.tostring?

18:27 lawfulfalafel: could someone recommend a good tutorial for making your first project with lein?

18:27 I am having a bit of trouble finding an explicit and up to date version

18:27 technomancy: lawfulfalafel: have you read through "lein help tutorial"?

18:28 lawfulfalafel: oh sweet, your the author right?

18:28 amalloy: https://github.com/technomancy/leiningen/blob/master/TUTORIAL.md

18:28 technomancy: aye

18:29 amalloy: looks like our good friend technomancy updated that yesterday. hard to get more canonical and current than that

18:29 lawfulfalafel: oh that looks really useful, I was stuck on the initial github page and didn't see it

18:29 technomancy: these days it's bundled with lein under the help task

18:33 brehaut: has anyone using clojure.contrib.sql or clojureql encounted "Generated keys not requested. You need to specify Statement.RETURN_GENERATED_KEYS to Statement.executeUpdate() or Connection.prepareStatement()."

18:36 hiredman: brehaut: yes

18:37 brehaut: hiredman: any suggestions on how i might fix it?

18:37 hiredman: it is a problem with c.c.jdbc

18:37 we ended up writing our own thinner wrapper over jdbc

18:37 that we use in conjuction with c.c.jdbc

18:37 just some convience stuff around raw jdbc statements

18:38 (not available anywhere, btw)

18:38 brehaut: ok, thanks

18:38 ataggart: Since the new clojure.java.jdbc is being worked on currently, it's a good time to give feedback.

18:38 scgilardi: https://github.com/clojure/java.jdbc also has some code that may be helpful.

18:39 hiredman: I think the new one already defaults to asking for generated keys to be returned, but I don't recall for sure

18:39 technomancy: the dude himself returns

18:40 brehaut: huh the most curious thing is that this same project works fine running locally connected to the live database via ssh tunnel

18:43 clizzin: any best practices for dealing with date/time in clojure? is there a wrapper for that hideous beast, the java calendar?

18:43 seancorfield: hiredman: brehaut scgilardi yes, c.j.j will return generated keys by default for any single insert operation

18:43 brehaut: seancorfield: cool

18:44 technomancy: clizzin: avoid j.u.Calendar and Date at any cost; you want clj-time

18:44 seancorfield: there will be a 0.0.1 release this weekend (snapshots exist right now)

18:44 brehaut: seancorfield: is that going to be backward compat with 1.2.x?

18:44 clizzin: technomany: ah yes, i remember using that once but had forgotten all about it. thanks!

18:45 seancorfield: brehaut: should be - all the new behavior is optional (naming strategies etc)

18:45 brehaut: seancorfield: thats great, thanks :)

18:45 seancorfield: oh, exceptions are no longer printed to *err* - but the print-* functions are exposed so you can leverage them

18:45 otherwise it should be just the same by default...

18:46 and it has its own resultset-seq so you'll be able to control how sql entity names are converted to keywords (and vice versa)

18:46 i'd love to get some folks using it (apart from me!) so i can get more feedback :)

18:47 zrilak: Just saw a Clojure snippet to lazy-generate a Fibonacci sequence: (def fib (lazy-cat [0 1] (map + fib (rest fib)))) , and happened upon something superficially very similar in the SICP chapter on stream processing. Is that some kind of well-known "pattern" (for want of a better word) in functional programming? :)

18:49 brehaut: zrilak: its (probably) not something you would want to do in clojure because the program will hold onto the head of the fib sequence

18:49 zrilak: meaning that as you realize more and more of it you will permenantly consume your heap

18:50 zrilak: I understood it will generate an embedded concatenation of [0 1] [1 [2 [3 [5... ]

18:50 gotcha, yes, I thought so myself

18:51 brehaut: zrilak: the pattern is well known; you see that sort of thing more in haskell though

18:51 zrilak: all right!

18:52 brehaut: that's good to know, since a good part of recognizing a piece of code lies in having been exposed to isomorphic examples

18:52 isomorphous*

18:56 joshua__: Where can I find a project.clj file which uses clojure-contrib 1.3? I'm trying to use 1.3 priority map, but lein deps is giving me errors.

18:56 VT_entity: christ are we already on 1.3?

18:56 joshua__: It is alpha etc.. but I need a priority queue and priority map works for that.

18:57 VT_entity: I dunno if I can help you... out of curiosity... what changed in 1.3?

18:58 technomancy: joshua__: I don't think there's a monolithic contrib that works with 1.3

18:58 joshua__: technomancy, I just want clojure-contrib/priority-map

18:59 technomancy: if there's no AOT in it you may be able to use 1.2

18:59 joshua__: technomancy, alright. Thanks.

19:00 VT_entity, https://github.com/clojure/clojure/blob/master/changes.txt shows some changes. The most interesting changes I've read about is the change to contrib. It is being set up so you can choose to include only the libraries you want.

19:00 VT_entity: thank you

19:06 clizzin: if i run a shell command from clojure (using java's Runtime.exec), does anyone know if that starts a separate process, or is it contained within the same java process?

19:07 technomancy: it's a separate process, with caveats

19:08 there's a bug in the JVM where the second process temporarily requires as much memory as the parent process

19:08 which makes it usually fail in production

19:09 clizzin: technomancy: i see. hmmm

19:12 if i'm exec-ing several processes simultaneously using future, does each new process require the cumulative memory amount of all the previously exec-'d processes?

19:12 Derander: anyone have any experience inserting piles of data w/ congomongo? I keep getting "db message size is too big (some number) max is (some slightly smaller number)"

19:13 clizzin: (basically, i have a ruby script that does some shell commands, and i thought i'd try to take advantage of clojure's concurrency to run some of those shell commands concurrently since they don't always depend on one another.)

19:13 Derander: https://gist.github.com/958174 <-- this is the clojure code that I'm running. it's trying to insert a collection of hashes.

19:16 technomancy: clizzin: not cumulative, no. each subprocess will just take as much memory as the parent

19:16 for it to work reliably you need the ruby process to be launched independently and communicate with it over a socket or rest or something

19:17 unless you know your JVM will never be using more than 50% of the system's available memory

19:19 clizzin: technomancy: oh, the idea is to replace the ruby script with the clojure program. this sounds potentially dangerous though, since each of the shell commands i'm running is a hadoop job (a small hadoop job, but still, potentially bad)

19:20 technomancy: who's doing the launching?

19:21 clizzin: clojure is launching the jobs

19:21 the goal is to cut ruby out entirely

19:22 technomancy: isn't the point of hadoop to run jobs on a remote cluster?

19:24 seancorfield: joshua__: this monolithic contrib exists for 1.3.0 http://build.clojure.org/releases/org/clojure/contrib/standalone/1.3.0-alpha4/

19:25 i recall it being a bit fussy due to some additional settings in leiningen

19:25 clizzin: yes. basically, there are a series of hadoop jobs i need to run, and i invoke them by calling 'hadoop jar job.jar class-name args' on the shell. but i want to run several of these jobs regularly, so i was hoping to automate that. i did it initially using ruby, but thought it might be easier to run several commands at once using clojure

19:25 seancorfield: if you want to try, i can look in git history of project.clj to see how i used to have it setup back then

19:25 clizzin: there is probably a better way to do this though -- any ideas?

19:26 jnberg: bash script + cron! :D

19:26 clizzin: jnberg: can that kick off asynchronous commands?

19:26 jnberg: thought you were just looking to queue up jobs for hadoop

19:27 clizzin: yeah. but when i run 'hadoop jar ...', the shell blocks until the job is done, no?

19:27 seancorfield: joshua__: here's what i had in project.clj for alpha2: [org.clojure.contrib/standalone "1.3.0-alpha2"]

19:28 jnberg: hmm, not sure with hadoop honestly, sorry :( With gridengine it doesn't block, but that doesn't help :-/

19:30 clizzin: oh wait, duh, i can run the command with '&' at the end

19:32 oh, well, ruby doesn't run that in background, but there's another easy way to do it. anyway, i'll stop talking about non-clojure stuff now.

20:30 zippy314: &(+ 1 1)

20:30 sexpbot: ⟹ 2

23:43 symbole: What's the recommended way of making a Clojure application aware of the environment that it's running in, and subsequently load the correct config file (properties equivalent in the Java world)?

23:43 hiredman: there is System/env

23:45 symbole: I was thinking of passing -Denv=foo, and loading foo's config file. Is this idomatic, or are multiple approaches used?

23:45 Loading foo's config file by looking at System properties, I meant.

23:52 I gess Clojureland is at sleep. I'll come back later.

Logging service provided by n01se.net