#clojure log - May 19 2009

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

2:20 ccmtaylor: help keys

2:23 hiredman: (doc keys)

2:23 clojurebot: "([map]); Returns a sequence of the map's keys."

3:07 yangsx: /join #ucw

6:18 unlink1: Is there a better way of achieving #(Math/sqrt %) ?

6:20 ah. (:use [clojure.contrib.math :only (sqrt)])

7:09 unlink: man, clojure really is nicer to use than scheme.

7:12 Though, I suppose that is unsurprising given the two languages' design philosophies.

7:16 hoeck: unlink: yeah, they only have the lisp-1 in common, i guess

7:17 unlink: and clojure comes with batteries included, whereas scheme wants you to build your low-level datastructures and primitives by yourself

7:19 unlink: hoeck: I'm referring to simple things like (let ((x 1) (y 2)) (+ x y)), little niceties like inc/dec, loop/recur, stuff like that.

7:20 but yes, having reader-macro access to hash sets, hash maps, etc, is major win.

8:46 cgray: if i make a class on the repl using proxy, what would its name be if i wanted java to call it?

8:46 i have to pass the name as a string... kind of annoying

8:46 Chouser: you shouldn't rely on the name of the proxy class, really.

8:46 kotarak: Proxy doesn't make classes, it makes objects.

8:47 Chouser: you can print it out with (class (proxy ...)), and pass that if you want

8:47 cgray: okay, so i need to use gen-class?

8:47 kotarak: The object is of an anonymous class.

8:47 Chouser: but don't hard-wire that proxy class name into a .java source file.

8:47 kotarak: If you need a class...

8:47 cgray: ok, thanks

8:48 Chouser: kotarak: well, proxy does create a named class if there's not an appropriate one already. But it's wisest to treat it as anonymous.

8:48 cgray: or gen-interface, and then proxy that. Or a write an interface in a .java and proxy that.

8:51 kotarak: Chouser: I see proxy to generate "an object which implements the given interfaces". It's like "new Runnable() { void run() { do.somethin(); } }" in Java. If I need a class, I would use gen-*class*.

8:54 unlink: What's the idiom for creating an object with methods? To pull an example from SICP... http://dpaste.com/45602/

8:56 Chouser: unlink: http://programming-puzzler.blogspot.com/

8:57 oh, that's not a good way to link.

8:57 http://programming-puzzler.blogspot.com/2009/04/adts-in-clojure.html

8:57 there. you've got some options.

8:58 I have no idea who Puzzler is, but that post is very good.

8:58 unlink: thanks, Chouser

8:59 * kotarak wonders, whether this is really necessary...

9:02 Chouser: kotarak: what?

9:03 kotarak: This whole "secure" stuff. To hide the implementation. There is an API, a contract on what's allowed and how to use the stack. Follow it and your are fine. If you do Voodoo stuff with the internals.... Well. You wanted to do Voodoo stuff. Don't complain.

9:04 Chouser: ah, yes. I think it's almost never (maybe actually never) necessary.

9:04 cgray: is gen-and-load-class broken, or is there some other reason that it is commented?

9:05 Chousuke: It's broken and unnecessary

9:05 Chouser: There's a reason the open stuff is simpler to do in Clojure -- it's probably what Rich thinks is right.

9:06 kotarak: And decoupling the methods from the object is also a good idea, I think. (read "multimethods")

9:11 puzzler is Mark Engelberg.

9:11 Chouser: ah, thanks.

9:12 kotarak: Somehow this post doesn't fit to his recent discussion on the list.

9:13 unlink: Well, there are disadvantages to the open style. It's certainly more verbose to use. (account-deposit account amount) vs. (account :deposit amount)

9:14 Chouser: you can probably put it in an account namespace, and probably have no conflicts (how many libs define "deposit")

9:14 ...then it would be (use '(myns.account :only [deposit])) once, and later just (deposit account amount)

9:15 and/or use a multimethod

9:16 scottj_: Is there a way to have namespace.test and use namespace without putting it on the classpath?

9:16 Chouser: you can load any .clj file directly with load-file

9:17 scottj_: In more words, I have some small utilities, such as date-converter, and I just run them by passing date-converter.clj to java -cp clojure.jar clojure.main date-converter.clj. I'd like to put some tests in a separate file, and the namespace in that file will need to use date-converter, but I don't really want to modify the classpath.

9:18 unlink: I'd like a defmethod which implicitly split the arguments into first & rest, dispatched on first, and passed rest to the method impls

9:18 clojurebot: http://www.pigdog.org/auto/mr_bads_list/shortcolumn/1914.html

9:18 Chousuke: :P

9:19 unlink: In fact, every time I've used multimethods I've wanted that.

9:19 Maybe I'm thinking of multimethods wrong.

9:19 Chouser: unlink: you are free to write such a thing. should be easy. Have you read the Clojure book?

9:19 unlink: yes

9:20 Chouser: oh, I thought his multimethod examples were great. Showed some nice cases where you want multimethods dispatching on other than the first arg.

9:20 unlink: s/I'd like a defmethod which/I'd like the default semantics of defmethod to be to/

9:22 Chouser: oh.

9:23 Chousuke: out of curiosity, why?

9:23 unlink: hmm

9:23 I guess those wouldn't be ideal.

9:24 I suppose what I'd rather have is a shorthand for (fn [x & _] (PRED x))

9:26 ok, fine, (defmacro dispatch [pred] `(fn [~'x & ~'_] (~pred ~'x)))

9:26 Chouser: #(do %& (PRED %)) ...it's barely shorter, but much more cryptic -- would it suffice?

9:26 har har.

9:26 chessguy_work: 'mornin

9:26 Chouser: chessguy_work: hi

9:27 kotarak: unlink: (defmacro dispatch [pred] `(fn [x# & _#] (~pred x#)) is cleaner

9:27 unlink: Some might say that O:-)

9:27 chessguy_work: i've been doing some thinking about how to represent chess patterns in clojure

9:28 i have my first sample pattern written, though there's nothing behind it

9:28 http://paste.lisp.org/display/80490

9:28 Chousuke: hmmm... (defn dispatch-on-first [p] #(p (first &%))); (defmulti (dispatch-on-first class))

9:29 unlink: I actually didn't know about &% until just now.

9:29 chessguy_work: i'm thinking that i can macro that whole thing into a function which takes a position and returns either a map of bindings for the various variables or nil

9:31 Chousuke: chessguy_work: use a vector instead of the list, at least; ((foo) (bar)) looks like a function call.

9:32 chessguy_work: Chousuke, you mean as the parameter to pattern?

9:32 Chousuke: yeah.

9:32 chessguy_work: gotcha

9:33 Chousuke: also, what exactly do the (enemy "a") etc do?

9:33 chessguy_work: it's sort of "declaring" those "variables"

9:33 Chousuke: hmm

9:33 chessguy_work: meaning "there exists an enemy, who we'll refer to with the string "a"

9:33 (enemy piece)

9:34 Chousuke: in that case, it might be better to do just [a :enemy, b :enemy] like let.

9:34 or however you represent your pieces.

9:35 chessguy_work: well ultimately this is going to return a map like { "a" :f7, "b" :e2 }

9:36 saying, "this pattern matches the position if you take the piece on f7 to be "a",..." etc.

9:36 so maybe i want [:a :enemy, ...] ?

9:37 Quiark: Hi.I have a list of items and need to update each of them, but the updating function needs to have access to the updates done so far. Something like (map fn data), but fn needs to see the most up-to-date version of the list. What would be the best way to do it?

9:38 chessguy_work: i want as much work as possible to be done with a macro here so that this is as close to the domain as possible

9:41 Chouser: Quiark: your fn needs access to the whole list?

9:41 liebke: Quiark: I'm thinking you'll need to loop/recur

9:41 Quiark: Chouser, yep

9:41 Chouser: Quiark: does it need to know which element it's on (by index or something) or just the value that it's processing?

9:42 Quiark: Chouser, the value is enough

9:42 Chouser: I think reduce will probably do it for you.

9:42 chessguy_work: Chouser, maybe something more like this: http://paste.lisp.org/display/80491

9:42 jdz: if i want to create my own exception classes i have to use gen-class facility, right?

9:43 Chousuke: chessguy_work: I think for the assertions you could use functions

9:44 Quiark: Chouser, I have a set of objects, with x,y coords and need to move them around and to check collisions (that's why I need the up-to-date list in the updating fn)

9:44 Chousuke: chessguy_work: that's going to be tricky to parse otherwise.

9:45 chessguy_work: Chouser, you mean for on and if-move ?

9:46 Chouser: Quiark: doing this the way you suggest will probably be O(n^2) and I imagine there are ways to do it faster.

9:46 Quiark: though it's a fun little Clojure puzzle, so...

9:46 Quiark: Chouser, yes, i know, but that's not an issue, I just want to try something out

9:46 Chouser: ok

9:47 Quiark: (and try clojure along the way :)

9:47 Chousuke: (pattern [(declare [a :slider, b :enemy, c :enemy, line :rank-or-file]) (assert-on line #{a, b, c}) (if-move [b :off line] (attacks? a c))]

9:49 chessguy_work: interesting

9:49 Chousuke: though declare needs to be renamed :p

9:49 as it conflicts with core

9:50 unless you just look for the symbol name. :)

9:50 chessguy_work: ok, i'll send rich an email and make him change it

9:50 Chousuke: :D

9:50 chessguy_work: oh, you mean i need to rename mine? :)

9:51 Quiark: so I guess I need to process nth item, remove nth item, insert updated one and then move on to (n+1)th item

9:51 chessguy_work: i guess i'm still not getting something about the difference between a and :a

9:51 Chouser: Quiark: I do think reduce could be made to work, but liebke's suggestion to try loop/recur is a good one.

9:51 Chousuke: well, in the macro context, a is a symbol, :a is a keyword

9:51 chessguy_work: i wouldn't have guessed i could use a, b, c, etc. like that

9:51 Chousuke: traditionally, symbols are names for things that the user names.

9:52 :P

9:52 (as if clojure has much tradition yet)

9:52 clojurebot: clojure is like life: you make trade-offs

9:52 chessguy_work: well a is ultimately going to be a key in a map

9:52 Chousuke: well, yeah

9:52 you can convert it from a symbol to a keyword for that purpose

9:52 chessguy_work: so i would have guessed it needed to be a keyword

9:53 ok

9:53 Chousuke: keys in maps can be anything

9:53 kotarak: Quiark: Chouser: Shouldn't (reduce (fn [up-to-date item] (conj up-to-date (update up-to-date item))) [] items) do the trick?

9:54 chessguy_work: cool. i love how little clojure syntax there is in that.

9:55 almost everything in there is domain-specific

9:55 Chouser: hm, maybe. Does update need access to the tails?

9:56 Quiark: it needs all items, to check for collisions

9:57 Chousuke: chessguy_work: the input to your macro is an unevaluated data structure. you can require it to be anything.

9:58 of course, best for you is something that's easy for you to process

9:58 but that might not be the best for the user.

9:58 kotarak: (defn tail-seq [s] (lazy-seq (when-let [s (seq s)] (cons s (tail-seq (rest s)))))) (reduce (fn [up-to-date [item & tail] (conj up-to-date (update up-to-date tail item))) [] (tail-seq items)), something like that?

9:59 Chouser: ,(take-while identity (iterate next [1 2 3 4]))

9:59 clojurebot: ([1 2 3 4] (2 3 4) (3 4) (4))

9:59 Chouser: Quiark: there are the not-yet-updated values...

10:01 guinea: How cheap are agents? Would it be reasonable to make a spreadsheet where each cell is an agent?

10:01 Chouser: guinea: yes

10:01 guinea: sweet

10:01 chessguy_work: Chouser, in this case, i want to make these as easy as possible for the user, since there could be domain experts looking at this code

10:02 Chousuke: I'm already getting used to being called Chouser. I'm not even confused.

10:03 Chouser: Chousuke: And I'm learning to ignore the yellow highlights in my window

10:03 chessguy_work: oy

10:03 sorry guys

10:03 Chouser: no, seriously, we're used to it.

10:03 chessguy_work: i didn't even realize you were both talking

10:05 choucroute: everyone who's cool has a nick starting with ch*

10:05 * chessguy_work couldn't agree more

10:05 Chousuke: oh no, another chou

10:05 Chouser: sheesh

10:05 gnuvince: holy crap

10:05 chessguy_work: haha

10:05 * gnuvince is now known as chouvince

10:06 Chousuke: chessguy_work: figuring out the interface is up to you; I don't know your full requirements or even what you're up to. Just remember that clojure has more than just lists, symbols and keywords that you can use in your DSL. vectors, maps and sets (didn't forget to mention them this time!) are fine too.

10:07 you could look at other DSLs for inspiration

10:07 :P

10:07 chessguy_work: Chousuke, yeah, i don't even really know the full requirements either. my main goal for this part is to make the description of precise chess patterns as absolutely readable to non-programmer chess players as possible

10:07 chotarak: Maybe the channel should be renamed: #chojure

10:08 chessguy_work: (while still making it sane to parse in clojure

10:08 Chouser: ,(reduce (fn [so-far [value & origs]] (conj so-far (* value value))) [] (take-while identity (iterate next [1 2 3 4])))

10:08 clojurebot: [1 4 9 16]

10:08 * chessguy_work is considering naming his chess engine chejure

10:08 Chouser: Quiark: that's for you. only study it if you don't want to come up with your own solution. :-)

10:09 kotarak: Chouser, like I wrote above. ;) But your take-while-iterate is more concise, than my tail-seq :)

10:09 chessguy_work: Chousuke, got any recommendations for DSLs to look at that you like?

10:09 Chouser: kotarak: oh, sorry. didn't see that.

10:10 Quiark: Chouser, thanks, looks nice. I was thinking about a loop/recur version, because I'm not yet much used to functional style

10:10 Chouser: but yes, exactly the same approach

10:13 Chousuke: chessguy_work: hmm, not for chess stuff.

10:13 chessguy_work: there are many html/xml relates DSLs around though :P

10:13 chessguy_work: well, if there were a good chess DSL, i wouldn't be making my own :)

10:13 Chousuke: enlive and clj-html for one.

10:14 chessguy_work: i meant another DSL

10:14 Chousuke: perhaps datalog in contrib?

10:20 chessguy_work: Chousuke, thanks, i'll take a look

10:25 opqdonut: is pprint broken in the current contrib?

10:25 user=> (use 'clojure.contrib.pprint)

10:25 java.lang.ClassNotFoundException: clojure.contrib.pprint.PrettyWriter (pprint.clj:0)

10:28 rhickey: what would it take to get a clojure-contrib.jar download that worked with clojure 1.0?

10:28 kotarak: opqdonut: you need to compile contrib: ant -Dclojure.jar=/path/to/clojure.jar

10:29 opqdonut: pprint needs some classes generated with gen-class

10:32 cgray: i'm doing (compile 'foo) and it's working, but when i do (import 'foo) it's giving me a NoClassDefFoundError: Could not initialize class foo

10:33 kotarak: cgray: you have to do (require 'foo) or (use 'foo)

10:33 opqdonut: kotarak: yeah thanks, i figured that out too

10:33 kotarak: cgray: import is for classes

10:33 cgray: but foo is a class

10:34 burkelibbey: So PragProg told me Programming Clojure would be shipping within a few weeks... out of curiosity, is there a firmer date floating around?

10:35 gnuvince: June 31st

10:36 burkelibbey: Heh, that's a pretty liberal use of "few weeks". I had gotten my hopes up. Can't wait :)

10:39 danlarkin: rhickey: probably just a post to the ML

10:45 opqdonut: hmm, now it's accumulators that is complaining

10:45 [java] Compiling clojure.contrib.accumulators to /home/jkaasine/src/clojure-contrib-read-only/classes

10:45 [java] java.lang.NoSuchMethodError: clojure.lang.MultiFn.<init>(Lclojure/lang/IFn;Ljava/lang/Object;Lclojure/lang/IRef;)V (accumulators.clj:21)

10:46 i'm using clojure 1.0.0

10:47 same error in complex-numbers if i comment out accumulators from build.xml

10:47 kotarak: opqdonut: try "ant clean" before building and make sure the clojure.jar is used. There is some old compiled code lingering around, which tries to use some old interface.

10:47 opqdonut: ok

10:47 kotarak: opqdonut: maybe also do a rebuild for your clojure.jar

10:47 with clean and everything

10:48 opqdonut: yeah, it works

10:58 dnolen_: so has anyone messed around much with c.c.shell-out?

11:01 Chouser: a bit. why?

11:01 dnolen_: Chouser: is there anyway pipe out the output from the shell immediately instead of waiting till the end?

11:02 Chouser: there have been discussions...

11:03 dnolen_: but not much more than that?

11:03 Chouser: in fact I thought there was a patch. hm...

11:06 how can the google group search be so poor?

11:06 dnolen_: heh

11:06 I use a special gmail account to load in all my mailing lists. works well.

11:07 i found the email, Perry Trolard submitted a patch.

11:07 Chouser: is that the "articulated" one? that's different

11:07 dnolen_: oh yes, it is.

11:08 Chouser: oh, this was private email, not on the group.

11:08 ok, so the main issue is what would be returned?

11:09 dnolen_: system status?

11:09 Chouser: you can get that now. But you want the whole stream, right?

11:10 dnolen_: yes, I want to be able to run commands like git, and see the output at the repl.

11:10 Chouser: it could return the Process, so that you can get stdout and stderr and even stdin from it, etc. But then shell-out's hardly doing anyting for you -- you might as well call .exec yourself.

11:11 dnolen_: i see, perhaps I was confused, what is the intended use case of shell-out over exec?

11:11 Chouser: it is meant to simplify common cases.

11:12 and handle the opening and closing of streams, collection of the sub-process (to avoid zombies), etc.

11:12 * kotarak imagines a cljsh (as in scsh)

11:13 p_l: kotarak: java's startup speed would work against i, I think..

11:14 dnolen_: so Chouser, so you think I should just use exec directly? I'm OK with that, shell-out just seemed convenient.

11:14 Chouser: I guess I'm not sure what you use-case is yet. One option would be something like:

11:16 dnolen_: I'm building a REPL-side library installer.

11:16 at the REPL:

11:16 (install 'compojure)

11:16 Chouser: (with-sh [[stdin stdou stderr] ("git" "status")] (read print etc stdin))

11:16 dnolen_: then you get feedback about git clone, downloading zip, unpacking zip, ant process.

11:18 Chouser: I guess I'd recommend using .exec directly for now. If you find a clean way to abstract the shelling-out part, perhaps we can use that to improve or replace shell-out

11:18 it doesn't currently have any way to get data from the process until it's complete.

11:19 dnolen_: k, good to know. thanks!

11:26 kotarak: Hmm.. the ants don't seem to be sooo antique....

11:29 StartsWithK: dnolen_: http://maven.apache.org/scm/ can help you with calling different tools (you will need them installed on your system), and ant can be used as a lib

11:34 dnolen_: i tried to do something similar a month ago (http://code.google.com/p/truba/) using ivy and ant to build a clojure lib repository (there are like 40 libs in there) but i guess that will wait for now..

11:35 biggest problem was, most clojure libs don't have any build system at all, or they require that clojure.jar clojure-contrib.jar are placed in some specific directory, and some event that env variables must be used

11:36 dnolen_: StartsWithK: I'm only slightly familiar with Maven, until someone proves to me that it's easy to use, I'm not going to bother with it. Same with Ivy. And I agree, most clojure libraries don't have or even need a build, it's just source.

11:37 StartsWithK: dnolen_: maven.scm is a separate library, no need for maven build/dependancy tools.

11:37 dnolen_: what I'm working on simply JSON objects hosted on Google Appe Engine that resolve the library. the client side code does everything, it's intended to work with: zip files, git repo, and jars. people can add support for other things if they want, but it's really just to make my own life sane.

11:38 StartsWithK: it gives you something like (checkout :git {:repo bla :rev ble})

11:38 kotarak: I have a fairly stable setup of ant with Ivy (with the latter completely optional). Only some minor adjusts need to be done for a given library. I use it for all my projects.

11:38 StartsWithK: kotarak: you don't need clojure repo for ivy (just use packager resolver with zip on clojure download site)

11:39 kotarak: something like http://github.com/ksojat/cloak/tree/master (see repo directory)

11:40 kotarak: StartsWithK: I also patched to contrib to provide one jar per module, so that I can say: <dependency ... conf="*->def"/> and only get clojure.contrib.def. 13k jar instead of 2.5Mb jar. :)

11:40 StartsWithK: if projects provided some sore of zip only downloads, repository could me made only as meta index

11:40 kotarak: i do watch what you do with contib+ivy integration

11:41 you hit that problem with classes/ directory where everything is mixed

11:41 kotarak: Hmm. cloak looks also interesting.

11:41 StartsWithK: i think cloak will save us :) i'm adding ant task for clojure to it, support for ssh and maven.scm for now

11:42 we need uniform build system that is no brainer anymore, without it, we can't even start to build repositories

11:43 kotarak: Yeah. Cloak is interesting. I was working on something similar called rabotnik, but that is now on ice it seems. :)

11:44 StartsWithK: hehe, i was planing to extend truba to be full blown build system too, but, as cloak is already there, it may be the best place to place the code

11:46 dnolen_: will your repo be then just a meta index or you will host download files too?

11:46 dnolen_: StartWithK: just meta index at first, and perhaps host really popular libs.

11:46 http://librynths.appspot.com/install/compojure

11:46 this is just a dummy placeholder for now.

11:46 StartsWithK: something like that i tried with truba too, like only a meta index

11:46 dnolen_: but it's coming along.

11:47 StartsWithK: but as i said, nothing has a build that works

11:47 so i eneded with creation of repo.zip on google code (40 clojure libs ~6mb)

11:47 dnolen_: StartsWithK: my thought was to have the proper build info in the meta index, that is the index shows how to correctly generate the build

11:47 perhaps we can use a cloak file here.

11:48 until the maintainer fixes their lib.

11:48 StartsWithK: dnolen_: truba does that too, it has a build declarations in its index, but they are ant files

11:49 yes, thats why i would like to make cloak functional in a short time, so something can be used for building, that would solve meta index problem

11:49 as http://code.google.com/p/ivyroundup/ is ivy based meta index for different java libs, i think i like how they did it the best, they use svn repo as 'the repo'

11:50 they don't even have separate download site or anything

11:50 and that also gives someone a chance to fixate on specific repo revision

11:50 dnolen_: perhaps the meta index supports stable libs.

11:51 anyways you get 1gb on GAE, should enough for the popular libs.

11:51 StartsWithK: as there are something like 70-80 libs for clojure, they are not loarger than 10-15mb combined

11:51 larger*

11:52 dnolen_: heh yeah.

11:52 AWizzArd: How do I quit a JVM? Something like (System/exit)?

11:53 kotarak: Bingo

11:53 gnuvince: ,(System/exit 0)

11:53 clojurebot: java.security.AccessControlException: access denied (java.lang.RuntimePermission exitVM.0)

11:53 kotarak: AWizzArd: are stop all threads.

11:53 IIRC

11:53 AWizzArd: thanks

11:54 StartsWithK: kotarak: souldn't you use configs for things like 'build', 'test' 'doc' dependancies, and modules for contrib separation?

11:56 as i see it now, if i create contribA with my configs, and someone creates contribB, (for libs A an B) lib C can only depend on contrib-all.jar as it can't know what is in contrib A and what is in contribB

11:56 kotarak: StartsWithK: Not sure. I'm not an Ivy wizzard. I tried to do some kind of recursive sub-module built, but without much success. The conf stuff "Just Worked(tm)".

11:56 I'm not sure it's the right way. But I also got no feedback on it, so far.

11:57 StartsWithK: here is a feedback :)

11:57 i only lurk on ml :)

11:57 kotarak: Have to read-up again on configurations.

11:58 StartsWithK: so config is used more like 'i have a lib X that i depend on when i generate docs, not when i distribute a jar'

11:58 so conf='test' could add <dependency org='junit' ... conf='test'/>

11:58 kotarak: But it seemed to me that they would be used for example for things like default, with-nifty-addition, with-another-optional-thing...

11:59 StartsWithK: well, artifacts are more for that

11:59 like contrib.jar contrib-src.jar contrib-docs.jar contrib-bla.jar

12:00 kotarak: Ah. I didn't know you could specify artifacts. I see, you did that in cloak.

12:00 StartsWithK: you for now have one module with one artifact, and use configs to generate different profiles of contrib

12:00 * kotarak is sad, that hg-git chokes on the cloak repo.

12:01 * StartsWithK thinks you want to use rosado cloak as a main project.. mine is just a fork

12:01 StartsWithK: in http://bitbucket.org/ksojat/neman/ (dosn't build anymore now :( )

12:01 i have something like neman-core -xml -web...

12:02 they are all separate directories, they get there own classes/ so no mixing of compiled files

12:02 every dir is a separate module with (for now) one artifact inside

12:03 they have inner dependancies declared inside there ivy.xml files and toplevel build knows how to compile them in correct order (that is provided with ivy)

12:04 so maybe a similar split inside contrib, but maybe not on per-file basis, like map-utils seq-utils .. could go in coll-utils module

12:05 or xml related libs in another..

12:06 kotarak: I grouped eg. types and generic, the whole scattered math stuff...

12:10 StartsWithK: kotarak: will you when finished place a contrib.zip on download page of google code?

12:11 kotarak: I'm not a member of contrib. But I can contact rhickey, if this is a desired goal.

12:15 StartsWithK: just a plain zip with all the jars inside is all that is requiered by ivy, and maybe some sort of version

12:15 kotarak: Wouldn't you have to download the whole zip, just to a single jar?

12:16 StartsWithK: yes, but ivy will cache it for you, and only that one jar is your dependency

12:26 kotarak: StartsWithK: I have to drop out now, but I will look into the issue and will let you know about the progress.

12:26 StartsWithK: kotarak: ok, thanks

12:27 dfdeshom: hi, how do I import a jar file from the cli?

12:28 s/cli/REPL

12:29 danlarkin: dfdeshom: if it's on your classpath, you do (import '(org.package name))

12:29 Drakeson: walters: ping

12:29 dfdeshom: danlarkin: what if it's not?

12:30 danlarkin: dfdeshom: add it to the classpath and restart your JVM

12:32 dfdeshom: danlarkin: thanks

12:38 danlarkin: have you used the fact library? I've added it to my classpath but (import fact) gives me an exception

12:39 maacl: Is it bad form to post a link to a Clojure question I have posted to stackoverflow.com?

12:39 danlarkin: dfdeshom: Oh... for using clojure code you use a different function

12:39 sorry, I thought you meant a java jar

12:39 technomancy: dfdeshom: from what I understand fact is deprecated

12:40 stuhood: maacl: i don't think that would be bad form

12:40 technomancy: its author has switched back to test-is

12:42 maacl: Clojure / java.library.path / swank question at stackoverflow.com : http://tinyurl.com/q3257t - can anyone help?

12:42 dfdeshom: danlarkin: oh, ok, i didn't know there was a difference

12:42 technomancy: what would you suggest using?

12:44 danlarkin: how do i load a clojure jar?

12:45 technomancy: dfdeshom: test-is is nice

12:46 danlarkin: dfdeshom: http://clojure.org/api#require or http://clojure.org/api#use

12:46 dfdeshom: technomancy: thanks, i see it's in contrib

12:46 danlarkin: thanks

13:12 cheddar: what does "namespace 'foo.bar' not found after loading '/foo/bar'" mean?

13:13 never mind i think i understand...

13:19 err actually i don't :-/\

13:20 technomancy: cheddar: do you define a namespace in foo/bar.clj?

13:22 cheddar: technomancy: I have as my first line <ns foo.bar> in a file /foo/bar.clj that is on my classpath

13:23 is there something i need to do?

13:24 danlarkin: cheddar: <ns foo.bar> or (ns foo.bar)

13:25 cheddar: "(ns <foo.bar>)" actually

13:25 ah.....

13:25 danlarkin: "well there's your problem"

13:51 technomancy: can you get metadata about a namespace?

13:51 ~^#'clojure.core

13:51 clojurebot: clojure is far closer to perfection then python

13:51 Raynes: than*

13:52 Chouser: ,^(the-ns 'clojure.core)

13:52 clojurebot: {:doc "Fundamental library of the Clojure language"}

13:52 technomancy: hmm; but the metadata doesn't include the path to the file that defined it?

13:53 I guess the mapping is tenuous since a namespace can be defined anywhere technically

13:53 Chouser: doesn't look like it. Could be multiple files.

13:53 I suppose the 'ns' macro could record something -- there's only supposed to be one of those per namespace.

13:53 technomancy: ...in theory anyway

13:54 I guess I could just assume it's in src/

13:55 Chouser: you could looks for vars in the namespace and see if any of them have files

13:56 ,(map #(:file ^%) (vals (ns-publics 'clojure.core)))

13:56 clojurebot: ("clojure/core.clj" "clojure/core.clj" "clojure/core.clj" "clojure/core.clj" "clojure/core.clj" nil "clojure/core.clj" "clojure/core.clj" "clojure/core.clj" "clojure/core.clj" "clojure/core.clj" "clojure/core.clj" "clojure/core.clj" "clojure/core.clj" "clojure/core.clj" "clojure/core.clj" "clojure/core.clj" "clojure/core.clj" "clojure/core.clj" "clojure/core.clj" "clojure/core.clj" "clojure/core.clj" "clojure/core.clj" "c

13:56 Chouser: there seems to be a consensus

13:59 technomancy: Chouser: very nice.

14:05 Chouser: ,(set (map #(:file ^%) (vals (ns-publics 'clojure.core))))

14:05 clojurebot: #{nil "clojure/genclass.clj" "clojure/core_print.clj" "clojure/core_proxy.clj" "clojure/core.clj"}

14:09 lisppaste8: technomancy pasted "slime stacktrace niceties" at http://paste.lisp.org/display/80502

14:10 technomancy: that should allow you to jump to the line referenced by the current line in the stack trace as well as dimming stack trace lines that refer to swank or clojure core stuff

14:10 try it out and let me know what you think

14:10 Chouser: sounds nifty. I don't use slime.

14:10 clojurebot: slime is icky

14:11 technomancy: it makes a huge difference to have all those noisy lines dimmed out; makes the relevant stuff much easier to find in a trace.

14:11 you should port it to whatever you use. =)

14:20 hiredman: clojurebot: botsnack

14:20 clojurebot: thanks; that was delicious. (nom nom nom)

14:34 twism: technomancy: i'll give it a whirl

14:47 jfields: how do I specify a java enum value?

15:12 Chousuke: hm.

15:12 are they just classes? :/

15:13 try EnumName/ITEM

15:15 Apparently they are just classes. they can even have methods and (non-enum) fields :)

15:21 Chouser: I guess I can't use gen-interface+proxy to make static factory methods, can I. It's gen-class or Java...

15:24 Chousuke: hmm

15:24 enums are actually a fair bit more powerful in java than I even thought.

15:24 you can actually have each enum value have its own implementation of some method :P

15:25 ever* thought too.

15:44 maacl: Clojure Box / java.library.path / swank question at stackoverflow.com : http://tinyurl.com/q3257t - can anyone help?

15:51 sh10151: I keep thinking that laziness somehow reduces a breadth-first-search's memory requirement, but that really doesn't seem right to me. Can anyone convince me that I'm right or wrong?

15:52 Chouser: if you've got a normal one-directional tree, something still has to keep track of parent nodes that you haven't traversed yet.

15:54 sh10151: But could that be a lazy sequence too

15:54 ?

15:54 Chouser: yes, but a lazy sequence over what?

15:56 when the seq-producer has returned the last item of a level, and is asked for the next node, how does it find it?

15:57 I think the answer is that it must have internally a list of the parents yet to be traversed, just like an eager breadth-first algo would.

16:03 sh10151: Hmm

16:04 I definitely see that

16:04 but I am having trouble finding it in my code

16:04 assuming everything is lazy

16:05 lisppaste8: sh10151 pasted "where is the space consumption?" at http://paste.lisp.org/display/80508

16:05 sh10151: if children returns a lazy sequence

16:08 hmm, I never used branch? -- just copied the tree-seq API

16:09 Chouser: pending accounts for the space consumption

16:09 sh10151: is it not a lazy sequence too?

16:10 Chouser: heh. um.. let's see

16:11 slippery, isn't it.

16:11 sh10151: I think it's somehow the thunks in the lazy sequence

16:11 I think

16:11 but it's driving me crazy

16:11 Chouser: ok, (children node) ... even if children is lazy, the "node" part is known and closed over and stored in the next iteration's 'pending'

16:11 sh10151: 'cause I am almost sure you are right

16:18 OK, I see it now

16:18 have to think about it at the very end, when there are a bunch of nodes

16:18 thanks

16:18 the leaves will all have this thunk that will return an empty sequence

16:19 now to write IDDFS with the same api :-P

16:19 technomancy: Chouser: the thing about getting metadata for a var is that the :file value is still relative to the classpath; I'm curious about where it is on disk

16:20 I can just search src/ in the project root, but that doesn't get me stuff that comes from dependencies.

16:20 Chouser: it could be in a .jar or something -- there may not be a regular disk path to it.

16:21 technomancy: right, but I'm working from Emacs; it can open up jars transparently.

16:22 Chousuke: memory usage with lazy seqs is tricky :/

16:23 Chouser: technomancy: seems like you'd want to get the classpath and poke through it yourself. or something.

16:24 Chousuke: to avoid closing over node, could you do (let [therest (children node)] before the lazy-seq?

16:24 technomancy: yeah, I can search myself if there's no existing function for it

16:28 sh10151: Chousuke: I think there's still a thunk for that, and the more nodes you take the children of, the more thunks there are

16:29 at the bottom of the tree there will be a lot of empty sequences

16:30 but pending contains all the thunks to get them when you reach it, thus making the max memory consumption equal to the number of leaf nodes

16:30 which is BFS's memory consumption anyway

16:33 it's confusing because infinite sequences *are* possible

16:33 but they only have one thunk at a time

16:33 bfs has as many thunks as the deepest level it's visited

16:38 Chouser: I thought 'compile' followed :require directives and compiled those namespaces first if needed.

16:54 twism: hmm..qq...

16:55 how would you create a function that takes an arbitray amout of arguments from a function that tkaes a fixed amount?

16:55 abritary*

16:55 Cark: (reduce + args)

16:56 (defn [& args] (reduce binary-fn args))

16:57 Chousuke: if the output of your function is acceptable as its input, then reduce is what you want. :)

16:57 twism: sorry didn t frame the question right

16:59 i wonat a function that would take a function with a fixed number of arguments and turn that function into the same function but can take an abritary amount of arguments

16:59 i want*

16:59 Chouser: those extra args would be ignored?

16:59 twism: some of them could be

17:00 Chousuke: the answer depends on what you want the result function to do :p

17:00 Chouser: what would you do with the ones that aren't ignored?

17:01 twism: the gist is that im trying to write a library that a user of this said library can write a function to be used (this function written by the user can take 2 or 3 arguments) but how would i tell how many arguments the function thats being passed by the user takes

17:02 Chousuke: pass it in as a parameter? :p

17:03 Chouser: this sounds familier

17:03 danlarkin: twism: haven't we gone over this already? or am I having deja-vu

17:03 hiredman: the answer is: pass a map

17:04 twism: yes

17:04 we did

17:04 danlarkin: twism: the answer hasn't changed :)

17:05 twism: but the solution we came up with the last time wasnt implemented until now, and did not work out

17:05 pass a map?

17:06 we came up with something like (defn fix-it [f] (do-callback <some magic happens here> new-f))

17:06 :)

17:07 Chouser: where fix-it takes a fn of 2 args and returns a fn of 3 args, where the 3rd is ignroed, right?

17:07 twism: or maybe i stepped away form the computer when this discussion came up

17:07 Cark: what they mean is this : define your callback function with a single parameter, which is a map, and destructure the map in order to get the parameter values

17:07 twism: 3rd could be ignored

17:08 ok that would work

17:09 hiredman: Cark: well, I would hardly put words in their mouths, but that is what I mean, for sure

17:12 twism: i dont like it

17:12 but it works

17:12 Cark: hiredman : you're the multiple parameter function of this chan, hence the plpural form

17:13 how about defining your callback like this : (denf cb ([p1] ...) ([p1 p2] ...)) ?

17:14 hiredman: maps are awesome, what is not to like?

17:14 twism: Cark: i prefer the maps

17:14 Chouser: heck, pass a vector and destructure that.

17:15 twism: i just wanted to provide a user the most straight forward way of defing a function

17:15 the user*

17:16 (defn cb [p1 p2]... or (defn cb [p1 p2 p3]...

17:16 Chouser: Would could provide a replacement for defn that does what you want.

17:17 twism: but (defn cb [[p1 p2 ... pn]] ... could work

17:17 Cark: if you can pass 2 or 3 parameter functions, that means that you need these 2 kind of functions, right ?

17:17 Chouser: but some users want that 3rd arg, and others don't care, right?

17:17 twism: im calling this function with 3 arguments

17:18 hiredman: hmmm

17:18 Cark: ok, then i don't see why you would allow a 4 parameters function to be passed

17:18 it's trivial for the user to adapt the arity

17:18 twism: if they provide 2 then i get the WrongNumberArguments Exception

17:19 hiredman: jamvm apears to run this 20x slower then the sun jvm

17:19 Cark: this callback function is part of the interface of your api

17:19 twism: yes

17:19 Cark: yes

17:19 hiredman: well, close to 20x

17:19 Chousuke: twism: so you need to require your user's function to accept 3 arguments.

17:19 twism: jamvm.. is iphone java vm right

17:19 ?

17:19 Cark: when i call a function in any api, i'm aware of the arity of this function, the same goes for callback

17:20 hiredman: jamvm is a super portable mini jvm

17:20 Chousuke: twism: they don't actually have to DO anything with all three arguments though.

17:20 they can just (defn mycallback [a _ _] ...)

17:20 twism: true i could force them to do that... but its rare for users to implement a function that requires the third argument

17:21 but specification requires i code for the case that this happens

17:21 Chousuke: they can just ignore it in the callback

17:21 twism: its not a big deal

17:22 i can force them to provide a function that takes three arguments

17:22 Chousuke: you could of course wrap the call in a try block and catch the exception, but... that's really ugly.

17:23 twism: it would only be icing on the cake (from where i stand) that they could provide 2 or 3

17:23 CHouske: yeah we went thru that here

17:23 Cark: you could provide two "callback registering" functions

17:24 (call-me-back-2 cb) and (call-me-back-3 cb)

17:24 Chousuke: IMO that's worse than just being forced to accept three arguments :P

17:24 Cark: hehe yes

17:24 twism: Cark: i agree with Chouske

17:25 im going to go with the (defn cb [a b _]... approach

17:25 hiredman: bah

17:26 clojurebot: maps?

17:26 clojurebot: maps are functions

17:26 hiredman: clojurebot: maps is also <reply>maps are *AWESOME*

17:26 twism: i had javm running on my iphone

17:26 clojurebot: c'est bon!

17:26 twism: jamvm*

17:26 was doing some cool rhino iphone stuff with it

17:27 i need to see how clojure fares on my iphone

17:28 hiredman: I have three implementations of this function (searchs a byte array to see if it contains a given byte) they all run much slower on jamvm

17:29 the fastest function on the sun jvm is thirdplace on the jamvm

17:29 er

17:29 second place

17:29 third place is the same

17:39 Chouser: twism: that's jailbroken?

17:42 hiredman: Steve Jobs has been quoted as saying "Java's not worth building in. Nobody uses Java anymore. It's this big heavyweight ball and chain."

17:42 Zing!

17:47 dnolen: hiredman: until I used Clojure, I would have agreed with him ;)

17:55 cads: you guys think anyone will ever make a bare metal clojure machine?

17:55 dnolen: like a Lisp machine?

17:55 cads: heh, no, a virtual machine

17:56 hiredman: I have been reading through http://www.loper-os.org/

17:56 cads: rather, a compiler/interpreter

17:56 hiredman: the loper-os guy seems to want to build a modern lisp machine

17:57 cads: i remember reading a tweet about "when clojure's compiler is written in clojure"... and it occurred to me that at that point we could change the target language away from jvm

17:58 hiredman: I was sad to hear that lisp machines existed and the disappeared

17:58 then*

17:58 hiredman: well, I think clojure will always be strongly tired to the jvm

17:58 cads: to me it doesn't lose much of its charm even separated from java interop

17:59 hiredman: clojurebot: clojure?

17:59 clojurebot: "[Clojure ...] feels like a general-purpose language beamed back from the near future."

18:00 cads: :)

18:01 except for #(f %1 %2), that feels like a mix between a lambda and some shell-script

18:01 dnolen: One Clojure can compile itself, I am sure people will want to port to other runtimes beyond the JVM. Clojure is an idea, and the JVM is a good place to grow it.

18:02 cads: dnolen: I think so too, and that will be a very neat process to witness

18:02 hiredman: clojurebot: clojure?

18:02 clojurebot: clojure is like life: you make trade-offs

18:03 cads: clojurebot: paste?

18:03 clojurebot: lisppaste8, url

18:03 lisppaste8: To use the lisppaste bot, visit http://paste.lisp.org/new/clojure and enter your paste.

18:09 hiredman: clojurebot: clojure?

18:09 clojurebot: clojure is far closer to perfection then python

18:09 technomancy: hiredman: did you see this? http://twitter.com/gvanrossum/status/1838308947

18:14 lisppaste8: cads pasted "pseudo-module" at http://paste.lisp.org/display/80515

18:15 cads: here I've tried to create a function which, given a "less-than" type comparison function, will instantiate custom versions of the rest of the comparison functions

18:16 hiredman: technomancy: yeah :P

18:17 cads: it has to do with how def (which the macro defn uses) works

18:17 lisppaste8: cads annotated #80515 "correction" at http://paste.lisp.org/display/80515#1

18:18 hiredman: the namespace def operates in is set at compile time

18:19 cads: hiredman: I was thinking that a macro could not only insure that the definitions end up in the right namespace, but also let you rename the functions to reflect your customization

18:19 hiredman: cads: I woud use intern

18:20 (doc intern)

18:20 clojurebot: "([ns name] [ns name val]); Finds or creates a var named by the symbol name in the namespace ns (which can be a symbol or a namespace), setting its root binding to val if supplied. The namespace must exist. The var will adopt any metadata from the name symbol. Returns the var."

18:20 hiredman: (intern *ns* my> (fn [x] something here))

18:22 cads: that'll work even if that line of code is in another namespace, right?

18:23 hiredman: actually, I think if you use intern it doesn't even need to be a macro

18:23 cads: I think so

18:23 cads: i'm trying my example again

18:29 mrsolo: i can't do (.PI Math) can i?

18:30 hiredman: ,(Math/PI)

18:30 clojurebot: 3.141592653589793

18:30 cads: you can do (. Math PI)

18:30 hiredman: ,(. Math PI)

18:30 clojurebot: 3.141592653589793

18:30 hiredman: PI is not a method

18:31 mrsolo: that i know i just like (.xxx yy) form better.. oh well

18:33 hiredman: you could write a macro

18:33 that does a transform on the input, but it would be tricky, due to .xxx being valid syntax in many cases

18:33 mrsolo: i can eventualy :-) my clojure fu isn't there yet

18:44 Chousuke: ,Math/PI

18:44 clojurebot: 3.141592653589793

18:44 Chousuke: right, that form works too

18:45 interesting that the function call form does as well.

18:48 lisppaste8: cads annotated #80515 "Revision" at http://paste.lisp.org/display/80515#2

18:48 cads: hiredman, check that out, that works pretty well!

18:48 thanks for the help :)

18:52 Chousuke: Looks like that should be a macro :/

18:54 cads: probably :)

18:55 do you think that pattern is acceptable for use?

18:55 Chousuke: well, if you end up generating many global names, you should perhaps rethink your design

18:56 but it's not really wrong

18:58 though using a runtime mechanism like that looks dubious. you'd never call equalifier programmatically during runtime (it'd be really weird if you did), so it's better to just make a macro.

19:00 cads: well it is a higher order function, I could see it being useful at runtime, but not really in the current side-effecting state. If equalifier returned maps storing fns it could be part of some kind of logic engine

19:00 Chousuke: yeah, that way it's just fine

19:00 even good functional design

19:01 but that side-effecting thingamabob isn't a function at all; it's a procedure.

19:02 cads: Since the side effect form is for humans to have it easier, I think there's nothing wrong with making it a macro like you say. Maybe a macro would let you have better control of the target namespace, or allow you to specify the modular structure in a less verbose way

19:02 Chousuke: well, actually making it a macro only has the difference is that a macro can be expected to make new global stuff appear, because it's generating code.

19:03 of course, you should document it if it does have global effects :)

19:05 cads: can I write a map that contains fns that are defined in terms of symbols that are not yet bound?

19:05 Chousuke: the difference is that macro calls are always written directly in the source. you can't pass around a macro and call it at runtime to generate stuff. (disclaimer: without hideous trickery and eval)

19:05 sure; declare the symbols first.

19:05 cads: yeah, but the idea of passing around equalifier and calling it here and there randomly in its current form is silly :D

19:08 Chousuke: if you made equalifier a function that returns a map of names to (anonymous) functions, you could very well use it to generate new functions at runtime; it wouldn't even be ugly at all. The functions are just values in a map, so it's no different from any other map returning function :)

19:09 cads: I want to represent a parametric module as a map of dependent functions defined in terms of the module's parameter symbols.. wait, hey, that's pretty much what you say

19:10 dnolen: cads very interesting, this got me thinking.

19:10 what I never like about putting fns in maps is that they can't change if you redefine them

19:10 putting vars in a map works

19:10 because vars implement IFn

19:11 lisppaste8: dnolen pasted "vars in maps" at http://paste.lisp.org/display/80518

19:13 dnolen: not sure if that's helpful to you at really, but it's something to think about...

19:14 Chousuke: doesn't need to be vars unless you have to redefine them later without touching the map. (which gets uglyish again)

19:14 lisppaste8: Chousuke annotated #80515 "untitled" at http://paste.lisp.org/display/80515#3

19:14 Chousuke: I make no guarantee of the parens, but you should see the general idea there :)

19:16 I also forgot to remove the docstring...

19:16 cads: well, for mine I'd need something like frozen unevaluated fns (def depent-fs {fname (*fn [a b] f-depend) & }), where the fn objects would have unbound symbols, and then another function that would act like (let [f-depend my-f] dependent-fs), where the unbound symbols would be bound and the functions evaluated to create actual ifns

19:18 Chousuke: hm

19:18 cads: of course I could represent it like this: (fn [f-depend] {f-name (fn [a b] (f-depend a b))})

19:18 Chousuke: that seems good.

19:18 cads: then, I could compose modules using functions that works with these special lambdas

19:19 Chousuke: looks monadic

19:19 cads: and have a final macro that interns a module with user specified dependency functions

19:19 god knows everything's a monad :D

19:19 Chousuke: :)

19:20 do those functions always have just one function they depend on?

19:21 you could make some macro sugar that allows you to use the f-depend name without explicitly writing the lambda

19:21 cads: a vector space might need 4-6 functions

19:21 and your modules may always need any number of constants

19:21 Chousuke: okay. scratch that then.

19:22 cads: but even in the case of functions, you might want the option of defaults :P

19:22 Chousuke: your "f-depend" shouldn't necessarily have to be a function.

19:22 it could just be a map of whatever the function depends on.

19:22 cads: ahah

19:23 Chousuke: and then you call ((dependent-f map-of-dependencies) args moreargs)

19:23 cads: and I could merge the user provided dependencies with a corresponding defaults map

19:23 Chousuke: yeah.

19:24 cads: this could be very useful to me

19:24 Chousuke: the dependent-f will only need to document what keys it uses to look up its dependencies

19:24 cads: yeah, and with a macro it could actually look very natural

19:26 * cads asks himself: is it done yet?

19:28 Chousuke: you could use a macro to bind the depends you need automatically (define-dependent-function foo [regular-arglist] [depend1 :depend-key, depend2 "another depend key"] (do-stuff-with (depend2 regular-arglist) depend1))

19:33 in fact the depend list could be a clojure map destructuring form and then you could use it in let as is :P

20:01 cads: (defn mod-intern [prefix mod & depends] let [insta-mod (apply mod depends)] (do-seq [[name fun] insta-mod] (intern *ns* (symbol (str prefix name)) fun)))) , where a module is a function that takes values and returns a map of name/value pairs

20:04 the equalifier example becomes (def equalifier (fn [<fn]

20:04 { "<" #(<fn %1 %2) ">" #(<fn %2 %1) "=" #(not (or (<fn %1 %2) (<fn %2 %1))) "<=" #(not (<fn %2 %1)) ">=" #(not (<fn %1 %2))}))

20:07 and usage is like this : (mod-intern "l_0-comp" equalifier (fn [a b] (< (apply max a) (apply max b)))), (l_0-comp= [1 23 123 5232 123 9999] [1 -13 9999 100 2003]) => true

20:08 hehe, I really need to learn how to write macros

20:16 Chousuke: yeah, you definitely don't want to use intern :P

20:17 also, keywords as map keys instead of strings would be more idiomatic for a map like that, I'd say.

20:19 and it still looks like generating global names at all (even with macros) is not the solution

20:20 or well, it depends :P

20:21 but your mod-intern is generating names like equalifier did too, so it's got the same problem.

20:22 though if the intent is to generate a programming API from a map of dependencies and other stuff, then it's fine I guess.

20:23 I'm just wondering where you'd use something like that.

20:24 cads: well you could create a html module that takes a string module as a parameter, and then lets you parse strings of that type

20:25 Chousuke: strings of what type?

20:25 html type? :/

20:28 cads: no, say you have a string module that lets you define ascii strings over sequences of an arbitrary datatype, and you've defined the ascii strings over sequences of braille charachters. Well now you get all the string processing functions you can do on ascii, only the modifications work to produce the braille equivalent. And, with your spiffy html module, you can now parse html represented as braille :P

20:28 hahaha, forgive me if the example is less than motivating, that's all pretty goofy :)

20:29 Chousuke: so hm, you could just map a braille->string function over your braille seq. :/

20:30 hiredman: ~functions

20:30 clojurebot: functions are maps

20:30 Chousuke: I guess I get the basic gist of it.

20:31 you want to parametrise a set of operations on some function that can have different output based on what the function is.

20:32 and then perhaps define a module that depends on such a set of operations

20:32 cads: I think the concept of namespace should be doing this for us

20:33 but I'm not sure

20:33 Chousuke: well, it could.

20:33 you could define the set of operations differently in different namespaces

20:34 and import them with an :as directive in the "user" namespace

20:34 cads: importing could involve passing the imported namespace some parameters and it instantiating some of its features

20:34 Chousuke: instantiating how?

20:35 cads: well it messes up with compiled code

20:35 Chousuke: true; you wouldn't be able to use multiple modules simultaneously

20:36 but that problem will remain if you generate names, too

20:36 or it'll just be transformed :P

20:36 cads: hm

20:37 I think the idea would be parametric namespaces, where different parts of the program can refer to different configurations of the same namespace

20:38 each different configuration relying on different values of the namespace's set of parameters

20:39 Chousuke: you could do it this way: model your module as a function; then from the user namespace, pass a configuration map to the module function, and hold onto whatever it returns; the returned thing would be some data structure containing anonymous functions and data that can be accessed with some functions *operating on the data structure* (ie, not global, generated names)

20:39 then you could have as many modules and configuration combinations as you want.

20:39 cads: and do all sorts of crazy stuff

20:39 hiredman: Chousuke: function could just return a namespace

20:40 Chousuke: hiredman: indeed it could!

20:40 cads: could a function return a namespace?

20:40 Chousuke: though, is that referentially transparent :P

20:40 cads: or would it just define the namespace?

20:40 hiredman: of course

20:40 Chousuke: nope

20:40 Chousuke: ,(create-ns 'foo)

20:40 clojurebot: #<Namespace foo>

20:40 Chousuke: there :P

20:40 hiredman: actually

20:41 Chousuke: ,(in-ns 'foo)

20:41 clojurebot: #<Namespace foo>

20:41 hiredman: hmmm

20:41 Chousuke: the problem now is, that the namespace definition is global

20:41 and you want to avoid that.

20:41 hiredman: does he?

20:41 cads: in part yes and in part no

20:41 I think modelling a module as a function is great, because that's what it is

20:41 Chousuke: also how do you get a value from a namespace?

20:42 cads: i can compose those functions in a monad and operate on them in other ways

20:42 hiredman: ,(find-var 'clojure.core 'map)

20:42 clojurebot: java.lang.IllegalArgumentException: Wrong number of args passed to: core$find-var

20:42 hiredman: bah

20:42 cads: but then I want to realize what I've created into a namespace, so that I can program with the generated module

20:42 Chousuke: cads: the equalifier thingy returning a map of keywords to functions is a simple example of what I described.

20:43 cads: equalifier is the module and the function is the parameter

20:43 cads: Chousuke: yup :)

20:43 and the realization part is a simple enough macro to write

20:43 cp2: ,(doc find-var)

20:43 clojurebot: "([sym]); Returns the global var named by the namespace-qualified symbol, or nil if no var with that name."

20:44 cp2: ,(find-var 'clojure.core/map)

20:44 clojurebot: #'clojure.core/map

20:44 cp2: e

20:44 r

20:45 cads: Chousuke: I think it would be pretty easy to create a fairly clean module system this way

20:45 Chousuke: hmm

20:45 hiredman: ,(find-var (ns-resolve (create-ns 'clojure.core) 'map))

20:45 clojurebot: java.lang.ClassCastException: clojure.lang.Var cannot be cast to clojure.lang.Symbol

20:45 hiredman: bah

20:46 Chousuke: ,(#'eval `(~(symbol "def") ~'foo 1))

20:46 clojurebot: DENIED

20:46 Chousuke: damn!

20:46 oh, right, it gets expanded into (var eval) so it's picked up ;(

20:47 ,((find-var 'clojure.core/eval) `(~(symbol "def") ~'foo 1))

20:47 clojurebot: #'sandbox/foo

20:47 Chousuke: ,foo

20:47 clojurebot: 1

20:47 Chousuke: \o/

20:48 hiredman: ,(intern *ns* foo 1)

20:48 clojurebot: java.lang.ClassCastException: java.lang.Integer cannot be cast to clojure.lang.Symbol

20:48 cads: I know that I could use it in many different places, for example in my vector space library, I'd like to create vector spaces parameterized over different linear data structures, such as strings of words, or polynomial equations. The exciting thing about this approach is that I can automate not only the constructions of the secondary vector space functions like vector magnitude or projection

20:48 hiredman: ,(intern *ns* 'foo 1)

20:48 clojurebot: #'sandbox/foo

20:48 hiredman: but don't spread it around

20:48 Chousuke: oh right, that works too...

20:49 cads: I can also automatically generate test code that will test to see if the basis functions I've defined for my vector space are consistent with the definitions of a vector space

20:49 Chousuke: oh well, you can still only define things.

20:49 the rest of the sandbox is still functional

20:50 hiredman: you could use the exception thing to DoS

20:50 Chousuke: clojure is too dynamic ;(

20:51 the JVM security model is not enough for it.

20:53 though I wonder if anythign is.

21:14 Drakeson: how do you (list \a \b) -> "ab" ?

21:14 hiredman: ,(apply str '(\a \b))

21:14 clojurebot: "ab"

21:15 Drakeson: thanks.

21:15 why can't we do (into "" ...) ?

21:16 hiredman: strings are not Collections

21:16 the seq function just happens to know how to turn them into sequences

21:17 and first, rest, etc call seq on their argument first

21:17 Drakeson: I see, thanks.

21:18 hiredman: although, I wouldn't mind into being inhanced to do that

21:20 Drakeson: yeah, that would be useful

21:24 mrsolo: why does this work? (:2 {:2 3})

21:24 hiredman: keywords are IFns

21:24 they look themselves up in a map

21:24 (:i {:i 2})

21:24 ,(:i {:i 2})

21:24 clojurebot: 2

21:25 hiredman: ,(:i {:j 2} 3)

21:25 clojurebot: 3

21:25 Chousuke: a map also is a functions of its keys

21:25 -s

21:25 hiredman: ,(ifn? {})

21:25 clojurebot: true

21:25 hiredman: ,(ifn? :foo)

21:25 clojurebot: true

21:27 mrsolo: ifns?

21:27 Chousuke: ,(map ifn? [[], #{}, {}, 'symbol, :keyword]) ; anything else

21:27 clojurebot: (true true true true true)

21:27 cp2: think you got it all

21:27 er

21:27 struct maps

21:28 Chouser: ,(map ifn? [[], #{}, {}, 'symbol, :keyword, #(), (fn [])])

21:28 Chousuke: those are maps

21:28 Chouser: you forgot functions

21:28 :-)

21:28 cp2: yeah i figured

21:28 Chousuke: mrsolo: IFn is hte interface that an object must implement to be usable in operator position

21:28 Chouser: omitted those as obvious; guess it isn't.

21:28 Chouser: naw, you're probably right.

21:29 mrsolo: ah ha.. jedi mind trick... thanks :-)

21:29 handy :-)

21:29 Chousuke: mrsolo: the only exceptions are special forms and macros (user-defined special forms!)

21:32 mrsolo: okay

21:32 Chousuke: ,(ifn? ->) ; macros are a bit weird anyway

21:32 clojurebot: java.lang.Exception: Can't take value of a macro: #'clojure.core/->

21:32 hiredman: ,(ifn? #'->)

21:32 clojurebot: true

21:32 Chouser: oh, vars.

21:33 Chousuke: hiredman: that's a var, not a macro, though.

21:33 Chouser: ,(ifn? #'proxy)

21:33 clojurebot: true

21:33 * Chouser is too slow

21:34 hiredman: ,(#'-> x foo)

21:34 clojurebot: java.lang.Exception: Unable to resolve symbol: x in this context

21:34 hiredman: ,(#'-> 'x 'foo)

21:34 clojurebot: (foo x)

21:34 Chousuke: the #'foo syntax gives you a nice way to cheat with macros like that.

21:34 hiredman: ,(#'-> 'x 'foo 'baz 'bleep)

21:34 clojurebot: (clojure.core/-> (clojure.core/-> x foo) baz bleep)

21:34 hiredman: hmm

21:34 Chousuke: it runs the macro function as usual but doesn't eval the result

21:35 hm, nice sunrise

21:36 insomnia has its benefits sometimes ;(

21:36 hiredman: ,(binding [-> (vary-meta #'-> assoc :macro false)] (-> 'a 'b 'c 'd))

21:36 clojurebot: java.lang.ClassCastException: clojure.lang.Var cannot be cast to clojure.lang.IObj

21:37 Chousuke: ~source defmacro

21:37 Chouser: wouldn't work anyway, I think. The compiler would expand -> before the binding was set

21:38 hiredman: I rebind doc in clojurebot somehow

21:39 Chousuke: ,foo

21:39 clojurebot: 1

21:40 Chouser: ,(alter-meta! #'-> dissoc :macro)

21:40 clojurebot: {:ns #<Namespace clojure.core>, :name ->, :file "clojure/core.clj", :line 1017, :arglists ([x form] [x form & more]), :doc "Threads the expr through the forms. Inserts x as the\n second item in the first form, making a list of it if it is not a\n list already. If there are more forms, inserts the first form as the\n second item in second form, etc."}

21:40 Chouser: ,(-> 'a 'b)

21:40 clojurebot: (b a)

21:40 Chouser: ,(alter-meta! #'-> assoc :macro true)

21:40 clojurebot: {:macro true, :ns #<Namespace clojure.core>, :name ->, :file "clojure/core.clj", :line 1017, :arglists ([x form] [x form & more]), :doc "Threads the expr through the forms. Inserts x as the\n second item in the first form, making a list of it if it is not a\n list already. If there are more forms, inserts the first form as the\n second item in second form, etc."}

21:40 Chouser: ,(-> 'a 'b)

21:40 clojurebot: (quote a)

21:41 Chousuke: ,(.setMacro #'->); should work too I guess

21:41 clojurebot: nil

21:42 Chousuke: ,(intern-ns 'my+ +)

21:42 clojurebot: java.lang.Exception: Unable to resolve symbol: intern-ns in this context

21:42 Chousuke: hm

21:43 oh well, time to go

21:43 later

21:43 Chouser: ,(ns-intern 'my+ +)

21:43 clojurebot: java.lang.Exception: Unable to resolve symbol: ns-intern in this context

21:45 Chouser: ,*ns*

21:45 clojurebot: #<Namespace sandbox>

21:45 Chouser: ,(intern 'sandbox 'my+ +)

21:45 clojurebot: #'sandbox/my+

21:45 Chouser: ,(my+ 5 10)

21:45 clojurebot: 15

21:50 eee: hi

21:50 reduce is my hammer right now, but I'm not sure it is right

21:50 i need to loop through a set

21:51 and update several data structures at the same time

21:51 conditionally

21:51 that's cake in python. totally confusing to me in clojure

21:51 anyone got advice?

21:51 thanks

21:52 hiredman: sure, reduce is for that

21:52 eee: one unsatisfying way would be with three reduce commands that each have the same logic

21:52 Chouser: if you're doing more than one thing per iteration, you might find loop/recure less confusing.

21:52 is there any reason not to iterate multiple times?

21:52 eee: the check is the same

21:53 for each item that p is true

21:53 do these three things

21:53 Chouser: put the check in a fn?

21:53 eee: why go through list and retest three times?

21:53 Chouser: hm. sure.

21:53 eee: loop recur hmmm

21:53 that could work

21:54 can loop recur's be nested?

21:54 hiredman: ,(reduce #(if (zero? (mod %2 2)) (update-in % [:evens] inc) (update-in % [:odds] inc))) {:evens 0 :odds 0} (range 20))

21:54 clojurebot: java.lang.IllegalArgumentException: Wrong number of args passed to: core$reduce

21:54 hiredman: bah

21:54 dnolen: (defn yr-fn [thing] (if (p? thing) (-> thing (step1) (step2) (step3)) thing)

21:54 (map yr-fn yr-set)

21:55 eee: i'm trying to understand

21:56 i've been avoiding that arrow

21:56 dnolen: ,(-> 4 (+ 1) (* 2))

21:56 clojurebot: 10

21:56 dnolen: it's not that scary ;)

21:56 eee: it is

21:57 i'm trying to figure out how to apply that to my problem

21:57 i'll write it in pseudocode

21:57 hiredman: ,(reduce #(update-in % [(if (zero? (mod %2 2)) :evens :odds)] inc) {:evens 0 :odds 0} (range 1 20))

21:57 clojurebot: {:evens 9, :odds 10}

21:57 dnolen: might not apply, the other solutions might be better. just my interpretation.

21:58 eee: those wierd faces make it hard to read :(

21:59 i can cutn paste to an editor

21:59 ahh now I can see it

21:59 hiredman: you might want to get a real irc client

22:00 eee: never found a free one for mac

22:00 hiredman: ~google free mac irc client

22:00 clojurebot: First, out of 219000 results is:

22:00 Macintosh Chat Clients

22:00 http://www.irchelp.org/irchelp/mac/

22:01 hiredman: I would just install irssi

22:01 eee: dnolen are those step 1 step 2 step 3 things each reduces?

22:01 dnolen: no they are just whatever update steps you want

22:02 eee: i think the other solution is what i have to do

22:02 but maybe I don't get it

22:02 i need to say

22:03 if current distance plus length less than previous length:

22:03 change value in heap

22:03 and

22:03 update "distances"

22:03 and

22:04 change path to go from current node to new node

22:04 and do that for each node

22:04 in a set

22:04 so three data structures need to be mutated, really

22:04 easiest way would be to use atoms or something

22:05 hiredman: nah

22:05 eee: but what hiredman wrote looks possible

22:05 hiredman: or you can use loop/recur

22:05 eee: i don't get the syntax yet

22:06 why that if is in square brackets

22:06 hiredman: oh

22:06 that is just for update-in

22:06 (update-in {:foo 1} [:foo] inc)

22:06 ,(update-in {:foo 1} [:foo] inc)

22:06 clojurebot: {:foo 2}

22:06 hiredman: ,(update-in {:foo {:bar 1}} [:foo :bar] inc)

22:06 clojurebot: {:foo {:bar 2}}

22:07 eee: ok

22:09 ,(reduce #(conj %1 %2) #{} {:evens 0 :odds 0} (range 1 20))

22:09 hiredman: that won't work

22:09 reduce takes 2 or 3 args

22:09 eee: ,(reduce #(conj %1 %2) #{} {:evens 0 :odds 0} (range 1 20))

22:09 clojurebot: java.lang.IllegalArgumentException: Wrong number of args passed to: core$reduce

22:10 hiredman: not 4

22:10 eee: so loop recur can be nested in loop recur?

22:10 i may try that

22:11 hiredman: yeah

22:11 eee: thanks

22:12 then when I am done with the loop recur because I am out of elements, return a list of the three structures

22:12 then destrcuture

22:12 insane

22:15 oh, now I understand dnolen

22:15 the function does one element for each structure

22:15 then I map it to the "foreach"

22:16 but can I do it without the arrow ....

22:18 dnolen: eee: loop/recur sounds like a better fit for what you are trying to accomplish.

22:18 the arrow isn't magical, just a macro that converts the expression to normal form.

22:18 eee: then return the three structures in a list? then destructure?

22:18 i can't switch back to normal form while learn all these parenthesis

22:18 dnolen: (-> 4 (+ 1) (* 2)) becomes (* (+ 1 4) 2)

22:19 oops

22:19 eee: yeah, let's stick to the second

22:19 dnolen: (-> 4 (+ 1) (* 2)) becomes (* (+ 4 1) 2)

22:19 i mean

22:19 eee: second is much clearer to me

22:20 anyway, so i need to return a list to get my three structures, right? ... from the loop-recure

22:20 -e

22:21 dnolen: yes that's one way to do it, or return a map, whatever feel most natural.

22:21 eee: oh, I see

22:22 this function is looking insane right now

22:22 40 lines long

22:22 and probably 50 more to go

22:22 thanks for the help

22:23 i'll try that. it's kinda cool to feel like I'm starting over learning how to program

22:24 hiredman: sounds like it's time to break the function up

22:39 danlarkin: yeah definitely

22:41 eee: ,(let [[a b & c] (range 3 9)])

22:41 clojurebot: nil

22:41 eee: ,(let [[a b & c] (range 3 9)] a)

22:41 clojurebot: 3

23:23 danlarkin: not a big deal, but maybe this error message should be the same:

23:24 ,(hash-map 1 2 3)

23:24 clojurebot: java.lang.IllegalArgumentException: No value supplied for key: 3

23:24 danlarkin: ,(array-map 1 2 3)

23:24 clojurebot: 3

23:24 danlarkin: umm weird

23:26 hiredman: array-maps are fast and loose

23:26 danlarkin: locally I get an error

23:27 java.lang.ArrayIndexOutOfBoundsException

23:27 hiredman: it is undefined bahaviour

23:37 danlarkin: ,(nth {1 2 3 4} 1)

23:37 clojurebot: java.lang.UnsupportedOperationException: nth not supported on this type: PersistentArrayMap

23:37 danlarkin: ,(first {1 2 3 4})

23:37 clojurebot: [1 2]

23:38 danlarkin: why is this

23:39 hiredman: nth operates on seqs

23:39 first calls seq on its arg

23:39 danlarkin: is it because it'd be suboptimal to call seq on nth's argument in every case?

23:40 why doesn't nth call seq just like first calls seq

23:41 hiredman: well, maps are not ordered, so taking the 3rd thing doesn't make sensesnse

23:41 but, yeah, first works

23:42 danlarkin: array-maps are ordered

23:42 plus if taking the 3rd thing doesn't make sense then taking the first thing doesn't make sense :)

23:42 plus fnext will work, etc

Logging service provided by n01se.net