#clojure log - Nov 19 2010

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

0:00 technomancy: rata_: the example on that page actually is a leiningen plugin; you just have to add it to :hooks in project.clj to activate it

0:00 I've been thinking about a function that would abstract away the messiness of being able to add-hook inside eval-in-project, but haven't written anything yet

0:00 rata_: yes, I got that part

0:02 the part I don't imagine how to implement is how to show the return value of a function call and all its locals

0:02 I thought that had to be implemented in swank-clojure

0:05 technomancy: hmm... lemme think

0:07 if you don't mind args being a single vector instead of being named, this would do it: http://p.hagelb.org/break.clj.html

0:07 it would be possible to make break-hook's args match those of the target function with a severe macro, but I don't think I'm up for the task right now

0:10 rata_: yes, that's close to what I want, but I'd like to see the locals, not just the args

0:10 that's the most complicated part probably

0:11 technomancy: the macro would have to construct the hook function based on the :arglists in the metadata of the target function

0:12 rata_: it'd have to insert the body of target there to have all the locals

0:13 but the hook can't be a macro

0:13 technomancy: no, not necessarily. you could construct a wrapper function which has the same argument list as the target function and simply pass the arguments on to the target function

0:13 right, the hook can't be a macro, but the hook function could be generated by a macro

0:14 rata_: yes... but the locals... even if you has the same argument list, you can't see the locals of target

0:14 technomancy: well, the way hooke works is that the target function is replaced by the wrapper function

0:15 so as long as the wrapper function passes the same args into the target, a break point in the wrapper will be equivalent to a break point inside the target

0:15 as long as the wrapper has the same names for all its arguments

0:15 the only difference is the first argument of the wrapper *is* the target

0:16 it's a juicy problem... if you don't do it then maybe we can tackle it at the next Seajure meeting

0:16 rata_: so, you are saying that with that break.clj, if you have a (let [x ...] ...) inside target, you could see the value of x?

0:17 technomancy: oh no not like that; just the function parameters

0:17 I see what you mean

0:17 rata_: =)

0:18 that's the difficult part I think

0:18 technomancy: I thought you meant you'd rather see (defn my-target [a b c]) as a b c rather than & args

0:18 rata_: no... I mean all the locals of the function

0:18 not the args

0:18 technomancy: I don't know if it's possible to get even the let-bound stuff

0:19 on a regular defn anyway, you could do it with a defn-debug... which is what you suggested in the first place. =)

0:20 it still might be tricky to traverse the body find all the tail positions in order to insert breakpoints

0:20 rata_: if you just want to see the locals, it's easy, you put a (swank.core/break) just before the expression that returns the value of the function, in the most nested let (don't care about let "branches")

0:20 yes, it might be tricky

0:22 but in addition to have the value of all the locals, it'd be great if you could see along them the return value of the fn

0:23 technomancy: that shouldn't be too hard; just replace the final value with (let [return-value# ~v] (swank.core/break) return-value#)

0:23 rata_: because it happens to me all the time that to see just the return value of one fn is difficult, because I normally put it inside a form, so I don't bound it directly to a local

0:23 technomancy: of course with pure functions once you have the locals it's easy to calculate the return value =)

0:24 rata_: it involves to write (or copy-paste) a lot of code to the repl

0:24 and it's annoying when you have to do it for many fns

0:24 to find where the bug is

0:25 KirinDave: Is there a clever way of invoking protected methods on instances from clojure?

0:26 rata_: that's why I suggested something like defn-debug that puts a (let [return-value# ~v] (swank.core/break) return-value#) at the right place

0:26 =)

0:27 technomancy: rata_: yeah, I think you have the right idea.

0:28 rata_: I find (swank.core/break) immensely useful when debugging, so I'm sure having something like defn-debug would be very useful as well =)

0:28 the first name I thought about was defn*, but then remembered that the asterisk is mainly used by the compiler

0:29 *thought of

0:31 technomancy: not just used by the compiler, but it does indicate an internal function

0:31 defn-debug is better

0:34 hiredman: KirinDave: clojure.contrib.reflect I believe

1:10 rata_: if "lein compile" with :warn-on-reflection true doesn't warn about anything, does it mean that type hints wouldn't help the performance?

1:12 tomoj: need to actually run the program, no?

1:13 KirinDave: hiredman: Thank you, btw

1:13 amalloy: tomoj: i don't think so. the reflection warnings are only at compile time

1:19 tomoj: how can clojure know at compile time whether there's reflection?

1:20 amalloy: tomoj: um, because if it can't resolve the method calls at compile time, it has to generate code that uses reflection to resolve them at runtime

1:21 rata_: so what about my question?

1:21 amalloy: rata_: i don't know. i don't use lein compile or warn-on-reflection

1:21 rata_: ok

1:23 methods are compiled as anon fns right? that is, they are compiled as fn__xyz?

1:23 amalloy: you mean, anon fns are compiled as methods?

1:24 either way it's not correct. functions, anonymous or not, are compiled as classes with an invoke(args) method

1:26 rata_: yes... I mean that methods are compiled to classes like fn__148

1:27 is there a way to give names to methods, like (fn name [...] ...)?

1:29 dnolen: (letn [f (fn foo [])] f)

1:29 ,(letn [f (fn foo [])] f)

1:29 erg

1:29 ,(let [f (fn foo [])] f)

1:29 amalloy: &(fn name [] 1)

1:29 sexpbot: ⟹ #<sandbox8506$eval10166$name__10167 sandbox8506$eval10166$name__10167@184dc98>

1:29 amalloy: ,(fn name [] 1)

1:29 clojurebot: #<sandbox$eval104$name__105 sandbox$eval104$name__105@de04cd>

1:29 amalloy: sexpbot: kill

1:29 sexpbot: KILL IT WITH FIRE!

1:29 amalloy: huh. sexpbot is dead. Raynes, you around?

1:29 anyway rata, that's exactly how you do it

1:30 clojurebot: java.lang.Exception: Unable to resolve symbol: letn in this context

1:30 #<sandbox$eval109$foo__110 sandbox$eval109$foo__110@260829>

1:30 amalloy: ah, good morning sexpbot

1:31 &(fn quetzacoatl [x] (+ 10 x))

1:31 sexpbot: ⟹ #<sandbox8506$eval10175$quetzacoatl__10176 sandbox8506$eval10175$quetzacoatl__10176@11a7733>

1:39 trybeingarun: Hey guys

1:39 how do you write a recursive function when you use #(function) format?

1:40 letfn here also?

1:40 amalloy: trybeingarun: you could do it with recur. but usually, "don't do it" is a good answer

1:40 trybeingarun: you do you recommend against doing it? Readability issues or anything else specific?

1:41 amalloy: well, rolling your own recursion is usually unnecessary - you get better and more readable code by using HOFs like reduce, iterate, map, etc

1:41 and if you want to, it's usually complicated enough to merit a (defn) or at least a (fn)

1:42 trybeingarun: hm

1:42 Am currently trying to write all the code in "The Little Schemer" in clojure

1:42 _ato: you can't do non tail recursion with #(...)

1:42 you can with fn though

1:42 (fn foo [x] (when (pos? x) (foo (dec x))))

1:42 trybeingarun: There is a specific chapter on lambda functions

1:43 dnolen: trybeingarun: #(f ..) is for simple stuff, easy abused, I avoid it now mostly.

1:43 trybeingarun: so I was wondering how to write recursion in such scenarios

1:43 amalloy: trybeingarun: (fn) is lambda

1:43 dnolen: trybeingarun: use fn

1:43 amalloy: #() is shorthand

1:43 trybeingarun: _ato: u mean 'recur' can't be used??

1:43 mister_roboto: dnolen: how is #() easily abused? curious what kind of scenario you're thinking of

1:43 _ato: recur can't be used to solve all problems

1:43 amalloy: &(macroexpand '#(inc %))

1:43 sexpbot: ⟹ (fn* [p1__10198#] (inc p1__10198#))

1:44 dnolen: mister_roboto: any scenario where the inside is complex, %1 %2 etc carries little meaning.

1:44 trybeingarun: amalloy & dnolen: currently I am using (fn ...). Just wanted to find out if the same can be done with %()

1:44 mister_roboto: dnolen: so when it's complicated enough that you want the args to have real names

1:44 amalloy: &'#(inc %)

1:44 sexpbot: ⟹ (fn* [p1__10206#] (inc p1__10206#))

1:45 _ato: ,(#(when (pos? %1) (recur (dec %1))) 10)

1:45 clojurebot: nil

1:45 amalloy: trybeingarun: not always

1:45 dnolen: mister_roboto: I do, plus #() is just weak, no destructuring arguments

1:45 &(map #(* % 2) [1 2 3 4])

1:45 sexpbot: ⟹ (2 4 6 8)

1:45 trybeingarun: hm

1:45 amalloy: #() really is shorthand for simple cases of (fn)

1:46 _ato: ,(#(when (pos? %1) (2 + (recur (dec %1)))) 10)

1:46 clojurebot: java.lang.UnsupportedOperationException: Can only recur from tail position

1:46 mister_roboto: dnolen: I use it all the time to map or apply something relatively small. normally don't care about destructuring in such cases.

1:46 pppaul: &(#(% %) #(% %))

1:46 sexpbot: java.lang.StackOverflowError

1:46 amalloy: for complicated cases, there's a reason you can't use #() :P

1:46 _ato: ,(#(fn foo [x] (pos? x) (2 + (foo (dec x)))) 10)

1:46 clojurebot: java.lang.IllegalArgumentException: Wrong number of args (1) passed to: sandbox$eval121$fn

1:46 _ato: ,((fn foo [x] (pos? x) (2 + (foo (dec x)))) 10)

1:46 clojurebot: java.lang.ClassCastException: java.lang.Integer cannot be cast to clojure.lang.IFn

1:46 trybeingarun: amalloy: :P

1:46 _ato: ,((fn foo [x] (pos? x) (+ 2 (foo (dec x)))) 10)

1:46 clojurebot: java.lang.StackOverflowError

1:46 _ato: heh

1:46 brain not working well today

1:47 nevermind

1:47 ;-)

1:47 pppaul: my code is better for stack overflows

1:47 dnolen: &(map (fn [[k v]] (* k v)) {1 2 3 4})

1:47 sexpbot: ⟹ (2 12)

1:48 amalloy: &(map #(apply * %) {1 2 3 4})

1:48 sexpbot: ⟹ (2 12)

1:48 pppaul: dnolen, that's the sexy destructuring i like

1:48 amalloy: definitely less efficient, though arguably more readable for such a simple case

1:49 dnolen: &(map (fn [[k v]] (* k (/ v 2))) {1 2 3 4})

1:49 sexpbot: ⟹ (1 6)

1:49 LauJensen: dnolen: Thanks for fighting the good fight on HN, I just read the comments :)

1:49 dnolen: LauJensen: ugh

1:49 amalloy: dnolen: there you go, that's one that cries out for (fn)

1:49 dnolen: amalloy: ;)

1:50 LauJensen: sometimes HN really lets you down. BTW, I'm really blown away by ClojureQL!

1:50 LauJensen: just add multi table joins :D

1:50 LauJensen: dnolen: I was quite happy to see that the majority of comments were positive actually, but its super sweet that you like it :)

1:50 amalloy: &(map #(/ (apply * %) 2) {1 2 3 4}) ; i guess?

1:50 sexpbot: ⟹ (1 6)

1:50 LauJensen: dnolen: multi table joins will be in 1.0.0 final, I just didnt have time before now

1:50 dnolen: LauJensen: also, do you do any SQL sanitizing?

1:51 LauJensen: dnolen: like what?

1:51 pppaul: mapping over hashmaps is ugly

1:52 dnolen: LauJensen: does ClojureQL ever take raw strings for substition into the final query?

1:53 LauJensen: dnolen: You can supply raw strings as column specs if you need. We also have an option to append a string to the final query

1:54 dnolen: LauJensen: so don't those need to be sanitized for SQL injection?

1:54 LauJensen: dnolen: You mean parameterized?

1:54 dnolen: LauJensen: sure, I'm no SQL expert.

1:55 LauJensen: Ah ok. Paramterization is on the chart for 1.0.0 final, its an important feature in guarding against injection attacks

1:56 pppaul: but i love injection attacks

1:56 dnolen: LauJensen: nice. As an aside I love how little code it ended up being. 700 LOC, less than Enlive ;)

1:56 LauJensen: dnolen: I was quite blown away by it myself. The old ClojureQL was thousands and thousands of lines in 10 different files. Arel is 4600+ lines in 30 something files. Also doing this in about 2 weeks was quite an experience

1:56 Shred + Rewrite FTW :)

1:59 dnolen: LauJensen: I have strong disgust for SQL syntax, not the tech. Like Clojure, ClojureQL puts a better interface on great technology.

1:59 LauJensen: dnolen: True. And I think Relational Algebra has always been the right way to do it. I dont know who dreamed up SQL92 instead :)

2:03 But its great to see how much elegance you get for free from Clojure, if you comepare Arels syntax to sexps there's quite a difference

2:06 dnolen: LauJensen: so is the idea to have ClojureQL be very focused on querying? leave transactions to clojure.contrib.sql and modeling to libraries like carte ?

2:07 LauJensen: dnolen: I would say that querying is such a huge part of our interactions with databases that it was just the natural place to start, however I will definitely introduce a (dosync) like semantic into it. Right now it automatically promotes inserts/updates to transactions when there are multiple rows involved

3:00 harishtella: anyway to import everything from a java package (like processing.core.*) ?

3:00 LauJensen: nope

3:01 harishtella: aww, why not?

3:05 _ato: possibly because it's not possible to get a list of all classes in a package, due to custom class loaders

3:06 my guess would be that javac's import foo.* doesn't actually search out all classes in the foo package, it instead just sets a search path for unqualified class names

3:07 Clojure's namespaces work differently to Java's, when you import something in Clojure it actually creates an entry in the namespaces

3:07 harishtella: ah, I see, thanks

3:41 cphang_: /join #clojure

3:41 auscompgeek: cphang_: You are already here.

3:41 cphang_: yap :)

3:41 didn't realized it

9:04 fliebel: morning

9:04 tonyl: morning

9:08 fliebel: There is a neat Twitter lib in Python that generates urls from method calls dynamically so that it requires little maintenance and supports all Twitter methods. How would I do such magic in Clojure? I'm talking about the second point: http://mike.verdone.ca/twitter/#why

9:12 I could do a macro that just converts function calls to strings, but I'm not sure that's the cleanest way to do it.

9:12 Chousuke: I don't think you can do that directly, since clojure doesn't have methods that you can create on the fly :P

9:13 but you could always have some function that takes a bunch of keywords and returns a function that fetches the url

9:13 or a macro

9:14 fliebel: like (twitter :statuses :user-timeline)?

9:14 Chousuke: fliebel: something like that

9:15 Tordmor: "you won't have to update your version of the API (though you may have to update your code" WTF?

9:15 Chousuke: or if you want to be fancy, (twitter :statuses.user-timeline)

9:15 Tordmor: As if that were something good.

9:16 fliebel: Tordmor: Kind of. Twitter wont just remove an url, but they might add one.

9:49 piva: hey there!

9:51 could someone please clarify a newbie mind towards this problem: I need to count words found in a given string, I thought that I could do that by splitting the string by whitespace and iterating over the resulting vector, create a map with the word as key and increase the value... I researched it vastly for over 4 hours yesterday and as a good newbie I stil don't have a clue to how to do it properly ://

9:53 chouser: piva: consider 'reduce'

9:53 tonyl: or split and count

9:54 cemerick: chouser: I see shades of Rich in you as time goes on ;-)

9:54 piva: chouser: I started to consider it only today, haha

9:54 tonyl: (count (clojure.string/split "my string of words" #"[:whitespace:]"))

9:54 Raynes: cemerick: He *is* rich. Just wearing a mask.

9:55 piva: tonyl: ah, I need to count every different word that appears

9:55 Raynes: cemerick: When they have to appear in public together, Rich get's Tom to wear the mask.

9:55 tonyl: oh so unique words?

9:55 piva: tonyl: that's why I thought in creating a map where each unique word is the key and increase the counting for each occurrence

9:55 Chousuke: piva: when you "increase the value" you actually need to create a whole new map :)

9:55 Raynes: forces*

9:55 tonyl: ok

9:55 yeah

9:56 piva: Chousuke: yeah, that's what is forcing my mind, ahha, coming from non-functional programming is a big step to think in immutability and etc

9:57 Raynes: cemerick: Did you see my indirect getting started post? I only mentioned maven in passing so as to make the hair on the back of your neck stand on end.

9:57 piva: I really started to play a little with functional about 3 days ago, before that I'd only heard about... so it's been a challenge

10:00 tonyl: piva: I am starting too

10:00 you are going to need reducing

10:00 piva: uhmm, great, I will get to study it so, thanks again :D

10:01 cemerick: Raynes: I looked at it briefly :-)

10:02 Despite popular opinion, I actually don't care about maven one way or the other. It's just the only thing that does all of what I need.

10:02 piva: would you like a working solution, or are you content to pick at the problem?

10:03 piva: cemerick: I think that would be better as a learning experience to pick at the problem, my real problem is to redefine my way of thinking

10:04 cemerick: as such, looking at reduce I see a light, but it still I think about mapping and increasing values and etc :/

10:04 cemerick: yeah, you still need to keep counts

10:04 tonyl: piva think of associating the values to the map

10:04 cemerick: that doesn't impact the utility of reduce, etc

10:04 Raynes: cemerick: I just like toying with you. <3

10:06 cemerick: piva: In any case, don't kill yourself trying to derive idioms on your own. :-)

10:06 piva: tonyl: I'm at that, but I'm thinking something like this: "ok, I've got to count every word occurrence and when each one is done then I associate it to the map" but that would need many lookups over the vector

10:06 cemerick: A naive impl is here for when you want to peek. https://gist.github.com/706621

10:06 Raynes: It's appreciated. :-)

10:07 it's just such a boring topic to me at this point (build-y things, that is)

10:07 piva: cemerick: thank you! I will pick at it some more and (as nothing is really gonna roll, lol) I'll look it

10:07 Raynes: Understandable. I have some vested interests in cake and the like though. I occasionally contribute things and write plugins.

10:09 cemerick: Sure. We all have our investments.

10:09 tonyl: piva: yeah you have to instert into map and update every time in the function that map is using

10:09 Raynes: Plus, ninjudd is just so darn awesome in person. <3

10:09 tonyl: it is hard to come around, at least was for me. and it still is sometimes

10:11 stuartsierra: ,(frequencies (seq (.split "The quick brown fox jumped over the lazy dog." " ")))

10:11 clojurebot: {"jumped" 1, "quick" 1, "fox" 1, "The" 1, "the" 1, "dog." 1, "over" 1, "lazy" 1, "brown" 1}

10:12 cemerick: dammit, frequencies!

10:12 :-P

10:12 piva: lol!

10:12 tonyl: *facepalm* I need to learn my functions

10:13 cemerick: tonyl: don't we all

10:13 There goes stuartsierra, makin' me look like a dope again ;-)

10:13 stuartsierra: It's nice no feel needed. :)

10:13 *to

10:14 tonyl: well, it was an exercise of the mind :P

10:14 piva: haha, thank you all very much, now I can see some light in how functional can be great :DD

10:14 and well, I'll try to continue my lil program, haha

10:14 tonyl: $source frequencies

10:14 sexpbot: frequencies is http://is.gd/hqiDv

10:18 fliebel: sexpbot at least gets the https thing right, line number are gone from core docs :(

10:20 cemerick: Your implementation could use fnil ;) Man, I read the whole core doc yesterday :)

10:21 cemerick: fliebel: heh -- see, I'm stuck with a 1.1 mindset still. fnil has always only ever been in contrib.core…

10:22 fliebel: cemerick: me, to. I'd still be using defstruct if it wasn't for chouser ;)

10:22 Raynes: fliebel: sexpbot is always right.

11:23 mjg123: Hi - how do I prevent this kind of thing: java.lang.IllegalArgumentException: Value out of range for int: 10315434503

11:24 tonyl: try bigInt

11:24 maybe

11:24 raek: mjg123: which version of clojure?

11:24 mjg123: 1.2.0

11:24 I found it though, my mistake

11:24 raek: how do you construct it?

11:24 tonyl: what was it?

11:25 mjg123: I was calling (int x) with x as a very large number

11:25 changed it to (num x)

11:25 raek: if you parse a number from a string, you might want to use long in this case

11:25 ah

11:26 jkndrkn: hey folks. i've defined a protocol using defprotocol and two types that use that protocol in the namespace foo.bar

11:26 how do i then use those types elsewhere?

11:26 chouser: deftype produces a class, so to use it directly you need to 'import' it

11:26 jkndrkn: i've tried using (:use [foo.bar]), (:import [foo.bar type1 type2]), and neither work

11:27 raek: jkndrkn: very often, you make a constructor function to create instances

11:27 you should be able to import them, though

11:27 jkndrkn: yes, i do have a constructor function. however, said function is not located in the namespace foo.bar and needs to be able to make use of it.

11:27 hm.

11:28 raek: by constructor function, I meant something like (defn make-foo [x] (Foo. x))

11:28 chouser: you probably need to require and then import

11:28 jkndrkn: ok, i'll try requiring too.

11:29 raek: if you expose the type directly, you will have to change all callers if you add a field

11:29 or rearrange them

11:30 I think types and records are often regarded as low-level and are kept as an implementation detail

11:30 samx: is there some simple way through the Java API to determine is a specific Var has been defined ? I'm currently using the following, but just thinking there might be a simple way: return clojure.lang.Compiler.eval(RT.readString("(true? (some (fn [x] (= (key x) '" + varName + ")) (ns-publics '" + namespace + ")))"));

11:31 jkndrkn: i've tried requiring as well, and that does not work either

11:32 is this import form correct? (:import [foo.bar Type1 Type2])

11:32 cemerick: samx: look at Var.find(Symbol).

11:32 tonyl: jkndrkn: i think you need to actually use the import form instead of the ns form

11:32 jkndrkn: i'm getting "error: java.lang.ClassNotFoundException: foo.bar.Type"

11:33 ah, i siee

11:33 samx: cemerick, thx

11:33 tonyl: i've had problems like that and using import worked for me before

11:34 raek: jkndrkn: the docs says you should write (:import (foo.bar Type1 Type2)), but sometimes vecors instead of lists happens to work

11:35 well, lists for prefix lists is the only documented way...

11:35 hrm, ok. looks like vectors worked in that case.

11:37 cemerick: was there a create-temp-directory fn floating around somewhere?

11:39 jkndrkn: ok, so i added an "(import [foo.bar.Type1])" under my ns form

11:40 tonyl: cemerick: not as far as I know, maybe sh (shell fn)

11:40 jkndrdkn: did that work for you?

11:40 jkndrkn: now i'm getting java.lang.IllegalArgumentException: Unable to resolve classname: Type1

11:40 both the ns form and the import form compile fine

11:41 the form that actually creates an instance of the type fails

11:41 mjg123: cemerick: you can use java.io.File#createTempFile() then delete the file & create a dir with the same name

11:41 cemerick: yeah

11:42 tonyl: once you imported can you create a Type1 object

11:42 cemerick: I wonder how many times I've written that in my life

11:42 jkndrkn: tony1: nope

11:42 tonyl: then it is the importing

11:43 that is weird, let me test it

11:43 jkndrkn: i'm using (:require foo.bar) in my ns form, and (import [foo.bar.Type1]) and then trying to compile a defn that creates an instance of Type1 using (Type1.)

11:44 the import form is free-standing and outside of the ns form

11:45 tonyl: ok, i'll test for both

11:50 KirinDave: jkndrkn: So you made a deftype in another file an you're trying to use it in this file?

11:51 mjg123: cemerick: (str (System/getProperty "java.io.tmpdir") (System/getProperty "file.separator") (.toString (java.util.UUID/randomUUID)))

11:53 cemerick: mjg123: heh, sure. I can never remember which one is which between file and path.separator. :-P

11:53 mjg123: No, I had to look it up, too. If that clashes with something you ought to buy some lottery tickets.

11:53 jkndrkn: KirinDave: that's right

11:54 KirinDave: jkndrkn: So one of two things needs to happen

11:55 jkndrkn: You either need to explicitly make sure the file saying deftype is loaded into the vm. (Alternatively, you need to :use or :require a symbol from the namespace that includes the deftype)

11:55 cemerick: mjg123: Yeah, I'd never dispute UUID. (doto (File/createTempFile …) .delete .mkdir) is a little more readable though :-)

11:55 KirinDave: jkndrkn: Or, you need to lein compile and make sure :aot includes that namespace

11:55 jkndrkn: k, i'll try that

11:55 KirinDave: jkndrkn: When you go for the final jar, it won't matter.

11:56 But during dev, I usual use slime and C-c C-l to load the module again.

11:56 tonyl: so for importing types they have to be compiled?

11:58 KirinDave: tonyl: for using import, I think they either have to be loaded or compiled. Things like gen-interface and deftype will doing the loading at the time of their evaluation

11:58 tonyl: But you have to make that evaluation happen

12:00 tonyl: ok

12:00 cemerick: KirinDave: I've suggested doing an implicit require on import before, but that's not gone very far.

12:00 tonyl: that is good to know

12:00 KirinDave: cemerick: I think the safest way is to compile. it's what I have to do for scala interop.

12:00 It's onerous, but...

12:01 cemerick: One of the nice parts of having a make-* function is that you can :use :only [make-*] and be pretty sure your class gets loaded.

12:01 cemerick: Agreed.

12:01 Re AOT compilation, there are maintenance downsides, e.g. binary compatibility between different revs of clojure.

12:02 tonyl: so if you do a make-mytype fn for the type in the same ns the type was declared then you can just require that make-mytype fn and use it to make the type?

12:03 KirinDave: tonyl: That's how it's explained to me.

12:03 tonyl: ok, if I don't want to go the compilation route, i'll try this.

12:06 tufflax: I'm trying out Vim for clojure, but one feature I miss from Emacs is the indentation; that I can just select a whole function and press tab and every row gets indented correctly, and that if I'm on a row and press tab that row get indented correctly even if that means moving backwards. Does anyone know if I can get something similar to work with Vim?

12:06 dakrone: tufflax: use = when selecting a visual block, or == to indent the current line

12:07 gg=G to indent the entire file

12:07 tufflax: Ok, thanks I'll try

12:10 Hm, I'm very new to vim, when you say "use =", what do you mean? Cause when I select the text and type = in normal mode I just replace the text :P

12:11 Or, I was in select mode

12:11 dakrone: are you using v or V to select things in visual mode?

12:12 tufflax: visual mode? :P I'm in select mode :P maybe I should study vim some more first :P

12:13 dakrone: so, from normal mode, hit V to enter visual line mode, move up and down to select some lines, then press = to indent them

12:13 tonyl: tufflax: have you try the vimtutor?

12:13 tufflax: I did some of it :P gonna continue soon :P

12:14 But I was very eager to see what vimclojure had to offer

12:15 Ah, now it works, very nice. Thanks!

12:32 amalloy: anyone know of a good intro to fnparse?

12:37 aoeu256: i saw a youtube video and clojure looks like a fun language (i program a little python). Im starting out, whats a good way to figure out which methods belong to a (Java) object. right now I am using clojure's lispbox

12:38 amalloy: aoeu256: there are a few ways. are you familiar with java, or is clojure your first java?

12:38 tonyl: aoeu256: you can use the class function

12:41 amalloy: aoeu256: https://gist.github.com/b12371be35213c7ff4a9

12:42 tonyl: this seems more friendly than (.getMethods (class x))

12:43 mroessler: if we partition on a pattern and emit like : (let [pairs (partition 2 1 tuples)] (for [[today todays_value] [yesterday yesterdays_value]] pairs] [today (- todays_value yesterdays_value)])) we necessarily have dropped the first tuple [today todays_value]. Is there a common method to add it back in? Like [today nil]?

12:43 tonyl: yeah true, i assumed he new java

12:44 aoeu256: i know a little java

12:44 amalloy: there's a (show) function somewhere that's supposed to do this in the repl, but since 1.2 i haven't been able to find it

12:44 tonyl: amalloy's would be more helpful though, class you just give you the full class name only

12:45 chouser: clojure.contrib.repl/show

12:45 clojure.contrib.repl-utils/show

12:45 I think

12:45 it will be replaced by something better in 1.3

12:45 amalloy: chouser: damn you. i looked in repl-utils, and it wasn't there until you told me to look again

12:46 tonyl: mroessler: what do you mean dropped the first tupple (vector) isn't [today todays_value] still there?

12:47 c.c bows to chouser

12:47 chouser: amalloy: heisenfunction

12:48 mroessler: tonyl: Thanks. I don't think it is, because my for is [today todays_value] [yesterday yesterdays_value], so the output is only emitted once there is a yesterday.

12:50 amalloy: mroessler: is that real code you pasted? i don't think that's a legal binding-form you used in your for

12:51 &(for [[[a a1] [b b1]] (partition 2 1 [1 2 3 4])] [(- a b) (-a1 b1)])

12:51 sexpbot: java.lang.Exception: Unable to resolve symbol: -a1 in this context

12:51 tonyl: you are missing a bracket

12:51 amalloy: &(for [[[a a1] [b b1]] (partition 2 1 [1 2 3 4])] [(- a b) (- a1 b1)])

12:51 sexpbot: java.lang.UnsupportedOperationException: nth not supported on this type: Integer

12:51 amalloy: mutter

12:52 tonyl: &(for [[[a a1] [b b1]] (partition 2 1 [[1 2] [3 4]])] [(- a b) (- a1 b1)])

12:52 sexpbot: ⟹ ([-2 -2])

12:52 amalloy: thanks tonyl

12:52 tonyl: np

12:52 he was missing a third bracket

12:53 mroessler: amalloy: well surely I'm inhibited by this being my third day with Clojure, but yes that code is running for me. This is a common issue when dealing with things such as moving averages. If we compute a 30 period moving average, the first 29 are nil, but we don't really want to drop them from the data.

12:53 tonyl: for never drops data as far as i know

12:54 mroessler: amalloy: the code I pasted is inside a let

12:54 amalloy: mroessler: you're missing a [ in your for

12:54 but whatever

12:54 tonyl: right, it never drops data, but if you have 30 data points there are only 29 pairs

12:55 i'm not really clear on what mroessler wants to do to invent the first pair

12:55 tonyl: oh i see

12:55 amalloy: mroessler: it seems to me that your issue is with partition, not for

12:55 mroessler: I want [today nil]

12:56 amalloy: &(partition 1 2 [[1 2] [3 4] [5 6]])

12:56 sexpbot: ⟹ (([1 2]) ([5 6]))

12:56 amalloy: er

12:56 &(partition 2 1 [[1 2] [3 4] [5 6]])

12:56 sexpbot: ⟹ (([1 2] [3 4]) ([3 4] [5 6]))

12:57 amalloy: &(partition 2 1 (repeat [nil nil]) [[1 2] [3 4] [5 6]])

12:57 sexpbot: ⟹ (([1 2] [3 4]) ([3 4] [5 6]) ([5 6] [nil nil]))

12:57 amalloy: mroessler: ^^?

12:58 mroessler: Likely I'm insufficiently clear: I'm emitting a date: today, matched by (- todays_value yesterday's value). Clearly I can't emit (- today_value yesterdays_value) until there is a yesterday, which drop the first [today todays_value].

13:01 amalloy: mroessler: what about computing the diff with tomorrow instead of with yesterday?

13:01 then you can use the little padding scheme i show above

13:04 mroessler: amalloy: I'll look into that, thanks.

13:14 orphe: Hi, i'm beginning with clojure and trying to find the best way to set it up. Should i get the downloads the site or take the source from github

13:14 technomancy: ~getting started

13:14 clojurebot: getting started is http://www.assembla.com/wiki/show/clojure/Getting_Started

13:14 * technomancy recommends the above

13:15 amalloy: orphe: Raynes made a blog post about this just yesterday: http://blog.raynes.me/?p=48

13:15 orphe: technomancy, amalloy : thanks

13:19 dnolen: so what are people using for string templating again?

13:26 orphe: amalloy: wow that cljr installer does everything

13:27 amalloy: orphe: heh. i haven't used cljr myself, but i imagine it's using maven to download the required packages, just like cake or lein

13:27 hugod: dnolen: recently came across this http://alliance.seas.upenn.edu/~harmony/ which looks like it could be turned into an enlive type approach for general text

13:28 probably overkill as string templating though

13:28 orphe: amalloy: yeah its using maven, i had tough already compiled clojure ,and was wondering how to set it up correctly , but if that does everything ... its looks like gems for ruby or npm for node

13:29 dnolen: hugod: interesting, saved for later reading :)

13:30 amalloy: orphe: yeah, i compiled clojure myself too, the first time. it turns out to not really be worth the bother, especially as all the tools fetch their own copy of clojure anyway (you can point them at your local copy if you want, i guess)

13:30 jjido: freemarker is good for templating on the jvm

13:31 dnolen: jjido: I really want something idiomatic

13:32 ((tmpl "Foo ~{keya} bar ~[keyb}') {:keya "blah" :keyb "argh"})

13:32 orphe: dnolen: i used in js and ruby http://mustache.github.com/ , maybe the clojure port is good too

13:33 dnolen: orphe: ah seems close to what I want, will check it out.

13:34 orphe: dnolen: don't know how it works in clojure since im starting but in js/ruby you can pass lambda functions , direct values...

13:37 hugod: dnolen: https://github.com/hugoduncan/pallet/blob/master/src/pallet/strint.clj does this based on c.c.strint

13:38 tomoj: hmm

13:38 dnolen: hugod: tried it, seems I cannot use strings in first class manner w/ it (please correct me if I'm wrong)

13:38 fliebel: hugod: That boomerang thing is very interesting! Would be awesome the have a Clojure DSL to do that kind of stuff.

13:38 dnolen: (let [s some-str m some-map] (<< s m)) ; FAIL

13:40 hugod: fliebel: I have a good use case for it in pallet, but no time to implement at the moment :(

13:41 fliebel: So many cool stuff to build… :(

13:41 amalloy: $sed -fliebel s/\(/)

13:41 sexpbot: <fliebel> So many cool stuff to build… :)

13:42 amalloy: no being sad about having cool stuff

13:42 fliebel: Okay, "So much cool stuff to build… :) but only one lifetime :("

13:43 amalloy: fliebel: that's better

13:50 re-ping: anyone know of a decent intro to fnparse?

14:08 dnolen: amalloy: you might have to write one, eh ? ;)

14:08 amalloy: dnolen: oh noes

14:09 edw: Hey guys, I was wondering how one should approach transforming a hash like this {0 :a 2 :b 3 :c 8 :d} into an array like this [:a 0 :b :c 0 0 0 0 :d 0 0].

14:09 dnolen: ,(flatten {0 :a 2 :b 3 :c 8 :d})

14:09 clojurebot: ()

14:09 mrBliss: ,(apply concat {0 :a 2 :b 3 :c 8 :d})

14:09 clojurebot: (0 :a 2 :b 3 :c 8 :d)

14:10 dnolen: ,(into [] (apply concat {0 :a 2 :b 3 :c 8 :d}))

14:10 clojurebot: [0 :a 2 :b 3 :c 8 :d]

14:10 amalloy: edw: what do you mean with all your zeros? you don't seem to want just flip_map

14:11 dnolen: (into [] foo)? i would think (vec foo) makes more sense

14:11 chouser: & (reduce (fn [v [x y]] (assoc v x y)) (vec (repeat 10 0)) {0 :a 2 :b 3 :c 8 :d})

14:11 sexpbot: ⟹ [:a 0 :b :c 0 0 0 0 :d 0]

14:11 edw: My Q was about a 1-dimensional output structure, but I want to convert a list of triples into a matrix, with the un-specified elements set to a default value.

14:12 I'm using Incanter.

14:12 chouser: edw: I think mine solves it for you

14:12 edw: though you left out the "length of the vector" parameter. I used 10

14:12 But I don't know anything about Incanter. Maybe it has a better way.

14:12 edw: chouser: 1) Thanks, 2) you are correct, and 3) thanks again.

14:13 chouser: yw

14:13 amalloy: chouser: wut. i don't even understand the problem, how can you have solved it already

14:13 mjg123: wtf?

14:13 chouser: amalloy: the map keys were to be used as indexes into the output vector

14:13 * mjg123 echos amalloy

14:13 edw: I've looked around Incanter's docs, and I don't think there is.

14:13 amalloy: oh i see

14:13 chouser: the map values are the vector values at those indexes

14:14 heh, not sure that helps

14:14 amalloy: yeah, actually it totally explains it. wild

14:14 tonyl: oh i see

14:14 * KirinDave grumbles.

14:14 KirinDave: Sometimes clojure is so ugly it pisses me off

14:14 Still love it but... an unruly child

14:14 amalloy: KirinDave: you can't blame evolution just because you made an ugly baby

14:15 KirinDave: amalloy: Oh I _can_.

14:15 I am just unreasonable enough to.

14:15 tonyl: lol yeah

14:15 chouser: KirinDave: which bit is ugly today?

14:15 fliebel: KirinDave: That's explicit complexity, rather than accidental ;)

14:15 KirinDave: chouser: All this fucking date handling I am doing.

14:15 chouser: oh

14:15 yeah

14:15 KirinDave: chouser: e.g., https://gist.github.com/706981

14:16 chouser: dates are deeply unhappy to work with

14:16 edw: Thanks everyone. The only place forgoing mutation in moving from Scheme to Clojure is in this sort of data structure initializion code.

14:16 amalloy: KirinDave: fun fact: java's DateFormat objects aren't threadsafe either

14:16 KirinDave: amalloy: I'm using joda

14:16 amalloy: are those threadsafe?

14:16 KirinDave: amalloy: Well, the immutable ones are.

14:16 THey have immutable versions of all their time stuff.

14:17 amalloy: KirinDave: sure? i never mutate my DateFormats and i still ran into problems because the parse() methods aren't threadsafe

14:17 KirinDave: amalloy: Please tell me that's not true

14:17 amalloy: KirinDave: scout's honor. took me a day and a half to discover

14:17 KirinDave: If JodaTime's parse isn't thread safe I'm going to sprout horns and a tail

14:17 amalloy: even though it's right in the javadoc

14:18 KirinDave: amalloy: "DateTimeFormat is thread-safe and immutable, and the formatters it returns are as well."

14:18 Whew

14:18 http://joda-time.sourceforge.net/apidocs/org/joda/time/format/DateTimeFormat.html

14:18 amalloy: hurrah

14:18 KirinDave: Yeah

14:18 dnolen: KirinDave: can date handling be made pretty? That code is at least clear.

14:19 fliebel: Can anyone name me a core function I might not know about?

14:19 amalloy: fliebel: fnil

14:19 incidentally, writing memoize in java looks disgusting

14:20 even with apache commons to help out

14:20 fliebel: amalloy: Know that one, replaces nil with a given value for fn.

14:20 chouser: fliebel: var-set

14:20 fliebel: chouser: Now you got me :(

14:20 chouser: fliebel: underive,

14:20 fliebel: &(doc var-set)

14:20 sexpbot: ⟹ "([x val]); Sets the value in the var object to val. The var must be thread-locally bound."

14:20 amalloy: fliebel: reductions. group-by

14:20 chouser: update-proxy

14:21 fliebel: chouser: I know that one, but the derive tree stuff is still magic to me.

14:21 chouser: probably know trampoline. If not, worth looking at.

14:21 fliebel: yea

14:21 KirinDave: Woah didn't know fnil

14:22 fliebel: update-proxy is some sort of java interop helper, right?

14:22 chouser: fliebel: allows you to change on the fly the implementation of an object created via proxy

14:22 so, yes

14:23 restart-agent is newish

14:23 ooh, rsubseq

14:23 fliebel: Oh, I am so going to make myself a Clojure quiz...

14:23 chouser: seque

14:23 tonyl: i would take that quiz! good learning tool i quess

14:23 *quess

14:23 amalloy: KirinDave: fnil works together especially well with update-in

14:23 chouser: release-pending-sends

14:23 fliebel: I know all of those, though I can;t remember what rsubseq is for.

14:24 is there deseque as well? I guess not :(

14:24 mjg123: &(doc rsubseq)

14:24 sexpbot: ⟹ "([sc test key] [sc start-test start-key end-test end-key]); sc must be a sorted collection, test(s) one of <, <=, > or >=. Returns a reverse seq of those entries with keys ek for which (test (.. sc comparator (compare ek key)) 0) is true"

14:24 KirinDave: amalloy: Can I see an example?

14:24 chouser: pvalues

14:24 amalloy: &(update-in {} [:a :b] (fnil inc 0))

14:24 sexpbot: ⟹ {:a {:b 1}}

14:24 fogus`: Are we playing the "name the obscure Clojure function game"?

14:24 chouser: fogus`: yup!

14:24 amalloy: &(update-in {:a {:b 2}} [:a :b] (fnil inc 0))

14:24 sexpbot: ⟹ {:a {:b 3}}

14:24 KirinDave: amalloy: Damn that's fantastic

14:25 amalloy: I can change code _right now_ :)

14:25 fliebel: pvalues gets you a vector of values computed in paralel.

14:25 amalloy: KirinDave: i forget if i got that trick from chouser or raek, but it's magic

14:25 KirinDave: Yeah that's quality.

14:25 Actually fnil seems like a pretty nice tool in general

14:26 chouser: ,(rationalize 4.234)

14:26 clojurebot: 2117/500

14:26 fliebel: chouser: Now in reverse, what's the name of the function that behaves like seq but gives an empy seq instead of nil?

14:27 * tonyl thinking of making a clojure.core fns cheatsheet for 1.2.0

14:27 chouser: fliebel: sequence

14:27 fogus`: ,(syntax-symbol-anchor '&)

14:27 clojurebot: fn

14:27 fliebel: whoo

14:27 amalloy: fliebel: not-empty

14:27 ossareh: "Caused by: java.lang.RuntimeException: java.lang.IllegalArgumentException: "Unparsable namespace form:" :reload" <- I get that when I run lazytest in watch mode on a brand new project - any thoughts on why this might be? (perhaps because I have 0 tests?)

14:27 chouser: fogus`: I have a patch in to make that go away

14:27 ossareh: clj 1.2 fwiw

14:27 fliebel: I'm leaving now, I'll show you guys the quiz later :)

14:27 amalloy: &(map not-empty [{} [:a]])

14:27 sexpbot: ⟹ (nil [:a])

14:29 Raynes: orphe: Was my post helpful? Just curious, as AFAIK, you're the first actual new person who might have read it. :>

14:30 fogus`: ,(namespace-munge 'foo.bar-baz)

14:30 clojurebot: "foo.bar_baz"

14:30 orphe: Raynes: lol, Yeah pretty helpful , tough i just used the cljr part! Would be nice to have a followup to what cljr does... (clojars and things like that)

14:31 Raynes: orphe: Yeah, that post wasn't meant to go into serious depth on any of them. A series of introductions to the various tools might be a nice series of articles to write sometime.

14:32 ossareh: Raynes: and critically required for the community to grow ihmo

14:32 *imho

14:32 amalloy: ossareh: I Hate My Opinions

14:32 ossareh: ;)

14:33 Raynes: (;

14:34 orphe: Raynes: I'm gettin myself a blog in a week or two , just finishing writing the engine , maybe if i like really much clojure i will write about it

14:34 Raynes: You're writing your own blogging engine?

14:35 orphe: Raynes: yeah , static site generator , like Jekyll

14:35 Raynes: Neat.

14:36 orphe: i'm trying to write usefull things, tired of only doing school labs and doing nothing with it

14:36 solution : write open-source

14:37 ossareh: orphe: or better still, once again imho, help other projects

14:37 damn.. I'm just all opinionated today

14:37 orphe: ossareh: yeah, that was included in "write open-source"

14:38 rata_: hi

14:38 what's the most convenient (and hopefully fastest) way to get something like rand-nth in a set?

14:40 mjg123: Raynes: good blog post, I'm pretty new so it's good to read about the various tools & such as well as the language

14:41 tonyl: rata_: with rand-int maybe

14:41 Raynes: Thanks! Glad you enjoyed it.

14:41 amalloy: rata_: (comp rand-nth seq) is the best i can think of

14:42 rata_: tonyl: but sets doesn't support nth

14:42 amalloy: does seq copy the set?

14:42 tonyl: they support get

14:42 amalloy: rata_: not exactly. i don't understand seq, but i believe it returns an iterator-type thing that uses the set as its backing collection

14:42 tonyl: &(get u (rand-int (count (apply sorted-set (range 17))))

14:43 sexpbot: java.lang.Exception: EOF while reading

14:43 tonyl: &(get u (rand-int (count (apply sorted-set (range 17)))))

14:43 sexpbot: java.lang.Exception: Unable to resolve symbol: u in this context

14:43 tonyl: &(get u (rand-int (count (apply sorted-set (range 17)))))

14:43 sexpbot: java.lang.Exception: Unable to resolve symbol: u in this context

14:43 tonyl: &(let [u (apply sorted-set (range 17))] (get u (rand-int (count u))))

14:43 sexpbot: ⟹ 12

14:43 tonyl: there it is

14:43 amalloy: rata_: it won't be very fast, because it will be traversing the whole set. but anything else would be biased in some way

14:45 rata_: amalloy: why would it be traversing the whole set? once you apply seq to a set, isn't it randomly accessible?

14:46 amalloy: rata_: seq will have to traverse the set once to make that happen

14:46 rata_: ah ok

14:46 amalloy: eg, suppose you knew the set were stored as a hash-table. you could use a random number as the hash key, then randomly select from the list of things that hash into that bucket. but some buckets will be larger than others, and some may be empty, so the results you get back won't be uniformly distributed

14:47 so i think the best you can do is convert the set to a seq, and use rand-nth, which will be uniform

14:48 rata_: in that case, it's better to store the thing as a vector, not a set

14:48 amalloy: &(counted? (seq (set (range 1000))))

14:48 sexpbot: ⟹ false

14:48 rata_: sets are implemented in clojure usign hash-tables then?

14:49 jarpiain: &(class #{1 2 3})

14:49 sexpbot: ⟹ clojure.lang.PersistentHashSet

14:49 amalloy: &(map (comp class set range) [1 10 1000])

14:49 sexpbot: ⟹ (clojure.lang.PersistentHashSet clojure.lang.PersistentHashSet clojure.lang.PersistentHashSet)

14:49 technomancy: yeah, sets are maps where the keys point to themselves.

14:49 * amalloy is surprised

14:50 amalloy: i thought the small one would be an array-set. or does that only exist for maps?

14:50 rata_: yeah, sets and maps are implemented as hash tables (trees, if sorted) in both java.util and clojure.lang

14:51 rata_: if they'd implemented as trees, I think it would be easy to make an analogous of rand-nth for them

14:51 aha... trees if sorted

14:51 maybe that's what I need

14:52 amalloy: rata_: no, rand-nth will be biased for trees too

14:52 chouser: I suppose counted-sorted-set might do it

14:52 amalloy: eg, suppose your tree is poorly balanced: one element in the left subtree of the root, and four in the right sub-tree

14:52 if you randomly choose a direction to go from each node, you'll return the left element four times as often as any other

14:53 rata_: counted-sorted-set? is that in clojure.core?

14:53 amalloy: which is why you'll have to seq it first

14:53 rata_: amalloy: and what about balanced trees?

14:53 well, it can't be perfectly balanced all the time

14:54 amalloy: rata_: well, of course clojure uses self-balancing trees. but they're very rarely 100% perfectly balanced, just balanced "enough"

14:54 rata_: yes

14:54 I just realized that after I asked you

14:54 amalloy: if you want uniformly random selection you'll have to traverse the whole set to get something you can random-access

14:54 no matter how the underlying set is stored

14:56 rata_: well... what I really need is a vector, but with less than O(n) for removal of an item

14:56 ossareh: rata_: more on the data structures: http://clojure.blip.tv/file/707974/

15:00 * fogus` wonders why init-proxy and update-proxy do not return the proxy

15:00 fogus`: ,(let [p (-> (get-proxy-class Object) (construct-proxy))] (init-proxy p {}) (update-proxy p {"toString" (fn [this] "blah")}) (str p))

15:00 clojurebot: "blah"

15:00 rata_: http://www.innoq.com/blog/st/2010/04/clojure_performance_guarantees.html

15:01 incredible... vector supports disj and is O(log n)!

15:01 I didn't know about that

15:01 &(disj [1 2 3] 2)

15:01 sexpbot: java.lang.ClassCastException: clojure.lang.PersistentVector cannot be cast to clojure.lang.IPersistentSet

15:02 rata_: mmmm... I think that site is wrong

15:03 KirinDave: rata_: Um

15:03 rata_: http://idisk.me.com/dfayram/Public/Pictures/Skitch/Clojure_Performance_Guarantees_-_Stefan_Tilkov_s_Random_Stuff-20101119-120625.jpg

15:03 rata_: it's also wrong in that lazy-seqs are O(n) for count

15:03 KirinDave: rata_: I don't see vector having disj

15:03 rata_: KirinDave: did you see the link I wrote?

15:03 KirinDave: rata_: I clicked the last link you posted

15:04 rata_: yes, that link

15:04 KirinDave: And screenshotted the table contained within

15:04 And between vector and disj, there is a -

15:04 fogus`: rata_: the columns are shifted in Chrome

15:04 tonyl: i think the header row in the table is shifted

15:04 what fogus said

15:04 KirinDave: Haha. Womp womp.

15:04 Chrome: wins again

15:04 rata_: yes, that was

15:04 it

15:05 fogus`: I mean it's is a very complicated table. so it makes sense that Chrome might choke

15:06 KirinDave: fogus`: Ha

15:10 rata_: mmm... so the best way to do it is probably to just (remove ...) from the vector and use (rand-nth ...)

15:11 or would it be better to (disj ...) the set and then use (rand-nth (seq ...))?

15:14 devinus: anybody know of SQL databases writtein in Java?

15:14 mister_roboto: If I want to write some clojure to plug into a spring app as an interface impl, do I just use defprotocol to create an interface usable by java?

15:14 devinus: *slightly off-topic question, but im curious about connecting to clojure*

15:15 mister_roboto: Devinus, hsqldb

15:16 tonyl: mister_roboto: I would do that and compile the protocol so that java can use it

15:18 mister_roboto: Thanks! I haven't yet played with the deftype family

15:18 tonyl: I am starting too

15:20 rickmode: What's the best way to test if a map is empty? (empty? m) vs (= 0 (count m)) vs (zero? (count m))

15:20 tonyl: I would go for (zero? (count m))

15:20 rickmode: I don't trust timing in the REPL, but empty? appears to be faster

15:21 tonyl: thanks

15:21 tonyl: I don't know what would be faster, though

15:25 rickmode: tonyl: the docs doesn't give speed guarantees for seq on a map, though I suspect it isn't O(1). Seems like empty? should be implemented by map directly, which would be O(1). count is supposed be O(1), so I guess (zero? (count m)) will be good.

15:25 chouser: seq, count, and empty? are all O(1) on a clojure map.

15:26 (if (seq m) ...) is most idiomatic, or if you need the inverse (if (empty? m) ...)

15:27 rickmode: chouser: i this case I wouldn't use the result of seq, however I am testing in an if and using the else clause

15:27 mjg123: for speed of comprehension, (empty? m) has it, imho

15:27 rickmode: (empty? m) would be the clearest ... I agree with mjg123

15:28 chouser: yes, it is normal, even preferred, to use 'seq' to test that there is something in the collection.

15:28 empty? is fine, but please avoid (if (not (empty? m)) ...)

15:29 rickmode: in this case it's something like (if (empty? error-map) (do-success) (do-failure error-map))

15:29 chouser: sounds good to me

15:30 mjg123: because (empty? m) just calls (not (seq m)) , so you don't want to waste time with (not(not(seq m))) - is that why, or is there another reason?

15:31 chouser: mjg123: HotSpot will likely make all that 'not'ing free anyway. It's more about clarity.

15:31 mister_roboto: Negative logic is harder to read too

15:31 chouser: right, why use "if not empty" when you can use "if something's here"

15:32 the way to say "if something's here" in Clojure is (if (seq m) ...)

15:32 rickmode: indeed: (if (not (empty? error-map)) (do-failure error-map) (do-success)) %(

15:32 mister_roboto: Even rickmode's formulation is irritating to me . Why not just do the failure if something in the map?

15:32 Rather than do success if failure map is empty

15:33 mjg123: as a beginner, I'd go to the doc to check what (if (seq m)) is trying to say. (if (not (empty? m))) is self-evident.

15:33 chouser: you still need both cases, and there are valid stylistic reasons for doing the success branch first.

15:33 rickmode: To my eye, this obfuscates the meaning a bit. But at this become a minor style issue. (if (seq error-map) (do-failure error-map) (do-success))

15:33 chouser: mjg123: the standard response to that is, do you want all your code written for beginners in the language?

15:34 mjg123: chouser: no :)

15:34 but I can totally see why someone might write it like that.

15:34 chouser: sure

15:34 mister_roboto: It doesn't obfuscate anything if u understand what seq does

15:34 chouser: until you talk him out of it

15:35 rickmode: Whereas this is more clearly good style: (when (seq error-map) (do-failure error-map))

15:35 Chousuke: the seq idiom will be confusing the first time you see it

15:35 then you learn it and it becomes non-confusing :P

15:36 dnolen: mjg123: heh wait till you learn about contains?

15:36 rickmode: Chousuke / chouser: it does give me the ick creating a seq on a map then tossing away the result, even if it's O(1). But I'll get over it.

15:36 mister_roboto: U could just throw an exception ;) (kidding!)

15:36 dnolen: it actually drives me insane now that other langs don't have it.

15:39 chouser: rickmode: don't worry about it. if it actually becomes the performance bottleneck in your app, bring it up with rhickey and he may just solve it for you

15:39 ossareh: if (:use some-ns) from some-other-ns are defrecords in some-ns visible ? it seems like they're not, but I didn't see anything in the docs that says that is the case.

15:39 amalloy: ossareh: no

15:39 chouser: you have to keep in mind the difference between the current implementation of Clojure, and the fullness of the language that is promised.

15:39 amalloy: they're classes: you have to (:import) them

15:39 ossareh: ahh

15:40 amalloy: thx

15:40 chouser: 'seq' is the primitive for testing if a collection has contents. Use it. :-)

15:41 ossareh: amalloy: and I assume that they are some-ns.RecordName ?

15:41 amalloy: ossareh: indeed

15:42 (ns myproj.stuff) (defrecord Things [data])...(import myproj.stuff.Things)

15:42 fogus`: Does anyone see a reason why this patch would be problematic? https://gist.github.com/707137

15:43 rickmode: I'm getting used the idea that seq means "give me a sequence on this collection if possible". It feels unlikely that (seq [1]) yields (1) (a chunked seq on the vector) and yet that's O(1). I guess the point is that this chunked seq is trivial to create.

15:43 tonyl: returning the proxy

15:44 chouser: fogus`: do they currently return nil?

15:44 fogus`: tnoyl: ?

15:44 chouser: yes

15:44 amalloy: rickmode: the chunked seq doesn't traverse the whole vector all at once

15:44 tonyl: I don't see a problem, but then again, I don't know what that method from proxy returns

15:44 chouser: fogus`: looks good to me

15:44 Chousuke: rickmode: the sequences are also lazy

15:44 rickmode: so they're pretty easy to create in constant time .P

15:44 ossareh: amalloy: cheers, worked a charm.

15:45 rickmode: Chousake / amalloy: and thus having a dedicated empty? implementation would be minor optimization at best

15:46 ossareh: wow, lazytest's watching is very very nice

15:47 chouser: can I point a pom.xml at a lein-generated jar in clojars?

15:47 stuartsierra: chouser: sure

15:48 add clojars.org/repo as a repository

15:48 chouser: I want [congomongo "0.1.3-SNAPSHOT"] ...what's the groupId?

15:49 stuartsierra: groupId and artifactId are the same when lein has a symbol with no / in it

15:49 chouser: ok, thanks.

15:49 stuartsierra: np

15:50 chouser: works. it's like magic.

15:50 stuartsierra: chouser: XML Magic (™)

15:50 chouser: nobody complains about the ugliness of the toad warts and bat ears required to make fantasy magic

15:50 stuartsierra: It's Mavelicious

15:50 chouser: so who am I to complain about XML?

16:00 fogus`: ,(doc get-proxy-class)

16:00 clojurebot: "([& bases]); Takes an optional single class followed by zero or more interfaces. If not supplied class defaults to Object. Creates an returns an instance of a proxy class derived from the supplied c...

16:00 fogus`: Lies! :p

16:00 ,(get-proxy-class)

16:00 clojurebot: java.lang.NullPointerException

16:02 tonyl: another fn that is not returning the proxy it creates?

16:03 looking at the source code I am guessing it returns a boolean

16:04 chouser: I think it returns the class ok, but the docstring is wrong about the args

16:04 ,(get-proxy-class java.util.Map)

16:04 clojurebot: sandbox.proxy$java.lang.Object$Map$ad8bc39c

16:05 fogus`: chouser: So the behavior is right, but not the doc?

16:06 dnolen: fogus: have you used your unifier much in macros? curious where you're putting it to work.

16:07 fogus`: dnolen: sorry, I need to run. drop me an email if you please

16:35 rata_: it seems something like this is what I need: http://sourceforge.net/projects/avl-array/

16:36 I'll need to learn how to write clojure types =)

17:05 mjg123: Is there a fn which counts the number of operations performed by a function call?

17:05 like (time (...)) but for complexity

17:08 tonyl: uff that is a tough one

17:10 mjg123: for comparing two different implementations of a function

17:11 tonyl: comparing results and time performance is not enough

17:11 mjg123: yes - probably

17:11 tonyl: this reminds me of php declare construct and ticks

17:11 mjg123: I'm just curious

17:11 looking at P38 from here http://www.ic.unicamp.br/~meidanis/courses/mc336/2006s2/funcional/L-99_Ninety-Nine_Lisp_Problems.html

17:12 that "logical inferences" business is a Prolog thing, I suppose

17:12 tonyl: yeah... read about prolog, but never used it

17:13 mjg123: OK I'll just time it & see what I get

17:13 tonyl: maybe posting it in the group, more people would help that are more knowladgeable

17:13 rata_: amalloy: is it possible to know how many elements there are in each bucket?

17:24 amalloy: rata_: externally? not as far as i know

17:25 dnolen: how can I get core.unify? do I need run mvn package from inside a clone of the repo?

17:25 rata_: there are so many containers out there, how isn't there at least one that is optimized for those three operations (remove by value, insertion and random-access)?

17:25 amalloy: dnolen: cake install?

17:26 if it's a clojure project

17:26 tonyl: rata_: you can make your own if you want

17:27 amalloy: rata_: because it's not really possible? you can't optimize for everything all at once; each goal has different kinds of bookkeeping to do, and sometimes they conflict

17:28 rata_: amalloy: I just think I don't know enough about different containers and their trade-offs, not that it isn't possible

17:28 dnolen: amalloy: will cake use a pom.xml ?

17:28 amalloy: rata_: could you expand on what you mean by "remove by value, insertion, and random access"?

17:29 dnolen: amalloy: yeah that doesn't work

17:29 amalloy: mvn package does build the 4k jar that I can copy into my project lib directories tho

17:29 amalloy: dnolen: mvn install

17:30 i think

17:30 puts it in your local repo, and maven/ivy look there before looking externally if you specify it as a dependency in project.clj/pom.xml

17:30 rata_: amalloy: fast random-access is that it can access an element by index in O(1), remove by value is like (disj set key) and insertion is just that (no constrains for that operation)

17:31 I must read more... but I'll do that at another time

17:31 dnolen: amalloy: yeah that seems to work, thx

17:32 amalloy: rata_: it can't be done. fast lookup by index, fast lookup by value, and fast insertion at an arbitrary point?

17:32 rata_: the last one isn't mandatory

17:33 amalloy: okay. then it's no problem. you can build as many indexes as you want, and update them every time you insert

17:33 (or remove)

17:34 rata_: I don't get it

17:35 amalloy: rata_: use an array as the backing store (fast lookup by index). keep a hashmap of {data, index-in-array} pairs. on every insert or delete, modify the backing array and adjust all of the keys in the hashmap

17:36 it makes insertion and deletion O(N), but access very fast, whether by index or by value

17:37 rata_: good idea =)

17:38 amalloy: rata_: but don't write it yourself :P. someone's done this already, probably even in clojure

17:39 rata_: don't worry, it's a good idea but not what I need

17:58 pppaul: amalloy, got a link for the object you are talking about?

17:58 i want my bloated collection object

18:00 sounds like a sorted hash-map

18:00 or double hashmap?

18:02 amalloy: pppaul: no, i've no idea where you can find one

18:03 but eg sql does basically this

18:04 pppaul: so, make a database

18:04 amalloy: sure. use Lau's clojureql, even

18:04 he'll love you forever

18:04 pppaul: a simple variation being a set of hashmaps

18:04 amalloy: pppaul: if your needs are modest, clojure.set/index might be good enough

18:05 pppaul: sets are sorted hashmaps?

18:05 or regular hashmaps?

18:05 amalloy: pppaul: sorted [set/map] is a tree, unsorted [set/map] is a hashmap

18:07 pppaul: i think databases has a lot of overhead

18:07 but, i could probably do an in-memory DB using clojureQL

18:08 guess it wouldn't be much of a DB

18:08 will lau still love me forever?

18:12 LaPingvino: use SQLite :)

18:12 or fake SQLite ;)

18:14 pppaul: i'm thinking of doing everything with tuples and sets. tutorialD still

18:15 style*

18:15 but, if lau will love me for using clojureQL, then that is a big motivation to use clojureQL

20:01 Lajla: &(symbol? (first '#(+ % 1)))

20:01 sexpbot: ⟹ true

20:02 Lajla: &(first '#(+ % 1))

20:02 sexpbot: ⟹ fn*

20:02 Lajla: &(string (first '#(+ % 1)))

20:02 sexpbot: java.lang.Exception: Unable to resolve symbol: string in this context

20:02 Lajla: &(set 'a-random-symbol)

20:02 sexpbot: java.lang.IllegalArgumentException: Don't know how to create ISeq from: clojure.lang.Symbol

22:26 cemerick: chouser: FYI, I've got a patch in for CLJ-432.

22:45 chouser: cemerick: nice.

22:45 cemerick: chouser: I hope :-)

22:45 rathwell: is there an easy way to create a stub java class? looks like there used to be gen-and-load-class, any way to do something like that?

22:47 cemerick: chouser: I suspect there's still a bug lingering with the generated classname given to reify classes; according to laurent's original writeup, the IBM JDK doesn't allow dashes in package names when loading classes from byte[]s either.

22:47 But then, I don't have an IBM JDK. :-P

22:47 chouser: rathwell: gen-class is still there, but you must use AOT compilation.

22:48 hiredman: you can use ASM...

22:48 rathwell: chouser: no way to do it dynamically though?

22:51 hiredman: there is always a way

22:51 cemerick: rathwell: is this class going to be used from Java, by name?

22:54 rathwell: cemerick: yes, it is referenced as a return type in a third party lib i'm using, but that class is no longer there, causing exception. i can just create the class in java and get it on the classpath, but would be easier if i could do it in clojure.

22:54 cemerick: so you need to match an existing API's package, name, signatures, etc?

22:54 rathwell: yes

22:56 cemerick: If it fits into deftype or defrecord's constraints, then one of it plus a definterface will work.

22:56 Otherwise, gen-class is the most swiss-army-knife-esque thing Clojure has to interop'ing with the java object model, etc.

22:56 one of them*

22:57 hiredman's ASM approach is generally a little to 133t for most. ;-)

22:58 rathwell: cemerick: I will try defrecord first then, if not, then have to figure out which of gen-class or just doing it in java will work best with deployment, thanks

22:59 yeah, dont think i'm there ;) (ASM)

22:59 hiredman: cemerick: it's only 133t the first time, the second time you can just copy and paste

23:00 cemerick: hiredman: True enough. Probably not very kind to the next fellow to look at the code though…

23:01 danlarkin: nice unicode ellipsis

23:02 hiredman: they sure are

23:02 technomancy: surely ellipsis isn't plural?

23:02 cemerick: danlarkin: no excuse for plebian typography – even in irc ;-)

23:03 danlarkin: technomancy: it's not, "ellipses" is the plural

23:03 * cemerick wonders if anyone notices the em dash :-P

23:03 danlarkin: <3 em dash

23:03 pppaul: -

23:03 technomancy: IIRC em dashes are supposed to be surrounded by narrow spaces; is that right?

23:03 pppaul:

23:03 technomancy: I guess monospaced fonts kinda make that a non-starter

23:04 cemerick: what do the linuxes use for inputting extended characters like these?

23:04 danlarkin: M-x ucs-insert :)

23:04 cemerick: uh-huh :-O

23:04 technomancy: back when I was doing a lot of web work I avoided learning about typography because you end up just agonizing over how limited you are, but I guess things are improving

23:05 cemerick: the right alt is usually mapped to "compose", which is a bit like option on Macs, I think

23:05 cemerick: typography geeks are always pissed at the web

23:05 technomancy: Right -- but is there a defined extended keymap for these things?

23:06 (I assume by "compose", you mean diacriticals: é, û, à, etc)

23:06 technomancy: cemerick: it might be locale-dependent... I mostly stick with Emacs input modes myself

23:06 hiredman: compose takes multiple characters and turns it into a single character

23:07 technomancy: having tab completion with M-x ucs-insert really helps for things like KANNADA LETTER TTHA ಠ_ಠ

23:07 cemerick: Apparently, there's a bit of OS X lockin that'll keep me there for a looong time.

23:07 hiredman: so it's not just diacriticals

23:08 technomancy: not to mention MUSICAL SYMBOL SIXTEENTH NOTE 𝅘𝅥𝅯 and HEXAGRAM FOR DARKENING OF THE LIGHT ䷣

23:08 krumholt: hi. i want my datastructures to implement some clojure interfaces like IFn and ISeq can i do that?

23:08 hiredman: yes

23:09 cemerick: technomancy: still keeping your catalog of unicode death metal names? ;-)

23:09 technomancy: cemerick: always on the lookout; let me know if you spot any good ones.

23:10 cemerick: krumholt: They're just like any other interfaces: implement the semantics, and you're in.

23:10 Raynes: technomancy: I've been thinking, and I think we should rewrite Leiningen in Scala for shock value. Any objections?

23:11 technomancy: Raynes: the hardest part would be coming up with a good name.

23:11 ports are always tricky like that

23:11 unless you're porting the Kelley project to Ruby; in that case the name kinda falls into your lap.

23:12 danlarkin: my suggestion: wasteOfTime

23:12 Raynes: Now there is a fine name to be had.

23:12 cemerick: technomancy: You could probably get a decent side biz going doing product positioning consulting. Firms score 7 figures to come up with a product name and a logo.

23:13 technomancy: http://tenderlovemaking.com/category/rkelly/

23:13 I didn't name that one.

23:13 cemerick: the public domain is a rich, rich resource.

23:13 cemerick: technomancy: OK, but jeez, don't tell the clients that! :-P

23:14 * technomancy monetizes

23:15 cemerick: 1. Consume Project Gutenberg. 2. ??? 3. PROFIT!

23:15 technomancy: wasn't one of the characters in Mona Lisa Overdrive employed checking names of potential projects for obscenity overlap in various languages?

23:15 hiredman: fun cooker!

23:16 * technomancy clearly needs to re-read the second two-thirds of the sprawl trilogy again.

23:16 cemerick: mmm, Gutenberg has a slick mobile app-ish site.

Logging service provided by n01se.net