#clojure log - Jul 02 2011

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

1:11 hiredman: amalloy: `(quote ~x)

1:21 amalloy: hiredman: good point. the compromise is more readable than either extreme

2:00 replaca: technomancy: are you hanging around late on a friday night?

3:09 are re-split and re-partition gone in the new contrib layout?

3:09 I could really use a function index of this new stuff

3:09 oh wait, I'm writing that code now... :)

5:27 fliebel: I remember seeing some talk about simplicity by someone of clojure/core. Anyone knows what that was?

5:32 terom: Perhaps this one? http://blip.tv/clojure/stuart-halloway-simplicity-ain-t-easy-4842694

5:33 fliebel: terom: Probably, I only remember it being long.

5:35 terom: No, it wasn't that.

6:12 stamp: hi

6:12 what framework do you recomend for simple blog?

6:13 I now little of clojure and didn't play with any frameworks

6:14 fliebel: stamp: Why do you want a framework for a blog?

6:18 stamp: simplest project to learn

6:19 fliebel: stamp: What I mean is, what do you want to get out of it? Get a blog? Use Wordpress or Jekyll. Learn X? use Y.

6:19 stamp: learn clojure and make blog with more than one contributor

6:27 fliebel: stamp: I'd go for the module bits on top of ring. I have the feeling that using things like Sandbar and Compojure teach you Clojure like Rails does ;)

6:27 *modular

6:32 stamp: fliebel: so i should build my own microframework on top of ring?

6:34 fliebel: stamp: Well, I'd say you have different options. If you write directly on top of Ring, you'll probably learn more clojure than using the RoR of Clojure. If you want to get going quickly with a simple CRUD app, Sandbar is probably faster.

6:35 stamp: ok, i'll check both options

6:36 fliebel: stamp: Another nice options is writing a static site generator, and use git for the multiple author aspect.

7:26 Dranik: I'm trying to insert an entity to DB using SQL. How to get the id of the inserted entity?

9:00 schasi: Can I see the stepwise execution of something like reduce?

9:04 fliebel: schasi: reductions does that

9:04 &(reductions + [1 2 3 4 5])

9:04 sexpbot: ⟹ (1 3 6 10 15)

9:09 schasi: fliebel: I meant one step in the execution of reduce :) like (reduce + [1 2 4]) -> (reduce + (+ 1 2) [3]). Or something. Don't really get the sourcecode of reduce :D

9:10 fliebel: $source reduce

9:10 sexpbot: reduce is http://is.gd/SRobxr

9:11 schasi: With "don't get" i meant "don't understand on reading". But I might just have gotten it. But thank you :)

9:12 fliebel: schasi: You could copy the code and replace calls to reduce/recur with println to see one step of the execution.

9:14 schasi: Thanks

9:26 mneedham: Hey all - beginner question for ya. I'm trying to use one of the functions listed on clojure.java.io - http://richhickey.github.com/clojure/clojure.java.io-api.html#clojure.java.io/output-stream - but I'm not sure how to do that. I have the REPL running with 1.3.0 but when I try to require the namespace I end up with an error

9:26 user=> (:require clojure.java.io)

9:26 CompilerException java.lang.RuntimeException: java.lang.ClassNotFoundException: clojure.java.io, compiling:(NO_SOURCE_PATH:1)

9:27 any ideas?

9:42 fliebel: mneedham: If you use a standalone require, don;t use the keyword ;)

9:42 &[:require require]

9:42 sexpbot: ⟹ [:require #<core$require clojure.core$require@10dbc37>]

9:43 mneedham: not sure I understand, sorry. What should I be doing instead?

9:44 Chousuke: mneedham: :require is part of ns's syntax, "require" is what you want

9:44 (doc require)

9:44 clojurebot: "([& args]); Loads libs, skipping any that are already loaded. Each argument is either a libspec that identifies a lib, a prefix list that identifies multiple libs whose names share a common prefix, or a flag that modifies how all the identified libs are loaded. Use :require in the ns macro in preference to calling this directly. Libs A 'lib' is a named set of resources in classpath whose contents define a library of Cloju

9:46 mneedham: ok. So should I expect (require clojure.java.io) to be ok if I'm just running a 1.3.0 based repl?

9:47 Chousuke: mneedham: you might need to quote the symbol, I don't remember whether require is a macro or a function.

9:50 mneedham: ahhh cool - thanks for your help

9:50 I was trying to understand what's happened with clojure contrib - I last played with clojure about 18 months ago

9:50 has some of the contrib stuff been pushed into the main libraries?

10:11 pcavs: why is this room so empty? Usually at least 100+ people in here...

11:06 mneedham: is there anyway from the repl to see which methods are available to call on an object? google hath failed me so far

11:13 ahritaur: hello, is there any way to print something to web-page? I have clojure+compojure+hiccup and i want something like (dotimes [i 4] (printToWebPage someDynamicContent)

11:55 mudge: hello

11:56 I want to convert clojure source code files into java source code automatically, any recommendations on how to do that? if it is even possible?

11:56 pcavs: You could do something really awful like compile clojure, then use a decompiler to decompile it into ugly java...

11:57 mudge: but I don't think that would be a good idea. What's the use case here?

11:57 mudge: pcavs: yes, i was thinking of trying to use a decompiler

11:58 pcavs: to be honest, my boss will absolutely not except any programming language except Java but I want to write in Clojure, so I thought if there was a way to generate exceptable Java from clojure source ...

11:59 pcavs: mudge: ouch, doesn't sound good. I don't really see that working...You'd lose out on the entire purpose of Clojure I think.

11:59 mudge: pcavs: why?

11:59 pcavs: if i could just write clojure in the normal way and if it could be converted to Java source and it was good enough, what's the downside?

12:00 pcavs: mudge: because the decompiled java bytecode will be impossible to understand and extremely ugly java code. It would be unmaintainable as java code, so in order to change it you'd really be changing your clojure code and then compiling it and decompiling it again.

12:00 So the decompiled java source code isn't really the source code

12:00 it's some sort of fake intermediary

12:01 mudge: pcavs: i see, so perhaps it isn't really possible then

12:01 pcavs: at least that's my 2 cents

12:01 mudge: pcavs: have you played with a decompiler and seen its output?

12:02 it would be cool if Clojure had a function that converted clojure source to java source

12:02 pcavs: mudge: I have not, but I've decompiled straight java code before, and it's quite ugly from what I remember, but this was back in Java 1.3-4 days so maybe the decompilers have gotten ebtter.

12:02 clojurebot: hmm… sounds like your out of heap space

12:03 mudge: pcavs: okay, i'll check it

12:48 pcavs: i used a java decompiler, i think decompiling clojure bytecode into java source is too unreadable

12:48 pcavs: yeah, I kind of thought that would be the case

12:49 mudge: pcavs: I wonder if it is possible to write a clojure program that takes clojure source as input and outputs readable java code

12:50 pcavs: that sounds like an interesting project

12:50 the readable java source could depend on clojure libraries

13:13 roblally: What are people's thoughts on Matchure? It looks nice, but I'm nervous about building a dependency on it. With the imminent arrival of 1.3 and the lack of recent project activity....

13:34 fliebel: roblally: Dunno, I din;t like it very much, so I wrote this: http://pepijndevos.nl/clojure-micro-pattern-matcher/index.html

13:35 roblally: Interesting, fliebel, I'll take a look.

13:41 fliebel: Is there any sane way of implementing IFn? ... Without implementing all ±30 methods. I think dnolen had a huge macro for it somewhere.

13:42 IMO, varargs is one point where Java interop fucked up.

13:46 cemerick: fliebel: extend AFn, and override the arities you want

13:46 fliebel: cemerick: I want varargs ;)

13:49 mids: what is the name again of that convenience wrapper around compojure / hiccup? it sounded like webiv

13:50 gfrlog: what do you get by wrapping compojure and hiccup?

13:51 mids: I could tell you if I remembered the name/site :)

13:52 gfrlog: well you must know what it does if you know that you want to use it :P

13:52 cemerick: fliebel: then extend RestFn :-)

13:52 fliebel: cemerick: RestFN? awesome, going to look it up :)

13:53 cemerick: fliebel: https://gist.github.com/1061456

13:53 mids: gfrlog: iirc it wrapped a couple rest/compojure/hiccup/sandbar things in a single dsl

13:54 gfrlog: ah ha

13:55 fliebel: whoa. that is a lot of java code...

13:58 $mail dnolen cemerick showed me RestFn, which could solve your IFn implementation problem as well, I think.

13:58 sexpbot: Message saved.

13:58 cemerick: fliebel: exactly; best to make use of it if it solves the problem.

13:59 It being a concrete base class is likely a difficulty in certain circumstances, tho.

13:59 fliebel: cemerick: yea, I guess. maybe dnolen just avoided it for performance reasons :D

14:00 cemerick: There is no penalty for calls to subclasses of concrete bases. The problem is e.g. you can't make a deftype a RestFn.

14:05 hiredman: cemerick: does it need to be? can't you just provide doInvoke from IFn?

14:07 cemerick: hiredman: doInvoke isn't anything special; it's the massive pile of boring args -> args + rest conversions in RestFn's invoke impls that you need

14:07 hiredman: roblally: matchure and a few other libraries I looked at struck me as digusting, so I also wrote my own too

14:07 cemerick: That could get macro'ed in easy enough, but that's a lot of class-size overhead in every single variadic fn for not a lot of benefit.

14:08 hiredman: cemerick: are you sure about that?

14:08 cemerick: (again, the concrete base class limitations still being relevant)

14:08 what, the class-size overhead?

14:08 fliebel: hiredman: Where does yours live? Which other?

14:09 hiredman: https://github.com/hiredman/match

14:09 fliebel: I forget exactly, I looked at two at least, and one of them was matchure

14:10 hah

14:10 and I have my own cond-let too

14:10 fliebel: hiredman: Hah, you use core.logic :)

14:11 hiredman: yeah, but it's not like I know how it works or anything

14:12 fliebel: hiredman: So how is yours different from Matchure? It too is 90% macro and has the silly a? syntax.

14:13 hiredman: matchure may have been the one that wasn't updated since pre clojure 1

14:13 one of them did eval'ing + fn creation which broke recur

14:16 needed it for https://github.com/hiredman/moravec/blob/master/src/moravec/four.clj

14:21 fliebel: hiredman: What's that?

14:22 hiredman: it may some day be a compiler

14:22 well, I guess it is already, it can generate byte code for the λ calculus

14:22 (I got closures working last night)

14:22 dnolen: fliebel: yeah I looked at RestFn, don't think I need it since I can sit in front of IFn w/ a macro.

14:25 fliebel: dnolen: Can I see your macro?

14:25 dnolen: fliebel: I could be wrong look at prelude.clj in core.logic.

14:38 admiralbumblebe3: Im new to clojure and I'm having a bit of an issue.. when I try: (byte-array (map byte [0xF0 0x41 0x32 0x00 0x05 0x00 0xF7])), I get the error "java.lang.IllegalArgumentException: Value out of range for byte: 240"

14:38 what am I misunderstanding here?

14:39 hiredman: on the jvm bytes are *signed* values, crazy

14:39 morphling: admiralbumblebe3: java bytes are signed, -128 to 127

14:39 admiralbumblebe3: oh.. damn

14:40 thats what I get for not knowing java

15:46 fliebel: Does Daniel Renfer com in here sometimes? He's working on OStatus in Clojure it seems.

16:40 mattmitchell: i'd like to create a macro that "captures" the & body arg in a hash, and returns the hash. I can't seem to figure out how to capture the syntax quoted & body arg. Would someone mind giving me a clue on to how to do something like: https://gist.github.com/1061620

16:44 gfrlog: mattmitchell: I'm a bit confused about the backquote there

16:45 (defmacro def-field [a b] {:fields a, :builder `(quote ~b)})

16:46 can you try that and say what's wrong with it?

16:46 * gfrlog goes to try it himself

16:46 mattmitchell: gfrlog: well, I'll tell you what I'm trying to do. I want to "capture" the body, so I can call it later. So I assumed I'd need the syntax quoted value?

16:46 gfrlog: oh sure, let me try

16:47 gfrlog: apparently it returns {:fields [:data], :builder (str "hello!")}

16:47 mattmitchell: creating a function to call later would be insufficient? you need the actual form?

16:48 mattmitchell: gfrlog: I guess I didn't want to have to call fn everytime I setup one of these "fields"

16:48 gfrlog: mattmitchell: you can do it in the macro

16:48 I'd bet half of all macros exist mostly for doing that

16:48 so let's change the macro definition to...

16:48 mattmitchell: gfrlog: oh, you mean create a function that wraps the body, the returns the function?

16:49 ok :)

16:49 gfrlog: (defmacro def-field [a & b] {:fields a, :builder `(fn [] ~@b)})

16:49 works for me

16:50 I changed the args so that you can give several forms for the function, for side effects

16:50 mattmitchell: wow, that's awsome

16:51 gfrlog: thank you for that. Very helpful. I'm going to pull that apart and see if I can get my tiny brain to understand :)

16:51 gfrlog: most of the macros I write assemble a fn for some reason or another

16:51 mattmitchell: gfrlog: ok, so that's a typical way to "capture" the body and eval later?

16:51 gfrlog: any macro called (with-<something>) usually doest hat

16:51 mattmitchell: yep

16:51 mattmitchell: i see

16:57 gfrlog: if I wanted to pass an arg to that function, how would I do that? I get a "Can't use qualified name as parameter"

16:58 gfrlog: mattmitchell: um

16:58 is that gonna be like a magic thing? like you'll call (def-field [:a] (+ x 12))

16:58 and the macro will set it up to have an arg called x?

16:58 mattmitchell: gfrlog: exactly, although... is that a bad thing?

16:59 gfrlog: I think it makes the code confusing. I've done such a thing only once, and tried to avoid it otherwise. If you explain the use case a little more I might be able to recommend something else. But yes, this is possible.

16:59 The reason what you tried didn't work is because the symbol is being processed by backquote; so rather than:

17:00 %`(fn [x] (+ x 12))

17:00 Chousuke: mattmitchell: in general, it's best to just let the user decide what to bind things to, even if there's just one that's almost always bound to the same name.

17:00 gfrlog: &`(fn [x] (+ x 12))

17:00 sexpbot: ⟹ (clojure.core/fn [clojure.core/x] (clojure.core/+ clojure.core/x 12))

17:00 gfrlog: you'd want &`(fn [~'x] (+ x 12))

17:00 mattmitchell: i see ok

17:00 gfrlog: damn I'm bad at triggering sexpbot today

17:00 &`(fn [~'x] (+ x 12))

17:00 sexpbot: ⟹ (clojure.core/fn [x] (clojure.core/+ clojure.core/x 12))

17:01 gfrlog: ignoring the body of the fn there, since that wouldn't be given explicitely in your macro

17:01 but anyhow I was asking what you're trying to do with all this

17:04 mattmitchell: gfrlog: well, i have a hash-map, where each key is an output key for a new document. The value defines a list of db fields to use when performing a select. I then want to use the function (builder) to transform data from the row, for the field. Does that make sense?

17:04 gfrlog: there are about 10-20 fields per table, and about 10 different tables. So my goal was to create a macro, that would eliminate a lot of (fn [x]) code

17:05 gfrlog: mattmitchell: is it all within one namespace? I think magic names like that is a lot more acceptable if you keep it all in one file

17:05 mattmitchell: gfrlog: it is yes, all in one file.

17:06 gfrlog: okay. you know about the #() syntax though right?

17:06 mattmitchell: The the map without magic looks like: {:address [:line1 :line2 :city :state :country] (fn [row] )

17:06 gfrlog: yes that's true, i could just use that

17:07 gfrlog: mattmitchell: and a lot of simpler functions can be built up compositionally without #() at all

17:07 e.g., if you're just going to do (fn [row] (:country row)), that's just :country

17:07 (fn [row] [(:country row) (:state row)]) is (juxt :country :state)

17:08 mattmitchell: i see, so maybe are you suggesting stay away from macros for this?

17:08 gfrlog: that's good default advice :)

17:09 Chousuke: heh, yeah

17:09 first rule of macro writing: make sure you actually need a macro

17:09 then don't write it

17:10 gfrlog: :)

17:10 Chousuke: then if you get annoyed enough, start thinking about writing it :P

17:11 mattmitchell: ok good, makes sense. But one of these days I need to come to grips with macros. I get so confused with all the quotes :(

17:12 gfrlog: mattmitchell: that's pretty normal. but I think you get a lot more mileage out of learning to use HOFs well than macros.

17:12 mattmitchell: gfrlog: and much more simpler to understand yes. OK, I'll back out a bit and try this again :)

17:13 gfrlog: good luck

17:13 mattmitchell: gfrlog: thanks! and thanks for your help.

17:13 gfrlog: np

17:35 currentB: What's the best way to test if a value is a clojure boolean

17:36 gfrlog: (map boolean? [true false nil 8 "wut"])

17:36 currentB: (isa? true java.lang.Boolean) doesn't work, for example

17:36 oh

17:36 didn't see that in the docs

17:36 gfrlog: isa? is between two classes I think

17:36 so ##(instance? true java.lang.Boolean) should work

17:36 sexpbot: java.lang.ClassCastException: java.lang.Boolean cannot be cast to java.lang.Class

17:36 gfrlog: &(instance? java.lang.Boolean true)

17:36 sexpbot: ⟹ true

17:36 gfrlog: there it is

17:36 currentB: awesome thanks

17:37 gfrlog: but of course ##(boolean? false) is nicer and shorter

17:37 sexpbot: java.lang.Exception: Unable to resolve symbol: boolean? in this context

17:37 gfrlog: but it doesn't exist

17:37 so I'm dumb

17:37 currentB: haha

17:37 gfrlog: but the other way works :)

17:38 &(isa? java.lang.Boolean java.lang.Object)

17:38 sexpbot: ⟹ true

17:38 terom: ,(map boolean [true false nil 8 "wut"])

17:38 clojurebot: (true false false true true)

17:38 gfrlog: terom: thanks :)

17:38 I'm forgetting all of my bot-triggers today

17:39 oh that's different anyhow

17:39 doubt it would have helped currentB

17:39 terom: True. (No pun intented...;)

17:40 gfrlog: (def boolean? (partial instance? java.lang.Boolean))

17:52 hiredman: gfrlog: not inlinable :/

17:52 gfrlog: hiredman: isn't it strange that boolean? doesn't exist?

17:53 hiredman: meh, booleans are just kind of odd anyway

17:53 gfrlog: yeah who needs them

17:53 hiredman: why not just call boolean on the value

17:53 gfrlog: could just use :true and nil

17:53 it's a good point

17:57 terom: ,(Boolean. "true") ; something to watch for...

17:57 clojurebot: true

17:57 terom: ,(true? (Boolean. "true"))

17:57 clojurebot: false

17:58 gfrlog: wut it does

17:59 pdk: ,(identical? true (Boolean. true))

17:59 clojurebot: false

17:59 pdk: ,(.class true)

17:59 clojurebot: java.lang.IllegalArgumentException: No matching field found: class for class java.lang.Boolean

17:59 pdk: ,(map type [true (Boolean. true)])

17:59 clojurebot: (java.lang.Boolean java.lang.Boolean)

17:59 terom: Boxed boolean, I guess, but not boolean primitive.

17:59 pdk: stay fresh clojure

18:00 gfrlog: ,(map #(System/identityHashCode %) [true (Boolean. "true")])

18:00 clojurebot: (14929221 28937278)

18:00 gfrlog: ,(map #(System/identityHashCode %) [true (Boolean. true) (Boolean. "true")])

18:00 clojurebot: (14929221 2760940 30908546)

18:01 terom: ,(.booleanValue (Boolean. "true"))

18:01 clojurebot: true

18:20 hiredman: the clojure mailing list should make everyone who sends an email over X characters provide a useful clojure library to the community before allowing the email through

18:23 "oh, it looks like you want to send 500 words that boil down to 'I think clojure is awsome and aren't we all so cool for using it!' to the mailing list, please take over one of the new contrib libraries and I will be happy to send it for you"

19:24 mjg123: Hello guys - how can I turn (:a 1 :b 2) into a map {:a 1 :b 2} :)

19:26 dnolen: ,(apply hash-map '(:a 1 :b 2))

19:26 clojurebot: {:a 1, :b 2}

19:26 dnolen: mjg123: ^

19:26 mjg123: oh that's cool

19:26 thanks dnolen

20:12 davekong: Is there a function like print that also takes a stream to print to as an argument?

20:32 amalloy: davekong: java interop. just call .write on the stream

20:32 davekong: amalloy: k, thanks

20:32 amalloy: (or, really, on the reader)

20:34 &(let [out-str (java.io.StringWriter.) out (java.io.PrintWriter. out-str)] (.print out "test") (str out-str))

20:34 sexpbot: ⟹ "test"

20:34 amalloy: davekong: 6

20:34 er, ^

20:34 still getting used to having my numbers and symbols swapped :P

20:35 davekong: for typing faster?

20:35 amalloy: but a lot of these cases can be solved with just ##(doc with-out-str)

20:35 sexpbot: ⟹ "Macro ([& body]); Evaluates exprs in a context in which *out* is bound to a fresh StringWriter. Returns the string created by any nested printing calls."

20:35 amalloy: davekong: mostly just so i don't have to hold shift so often. i don't think it will improve speed that much, but it should help with comfort

20:36 &(with-out-str (dotimes [n 10] (prn n)))

20:36 sexpbot: ⟹ "0\n1\n2\n3\n4\n5\n6\n7\n8\n9\n"

22:28 hugod: swank-clj is now ritz, to try and avoid confusion with swank-clojure

22:38 tmciver: hugod: I spoke to you the other night about debugging clojure code and you informed me that you could open the .clj files from the jar in emacs, edit and then C-c C-k to compile. When I do this, I get a FileNotFoundException for the jar file. Any ideas?

22:45 hugod: Even with this error it seemed to work just saving the file. But tonight I think I'm getting some strange behavior that may be classpath related. Do you know how the slime classpath is set up?

22:46 hiredman: tmciver: use C-c C-c

22:46 (will re-evak the current top level form)

22:46 hugod: tmciver: not sure what the problem is compiling - works fine here - all the file's namespace dependencies have to be on the classpath

22:47 tmciver: hiredman: Ah yes, that seemed to work! Thanks.

22:47 I'll have to add that one to my list of slime commands.

22:52 hiredman: does 'top level form' mean that it compiles the whole file?

22:52 hugod: how can I determine what my 'slime' classpath is?

22:53 hugod: (.getURLs (.getClassLoader clojure.lang.RT))

22:54 the slime classpath is determined by the project you started the swank server in

22:55 tmciver: hugod: so it will be lib/*:lib/dev/* in that project?

23:02 hiredman: tmciver: the top level expression

23:07 hugod: tmciver: if you're using lein, then yes, plus source, classes and resource paths

23:07 tmciver: Great. Thanks again!

Logging service provided by n01se.net