#clojure log - Oct 17 2008

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

1:23 Lau_of_DK: Top of the morning gents

2:12 anybody else caught this? :) http://robert.zubek.net/blog/2008/04/26/clojure-web-server/

2:15 arbscht: that made the rounds some months ago. very nice though

2:17 Lau_of_DK: Yea pretty cool

2:18 Our company is considering launching a new development division next year, and Im really considering pushing hard for it to be clojure based. Any thoughts?

2:19 arbscht: exclusively clojure based?

2:20 Lau_of_DK: No, Im thinking 80% clojure, 20% php/perl/c. But that will also reflect the demands from our customers

2:23 arbscht: if it's suitable for the job, that may be worthwhile. I presume php/perl/c are the only alternatives

2:24 but then I'm not one to give useful advice on these things :) in my work, it's more like 10% among 10 different language systems

2:24 Lau_of_DK: Yes that seems to be the case

2:24 Ok

2:24 My only hang-up is, that Im wondering if Clojure is not enterprise ready in all areas. That we might hit dead ends

2:25 tWip: You can always work around in Java or patch Clojure... is that really a critical issue?

2:25 arbscht: can you try to prototype first?

2:26 early failure can be cheap

2:26 tWip: and also... what does "enterprise ready" even mean? seems like buzzwords

2:26 Lau_of_DK: tWip, it can potentially be a big issue

2:27 arbscht a prototype is difficult, because initially we will need to find 4 Lispers, which is a pretty big investment

2:27 tWip, by Enterprise ready, I just mean that its solid enough to build larger project on, without something breaking

2:28 arbscht: I'm curious, why are 4 necessary?

2:29 Lau_of_DK: Its an estimate, that with current order-flow thats what we'll need to be prepared to handle the coming workload. We dont want to reject/postpone certain contracts, because the division is not fully operational

2:30 (brb, afk)

2:32 tWip: I completely trust that Clojure is enterprise ready (in the sense you mean)

2:47 Lau_of_DK: K - Thanks alot for your input

3:03 johnwayner: Pupeno: regarding indention issues. I had some problems and it turns out there are at least two clojure-mode's floating around. I had more luck with this one: http://github.com/jochu/clojure-mode/tree/master . You may want to check which you are using.

5:08 Lau_of_DK: Any of you sitting with some good Clojure links ? blogs, tutorials, etc.

5:51 Any of you sitting with some good Clojure links ? blogs, tutorials, etc.

6:29 blackdog: Lau_of_DK: http://blog.thinkrelevance.com/2008/9/25/pcl-clojure-chapter-16

6:30 Lau_of_DK: Thanks Big Dawg

6:32 hoeck: Lau_of_DK: http://www.loufranco.com/blog/files/20-Days-of-Clojure-Day-7.html (clojure vector implementation explained)

6:37 Lau_of_DK: Thanks Hoeck :)

6:55 dmiles: wild.. a channel

7:26 emacsen: dmiles, yes, wild...

7:31 dmiles: clojure comes closer to having def-java-class from jLinker than abcl huh?

7:34 i been implementing as much of the jLinker (allegro docs) in my javalisp .. but thinking i ought to use clojure classgening for letting lisp subclass exisitng java objects

7:37 has anyone tried a classloading class transformer to instrument preexisting java classes to allow lisp to redefine methods? .. pretty much just adding in a redefined?callClojureInstead

7:38 rhickey: dmiles: interesting

7:38 but is there much demand for that?

7:38 dmiles: i did this a while ago for beansell .. but i forgot alot of things since then

7:40 rhickey, i cant say there has been alot of use cases needing this.. but i am thinking there is sometimes this has to be done to catch exceptions and things

7:40 or to make legitimate subclasses

7:41 legitimate subclass .. trying to figure out a better explaination

7:43 oh i remember.. allowing objects to get created by third parties before and after clojure.. the classes are preinjected (classload transformer) with supporting allowing redefinations

7:44 mainly its for the cases when clojure wasnt able to manage the creation of objects

7:46 rhickey: dmiles: I'm still not quite clear - genclassed classes can get instantiated separately but have their methods redefined - or is this just an init-order thing?

7:48 dmiles: gened classes have power to redefine their methods runtime right?

7:48 rhickey: yes

7:51 dmiles: well what made me think i needed this was when i wanted to catch an exception that was thrown as a result of something i did and cliamed to handle.. yet in the object doing something with my method wasnt letting me handle it... i really should come up with a clearer explainaion ;P

7:52 i wanted to make the handler catch an exception .. yet the code that caused the exception was from a class i didnt write.. but was preloaded

7:53 so i was supposed to return a result that wasnt null.. but was bad and returned null.. causing the user class to get a npe

7:54 i sorta wished that user class was calling 'thru' some safety wrapper of mine that calls the orignal code

7:55 then i could let lisp handle the NPE and not java

7:56 so really what this is all about is having a higher resolution into call stacks

7:57 even though i am sure .. at some point i'd been looking for even a higher resolution into the calls than per-method :P

7:59 i guess the main idea.. is nothing in un-redefinable

7:59 rhickey: I know bytecode injection/transformation is all the rage, but I'm concerned about the composability of these techniques

8:01 dmiles: today i really wanted to been able to change java.lang.reflect.Array.* to be able to work with lisp sequences and lisp arrays

8:03 i wanted a class that i didnt write that used Array.* methods.. to use my lisp array instead of its member

8:04 rhickey: Clojure goes pretty far in complying with Java interfaces for interop, but something like that is out-of-scope - maybe AspectJ?

8:06 dmiles: might look into aspectJ for satisifying the class definition needs i think i have.. but .. yeah i havent proved to myself i need this yet ;P

8:08 can clojure subclass something like java.util.Date ?

8:09 erm sorry of course it can.. and override any members overridable

8:09 rhickey: as long as it's not final

8:14 dmiles: forgive the naive question, how hard would it be to make clojure switch in the middle of execution to a full CL mode levearging ABCL when that need arises?

8:15 i almost thinking about trying to see if i can make ABCL switch to a clojure mode to leverage things that cojure might do more optimally

8:16 rhickey: dmiles: to the extent ABCL exposes itself as a Java library, it should be easy to interop.

8:17 emacsen: rhickey, is there a canonical documentation source?

8:18 the pages on the site seem somewhat spartan

8:18 rhickey: (doc fnname) is canonical, prose docs at http://clojure.org

8:18 The site is a reference, and has shortcomings as a tutorial

8:18 emacsen: the reference pages are fine for a lisper. They suck as something to point a java person at

8:19 maybe I should just point them to the PCL port

8:20 rhickey: The best start for non-lisper Java programmers would be these talks: http://blip.tv/file/982823 http://blip.tv/file/982957

8:21 emacsen: yeah the java ones?

8:21 rhickey: yes

8:21 emacsen: I'm just about to send a friend those but want to say "Okay, so once you're convinced, this is what you should be reading"

8:23 it's clear in that talk you were pressed for time (even though it's 3 hours) you only didn't even get much into even the concurency model

8:23 which reminds me, I don't see anything on the reference site about this... does clojure have a conditionals system ala CL?

8:23 erm conditions, not conditionals

8:23 rhickey: emacsen: there a separate 3 hr concurrency talk, also very much directed at Java programmers

8:23 emacsen: ah, sorry, didn't see that one yet

8:25 rhickey: It's a challenge to get all the docs needed to get a Java programmer up to speed - the first focus was on documenting what Clojure does

8:25 but then there are fundamental Lisp and FP concepts

8:25 karmazilla: rhickey: that's the one where you wave jcip at the audience, more or less implying they can't call themselves professional if they haven't read it?

8:25 emacsen: sure. I guess the book will solve some of that too

8:25 as will the book ports

8:25 oh, and here's one that I know is covered somewhere

8:25 what's the term for a clojure user

8:25 clojist?

8:26 rhickey: karmazilla: I don't think I questioned anyone's professionalism :)

8:26 emacsen: As in "The Little _____"

8:26 rhickey: Clojurian seems to be catching on

8:26 karmazilla: rhickey: maybe I remember it like that :)

8:26 emacsen: The Little Clojurian...

8:29 dmiles: listening/watching theblip.tv intros i am coming from a jvm lisp.. so this is great

8:29 AWizzArd: indeed, sounds like one of the best ideas I've heard in the past few years

8:30 dmiles: and not vapourware

8:32 AWizzArd: If you want to get famous put work into Clojure ;-)

8:34 dmiles: i am hoping to see if we can compile the CYC sublisp (which is a .lisp 2 .java) into maybe a (.lisp 2 .clj)

8:36 sometimes the .java step tricks us into doing some suboptimal that maybe a .clj lets us leave soemthing that might been bad the why we do the .java .. will let us make the .clj to .class be smarter than us

8:36 bad the why we do the .java/ bad the way we do the .java

8:38 but some questions still up in the air.. how hard will it be to make a .lisp->.clj

8:38 translator

8:39 and will clojure runtime performance exceed Cyc's javalisp

8:39 H4ns: dmiles: i don't think it is feasible to automatically convert from lisps with mutable data structures to clojure.

8:39 rhickey: It's easy once you have an imperative->functional translator

8:39 ;)

8:40 H4ns: rhickey: i'm not used to be the pessimist! :)

8:40 AWizzArd: The question that longtime lispers should ask is *why* they want to translate CL into CLJ.

8:40 Maybe it's the few libs that Java offers...

8:41 dmiles: we have a sublisp2c and sublisp2java ... the 2java is faster than the 2c.. i didnt write the translators.. bu ti can hack our translators to producing other languages.. like c#.. but maybe even .clj

8:41 rhickey: More broadly, and back to emacsen's documentation qs, some sort of 'how do I transform this imperative xxx' guide would be quite useful

8:46 arnfred: is there any function in clojure returning true if a char is in a string or if an atom is in a list? like haskells 'elem'?

8:48 wlr: rhickey: that guide would be good in tandem with "how to think/design/program in terms of rhickey's State and Identity essay"

8:50 jdz: what's the way to find out wheather a value is an array?

8:52 rhickey: wlr: I think the most success comes from understanding the problems Clojure is trying to address. Anyone who's built large OO systems with mutable objects knows the problem, add threads, and knows the pain

8:52 jdz: oh, it's vector?

8:54 wlr: rhickey: sure. but i thought the general topic was "help for the rest of us..."

8:55 karmazilla: jdz: how about (defn in? [x xs] (reduce #(or %1 (= %2 x)) false xs))

8:55 rhickey: wlr: I think this describes the complexity problem well: http://web.mac.com/ben_moseley/frp/paper-v1_01.pdf

8:56 jdz: karmazilla: not "in" array, but "an" array :)

8:56 rhickey: wlr: not specific to the state and identity concept

8:56 karmazilla: oh

8:56 silly me

8:56 jdz: but my bad on the terminology. in clojure they are called vectors.

8:57 rhickey: (some #{\a \c} "abacab")

8:57 dmiles: so a vector is the impl of a clojure array?

8:57 arnfred: nevermind, I made one myself: (defn elem [x list] (reduce (fn [z w] (or z w)) (map (fn [y] (= y x)) list)))

8:57 rhickey: arnfred: see some above

8:58 (some #{4} [1 2 3 4 5 6])

8:58 dmiles: so a vector is the impl of a clojure array? a prexisting java array like char[] returned from a 3rd party lib to closure is called a what?

8:58 arnfred: oh, right, that's a lot neater

8:58 thanks

8:58 dmiles: oops didnt mean to repeat my question

8:59 rhickey: dmiles: vector is Clojure's indexed sequential thing, we reserve the term array for Java arrays

9:00 AWizzArd: I expect from Clojures vectors a +/- constant access time for random elements

9:01 arnfred: rhickey, what does the "#{4}" mean in "(some #{4} [1 2 3 4 5 6])"?

9:01 rhickey: arnfred: It's a set literal - sets are functions of their elements - (#{1 2 3 4} 3) -> 3

9:02 karmazilla: callable collections is still a rather new concept to me

9:02 parth_m: (instance? (class [1]) [1 2 3]) => true, while (instance? (class []) [1 2 3]) => false.

9:02 arnfred: that's way cool!

9:02 parth_m: rhickey: Is this expected?

9:02 AWizzArd: arnfred: http://clojure.org/data_structures

9:03 parth_m: I see one is PersistentVector while the other is LazyPersistentVector

9:03 rhickey: so the (some set ...) technique works for every thing except nil and false, for which you have nil? and false? predicates

9:04 parth_m: you can't depend on any specific concrete classes, use the interfaces

9:05 http://clojure.googlegroups.com/web/chart.png

9:05 parth_m: ok. I was thinking of jdz's question on how to check if something is a vector.

9:05 What would be a good way.

9:05 jdz: parth_m: i already found my answer :) it's the function vector?

9:05 rhickey: (vector? x)

9:06 parth_m: Ah ... :) Thanks.

9:06 rhickey: the chart above is nice, shows the interfaces and the predicate if any

9:07 parth_m: Nice.

9:07 rhickey: IBlahs are safe to use with instance?, as well as Associative, Reversible, Sorted, Sequential - all of which have predicates

9:08 parth_m: Thanks for the clarificaiton. I understand this much better now.

9:08 karmazilla: not everything is an IObj I see. so what is an IObj?

9:08 arnfred: is there a function to append one list to another? like ++ from haskell?

9:09 rhickey: karmazilla: IObjs have metadata

9:09 karmazilla: ah

9:09 rhickey: arnfred: concat and lazy-cat

9:10 arnfred: thanks a lot

9:15 AWizzArd: arnfred: the documentation is also helpful: http://clojure.org/sequences

9:17 arnfred: AWizzArd, I know, I've been reading through it repeatedly all day :)

9:18 AWizzArd: excellent

9:36 blackdog: Chouser: how did you implement your repl in Clojurescript without the clojure compiler, or are you running that in an applet?

9:37 i didn't investigate further than the svn log :P

9:45 Chouser: blackdog: it uses ajax-like techniques to have a jvm somewhere do the compiling.

9:46 emacsen: Does anyone have a recommendation for a web framework for use with Clojure. I have a very simple web site idea. I could do it in, I dunno, a day or two in Django, but thinking this may be a good time to learn.

9:46 blackdog: Chouser: ok

9:46 Chouser: emacsen: you might want to look at Compojure -- haven't really used it myself yet, but I know others are.

9:47 blackdog: you can try it if you want. Be gentle: http://chouser.n01se.net/clojurescript/

9:48 blackdog: emacsen: i have a nice servlet utility for jetty, where you can do (defn x[] (isServlet "text/json" .... and print to the output

9:48 the emphasis is on simple

9:48 not a framework

9:49 emacsen: blackdog, I'm thinking I may stick with what I know because the site is /so simple/ - or I think it is :)

9:56 lisppaste8: blackdog pasted "a jetty servlet " at http://paste.lisp.org/display/68682

10:02 H4ns: blackdog: i don't understand the use of make-array and aset in createHandler. wouldnt a [resourceHandler servletHandler] in the call to .setHandlers do?

10:02 blackdog: possibly :) it works though, i didn't investigate all the possibilities

10:03 there could be better ways,

10:03 H4ns: blackdog: ok - so take it as a suggestion. looks less imperative that way :)

10:04 blackdog: yea, i'm new to all the functional lispish goodness so suggestions welcome

10:06 H4ns: blackdog: don't place closing parens on lines by themselves, and use an editor that does the indentation correctly

10:06 blackdog: (correctly and, most importantly, automatically)

10:07 blackdog: oh, well that was me, i was fighting the emacs all the way :) when i was moving over from js java i felt more comfortable with the indentation, but I'm beginning to write more regular stuff now

10:09 actually that array stuff was commentet out, i did find a better way

10:11 H4ns: blackdog: C-M-q on the opening paren reindents an s-expression. I use that, and C-M-k to kill s-expresssions all the time when refactoring code.

10:11 blackdog: then there is paredit, but i've not gotten used to that.

10:12 blackdog: ok, thanks!

10:12 lisppaste8: blackdog pasted "servlet usage" at http://paste.lisp.org/display/68684

10:13 blackdog: if you'er interested

10:13 H4ns: looks nice! :)

10:14 blackdog: to me it's a lot easier than using the appservers, i can just upload a dir and run, and jetty is awsome

10:32 how does one make a pin on Graham Fawcett's google map, I seem to be missing the obviousl

10:33 H4ns: press "edit" then choose the placemark icon on top of the map

10:33 blackdog: ha

10:37 ok i'm not completely daft, edit wasn't visible in epiphany browser, but ok in firefox

10:39 karmazilla: is there a website for compojure more official than the github repo page?

10:49 * drewr couldn't make it without paredit now

11:37 Lau_of_DK: Good afternoon gents

11:37 Chouser: hi

11:38 emacsen: not quite yet afternoon here

11:41 asbjxrn: It's about time for bed here.

11:42 tWip: it's about time for some friday night activities here

11:43 Lau_of_DK: hehe

11:43 Okay guys - What I meant was, good to see you all again

11:44 scottj: Lau_of_DK: you were talking earlier about enterprise apps. What type of apps does your copany specialize in?

11:45 Lau_of_DK: scottj, I got some good input in the discussion earlier, but someone regretting asking the question in a channel that has public logs. So I think I'll park the subject if thats okay with you

11:46 (someone = somewhat regrettet)

11:47 scottj: understood

11:47 Lau_of_DK: :)

11:53 Is there any difference between a regular 'set', and then a persistanthashset, in the way the respond to conj and contains?

11:53 karmazilla: your from denmark?

11:53 Chouser: (class (set [])) ==> #=clojure.lang.PersistentHashSet

11:54 Lau_of_DK: Thanks

11:54 So the shorthand #{} will work fine

11:55 nicknull: how do i try-catch?

11:56 Chouser: http://clojure.org/special_forms#try

11:57 hm, that doesn't actually work. Anyway, search that page for "catch"

11:58 drewr: nicknull:

11:58 http://clojure.org/special_forms#toc12

12:02 Chouser: I'm surprised merge doesn't act like set/union

12:03 lisppaste8: q pasted "a" at http://paste.lisp.org/display/68692

12:04 nicknull: http://paste.lisp.org/display/68692

12:05 ^^ there it came, im using tyr-catch there but it isnt working, what is the correct use? an example in the documentation would help

12:05 Chouser: (try (/ 5 0) (catch ArithmeticException e 0.5))

12:05 drewr: nicknull: Let me guess. You're getting a ClassCastException because 0.5 isn't a fn?

12:05 Ah, and the binding form for the exception object...

12:05 Chouser: also was missing the local to bind to the exception (in my example "e")

12:13 nicknull: it works now thanks

12:13 what is e?

12:13 drewr: Arbitrary. Call it whatever you want.

12:13 nicknull: arithmeticexception e

12:13 ok

12:14 drewr: It's a symbol that the exception object gets bound to. You can inspect it, print stacktrace, etc.

12:15 In Python, that would be: except FooError, e: ...

12:15 Same concept.

12:15 nicknull: ah i see

14:29 Chouser: could re-find and friends call str on their second argument, since strings are the only thing that regexes work on?

14:31 albino: Is str ascii or how does that fit with unecode?

14:31 drewr: Why would they want a String when they need a Pattern?

14:32 Chouser: for example, this currently throws an exception: (re-find #"foo" 'foo)

14:33 drewr: Oh, sorry the second *argument*.

14:33 Chouser: I'm just wondering if it'd be reasonable for it to behave like (re-find #"foo" (str 'foo)) automatically.

14:33 drewr: Right, that seems reasonable.

14:33 danlarkin: Chouser: I think it would be unreasonable

14:33 drewr: danlarkin: I what scenario would the magic there be confusing?

14:34 Chouser: albino: str returns a Java string, which is unicode.

14:35 danlarkin: well regexes work on strings, so you pass it a string or you get an exception... which is good. and if you considered this case you can either call (str 'foo) yourself or catch the exception and deal with it

14:36 rhickey_: Chouser: I think there are many functions taking a logical 'name' or designator, for which taking either strings or symbols would be ok, I don't know that this falls into that category, but arbitrary (str x) seems like a bit much

14:38 Chouser: ok

15:21 ozzilee: Macros hurt my brain. I'm trying to write a macro combinations such that (combinations [1 2 3] [4 5 6]) expands to (for [a [1 2 3] b [4 5 6]] [a b]). Help?

15:22 combinations may take any number of vectors

15:33 drewr: You sure you need a macro for that?

15:41 ozzilee: drewr: If you can show me a way without a macro I'm all ears.

15:41 Chouser: to use "for", I think you need a macro. There might be a better way than using "for", though.

15:41 lisppaste8: Chouser pasted "combination macro etc." at http://paste.lisp.org/display/68701

15:43 ozzilee: Chouser: Ah, hmm. Might take me a bit to absorb that, thanks.

15:45 Chouser: build two vectors and stick them in a "for", right?

15:45 ozzilee: "(vec (apply concat (partition 1 2" just says "take every other one", correct?

15:45 "and make a vector out of them"

15:45 Chouser: right!

15:46 hm, shoulda used take-nth

15:49 ozzilee: Yeah. Also interleave would work for v, I think.

15:49 But I get the meaning, no matter.

15:50 I tried writing the v and o inline with the for and got myself horribly confused, this is much cleaner, thanks.

15:50 Chouser: ah, sure.

15:50 but since the inputs to combinations are all regular eval'ed values, it doesn't need to be a macro.

15:51 if it were a regular function than things like "apply" can work on it, which could be useful.

15:53 ozzilee: Chouser: Yeah, that's true, I just wasn't sure of the right algorithm, and for was so nice and handy...

15:53 Chouser: yep

15:55 ozzilee: Perhaps I'll look up how for works later. Thanks for the help.

15:57 lisppaste8: Chouser annotated #68701 with "combination fn" at http://paste.lisp.org/display/68701#1

15:59 * ozzilee will have to try to absorb that one when his head hurts less :-)

15:59 Chouser: yeah, that one's a stretch for me.

16:02 lisppaste8: Chouser annotated #68701 with "better combinations macro" at http://paste.lisp.org/display/68701#2

17:04 Pupeno: Hello.

17:04 Chouser: hi!

17:04 Pupeno: So, to distribute a Clojure program you just distribute the source files in a jar and a little java class/program that gets it started?

17:05 Chouser: if you put something in user.clj in the classpath, clojure.jar will start it for you

17:06 Pupeno: Ok... but still putting the source code in plain view? Right?

17:06 Chouser: yessir

17:06 AWizzArd: currently yes

17:07 but if you don't think only shortterm, then I think we can assume this will go away

17:09 lisppaste8: Chouser annotated #68701 with "combinations, lazy fn" at http://paste.lisp.org/display/68701#3

17:18 Chouser: oh, nevermind -- annotation 1 is lazy too.

18:00 mmcgrana: Hi all, I have some question about loading other Java and clojure code from a clojure script.

18:01 First, what is the best way to load up eg clojure-contrib for use in a one-off script?

18:02 wwmorgan_: mmcgrana: (doc ns)

18:03 blackdog: mmcgrana: e.g. (ns user (:require

18:03 [clojure.contrib.duck-streams :as ds]))

18:04 and add the root of contrib to your classpath

18:04 mmcgrana: rtm, right. but for example if I just do (ns my-ns (:require (clojure.contrib str-utils))) it clearly won't find that resource. so presumably it needs to go in the classpath, so then how does one get it in a jar etc?

18:04 sorry if this sounds noobish...

18:05 blackdog: you can jar up contrib then add a -cp contrib.jar

18:05 mmcgrana: ok so ant from clojure-contrib/ builds a jar, then put that in classpath

18:05 blackdog: yes

18:06 another good one is -Djava.ext.dirs=$LIBDIR where you can have a dir full of jars

18:06 and add them all at once

18:07 AWizzArd: What does Paul Grahams accumulator look like in Clojure? (defun foo (n) (lambda (i) (incf n i)))

18:07 mmcgrana: ah nice thanks

18:09 AWizzArd: not that I need it, I just would like to know the trick how to go around the immutable state

18:10 Chouser: (defn foo [n] (fn [i] (+ n i))) ?

18:10 mmcgrana: http://www.paulgraham.com/accgen.html

18:10 AWizzArd: this is not an accumulator Chouser

18:10 (def bar (foo 3))

18:10 mmcgrana: i think the praham one has state, so the result changes with successive calls

18:10 AWizzArd: (bar 5) ==> 8.. (bar 1) ==> 4

18:11 jerryk: Is anybody out there interested in, or already working on, an interval artithmetic package for Clojure?

18:11 AWizzArd: it should be 9

18:11 Chouser: sorry, gotta run

18:11 AWizzArd: mmcgrana: right

18:11 wwmorgan_: AWizzArd: you might use refs to get that behavior

18:12 AWizzArd: this is what I supposed, but as I discovered Clojure only yesterday I don't know how that would look like

18:15 blackdog: AWizzArd: this guide is good, and it had somewhere a good example of an accumaltor but I can't find it now http://blog.thinkrelevance.com/2008/9/16/pcl-clojure

18:15 http://blog.thinkrelevance.com/2008/9/16/pcl-clojure-chapter-6 there it is

18:15 counter example

18:15 if that's what I think you're looking for

18:16 wwmorgan_: AWizzard: Here's one way to do it http://paste.lisp.org/display/68712

18:19 AWizzArd: thanks you two

18:21 mmcgrana: So I have the clojure-contrib.jar all set and in /jars within the project root. But I also have a "clj" script in usr/local/bin that calls java with clojure and jline in the classpath. Does anyone have any practical advice on how to invoke clojure with extra stuff in the classpath (like jars/clojure-contrib.jar) without having to type java -cp .... etc directly, ie using something like a "clj" script but that is aware of

18:23 has anyone tried something like this: http://github.com/dudleyf/clojure-bin/tree/master/clojure ?

18:24 wwmorgan_: mmcgrana: add-classpath may do what you want

18:26 mmcgrana: hmm interesting. Do people generally load additional resources from within a single root resource (like one would in Ruby with "require") or all at the beginning (like one might with -cp in a java invokation) ?

18:27 another related one: if I have several clojure files to load from an inital boot file, would clojure/load-file be right for that or is something else preferred?

18:31 wwmorgan_: I use enclojure which figures out all the classpath stuff automagically. From the command line I invoke java with -cp to my source root and the ns macro in each file does everything else

18:39 mmcgrana: ok thanks for the thoughts blackdog and wwmorgan_, I going to try re-reading clojure/ns and friends, then see if I can put together an example project that does all these various things

18:40 dmiles: so clojure doesnt have a rplacd ?

18:41 mmcgrana: not really, its in a very functional style

18:41 mutating state should be managed by refs, agents, or vars

18:42 dmiles: ah and setting it up via transactions?

18:43 mmcgrana: yeah for refs. clojure's mvcc is very cool, you should investigate

18:43 dmiles: if someone really felt they needed lisp conses mutable.. they could write a series of macros that implment mutable conses?

18:44 mmcgrana: actually i don't think that clojure provides a means of mutating non ref,var,agent state from within clojure code, you would have to drop into java i think. not sure though

18:44 Chouser: dmiles: yeah, but don't do that. :-)

18:46 Clojure interacts with mutable Java objects all the time, so you could write your own mutable cons cell in Java, built on arrays or something, or in Clojure built on refs.

18:46 dmiles: oh right

18:47 Chouser: The latter might be slightly preferrable as it would be thread safe (refs can only be mutated inside transaction), but either way you'd be doing a lot of work to fight the language.

18:48 dmiles: i am trying to see if it will be worth translation of pre-existing lisp code to clojure code

18:48 Chouser: mechanical translation?

18:48 dmiles: the lisp runtime is written in java.. it is pretty fast.. but wondering if it translates to cljure if it might be faster

18:49 mechanical prefered there is over 6 million lines of lisp code

18:50 walters_: wow

18:50 Chouser: would you expect to maintain it in clojure then, or maintain it in lisp and re-translate every time you update?

18:50 dmiles: its the codebase to CYC

18:50 thinking it should be option for people to maintain their code in clojure

18:51 Chouser: can the existing lisp code be called from Java?

18:51 dmiles: as long as we can also debug clojure from the lispworks runtime at some points since they cant always have a jvm

18:52 yes, the RTL has a java port.. so it can be leveraged from 3rd party libs

18:52 so an application written in java can use hte javalisp features now.. but thinking if it possible to ever swap out javalisp for cojure runtime

18:53 Chouser: if you want to keep the imperative, mutable model, I would guess a better use of your time would be to improve the lisp runtime with ideas from Clojure.

18:53 dmiles: lisp code is currently interpetd unless the user use the lisp2java translator and then compiles

18:53 Chouser: The Clojure compiler isn't terribly large.

18:54 I think it would be pretty hard to translate from existing lisp code to idomatic Clojure.

18:54 dmiles: how about java2clojure?

18:55 meredydd: Ditto.

18:55 dmiles: i guess thats just syntax

18:55 meredydd: It would be fairly hard to replicate Java's mutable local variables

18:56 You'd need to wrap all locals in a ref or something unpleasant like that, at a guess.

18:56 dmiles: i guess even if you emulated those, i wonder if you ever gain.. but hrrm yeah i guess it should be sposible

18:56 meredydd: Although Clojure can call into and out of Java very nicely, the language itself is structured quite differently.

18:57 dmiles: does clojure use a try/finally to implment (let ... ... ) ?

18:57 meredydd: Why do you need try/finally for (let)?

18:58 dmiles: to allow symbol shadowing

18:58 meredydd: There's no need for that - you can figure out which binding a symbol refers to statically, at compile time.

18:58 dmiles: erm well a view of letted values

18:58 meredydd: It's all lexically scoped.

18:59 (let [a :foo] (prn a) (let [a :bar] (prn a))) is completely unambiguous.

18:59 dmiles: (let [a :foo] (prn a) (let [a :bar] (prn a)) (prn a) ) ?

19:00 :foo :bar :foo ?

19:00 meredydd: yep

19:00 Get away from the idea that 'a is a local variable that "let" is modifying - it's not.

19:00 dmiles: so the middle a is not the same a.. its a copy?

19:01 meredydd: 'a, the symbol, is bound to a particular variable. The binding we call 'a inside that inner (let) has nothing to do with the binding we call 'a *outside* that (let)

19:01 It's a completely new creature.

19:01 dmiles: oh .. it wouldnt even need to be 'copy' its a new thing?

19:01 right

19:01 meredydd: yep.

19:02 dmiles: (let [a :foo] (prn a) (let [a a] (prn a)) (prn a) ) ?

19:02 meredydd: it's like you said (let [a1 :foo] (prn a) (let [a2 :bar] (prn b)))

19:03 That corresponds to: (let [a1 :foo] (prn a1) (let [a2 a1] (prn a2)))

19:03 dmiles: the global mutables like *standard-output*.. is there lexical bindingings of them?

19:04 meredydd: Those are different. (let)-ed variables are fundamentally different to (def)-ed variables.

19:04 You can do two things:

19:04 1. (def a :foo) (let [a :bar] (prn a))

19:05 which is equivalent to (def a :foo) (let [a1 :bar] (prn a1))

19:05 2. (def a :foo) (binding [a :bar] (prn a))

19:06 AWizzArd: btw, I just read you were talking about compilers 10 minutes ago.. did Rich mention that he wants to implement Clojure fully in Clojure one day?

19:06 dmiles: the operator 'binding' is new to me

19:07 meredydd: That's using dynamic rather than lexical binding - any time between the *time* execution enters that (binding) block and the *time* that execution exits that block, anyone reading that global variable 'a sees :foo.

19:07 mmcgrana: actually I think he mentioned somewhere that he wasn't particularly interested

19:07 AWizzArd: I mean, it was bootstrapped in Assemb... Java, so now it's there and in principle could get rid of all Java, no?

19:07 meredydd: (Actually, it's stricter than that - it's any code running *in the same thread* as the (binding) block)

19:07 AWizzArd: ic

19:08 meredydd: AWizzArd: The runtime is still in Java. Theoretically you could rewrite the runtime using a couple of primitives in raw Java ASM, then build the rest in Clojure.

19:08 mmcgrana: AWizzArd: i think it was in one of the clojure videos on http://clojure.blip.tv/ where he mentioned this

19:09 dmiles: so (binding [*standard-output* myfile] (prn :foo)) might write to my file assuming *standard-output* was used by prn?

19:09 meredydd: Aside, on the "programmatic translation of Java to Clojure" idea - you could probably more-or-less emulate local variables using (binding)s and (set!). Definitely counts under "creative abuse of the language", though...

19:10 dmiles: Correct.

19:10 AWizzArd: mmcgrana: I've seen yesterday one vid there where he mentioned that tons of stuff is done in CLJ itself. What I mean is an implementation which is written 100% in CLJ, without even a single line of Java.

19:10 Although the time is not ready for this yet.. the language is still getting more and more mature and there are several things to do first.

19:11 mmcgrana: yeah i think he explains in another one why he wasn't particularly excited about it: something like the compiler works fine as is, the data structures need a lot of java features that would otherwise need to be added to clojure, and as you said most of the user-facing aspects of the language are already defined in boot.clj and friends

19:11 AWizzArd: For example currently you need to distribute your source code with your programs, and your programs get every time compiled before execution. The concept of a .fasl is still missing.

19:12 mmcgrana: that reminds me, there's been talk of AOT compilation - is this recompiling like .pyc files or something else?

19:12 dmiles: meredydd: yeah .. sounds like a good excersize gfor me to try :)

19:13 meredydd: dmiles: Honestly, I'd recommend against it.

19:13 Not because it wouldn't be fun, but because it would be really difficult to do right before you have a good solid grasp of how to use Clojure "right".

19:14 (Creative abuse tends to require a feel for what you're abusing)

19:17 dmiles: more and more often i question exactly what programs i need to write for myself

19:19 i have a few i need to write and a few i have written that integratiomn with java libs are needed.. so sometimes thinking of porting

19:20 meredydd: mmcgrana: The compiler generates Java bytecode, one top-level S-expression at a time, then executes.

19:21 mmcgrana: thats what it does now, right?

19:21 meredydd: mmcgrana: There's no theoretical reason why AOT compilation isn't possible, but ISTR there are some unpleasant corners rhickey has expressed himself not-particularly-enthusiastic about working around for now.

19:21 dmiles: and there usually a pretty clear S-epression->.class

19:22 mmcgrana: oic. yeah i was just curious, i don't have any problems with the current compiler.

19:22 meredydd: Right now, if you generate a .class with (gen-and-save-class), it's just a shim that (load-resource)s an appropriately-named Clojure source file.

19:22 dmiles: i wonder how much AOT can be done on the .clj soure to .clj source

19:22 meredydd: dmiles: Explain?

19:23 dmiles: meredydd, i guess method hints could get annotated in?

19:23 but that'd happen in the compilling anyways

19:24 meredydd: dmiles: Why bother? It's not like that would pick up anything the type-inference stuff wouldn't figure out during actual compilation.

19:24 Chouser: I think AOT compilation is coming Really Soon Now.

19:25 But that's not the same as rewriting the remaining Java pieces in Clojure. I don't ever really expect that.

19:25 meredydd: Chouser: That would be Really Sweet(tm).

19:26 dmiles: meredydd: yeah i am wondering what AOT means really.. is it a database or transformations to do on S-Expressions?

19:26 or/for

19:26 Chouser: he had a version checked in a couple days ago that compiled all forms to .class files, then read them back off the disk to execute.

19:26 meredydd: Is there a realistic prospect of then packaging a limited version of the runtime that doesn't include any custom classloaders?

19:26 Chouser: meredydd: yes

19:26 meredydd: Excellent. Android may yet become easier to live with :D

19:26 Chouser: possibly no custom classloader, no Compiler, and no ASM lib.

19:26 meredydd: exactly.

19:27 meredydd: dmiles: Compilation right the way down to .class files you can call from any other Java runtime.

19:27 Chouser: Of course, GC's still going to bite, hard. (The GC lag on that thing is not-fun). But if he can get the RTL footprint down far enough, I'd be a very happy chappy.

19:28 Chouser: ClojureScript works roughly the same way, except it produces .js instead of .class files.

19:28 meredydd: GC on Android is poor?

19:29 meredydd: Chouser: The SDK docs all warn loudly about it. I may be mistaken, but the implication I got was that they might even have a naive mark-and-sweep like some of the early J2ME runtimes

19:29 Chouser: oh. ow.

19:30 meredydd: (early SDK documents, unreliable memory, blah blah. But yes - "Ouch" is the impression I distinctly remember.)

19:30 Chouser: Rich has stated before that Clojure depends on well-performing ephemeral GC.

19:30 meredydd: (They were warning you to avoid using Iterators at all, ever, for example.)

19:30 dmiles: meredydd: i see

19:30 meredydd: Well, duh. Persistent data structures don't work without one :)

19:30 Chouser: right

19:31 dmiles: meredydd: yeah this AOT/Whole program optimization.. may as well be farmed out to a 4th party lib like Soot

19:31 meredydd: dmiles: Why? rhickey's already written a full compiler capable of generating .class files.

19:33 dmiles: meredydd: oh in refering to: <meredydd> mmcgrana: There's no theoretical reason why AOT compilation isn't possible, but ISTR there are some unpleasant corners rhickey has expressed himself not-particularly-enthusiastic about working around for now.

19:34 meredydd: dmiles: Oh, right. Well, for starters, that was out of date (from what Chouser's saying). But I think the corners were to do with (def)s and similar, and other things that are far easier to deal with within the compiler than in an external library.

19:35 Chouser: I'm googling now - "dalvik garbage collection" doesn't bring up much. It's possible they do use a generational collector, but it's definitely stop-the-world, which isn't fun if you're trying to do a fluid user interface.

19:36 dmiles: meredydd: ah i see

19:37 AWizzArd: In principle I think we don't need to care much about AOT and WPO. As long Clojure compiles to bytecode which is then seen by the jvm we can just wait for them to implement a AI system which will do the right stuff.

19:37 dmiles: (possible (re)def(s) can happen arbitrarily and such)

19:38 AWizzArd: what I find more interesting is: what will happen when tail call optimization will come into the jvm?

19:40 at the moment we need to do TCO manually, right?

19:41 that is, providing some intermediate parameters to recursive functions

19:46 mmcgrana: i'm sure what you mean by that last but, but yeah you have to use "recur"

19:50 AWizzArd: mmcgrana: yes, but now let's say Sun introduces tco into the jvm. Recur is no longer needed

19:50 Will it stay for backwards-compatibility? Or go away? If the jvm supported tco today then recur would never have found its way into Clojure in the first place, would it?

19:51 walters_: AWizzArd: remember that OpenJDK exists now *you* (or anyone) can add TCO into the JVM =)

19:52 AWizzArd: I will better concentrate on adding other things to Clojure. But what do you think will happen with recur? What should happen?

19:58 pjb3: If I do (defn foo [] "foo"), why can't I call that with ((symbol "foo"))?

19:59 AWizzArd: because your function foo takes no arguments

19:59 nevermind

20:00 pjb3: I'm not clear as to how (foo) and ((symbol "foo")) are different

20:02 AWizzArd: ah, I see what you mean

20:02 yes, good question

20:02 mmcgrana: (class foo) vs (class (symbol "foo"))

20:02 ((resolve (symbol "foo")))

20:03 pjb3: mmcgrana: ok, right

20:03 Is there an easier way to call a function if I have the name of a function in a string?

20:04 mmcgrana: hmm not sure

20:09 AWizzArd: has anyone of you tested already writing programs for your mobile phone in Clojure?

20:13 dmiles: is there some syntax char to make (class (symbol "foo")) act like (class foo) .. like (class ~(symbol "foo")) .. but doesnt supose it's in backquote?

20:14 lisppaste8: pjb3 pasted "calling a function from a string" at http://paste.lisp.org/display/68718

20:18 dmiles: from watching the talk on CJ for java progrtammers.. since you can add metadata to any object like [1 2 3] .. i almost wonder why one shouldnt be able to (def 666 ..as a function..) and call 666

20:19 i mean any value could be def fnable

20:19 AWizzArd: (def 13 4)

20:19 (+ 13 2) ==> ?

20:20 dmiles: just that only doing that to symbols seems for sanity sakes only

20:20 AWizzArd: you don't want that :-)

20:21 dmiles: AWizzArd, good example

20:21 AWizzArd: also http://clojure.org/special_forms#toc1 explicitly says that the first argument to def has to be a symbol (and not an object)

20:22 dmiles: but maybe i want (def say-person :say-joe-sixpackfn) (say-person) (def say-person :say-joe-plimber) (say-pesron)

20:23 but right i can always use ((say-person))

20:24 mainly looking for auto-dereferencing of symbols

20:24 so you keep drefing an object until it has a function value

20:26 dunno .. not important.. if it was the way i said.. then it wouldnt vbe the same programming language

20:27 but (+ 13 2) => 15 but (+ (13) 2) => 5

20:27 erm 6

20:29 or (+ @13 2) => 6

20:30 Cool, watching Clojure for Lisp Programmers

20:33 AWizzArd: I just don't see a place where it would be useful to be able to say (13) ==> 4

20:34 and why should one only be able to bind a function object to 13 and not other objects, that is, why only: (def 13 #(4)) and not (def 13 4)?

20:35 dmiles: i was thinking it be ok to bind functions to anything

20:36 question is (class "foo") ok?

20:36 "foo" being a class differnt from 'foo though

20:37 AWizzArd: obviouslj

20:37 "foo" is a string object

20:37 dmiles: (class 13) ?

20:38 AWizzArd: It's an int

20:38 Chouser: I don't know which result is most likely, but I for one would vote to keep recur, even if the JVM had TCO.

20:39 AWizzArd: Chouser: fair enough.. only that no one would use it anymore

20:39 Chouser: I would use it. I think it makes code clearer.

20:39 When you use recur explicitly, the compiler checks to make sure it's in the tail position -- you can have condfidence you're not threatening the stack.

20:39 abrooks: Chouser: re: recur -- I concur.

20:39 AWizzArd: I think having the name of the function there and no loop is more clear

20:40 Chouser: I really don't know how Rich would come down on this, but I think use of recur (when possible) should remain the preferred idiom.

20:40 AWizzArd: no loop+recur looks more like pseudo code and math, while now it looks like a helping construction to protect from stack overflows

20:41 Chouser: you don't need loop -- you can use recur with a fn and no loop.

20:45 AWizzArd: okay, this makes it better then imo

20:47 mmcgrana: so I have a public java class com.mmcgrana.HelloWorld with a public static method sayHello. I can compile and jar fine, then load with (add-classpath "file:jars/hello.jar"), use (:import com.mmcgrana HelloWorld) in the ns macro, but then when I try (. HelloWorld sayHello) it gives me: ava.lang.IllegalAccessError: tried to access class com.mmcgrana.HelloWorld from class user.eval__2550 (NO_SOURCE_FILE:0)

20:48 *(:import (com.mmcgrana HelloWorld))

20:48 shouldn't I be able to access the public method?

20:50 pjb3: mmcgrana: You call static methods with (HelloWorld/sayHello)

20:50 mmcgrana: eg a public static method in clojure: (. clojure.lang.RT (var "clojure" "map"))

20:50 pjb3: or if it's not imported, (com.mmcgrana.HelloWorld/sayHello)

20:51 mmcgrana: (. HelloWorld sayHello) (HelloWorld/sayHello) and (com.mmcgrana.HelloWorld/sayHello) all give the same error. I must be doing something really basic wrong.

20:52 ok figured it out needed *public* class HelloWorld. Sorry guys.

20:52 <= java noob

20:53 rottcodd: should I be using (seq ...) where I would use (values ...) in Common Lisp?

20:54 pjb3: I guess the (.staticMethod org.whatever.Class arg1 arg2) syntax does till work, I thought that was going away

20:55 mmcgrana: so (org.whatever.Class/staticMethod arg1 arg2) is now preferred right?

20:55 pjb3: I think so

20:56 Has something to so with the way classes work

20:56 for example this doesn't work, but you would think that is would

20:56 (let [m java.lang.Math] (.floor m 4.5))

20:58 Chouser: rottcodd: sorry, don't know CL well enough. You want just the values from a hash-map? or something else?

20:58 AWizzArd: mmcgrana: I have the same problem like you, don't know the Java lib well enough

20:58 mmcgrana: pjb3 found this in the group: http://groups.google.com/group/clojure/browse_thread/thread/91c715364604a3a4/d825a71aa23d5953?lnk=gst&q=static+method#d825a71aa23d5953

20:59 several others here if you're curious: http://groups.google.com/group/clojure/search?group=clojure&q=static+method&qt_g=Search+this+group

21:00 AWizzArd: rottcodd: seq returns a fresh sequence... it does not make your function return multiple values

21:00 so no, don't replace values with seq

21:01 Chouser: oh, is that related to multiple return binding?

21:01 mmcgrana: Yeah, for me its no so much the Java lib as it is the Java environment, especially code loading. I've been spoiled by python and ruby where you just point it to the next file to load

21:02 pjb3: mmcgrana: Right, so the reason (let [m java.lang.Math] (.floor m 4.5)) doesn't work is because that is like saying Math.getClass().floor(4.5) in Java

21:02 which doesn't work in Java because Java is stupid :)

21:02 mmcgrana: classes aren't quite first-class, right?

21:03 AWizzArd: they are I think

21:03 pjb3: mmcgrana: right, not like they are in Ruby, for example

21:04 rottcodd: Chouser: yes, I want to return multiple values, what is the clojure idiom?

21:05 AWizzArd: I think Clojure has no multiple return values, so just return a set of things

21:05 Chouser: rottcodd: clojure uses java calling conventions, so you can only return one thing. But destructuring make returning a vector fairly pleasant.

21:05 mmcgrana: rottcodd: probably returning a vector of values and then using destructuring in the reciever

21:05 AWizzArd: yes, returning a list, vector or just a set

21:05 Chouser: (defn a [] [20 30]) (let [[x y] (a)] ...)

21:05 AWizzArd: it is trivial on the caller side to unpack these things

21:06 mmcgrana: btw related questions: would you suggest using lists or vectors for this purpose?

21:06 AWizzArd: why not just a set?

21:06 walters_: pjb3: that'd require reflection in general

21:06 mmcgrana: well a set is unordered the semantics are different

21:06 Chouser: AWizzArd: how would you use a set? they're unordered

21:06 AWizzArd: okay, then I understood it not right, thx

21:07 rottcodd: wouldn't a seq be better, since it is lazy

21:07 Chouser: you could return a hash-map or something, that can be powerful.

21:08 (defn b [] {:ra 7 :rb 8 :rc 9}) (let [{:keys [ra rc] (b)] (prn ra rc))

21:09 rottcodd: that's really nice

21:09 Chouser: rottcodd: sure, if computing the second value is expensive enough to bother skipping, and many callers will only take the first item, returning a lazy-seq might make sense.

21:11 bah, missing a } up there.

21:22 pjb3: What is the difference between defn and defn- ?

21:22 "same as defn, yielding non-public def"

21:23 ?

21:23 mmcgrana: as in "private"

21:23 i think that means not visible outside of the namespace

21:23 pjb3: ah

21:23 Chouser: it marks the def'ed var as private, so it isn't pulled in by "refer"

21:23 mmcgrana: its used e.g. for helper functions that are not exposed to library users

21:33 AWizzArd: Can one have multiple multimethods in Clojure? Example: I want to have a multimethod foo that takes a sequence and returns 0 if the sequence contains 3 elements and which returns 1 if the sequence contains 4 elements. Easy so far. But now I want another foo which returns 2 if the first element of the sequence is a 100.

21:34 Chouser: sure

21:34 AWizzArd: Would that work? Or don't we want that because of the disambiguity, as [100 200 300 400] contains 4 elements (thus should return a 1) but also begins with 100, so it must return a 2

21:34 (defmulti foo (fn [c] (count c)))

21:34 (defmethod foo 3 [arg] 0)

21:34 (defmethod foo 4 [arg] 1)

21:35 but how do I get the "is-first-arg=100-thingy" into the game?

21:35 Chouser: AWizzArd: http://groups.google.com/group/clojure/browse_thread/thread/7abeb31b2c34980/ee9179ca679b0a27

21:36 for multi-line pastes, please use http://paste.lisp.org/new/clojure

21:36 AWizzArd: Chouser: yes, thx

21:37 Chouser: AWizzArd: you'd have to set up your dispatch function(s), and it'd end up being unambiguous.

21:40 AWizzArd: Chouser: this sounds a bit like manual dispatching again

21:40 for example in that thread you posted I see Stuart giving an answer where he is doing kind of a manual dispatch with his if

21:41 Chouser: sure, and Rich later recommends against that.

21:43 the more specific your dispatch requirements, the more manual it's going to feel, I would imagine.

21:44 AWizzArd: I am comparing the generality of this concept against pattern matching

21:52 lisppaste8: Chouser pasted "more nested multimethods" at http://paste.lisp.org/display/68722

21:56 AWizzArd: Yes, good idea

21:56 I will see if it makes sense to define pattern matching on top of that, with some kind of (defpattern foo ...)

21:56 Chouser: not quite as general as pattern matching of course, but not tons of overhead and no ambiguity.

21:58 AWizzArd: yes, it's okay, but I still don't see why *not* having pattern matching when already defining a new lisp

21:59 Chouser: some of Rich's comments on pattern matching: http://groups.google.com/group/clojure/msg/0d01874b383f7bdd

21:59 AWizzArd: CLs multimethods are a big step forward over single dispatch as in C#, Ruby, Java, Python, ...

22:00 Clojures multimethods seem even more general right now, I am not sure yet. But again, stopping at half the way to general expressibility

22:02 scgilardi: do you have some generality in particular in mind that's missing?

22:08 AWizzArd: Well, that is tricky, as whatever I name can be solved in a turing complete language like Clojure.

22:08 but pattern matching would give an easy an clean solution to the situation I just mentioned

22:09 Chouser showed a nice way how to do it

22:09 but this also makes things a bit harder to follow... in the end it probably makes most sense to have both constructs side by side

22:11 scgilardi: it did seem nice. I may have missed part of the conversation, but did you/could you post how it would look with pattern matching in place? (I did look at Chouser's paste)

22:12 AWizzArd: there are several different pattern matching implementations in different languages, and we can make it look like we want, well yes, let me come up with something

22:14 scgilardi: Chouser: Thanks very much for the irc log. Would changing the update interval to something shorter (say 15 minutes) increase the load it makes on your system(s) to an uncomfortable level?

22:15 Chouser: scgilardi: hm, probably not. It's doing more work per run than it should.

22:16 pjb3: If I want to have a cond with a default case, is the way to do it by using an or?

22:16 (defn foo [x] (or (cond (> x 0) "positive" (< x 0) "negative") "whatever"))

22:16 lisppaste8: AWizzArd pasted "Pattern matching" at http://paste.lisp.org/display/68724

22:16 Chouser: I have plans (though don't hold your breath) to provide an atom feed with hourly entries.

22:17 pjb3: (cond (> x 0) "positive" (< x 0) "negative" :else "whatever")

22:17 walters_: pjb3: that'd require reflection in general

22:17 oops, mt

22:17 pjb3: Chouser: else, thanks

22:18 walters_: (typing alt-tab + up + return quickly can be hazardous)

22:18 Chouser: pjb3: nothing special about :else, it's just a non-false value used by convention.

22:18 pjb3: cond :else isn't in the docs, maybe that should get added

22:19 ah, I get it

22:19 so I should replace it with true or :whatever

22:19 ^could

22:20 Chouser: yep, you sure could. :else is a nice choice though. :-)

22:21 scgilardi: thanks, AWizzArd. I'm looking at it. It seems that we have all the plumbing in place to do those tasks. defpattern would be more about a clear, compact representation. does that sound right?

22:21 Chouser: just make sure you put it at the end.

22:25 AWizzArd: scgilardi: of course it can be implemented.. in probably 2-7 days. There are seveal pattern matchers available for Lisp. But having one specific one in Clojure would mean that everyone would use it. And defpattern is indeed a way to represent some problems very well. Although it is "static" in the sense of: not extensible as defmethod. But why not having both? And in principle one could always allow to add new clauses to a pattern.

22:25 in fact, it could be a list/vector of patterns, and one could dynamically add/remove some

22:25 Chouser: AWizzArd: in the first example, how does it know "n" is to be bound and not to be evaluated?

22:26 AWizzArd: yeah, I forgot to put n into the argument list

22:28 this fibonacci thing would have to be compiled into something that uses recur

22:29 I am still thinking about a way for adding currying to Clojure

22:30 the #(...) notation could be a great way to implement it

22:30 Chouser: doesn't #() make currying largely unnecessary?

22:30 there's also (partial)

22:30 AWizzArd: hmm, is #(...) === (fn [] ...) ?

22:31 Chouser: almost. #(...) == (fn [...] (...))

22:31 #() takes as many args as are mentioned: #(+ %1 %2) take 2 args

22:32 AWizzArd: ah okay, then I must think if this is what I meant

22:32 but I would really prefer #(+) more here

22:33 if we ignore for a moment functions that take any number of arguments

22:33 Chouser: you can even do #(apply + %&) for var-args

22:33 AWizzArd: let's look for a moment at stuff that takes a specific number of arguments

22:34 Chouser: ok

22:34 AWizzArd: for example a function RGB that returns a RGB object

22:34 then I would like to make something that is very red in any case, but not decided how green/blue it is: #(rgb 255)

22:35 (def reddish #(rgb 255))

22:35 (def greenish #(rgb _ 255))

22:35 Chouser: #() does not, in itself, curry.

22:35 pjb3: Chouser: Thank you for not making / a character than has to be escaped in regexs

22:35 Chouser: (def reddish #(rgb 255 %1 %2)) (def greenish #(rgb %1 255 %2))

22:35 pjb3: You were right, that's paying off for me right now :)

22:36 AWizzArd: yes Chouser, this comes close

22:36 Chouser: pjb3: you're welcome!

22:36 AWizzArd: but what I want is to use the underscore for anonymous args on that position

22:36 Chouser: AWizzArd: but that means you can't use the same arg twice, right?

22:36 AWizzArd: we keep the %x thing to be able to do this

22:37 but in 90% of the cases we will not reuse an arg

22:37 we have: (filter #(< 5) ...) or things like that

22:37 I don't want to give any %num or _ after the last specific arg has been given

22:37 Chouser: (filter #(< 5 %) ...)

22:38 AWizzArd: yes, it comes close and I could live with that

22:38 although I find my approach nicer

22:38 Chouser: AWizzArd: yeah, I know that's what currying is. Personally I kinda like the explicitness of %, and it only costs me 2 keystrokes.

22:39 plus hooks me directly into a mechanism that allows splitting args (like #(rgn %1 255 %2)), etc.

22:39 AWizzArd: yes, this is definitly better than CLs explicit (lambda (args) ...) thing

22:39 what do you mean by splitting?

22:39 Chouser: but you could certainly write a macro (curry rgb _ 255 _)

22:40 AWizzArd: sure, but I don't want to say curry

22:40 Chouser: oh, by splitting I just mean currying into positions other than the last arg.

22:40 AWizzArd: #(rgb _ _ 50) ; a bit blue

22:41 and #(rgb 10) == #(rgb 10 _) == #(rgb 10 _ _) == #(rgb 10 %1) == #(rgb 10 %1 %2) == #(rgb 10 _ %2)

22:42 although, I must admit, that my solution needs some extra care for functions that take any number of arguments

22:42 we don't know if #(+) is either: (apply + args) or (+) which would evaluate to 0

22:43 Chouser: that's a little different from fully automatic currying seen in some languages -- I do like the explicit # you're proposing better.

22:43 AWizzArd: I want the #

22:43 I don't want implicit currying

22:43 Chouser: we agree on that.

22:44 AWizzArd: but with the # it is damn close to implicit currying, but gives the eye an extra mark that tells the reader for what he needs to care

22:44 so, the easiest extension would be to allow any number of underscores instead of %1 %2 and so on

22:44 #(rgb 0 _ _)

22:44 because it really does not matter which the first arg is, and which the seconde one is

22:45 but the %1 %2 stuff does not go away.. if we really want (def square #(* %1 %1)) we should be able to do it

22:46 Chouser: to make a case for this, you'll want to write it up and send to the google group. Rich isn't here at the moment so likely won't see this.

22:46 AWizzArd: right

22:46 I need to think if we get any problems with functions that take any number of args

22:46 Chouser: _ is a currently a valid symbol

22:47 AWizzArd: yes

22:47 scgilardi: (defn a [b _ _ c] b) is legal now (which makes sense now that I think about it). (a 1 2 3 4) yields 1.

22:48 pjb3: Is there a way to do a mutlimethod that takes one arg, and if that are is a map I do one thing, regexp I do another, and then have a default case?

22:48 AWizzArd: (defn foo [a a a a] (list a a)) and then (foo 1 2 3 4) ==> (4 4)

22:48 pjb3: but have the map part work for all map types?

22:49 rottcodd: how about changing things so #(f % %) == #(f %1 %2) instead of #(f %1 %1)

22:49 scgilardi: pjb3: the multimethod's dispatch function can be "class" which could accomplish that

22:49 AWizzArd: I personally think that the % is not so nice for the eyes

22:50 pjb3: scgilardi: but class returns PersistentHashMap on {}

22:50 AWizzArd: this is the problem.. as soon a language begins to add syntax (as Clojure does) people begin to care about it :-)

22:50 Chouser: pjb3: http://clojure.googlegroups.com/web/chart.png

22:50 AWizzArd: in Common Lisp we don't have that problem as there is far less syntax

22:50 Chouser: pjb3: so you probably want clojure.lang.IPersistentMap

22:50 AWizzArd: but I think losing the underscore as a valid symbol is no real loss

22:51 who in the world names his parameters with underscores and would miss them if he couldn't do that anymore?

22:51 pjb3: Chouser: sure, but what method can I call on a map to have it return that interface?

22:51 Chouser: pjb3: use (defmulti foo class) -- the result of that will be compared using "isa?"

22:51 pjb3: I think I have to invent a method that returns the "base" type for an object

22:51 scgilardi: underscore is currently being used in Clojure as an argument that should be ignored.

22:52 pjb3: Chouser: oh, it uses isa? for checking the method

22:52 that should work then

22:52 AWizzArd: scgilardi: are you sure? Is this documented somewhere?

22:53 Chouser: I agree with scgilardi that's currently a convention (though not a particularly deeply ingrained one, I would say)

22:53 pjb3: AWizzArd: underscore is used as the "I don't case about this value" param

22:53 AWizzArd: okay

22:53 so that is great

22:53 it means: the underscore alread is not a valid symbol anymore, in the sense that a var could be bound to it

22:54 I would like to extend it's use to the #(...) macro

22:54 scgilardi: symbols are independent of "places" (vars) in Clojure

22:54 AWizzArd: because there it also should mean: I don't care.. there will be some argument, but for my function definition it doesn't matter

22:55 scgilardi: I understood your example first like (defn foo [a a a] ...). And this even works, although I don't think it is a good idea.

22:57 scgilardi: I think it's a fine idea if (as is the case in the uses of _ I've seen so far) you don't care about/won't use the value.

22:57

22:58 AWizzArd: you mean it is good that (defn foo [a a a] ...) is possible and does not produce an error or at least a warning?

22:58 I think the underscore in the parameter vector of defn makes sense and is a fine thing.

22:58 But being able to repeat parameter names?

23:00 scgilardi: repetitions are allowed because nothing checks for them and precludes them. Repeating a name allows one to repeat _ which I think is a good thing. (currently _ gets no special treatment)

23:01 AWizzArd: I think there should be check for repetitions of symbols that are not _ and produce at least a warning

23:02 scgilardi: _ as "don't care" isn't documented anywhere that I know of. It is used once in boot.clj. A pretty cool implementation of drop_last. I've seen it in other cases where there needs to be an argument, but its value doesn't matter.

23:02 That sounds like a fine warning to me.

23:03 AWizzArd: yes, the _ is fine, I agree. Nice thing

23:03 I just think it makes sense that anything else in the argument lis.. vector should not repeat

23:07 is there something like (remove element collection) or should one say (filter #(not= element %1) collection)?

23:08 scgilardi: remove was added yesterday, but it takes a predicate. to remove an element you can use a set as the predicate #{element} matches element and nothing else.

23:09 AWizzArd: :-)

23:15 rottcodd: searching the clojure source and contribs, looks like every occurance of %1 and %2 are in order

23:15 AWizzArd: this makes mostly sense

23:16 otherwise it would be highly confusing

23:17 ( #(/ %2 %1) 10 2) ==> 1/5 and not 5

23:17 rottcodd: and no usage of %1 and %1, so perhaps #(f % %) => #(f %1 %2) would be a better default

23:17 AWizzArd: I suggest that we say #(f) instead

23:18 scgilardi: #(f) to mean what?

23:18 AWizzArd: (apply f %&)

23:18 scgilardi: #(...) puts the name and the body of the function between the parentheses

23:18 AWizzArd: yes

23:19 forget my (apply f %&)

23:19 I mean: #(f) returns a function that takes any number of arguments and then calls apply like I said

23:19 scgilardi: scratch my last... #(...) is anonymous and contains the body of the function between the parentheses

23:19 AWizzArd: so #(f) == #(f % %)

23:20 I want to be able to omit all underscores or %1 %2 thingies as soon all specific curried arguments were given

23:21 Chouser: no you were right the first time: #(apply f %&) which === f

23:21 AWizzArd: of course currying makes no sense if you won't give any argument, because then one could do what Chouser just said, simply providing f

23:22 but for a function that takes 11 args where I want to give only the third I wish to say: #(f _ _ 100)

23:22 and not #(f _ _ 100 _ _ _ _ _ _ _ _) or even #(f %1 %2 100 %3 %4 %5 %6 %7 %8 %9 %10 %11)

23:23 if the #(..) macro sees underscores it first replaces them with the percent/number thing, as in #(f _ _ 100) becomes #(f %1 %2 100)

23:24 Chouser: #(apply f %1 %2 100 %&)

23:24 scgilardi: currently you would still need to match one of the defined arities of f

23:24 AWizzArd: and then it returns a function that takes any number of args and is... exactly Chouser

23:25 Chouser: you could name your new curry macro just _ and then call it like (_ f _ _ 100) instead of #(f _ _ 100)

23:25 scgilardi: Chouser: that wouldn't work with an 11 arg f, would it?

23:25 AWizzArd: it would work with 11 args

23:25 Chouser: scgilardi: why not?

23:26 AWizzArd: and yes, having a single character macro could be a way, but I would still prefer something readable.. in Common Lisp I did it with brackets, as in [f _ _ 100]

23:27 Chouser: AWizzArd: that looks like arc

23:27 AWizzArd: but as they are already used for vectors and also {} are in use and <> don't look good I would like #(...) most

23:27 Chouser: except in arc that syntax always takes exactly one arg I think, so your example would mean (fn [x] (f x x 100))

23:29 scgilardi: Chouser: are you talking about calling #(apply f %1 %2 100 %&) with 11 subesequent arguments? If so, then I understand and it would work.

23:29 (#(apply...) a b c d e f g h i j k) would work

23:29 AWizzArd: Yes

23:30 but we want to curry these arguments away

23:30 (filter #(< 5) sequence)

23:30 Chouser: which is what #(apply ...) does today.

23:30 AWizzArd: exactly

23:31 scgilardi: #(...) is a reader macro which returns a function object

23:31 it already is doing it today

23:31 scgilardi: yes, I understand that

23:31 AWizzArd: and not too bad, I did not even know about it before Chouser mentioned it

23:32 (because I found Clojure only yesterday)

23:32 scgilardi: :-)

23:32 AWizzArd: What I suggest is to extend #(...) a little bit

23:32 Chouser: I'm not sure I like the idea of _ meaning different values in the same scope.

23:33 AWizzArd: it means: for my abstraction I don't care what these are as soon I want to evaluate them

23:34 It say: yep, there is something, but whatever it is, in #(rgb _ _ 20) I want to make a function that creates something which is only a little bit blue

23:34 scgilardi: AWizzArd: are you thinking to extend it by giving meaning to something between the parens that is currently meaningless or by changing something that already has a meaning?

23:34 Chouser: AWizzArd: but the first time it means the first arg, second the second ... that's very unusual for a word.

23:34 AWizzArd: scgilardi: I want to be able to use the underscore, so that I can say #(rgb _ _ 20) instead of #(rgb %1 %2 20)

23:36 in (defn [a b _ _ e f] ...) the first underscore means also: don't care for the 3rd arg and only a second later it means "don't care for the 4th arg"

23:36 Chouser: it would also mean that *all* #() constructs would take any number of args.

23:36 AWizzArd: right, so that is an efficiency hit?

23:36 Chouser: dunno.

23:36 AWizzArd: apply must always be a bit slower I guess than a direct call

23:37 Chouser: it is in clojurescript :-) not sure about clojure.

23:37 AWizzArd: what is clojurescript?

23:37 scgilardi: in a microbenchmark today, apply was being as fast as reduce in an application where they were equivalent. fwiw.

23:38 Chouser: AWizzArd: a partially complete clojure-to-javascript compiler.

23:38 AWizzArd: Chouser: oh nice, didn't know that

23:38 walters_: Chouser: wouldn't it be easier to use applets?

23:39 AWizzArd: walters_: why making html at all? Let the whole website be an applet :-)

23:39 i think much more users turned java off in their browsers, but leave Javascript turned on

23:39 Chouser: walters_: if an applet works in a given context, by all means use it.

23:40 currently applets must be signed to work, which throws up a security dialog (this may change with AOT compilation)

23:41 applets also require Java which is not quite as wide-spread in browsers as JavaScript.

23:41 walters_: hm...sounds like it shouldn't be that hard to fix

23:42 AWizzArd: apropos.. do you know if one could run ons Clojure programs on mobile phones?

23:43 in principle j2me is also jvm

23:45 Chouser: walters_: it has to do with clojure currently using a custom classloader. dunno if that would be a problem for j2me or not.

23:46 pjb3: (some #(even? %) [1 2 3 4]) returns true, shouldn't it return 2?

23:47 Chouser: no, some returns the value returned by the predicate

23:47 you may want filter

23:47 walters_: also, (some even? [1 2 3 4]) seems shorter =)

23:47 pjb3: "Returns the first logical true value of (pred x) for any x in coll, else nil."

23:47 Chouser: pjb3: right, and (even? 2) return true, so some returns true.

23:48 pjb3: I interpreted that mean the value, not the value of the pred

23:48 yeah, I guess now that I re-read it

23:48 Chouser: (some #(when (even? %) %) [1 2 3 4])

23:48 pjb3: I want something that stops at the first logical true value, and returns the value

23:48 AWizzArd: well, in principle 2 also stands for something true: (if 2 1 0)

23:49 Chouser: pjb3: I've stumbled on that a couple times.

23:49 AWizzArd: pjb3: you need to implement your own some

23:49 Chouser: first (filter even? [1 2 3 4]))

23:49 pjb3: Anything based on filter will go through the whole seq, right?

23:50 Chouser: filter is lazy, so with (first) around it, you'll only do the required work.

23:50 (first (filter even? (iterate inc 1))) works fine even though (iterate ...) is an infinite seq.

23:51 pjb3: ah, wow, lazy seq FTW

23:52 AWizzArd: Chouser: I am still thinking about this apply thing, if apply costs performance

23:54 pjb3: So I assume (first (filter (< % 1) (iterate inc 1))) should just go forever, never terminate?

23:54 AWizzArd: in principle the jvm can optimize stuff if it knows that we have a (fn [a1 a2 a3 a4 a5... a11] (f a1 a2 a3 100 a4 a5... a11)) instead of a (fn [a1 a2 a3 & more] (apply f a1 a2 a3 100 more))

23:55 pjb3: if you are brave paste your code to the repl :-)

23:56 Chouser: AWizzArd: you might want to take a peek at the implementation of apply. Or just ask rhickey.

23:56 AWizzArd: yes, I will ask him

23:56 pjb3: yup, just goes forever

23:57 AWizzArd: if it makes no practical difference, even when we have to map over billions of objects, then I will propose my changes to #(...)

Logging service provided by n01se.net