#clojure log - Oct 13 2009

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

0:05 ambient: http://paste.pocoo.org/show/144638/ anyone know how to do these highpass and lowpass filters better?

0:05 those functions just seem so awkward

0:05 durka42: what is it you're trying to do?

0:05 ambient: they're basically IIR filters

0:05 for example (lo-pass-crappy 0.2 (take 10000 (map #(- (* % 2.0) 1.0) (repeatedly rand)))) gives 10k samples of low-pass filtered noise

0:05 http://en.wikipedia.org/wiki/High-pass_filter

1:29 wavis: ~def deref

1:41 peter_12: "Symbols beginning or ending with ':' are reserved by Clojure." Reserved for what?

1:43 chouser: generally later use

1:44 if you try to read a symbol starting with : you'll get a keyword instead

1:49 peter_12: chouser: so a keyword is its own datatype in clojure?

2:32 gilbertleung: hi everyone

2:38 how do i find the first thing in a list that satisfies a certain predicate?

2:38 is there a function for that?

2:38 arbscht_: ,(doc find-first)

2:38 clojurebot: "([pred coll]); Returns the first item of coll for which (pred item) returns logical true. Consumes sequences up to the first match, will consume the entire sequence and return nil if no match is found."

2:38 arbscht_: that's in contrib

2:39 http://richhickey.github.com/clojure-contrib/seq-utils-api.html

2:39 durka42: note it's just (comp first filter)

2:43 gilbertleung: would filter work on an infinite list?

2:43 Chousuke: yes.

2:43 gilbertleung: cool, thanks

5:21 liwp: ~max

5:21 clojurebot: max people is 182

5:21 jdz: nice, a disciple of AWizzArd

5:21 gerryxiao: hello

5:22 jdz: ~max

5:22 clojurebot: max people is 182

5:22 jdz: fail

5:22 gerryxiao: (def board (proxy [JPanel] [] (paintComponent [g] (proxy-super paintComponent g) ...

5:23 how to type hints for proxy-super?

5:23 clojure complains paintComponent method can't be resovled

5:23 Chousuke: typehint g?

5:24 gerryxiao: not work

5:24 Chousuke: how are you doing it?

5:24 gerryxiao: #^Graphcis2D g

5:25 Chousuke: in the proxy-super call or in the argument list?

5:25 gerryxiao: in the proxy-super call

5:25 Chousuke: both should work, though, but perhaps not :)

5:26 gerryxiao: ok, let's try args

5:27 not work

5:27 i have typetints for board, also not work

5:28 neither work

5:29 Reflection warning, Personal/Gerry/GoBoard1.clj:99 - call to paintComponent can't be resolved.

5:29 Chousuke: hm. maybe proxy-super has a bug then :/

5:29 gerryxiao: does macro support type hints?

5:30 Chousuke: what do you mean?

5:30 you can attach a type hint to any clojure form, but it's up to you to ensure that it's the correct one :)

5:30 arbscht_: gerryxiao: paste your code?

5:31 gerryxiao: i mean whether i use type hints in defmacro

5:31 arbscht_: what code?

5:31 Chousuke: gerryxiao: remember that the macro is a function that returns clojure code to be evaluated.

5:31 arbscht_: your proxy form

5:32 gerryxiao: ok

5:32 arbscht_: lisppaste8: url

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

5:32 Chousuke: gerryxiao: you must ensure that the clojure code *returned* is the one that has the type hints

5:34 for example, (defmacro foo [x] `(.someMethod #^Type ~x)) would fail because the type metadata doesn't get attached to the symbol that is the value of x

5:35 you'd need to do `(.someMethod ~(with-meta x {:tag 'Type}))

5:36 lisppaste8: gerryxiao pasted "proxy hints" at http://paste.lisp.org/display/88580

5:37 Chousuke: ~def proxy-super

5:38 ah, that would be the problem

5:38 "this" in the proxy-super is not type-hinted

5:40 gerryxiao: proxy-super line not include this

5:40 Chousuke: yeah, but the implementation does

5:41 you need to do it manually: (proxy-call-with-super #(.paintComponent #^JPanel this g) #^JPanel this "paintComponent")

5:41 I hope that's correct :P

5:42 gerryxiao: ok, no this type hints, i can live however :)

5:53 Fossi: is there a doall map/for wrapper that signals sideeffects? in contrib or such?

5:54 Chousuke: hmm

5:55 what do you mean signals?

5:56 Fossi: i still often find myself forgetting the doall

5:56 gerryxiao: is clojure github reps broken?

5:56 Fossi: especially with constructs like (if (map println ["foo]) "something") where i more or less just want the side effect

5:57 Chousuke: you want a strict map?

5:57 Fossi: so i wonder if there's a "realize" or such in contrib

5:57 which does (doall (map func! data))

5:57 Chousuke: (def s-map (comp doall map))?

5:58 Fossi: yeah, i know how to define it, i just wondered whether there is a "standard" function for that in contrib yet

6:00 tomoj: is map really OK for side-effects?

6:01 Fossi: eh, we just kinda had the same discussion. why shouldn't it be?

6:02 tomoj: I guess by itself it's ok

6:02 Chousuke: it is, but you must not forget to force it :)

6:02 unless you specifically want lazy side-effects

6:02 tomoj: but (doall (take 10 (map println ...))) is not so OK I think

6:03 it's certainly not OK

6:03 this makes me want to avoid mapping over side

6:03 er, mapping over side-effects altogether

6:04 but I guess if you force it immediately without passing it anywhere or doing anything else with it, it's OK

6:04 isn't doseq sorta like what you're asking for?

6:05 for a "doall for" wrapper anyway

6:19 licoresse: I need some input regarding compiling clojure files

6:20 I've set the *compile-files* to true, and the *compile-path* is set to "classes"

6:20 the full path has been added to the classpath

6:21 does *compile-path* need to be the full path or is it enough with "classes"?

6:23 tomoj: my compile-path is just "classes"

6:24 licoresse: ok

6:24 LauJensen: Morning gents

6:24 licoresse: so a M-c-k should in theory produce a .class file then

6:29 ankou: is there a possibility to refer to the current line number/source file?

6:49 raek: ,(class *in*)

6:49 clojurebot: clojure.lang.LineNumberingPushbackReader

6:51 raek: ,(.getLineNumber *in*)

6:51 clojurebot: 55

6:51 raek: I'm not too familiar with the line numbering readers

6:53 but there should be some info in the javadocs, I think

6:54 or here: http://github.com/richhickey/clojure/blob/master/src/jvm/clojure/lang/LineNumberingPushbackReader.java

6:56 ankou: You can wrap your FileInputStream with that one, if you like

6:59 djpowell: ,(disj! (transient #{1 2 3}) 1)

6:59 clojurebot: #<TransientHashSet clojure.lang.PersistentHashSet$TransientHashSet@f9a36a>

6:59 djpowell: ,(disj! (transient #{1 2 3}) 1 2)

6:59 clojurebot: java.lang.ClassCastException: clojure.lang.PersistentHashSet$TransientHashSet cannot be cast to clojure.lang.IPersistentSet

7:00 djpowell: hmm, a bug in disj! there

7:00 ambient: can someone help me build better IIR filters as infinite seqs? http://paste.pocoo.org/show/144638/

7:01 need just some suggestions where to go from there

7:01 octe: if anything throws an exception in the repl i will see it if there's no try/catch involved right?

7:02 djpowell: if the exception isn't caught, the repl will print the exception name and message

7:02 for more details type (.printStackTrace *e)

7:02 octe: strange

7:02 LauJensen: ambient, looks like you can implement both using reduce

7:03 ambient: LauJensen i dont know if i can make infinite seqs with reduce

7:03 wait..

7:03 i mean lazy

7:03 sorry i just woke up, i've yet to had my coffee

7:03 i'll check reduce

7:04 LauJensen: reduce is not lazy - which is evident from its wonderfully clear docstring :)

7:04 ambient: here's the whole code http://paste.pocoo.org/show/144676/ my purpose here is to make lo-pass and hi-pass part of a lazy infinite sequence

7:05 the audiochan-play part at the bottom

7:05 i don't really know if that's possible but i'm going to try anyway

7:06 * Maddas isn't sure lazy infinite sequences and IIR filters are a good match

7:06 Maddas: (assuming you actually want to compute the exact result)

7:06 ambient: some wise guy said to me yesterday that in clojure.contrib there's some code that can be used to implement this

7:07 Maddas i dont really care about exactness, just some way to filter high or low frequencies

7:08 raek: ambient: I think your project is really awesome!

7:08 ambient: raek heh, thanks :)

7:08 raek: you're making a synth, right?

7:08 ambient: yep

7:09 * ambient is praying the programming gods that he can convert 24Db Moog resonant low-pass to lazy infinite sequence

7:09 raek: I like the use of infinite sequences

7:09 ambient: *dB

7:09 they're basically streams

7:09 using the stream mental model i _should_ be able to program a modular synth

7:10 and streams in scheme are just infinite lazy seqs afaik

7:10 * raek picks up his book on "singals and systems"

7:10 Maddas: ambient: I don't know any clojure, but won't your hi-pass function never return if coll is an infinite sequence?

7:11 ambient: Maddas that's because both hi-pass and lo-pass are not lazy infinite seqs at the moment. it's where i'm trying to go but am not yet

7:11 djpowell: if you can write it using cons and recursion, then you can slip the lazy-seq macro in to make it lazy

7:11 see: http://clojure.org/lazy

7:13 tomoj: ambient: what are you using to make sound? some java lib?

7:13 ambient: javax.sound.sampled.*

7:13 core

7:14 raek: lazy-cons?

7:15 tomoj: sounds like fun

7:17 djpowell: lazy-cons is dead; you use lazy-seq + cons now

7:18 raek: oh

7:21 * raek re-reads http://clojure.org/lazy

7:24 gerry_: hello

7:24 raek: hi

7:25 gerry_: why not defclass in clojure?

7:26 as like ocaml or f#, both is fp language

7:26 tomoj: what do you need defclass for?

7:27 gerry_: i want define java class from clojure

7:27 or interface

7:27 especially interfaces

7:29 tomoj: you can define java classes without a defclass

7:29 rhickey: ,(doc gen-class)

7:29 clojurebot: "([& options]); When compiling, generates compiled bytecode for a class with the given package-qualified :name (which, as all names in these parameters, can be a string or symbol), and writes the .class file to the *compile-path* directory. When not compiling, does nothing. The gen-class construct contains no implementation, as the implementation will be dynamically sought by the generated class in functions in an impleme

7:29 rhickey: ,(doc gen-interface)

7:29 clojurebot: "([& options]); When compiling, generates compiled bytecode for an interface with the given package-qualified :name (which, as all names in these parameters, can be a string or symbol), and writes the .class file to the *compile-path* directory. When not compiling, does nothing. In all subsequent sections taking types, the primitive types can be referred to by their Java names (int, float etc), and classes in the java.lan

7:31 gerry_: that's great

7:33 LauJensen: http://groups.google.com/group/clojure/browse_thread/thread/d8064dbb94c5cd2c

7:33 Does anyone know why this year old suggestion to bring spit into core has not been accepted?

7:35 gerry_: rhickey should knew why :)

7:41 octe: this is probably dumb but.. how do i change this function to return the struct? http://pastebin.ca/1617651

7:45 hoeck1: octe: just make conn the last expression in the let form

7:46 octe: like: (let [conn (struct ...))] (.connect ...) conn)

7:48 gerry_: octe: not need get for map

7:50 octe: hoeck1, gerry_: thanks :)

7:52 spuz: if I have a vector such as [1 2 3 5 6 7 8], how can I write a function which returns a list of elements n for which the previous element is equal to n-1. In otherwords, a list of all the numbers that are 1 greater than the previous number?

7:53 LauJensen: octe I think you can eliminate 3x (get conn :channel) by wrapping your statements in (doto (get conn :channel)...) and instead of 'new' suffic the class with a period "."

7:55 Maddas: .oO( And I thought you needn't be worried about getting homework questions in #clojure ;-P )

7:55 tomoj: spuz: not exactly sure what you mean, but maybe:

7:56 ,(map first (filter (fn [[x y]] (= (inc x) y)) (partition 2 1 [1 2 3 4 5 6 7 8])))

7:56 clojurebot: (1 2 3 4 5 6 7)

7:56 tomoj: ,(map first (filter (fn [[x y]] (= (inc x) y)) (partition 2 1 [1 2 5 6 3 3 4 7 8])))

7:56 clojurebot: (1 5 3 7)

7:56 eevar2: ,(map inc [1 2 3 4 5 6 7])

7:56 clojurebot: (2 3 4 5 6 7 8)

7:56 tomoj: eh, I got it backwards, map second instead of first

7:56 eevar2: might be what he ment? ;)

7:57 spuz: it should return (2 3 6 7 8)

7:57 tomoj: ,(map second (filter (fn [[x y]] (= (inc x) y)) (partition 2 1 [1 2 5 6 3 3 4 7 8])))

7:57 clojurebot: (2 6 4 8)

7:57 eevar2: ^^ nm

7:57 spuz: ,(map second (filter (fn [[x y]] (= (inc x) y)) (partition 2 1 [1 2 3 5 6 7 8])))

7:58 um...

7:58 clojurebot: (2 3 6 7 8)

7:58 tomoj: I don't see where (2 3 6 7 8) could come from

7:58 spuz: well it works :)

7:58 tomoj: ah, yes

7:58 spuz: thanks tomoj :)

7:59 now, I've just got to understand it

7:59 tomoj: just play around on the repl with the parts

8:00 (partition 2 1 ..) takes partitions of size 2 stepping 1 each time, so it gives ((1 2) (2 3) (3 5) ...)

8:00 spuz: ok, yeah it makes sense. I've just got to figure out a slightly more complex version of that

8:18 AWizzArd: Is there a way to kill a running agent?

8:18 Without checking in the agent fn for some signals which will then simply exit the function.

8:20 LauJensen: AWizzArd, one particular or can it be all agents?

8:21 AWizzArd: One particular. For example when my agent swap!s the value of an atom I might want to end its job from outside.

8:21 LauJensen: Its a self-calling agent ?

8:21 AWizzArd: No

8:21 LauJensen: So altering some shared 'running' variable is out of the question?

8:22 AWizzArd: If there is not already a built in function for that I will simply ask in the agent fn if (= *running* true) or something like that. I just thought there might be some other way.

8:22 tomoj: how do you know from the outside when the agent swap!s the value?

8:22 AWizzArd: uhm (if *running* ...) :)

8:22 LauJensen: (when *running*...) :)

8:23 AWizzArd: LauJensen: oki, I will do just that then.

8:23 LauJensen: I don't know of a function which does what you want specifically, but you're welcome to post the code if you want some more input

8:27 licoresse: ,(doc *compile-path*)

8:27 clojurebot: "; Specifies the directory where 'compile' will write out .class files. This directory must be in the classpath for 'compile' to work. Defaults to \"classes\""

8:27 ambient: anyone know the fate of http://clojure.org/streams ?

8:27 (doc stream) is nil

8:27 clojurebot: "clojure.contrib.http.agent/stream;[[http-agnt]]; Returns an InputStream of the HTTP response body. When called by the handler function passed to http-agent, this is the raw HttpURLConnection stream. If the default handler function was used, this function returns a ByteArrayInputStream on the buffered response body."

8:27 licoresse: when I "touch" this symbol with the cursor, emacs crashes

8:30 raek: AWizzArd: if you want to controll the "running" on a per-agent basis, you might want to let the agent keep track of it's own running-value

8:30 like this: (def a (agent {:running true}))

8:30 (send-off a assoc :running false)

8:31 but then, all it's actions must eventually time out

8:31 otherwise, the agent will never run the "stop action"

8:32 I use this approach in an agent reading from a socket

8:45 AWizzArd: Btw, is there a way to exit a doseq before it traversed its collection(s)?

8:47 LauJensen: AWizzArd, you mean like :when or :while ?

8:58 AWizzArd: LauJensen: good thx

9:00 LauJensen: np

9:06 ambient: does there exist a profiler in clojure that can identify which functions take how much time in the entire program execution?

9:06 LauJensen: I know JSwat does that, but I also think you can get it from jvisualvm

9:07 ambient: hmm, i thought that basic java profilers couldn't tell about defn funcs

9:07 LauJensen: if you followed by brians transient brain blogpost, you'll see future, deref, filter, concat etc all show up

9:08 liwp: ambient: each clojure function compiles into a java class with a bunch of invoke methods, so those should definitely show up

9:08 ambient: ok, thanks

9:08 liwp: seems like LauJensen has actually tried this ;-)

9:10 ambient: im super lazy, i think i need to do my own lib that i can just (use clojure.profiler) and (profile foobar) :p

9:11 liwp: that would be nic

9:11 nice even

9:11 LauJensen: c.c.profile aint doing it for you?

9:11 ambient: umm

9:11 there are plenty of things i'm unaware of

9:12 LauJensen: http://blog.bestinclass.dk/index.php/2009/10/brians-transient-brain/

9:12 read the last comment

9:13 ambient: great :)

9:14 liwp: seems like you have to annotate your code when you use c.c.profiling which is a bit icky

9:14 OTOH I guess you get more control that way and you can concentrate on those bits of the code that you want to work on

9:16 LauJensen: Everythings a trade in some regard

9:17 ambient: unless you steal and cheat

9:17 LauJensen: hehe

9:17 trade your soul for a gold watch

9:17 ambient: that actually holds true for programming also

9:18 you dont actually have to implement _the_ algorithm. just implement _an_ algorithm that _looks like_ the original one

9:18 when it comes to human interaction

9:20 low-pass filter with clojure: (reductions #(/ (+ %1 %2)) (oscillator))

9:20 * ambient just blew his own mind

9:21 ambient: * (/ (+ %1 %2) 2)

9:25 (defn lo-pass [d coll] (reductions #(+ (* %2 d) (* %1 (- 1.0 d))) coll))

9:25 this is just so amazing...

9:26 raek: ambient: that's beautiful

9:31 churib: /help

9:31 ankou: I'm using a function, that defines a macro, does this also work with aot-compilation? Or is macroexpansiontime with aot-compilation completly at compiletime?

9:32 chouser: unless you call compile or eval, no macros will be expanded after AOT

9:34 raek: ambient: do you have a repository for your synth project?

9:37 I want to try your code...

9:37 ambient: raek: http://bitbucket.org/amb/clojure-snippets/src/tip/audio.clj

9:37 it's just in my random-code folder, might make a separate project if it grows larger

9:39 raek: bitbucket looks an awfully lot like github...

9:40 I like github, so that's good, I guess

9:50 LauJensen: raek, Gitorious is the best though

9:52 noidi: what advantages does it have over github?

9:52 LauJensen: Speed, Speed and a consitent use of markup across the site. It's more community-oriented

9:55 noidi: hmm.. those merge requests with a status flag look handy

9:55 LauJensen: On ClojureQL we use the merge-request system to do code-reviews

10:29 octe: when writing code that is inherently stateful, for example an irc client, how would one structure that?

10:29 in an oo-language you'd create a stateful object containing the socket connection, etc

10:29 i've started a bit by creating a struct that holds those stateful objects, with a connect-function that creates it and returns it

10:29 then define the other functions to take it as a parameter

10:29 is that a good design?

10:32 arbscht: octe: interesting coincidence. that's -exactly- what I'm working on right now, and pretty much with the same approach

10:33 octe: maybe i'm on the right track then :)

10:34 arbscht: exactly as an irc-client too, or rather just the same issue?

10:34 arbscht: irc client

10:34 octe: ah

10:34 it's usually a good learning project..

10:35 arbscht: I suppose. I just got sick of pircbot :)

10:35 drewr: arbscht: that's what drove me to it too :-)

10:35 chouser: i've done a couple of these stateful connection-oriented things now, and they all look pretty much like this.

10:35 I suppose it's inevitable.

10:36 arbscht: the pattern shows up in my Swing code, too

10:36 chouser: It's very easy, though, to let the statefulness and mutation leak into more of your code than necessary. Be viligent.

10:36 arbscht: drewr: what came of it? have you published a library?

10:37 drewr: arbscht: heh, I'd show you if github weren't down...

10:39 octe: drewr: perhaps you could link it anyways so i won't forget to check it out when it comes back up..

10:40 drewr: http://github.com/drewr/clot/tree/master

10:42 octe: thanks

10:42 drewr: experimenting with sockets and dynamic message dispatch

11:25 kefka: ,(ns a)

11:25 clojurebot: nil

11:25 kefka: (def x 4)

11:25 ,(def x 4)

11:25 clojurebot: DENIED

11:25 kefka: Ah, right.

11:25 octe: github back up..

11:25 clojurebot: http://github.com/richhickey/clojure/tree/master

11:26 kefka: So here's a question. If I create a namespace a with x bound to 4, then create a namespace b that uses a, then when I'm in b, x will resolve to 4. However, outside of b, b/x does not resolve to 4.

11:26 Why is this?

11:27 Chousuke: have you required the namespace?

11:28 kefka: it's not a file. Actually, I meant _refer_, not _use_

11:29 anyway, use is supposed to be require + refer, right?

11:30 Chousuke: hm

11:30 kefka: How do I do the Lisp-paste again? I'll show an example.

11:30 drewr: every time I use defnk I want it to be in core

11:30 Chousuke: lisppaste8: url

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

11:30 drewr: kotarak ftw

11:31 chouser: kefka: That is the designed behavior, so that your main app namespace isn't cluttered with names from secondary libs.

11:32 kefka: chouser: Got it. Thanks. That makes sense. So I guess combining multiple namespaces into one is bad form?

11:33 What I have is multiple files that usually should go together in one namespace.

11:33 The files are broken apart because they're large (1000+ loc).

11:33 chouser: ah, well, you can do that with 'load'

11:33 such as core.clj, core_proxy.clj, core_genclass.clj

11:37 kefka: Ok. We're trying to avoid loading a bunch of files, except when we want to (e.g. reloading clj files).

11:37 My understanding of the advantage of require/use is that things are only loaded once.

11:38 chouser: hm. Well, I think there's a thing in contrib that allows you to pass values along from one namespace to the next, but I'm not sure its use is recommended.

11:40 tomoj: immigrate?

11:40 chouser: that's the one.

11:41 I haven't used it.

11:41 kefka: Ok, thanks. I'll look into that.

11:41 chouser: There was a thread on the group recently where it sounded like a couple people who had in the past no longer use it because they didn't like how it behaved.

11:41 tomoj: it does weird things

11:42 http://groups.google.com/group/compojure/browse_thread/thread/400aac94e536e633#

11:42 kefka: I guess it's just odd to me that x, when in b, resolves to something different than b/x when outside of b.

11:45 cemerick: is it right that proxy has no access to protected methods/members, and gen-class is the only available route?

11:46 chouser: cemerick: yes

11:46 cemerick: or reify

11:46 * cemerick hasn't messed with stuff like this in a while :-/

11:46 cemerick: reify isn't fully baked yet though, right?

11:47 chouser: yeah, the bridge method stuff isn't there, and it's all in a side branch. which is why I started with "yes" :-)

11:48 cemerick: is it planned on for the nebulous 1.1, or is it on the back burner for now?

11:48 chouser: iirc, it's the main feature defining 1.1

11:49 cemerick: yeah, that's what I thought. I didn't know if things had changed of late, though.

11:49 I've been stupidly busy.

11:49 chouser: stupidly?

11:50 cemerick: Yeah...doing a lot of work treading water, or so it feels like.

11:50 chouser: bleh

12:02 octe: drewr: i found your use of agents interesting

12:02 rhickey: just to fill you all in, I've been actively looking at something like dynamic type classes for Clojure. This driven by concerns that reify will leave us with the same limitations Java has re: extensibility - you can't add interfaces to existing classes. So reify won't help the if/else stuff in RT to have the abstractions reach java things

12:02 but dynamic type classes would

12:02 they're not quite type classes, I've been calling them 'protocols'

12:04 leafw_: sounds like "interface".

12:05 rhickey: leafw_: abstractly yes, but that has a meaning already that includes some thing that protocols wouldn't - requires derivation (at type definition time), creates isA relationship, non-injectable

12:05 a protocol could be extended to any class after the fact

12:05 and wouldn't create an isA relationship

12:06 leafw_: I understand, the vocabulary is taken. The definition you gave is that of an interface, yet not a java interface (since yours would be injectable)

12:06 the protocol as you want it is a formalized duck-typing then.

12:06 rhickey: leafw_: not at all, not match by name

12:07 leafw_: then I'll shut up and wait what you come up with.

12:07 chouser: rhickey: out of curiosity, is there a forum (presumably offline) where you discuss such things, or is this the first you've said it "aloud"?

12:07 rhickey: you'd need a (implement protocol aClass fns)

12:07 chouser: first aloud

12:07 chouser: ok

12:08 thanks for sharing. :-)

12:08 rhickey: I'm still working out the dispatch design, but it will be really nice, definitely what I would want, protocols orthogonal to types

12:08 could do a lot of what Haskell type classes do, but not all, since no inference and dynamic

12:09 cemerick: this is in addition to reify, or is reify's usage of interfaces a subset of protocols?

12:09 rhickey: cemerick: I'm still working out the relationship between a protocol and an interface - obviously having some connections to interfaces enables extension from Java

12:10 but they are truly different in that protocols aren't types (except as an implementation detail)

12:11 and protocols much more Clojure-centric in directly yielding callable fns, aa opposed to host-world .callable things

12:12 cemerick: Sounds nice.

12:12 of course, insofar as that "implementation detail" is stable, protocols are a superset of interfaces

12:13 rhickey: so there would just be a protocol for Seqable and it would define clojure.core/seq

12:13 cemerick: (which has the pleasant characteristic of fitting into my head easily :-))

12:13 rhickey: and you could say (implement Seqable String ...)

12:13 lpetit: rhickey: just to be sure I'm not mistaken things, this really has nothing to do with the way Qi allows to create types, one other feature you were talking about some day ?

12:14 rhickey: and there would be no need for RT.seqFrom and all the conditionals there

12:14 lpetit: rhickey: is there literature that comes close to what you have in mind ?

12:14 rhickey: lpetit: not about types

12:15 lpetit: you could get to protocols by looking at CL literature about generic functions and grouping them (there is no construct, but often desired), or from interface injection, or from Haskell type classes (think dynamic)

12:16 chouser: so clojure.core/seq would be a IFn created when the Seqable protocol is defined?

12:16 rhickey: the critical thing is that they support orthogonal extension in the type or function dimensions, without intrusion into existing stuff

12:16 chouser: yes

12:16 lpetit: rhickey: OK. I remember discussions between you and someone which haven't shown up for a couple months on the ml , don't remember his name, but he was always talking with you about orthogonality of protocols v/s types, and he also wanted to port more or CLOS to multimethods (or as one of the "out-of-the-box" multimethods dispatching strategies)

12:16 chouser: sort of multimethods in batches.

12:17 rhickey: chouser: a little bit yes, with some restrictions (dispatch function built-in)

12:17 but much easier than dealing with multiple multimethods, and yielding a proper abstraction in a set

12:17 chouser: yep, makes sense.

12:18 rhickey: I spent a lot of time thinking about this on my Denmark trip, just working out the gory details now

12:18 but I am still focused on cinc, and what facilities the language should have to enable that. RT indicates reify is not enough

12:19 adopting interfaces is easiest and most like the current impl, but could be not the best fit for Clojure (of course there will always be a way to implement interfaces)

12:20 I really like moving away from isA as the only way to share abstractions

12:22 I don't like the auto-adapter-wrapper technique of Scala implicits

12:22 cemerick: isn't this something that could be implemented with some sugar on multimethods?

12:22 ambient: how would i go about introducing side effects to a closed stream (lazy-seq)?

12:23 value stream from user-controlled swing slider

12:23 cemerick: (not as an actual impl strategy, just getting my head around it)

12:23 rhickey: cemerick: first pass might be just to try out the syntax etc, but no, there will be some heavy lifting under the hood for perf probably

12:25 that's what Im working on now (dispatch strategy), with an eye towards perf and possibly leveraging JSR292

12:25 lpetit: rhickey: to say it differently (so that I can check I understand the basics), is it ok to start with "it's a way to group related multimethods together, a more structured way than to just place them together in their own namespace" ?

12:27 rhickey: lpetit: except they are only available/extensible as a set, have a fixed dispatch strategy, and possibly some relationship to an interface for extension via Java

12:28 lpetit: rhickey: ok, I can see the plus. If you can think of a design that can make it possible to also do some static analysis for IDEs :-) (ok in this case this would really resemble what java interfaces do, but java interfaces are not bad, AFAIK)

12:28 rhickey: it would provide a very clear option for people coming from OO wondering how to encode their abstractions

12:29 I like interfaces except for isA and not being able to add them to existing things

12:30 lpetit: rhickey: ok, "not being able to add them to existing things", => the new "protocol" concept is a dynamic extension (a superset) to interfaces in this area, right ?

12:30 rhickey: perf a critical question, as interfaces are very fast. so there's the static/dynamic tension

12:31 lpetit: they differe in critical ways, so not/super/subsets. Interfaces imply an isA relationship

12:31 lpetit: rhickey : one more time please on the "isA" issue = do you mean there will be no such thing ? I guess I still don't totally understand in this area (Ah, java background)

12:32 rhickey: when you implement Seqable for String that won't make a String a Seqable

12:32 but String will implement the Seqable protocol

12:33 i.e. code written to Seqable will work for Strings

12:33 cemerick: rhickey: are you really aiming to make protocol dispatch performance on par with interface dispatch?

12:33 rhickey: and all of the things I have to go into RT to do now you will be able to do yourselves

12:33 lpetit: rhickey: but that would make a String implement the Seqable protocol. No speaking about types, but about protocols/behaviours, can't a behaviour be defined as an extension to an already existing protocol (interfaces do that, and I don't see that as the same "isA" relationship as "extends" conveys for java classes)

12:34 rhickey: cemerick: probably not possible without JSR292, and not sure even then

12:34 cemerick: OK, that sounds sane. :-)

12:34 rhickey: cemerick: but it needs to be really fast if to be the base for Clojure's abstraction set

12:35 cemerick: Right.

12:36 rhickey: lpetit: I haven't decided on extending protocols, not sure there's as much need in a dynamic lang, since oyu can always just create another protocol and implement that, the only time you care is if asking - do you implement protocol Z? you'd like the answer to imply something about X and Y

12:36 lpetit: rhickey : this indeed would be awesome, if the core does this.

12:37 rhickey: I mean, for such generic protocols as Seqable, ..., really awesome !

12:38 rhickey: I'm trying to eliminate the closed extension I had to do in RT, which falls out of the limitations of interfaces

12:38 cemerick: I can't say I have a use case for this right now. Maintaining RT can't be fun, but I worry about the implications (esp w.r.t. perf) of pushing RT stuff down into clojure.

12:39 * cemerick valiantly picks up the devil's advocate mantle :-P

12:39 cemerick: or, the skeptic's, anyway

12:40 rhickey: a Clojure encoding of the RT conditional logic would have identical perf, it has more to do with interfaces vs (more dynamic) protocols

12:40 but I totally agree, needs to be well considered. I think the interface bridging might provide a way to get the best of both worlds

12:41 cemerick: I've no idea what "interface bridging" is, but that's OK. :-)

12:41 rhickey: cemerick: having an interface fall out of defprotocol

12:42 an implementing that interface would sidestep the more involved dispatch

12:42 and

12:43 Chousuke: would you be able to "map" protocols to arbitrary interfaces then? Like the C++ concept map idea.

12:43 cemerick: ah, indeed, back to my thinking of protocols as a superset. Sure, they aren't is-a, but if you can map protocols to a basket of interfaces, that might be good enough for fast dispatch.

12:43 rhickey: Chousuke: I don't know, not a priority. The point is to provide a Clojure abstraction mechanism. Interfaces are a host thing

12:44 Chousuke: right. The quest to define Clojure without any mention to Java :)

12:45 rhickey: cemerick: right, the point though is that you can't rely on and should never ask if x isA protocol, because not all implementations can be

12:45 cemerick: rhickey: aside from your distaste of is-a, is getting away from interfaces really necessary for cinc? What potential hosts don't have interfaces or something similar?

12:45 rhickey: cemerick: It would make me sad for cinc to have the if/else stuff from RT still

12:46 octe: what is cinc?

12:47 rhickey: it seems like a fixed set (Clojure's abstraction * Java's built-ins), but represents a bigger problem (the expression problem)

12:47 Chousuke: I suppose the gist of it is that if cinc were defined in terms of interfaces, it would limit any implementation to emulating interfaces, but if we use something more "Clojurey" at the high level, the implementation could then use interfaces, or whatever fits

12:47 rhickey: I've been banging my head against the expression problem my whole career, would love to be done with that.

12:47 cemerick: rhickey: I'll buy you a beer to make you happier, then. I'm just saying, it's really OK if the host platform needs a bit of a hairball underneath. I'm just offering a cost/benefit sanity-check here.

12:48 ambient: octe: clojure in clojure afaik

12:48 lpetit: octe: Clojure IN Clojure

12:48 rhickey: cemerick: the problem will reappear in large Clojure apps and libs, just like it does now in Java - ever get an API that says 'just derive from this' that you want to use with classes you don't control?

12:48 octe: oh, thanks

12:49 rhickey: if interfaces are the way Clojure users create abstractions, we'll have that problem, plus the dot-or-not dichotomy

12:49 cemerick: aren't multimethods (or perhaps some sugared multimethods) the answer there, especially for app-level stuff?

12:50 rhickey: cemerick: sure, this is just a multimethod variant, but consider how often people wish certain Clojure fns were multimethods

12:51 they're not because they are interface + hand-switch based

12:52 lpetit: rhickey: so for example, with protocols, one would be able to make new "types" adaptable to the protocols really used on defns arguments ?

12:52 cow-orker: Is there a way to use unqualified symbols in a macro? I have (defmacro mkfoo [name] `(defn ~name [param#] (foobar param#))) and it works, but the argument list shown by (doc some-made-function) is quite ugly (gensym'd param)...

12:53 As this macro is only called at the toplevel in a ns i control I guess I don't have to worry about capture?

12:53 rhickey: lpetit: right, a protocol is an extensible fn set, much like a multimethod is an extensible fn

12:53 lpetit: cow-orker: explicitly specifying a :args entry to the attrs-map is generally what is done by people which build such macros

12:54 too sad I must leave the chat now, bye all

12:56 cow-orker: I guess capture should always be intentional, your macro could be encapsulated in a complex 'let some day ?

12:57 Chousuke: cow-orker: lpetit's advice is good. (defmacro mkfoo [name] `(defn foo [param#] {:arglists ~'([param])} ...) should work

12:57 cemerick: rhickey: IIUC, that sounds just a little scary, on its way to python monkey-patching or somesuch. The nice thing about multimethods is that the hierarchies are naturally safe (using namespaced keywords, etc), and your ill-conceived hierarchy can't touch mine. But if core fns are hierarchies, then someone adding a dispatch to + for [:plum :heat] to return :prune is going to get messy.

12:57 Chousuke: you can also do (defn foo [~'param] ...) but that's evil. :)

12:57 cemerick: s/hierarchies/multimethods

13:00 cow-orker: Chousuke: yes I just found that in some example code by SH. Thank :-)

13:00 rhickey: cemerick: it is definitely not monkey-patching, in that fns are namespaced. I'm not sure what you mean by fns being hierarchies

13:00 protocol fns are namespaced

13:00 cemerick: yeah, I meant s/hierarchies/multimethods there

13:01 rhickey: so right now someone can extend seq to some bizarre thing by deriving from Seqable

13:01 cow-orker: As for evil.... I consider this macro to be an implementation detail for the ns.... but can I count on this behaviour in future versions?

13:01 rhickey: using proxy e.g.

13:02 also, I doubt + will become a protocol

13:03 Chousuke: cow-orker: which behaviour do you mean?

13:04 cow-orker: the evil example will just capture the name "param" from its environment, so for example (let [param 2] (mkfoo somefoo (stuff-with param))) would not work as expected

13:06 cow-orker: that ~'sym works like that and is allow - that there won't be an effort to disallow this in the name of macro hygiene :-)

13:06 ...allowed....

13:06 Chousuke: ah, yes.

13:06 of course.

13:07 there's no way to disallow it, actually.

13:07 without adding special logic to how ~ works. and even then you could find ways around it.

13:08 cow-orker: yes... I guess so... so, use it sparsely and responsibly :-)

13:08 Chousuke: variable capture can be useful when desired

13:09 with the clojure syntax-quote it's also easy to spot

13:09 ~'foo looks ugly enough that it'll make people stop and think whether it's really the right thing to do.

13:13 serp_: does clojure have macros?

13:15 cow-orker: Chousuke: true. I hope I do the right thing... the functions I create are part of the API for the ns so I think the (doc) should be nice.

13:15 Chousuke: serp_: of course. it's a lisp after all :P

14:09 ambient: how would i make this into a lazy sequence modifier: "y[i] := a* x[i] + (1-a) * y[i-1]" where a is constant, y is new seq, x is old seq

14:09 with reductions it seems to be "y[i] := a * x[i] + (1-a) * x[i-1]"

14:09 manually with rec-seq?

14:10 chouser: reductions should be passing you your previous return value, the the previous input value

14:11 ambient: i think i have to read the source some more to actually get it

14:11 chouser: hm, not sure that's the easiest.

14:12 ambient: im dealing with algorithms where i need to have more than one items of history for both new-sequence and old-sequence

14:13 chouser: (reductions (fn [yi-1 xi] (+ (* a xi) (* (dec a) yi-1))) init-y y)

14:13 that ought to do it, I think.

14:14 ambient: i already had (reductions #(+ (* %2 d) (* %1 (- 1.0 d))) coll) but i was doubtful of its correctness

14:14 it sounds right but i can't be sure if it actually _is_ right

14:14 and that really bothers me

14:15 and this is the simplest algorithm i have...

14:15 tomoj: can't you test it out?

14:15 ambient: i already threw the correct function into trash

14:17 chouser: ,(reductions + 10 (range 5 10))

14:17 clojurebot: (10 15 21 28 36 45)

14:18 tomoj: ambient: what kind of audio algorithm is that?

14:18 ambient: here's the other one. "y[i] := a * (y[i-1] + x[i] - x[i-1])"

14:18 low-pass iir filter

14:18 tomoj: just do reductions on (partitions 2 1) for that one, I think

14:22 except.. what's y[0]?

14:22 ambient: head of new-sequence

14:22 hmm no, tail

14:23 what value it is, doesn't really matter

14:23 tomoj: well, I dunno, but

14:23 ,(reductions (fn [y [x1 x2]] (* 2 (+ y (- x1 x2)))) 0 (partition 2 1 [1 2 3 4 5 6]))

14:23 clojurebot: (0 -2 -6 -14 -30 -62)

14:26 ambient: [0.3 -0.1 0.9 0.95 0.7 -0.99] original seq ... [0.3 0.15 -0.05 0.5750000000000001 -5.551115123125783E-17] correct seq when a=0.5

14:26 ,(reductions (fn [y [x1 x2]] (* 0.5 (+ y (- x1 x2)))) 0 (partition 2 1 [0.3 -0.1 0.9 0.95 0.7 -0.99]))

14:26 clojurebot: (0 0.2 -0.4 -0.22499999999999998 0.012500000000000011 0.85125)

14:28 ambient: there might be some errors in my "correct-seq" though

14:28 tomoj: your correct sequence has a different length than the original

14:29 ambient: it's because y[i-1] when i=0 is not defined

14:29 tomoj: I see, so you need to skip one

14:29 ambient: i can also use default values, like 0

14:30 it doesn't make a large difference in audio quality

14:31 tomoj: well you have to have some initial arbitraty y

14:32 if y[-1] is not defined, then neither is y[0], and so on

14:32 looks like you're saying y[0] = x[0]

14:32 ambient: i used to do C so i wasn't so particular about reading from obscure memory locations if the value had no significance ;)

14:33 (+ nil 1)

14:33 ,(+ nil 1)

14:33 clojurebot: java.lang.NullPointerException

14:35 ambient: i can't tell the difference between the correct one and yours by ear

14:36 good enough ;)

14:36 thanks for the help

14:36 tomoj: good luck

14:36 I can't figure out where that correct seq is coming from

14:36 ambient: http://paste.pocoo.org/show/144753/

14:42 next up: converting this https://ccrma.stanford.edu/courses/220b-winter-2003/lectures/9/examples/moog.lisp into lazy-sec ;(

14:55 hiredman: clojurebot: protocols?

14:55 clojurebot: Titim gan éirí ort.

14:55 hiredman: clojurebot: protocols is <reply>http://clojure-log.n01se.net/date/2009-10-13.html#12:02

14:55 clojurebot: c'est bon!

15:04 lpetit: rhickey: currently multimethods have the insanely powerful property of being able to do multiple (and even more, arbitrary) dispatch on the arguments. What about protocols ? All these considerations of protocols being compared to java interfaces leaves me perplex. Is protocol a grouping of functions with a dispatch restricted to the first argument, as are java interfaces ? I guess there's a...

15:04 ...piece of the puzzle that's still missing in my head ...

15:06 chouser: lpetit: yeah, he said protocols would not have customizable dispatch function

15:06 rhickey: but might allow dispatch on other than the first arg

15:07 multimethods will still be there for more advanced things, but protocols are likely to be simpler for others

15:08 lpetit: rhickey: do you have some "surface" example of what coding to protocols could look like ?

15:09 rhickey: lpetit: not that I want to share just yet, but would look like gen-interface with less cruft

15:10 lpetit: rhickey: ok, and the restriction on the dispatching mechanism certainly will make it just work with the concept of 'type, I guess ?

15:11 rhickey: (defprotocol Seqable [coll] (seq [coll] "Returns a seq on the collection"))

15:12 lpetit: the interaction with type is something I'm still thinking about, including making type a more proper slot like meta

15:14 lpetit: rhickey: is using a capital letter as the first letter of the protocol name a convention suggestion, or is it just to make the parallel with the current java type name ?

15:14 rhickey: (implement Seqable [String] (seq [s] (StringSeq/create s))

15:15 lpetit: dunno right now

15:16 lpetit: rhickey: wouldn't using a name like implement break the convention of prefixing such things with 'def: defmulti/defmethod ?

15:16 chouser: implement isn't interning any new name in the namespace like the other defs

15:16 that was done with defprotocol

15:17 lpetit: chouser: does defmethod intern a new name in the namespace ?

15:17 chouser: nope

15:17 good point.

15:17 then again, I tend to trip over that :-)

15:17 rhickey: don't worry about the names just yet, will be easier once there are semantics :)

15:18 lpetit: chouser: but maybe it's defmethod which breaks the convention, given your arguments :)

15:18 chouser: I have to think of both defmulti and defmethod before I can remember which to use for which.

15:18 LauJensen: rhickey, Is there a wiki entry coming up on assembla on this ?

15:19 lpetit: rhickey: thanks for all the input. I think I'll now refrain myself from asking more, and wait for something more elaborate on your part (and by not asking more questions myself I'll leave you some time to do so ;-) )

15:22 rhickey: LauJensen: not yet, needs more think-time

15:36 itistoday: anyone here used compojure?

15:36 used or uses actually

15:41 LauJensen: Yea, all the time, its great :)

15:43 mwoelker: Here's a minimal prototype base "type system" for clojure: http://gist.github.com/209477

15:43 itistoday: LauJensen: what happens if you want to change a file? do you have to restart the server to recompile and load it?

15:43 mwoelker: I hope it's not considered heresy to put objects into a functional language...

15:44 Has anyone ever tried something like this?

15:44 opqdonut: hehe

15:44 have you heard of haskell, ocaml

15:44 LauJensen: itistoday, if you're working locally, usually you just re-eval whatever function your working on, at changes are immediate. On my server I don't have a live repl, so I change the file and restart

15:44 opqdonut: they are strongly typed functional languages

15:45 hiredman: that's not a type system

15:45 that there is an "object" system

15:45 itistoday: LauJensen: (i'm new to clojure) do you get the repl the same way you get the repl to a running clojure program, by running it with a property to connect on a port?

15:45 kotarak: mwoelker: ocaml has objects ("Objective" Caml)

15:46 hiredman: mwoelker: don't do it

15:46 mwoelker: I meant specifically for clojure...

15:47 LauJensen: itistoday, you start a repl as you normally would, hopefully M-x slime, then you define your servlet and eval (run-server servlet params), that'll leave you with a repl and a running server

15:47 hiredman: what you have is the most naive way to implement objects

15:47 Chousuke: mwoelker: your mutate function is badly named :)

15:47 itistoday: LauJensen: but i mean if you're running this on a remote server

15:48 LauJensen: on a remote server I don't keep open repls

15:48 mwoelker: hiredman: I thought it might be a nice way to get some polymorphism in there, but maybe I'm just still to stuck in my OO ways

15:48 hiredman: there is a spinoza

15:48 Chousuke: mwoelker: it mutates nothing. (which is a good thing)

15:48 hiredman: but spinoze is also a mistake

15:48 mwoelker: multimethods

15:49 Chousuke: polymorphism doesn't imply object-orientation

15:49 mwoelker: Chousuke: yeah I am not quite happy with the mutate name or implementation really

15:49 hiredman: multimethods have global effects don't they?

15:49 hiredman: mwoelker: global effects?

15:51 mwoelker: hiredman: well if I defmethod to handle vectors for instance, all future calls are gonna call that method, this approach allows only local effects

15:51 Asked another way what would the example code look like in idiomatic clojure?

15:52 Chousuke: (def a {:given-name "John" :surname "von Neumann"}), similarly for b :P

15:53 mwoelker: i.e. two pieces of "data/stuff" that should somehow behave differently

15:53 hiredman: mwoelker: it depends on your dispatch function

15:53 mwoelker: Chousuke: okay and full-name?

15:53 Chousuke: maybe with a :name-classification 'hungarian key as well

15:55 lpetit: mwoelker: hello!

15:55 Chousuke: then just (defmulti full-name :name-classification) (defmethod full-name 'hungarian [thing] (str (:surname thing) " " (:given-name thing)))

15:56 lpetit: mwoelker: from now on, have you already read through defmulti/defmethod, or is it a new are for you ?

15:56 mwoelker: I found some detail (and some documentation parts) not easy to follow on, but the intent of defmulti is really super-powerful

15:57 Chousuke: mwoelker: Clojure generally doesn't use camelcase btw.

15:57 so identifiers like fullName are nonidiomatic

15:57 except when dealing with Java interop.

15:57 mwoelker: or is my premise wrong: mixing data and behaviour?

15:57 lpetit: Chousuke: is your use of 'hungarian rather than e.g. ::hungarian intentional ?

15:58 Chousuke: lpetit: hmm, good point. no. :)

15:58 lpetit: mwoelker: yes, it's wrong

15:58 chouser: if you *really* want to attach functions to your data (ala javascript prototypes), idiomatic use of multimethods isn't going to get you all the way there.

15:58 Chousuke: lpetit: I just thought I should use something other than a keyword

15:58 chouser: is it wrong? have you looked at clojure.zip?

15:58 Chousuke: if you want to attach functions to your data, do so, but don't make so big a deal over it.

15:59 after all, functions are just another kind of data.

15:59 mwoelker: sorry afkphonecall

15:59 lpetit: Chousuke: but I can understand - currently using raw keywords has its pro, but one big cons is that you're not helped at all with typos. In other areas the clojure compiler already does a good job of informing you (e.g. var symbols)

16:00 * lpetit recons he made a strong point where he should have been more nuanced

16:01 lpetit: of course data must be manipulated somewhere :)

16:02 mwoelker: I'm back, I still think the defmulti approach is somehow less clean and functional

16:02 lpetit: mwoelker: can you explain ?

16:03 mwoelker: the key keyword approach has the advantage that it adds a layer of indirection between caller and callee

16:03 lpetit: mwoelker: did you miss the recent IRC discussion on protocols, initiated by rhickey ?

16:03 mwoelker: lpetit: yeah I missed the protocols, was aware of multimethods though

16:04 with the prototype approach you could replace plain data with functions and vice versa

16:04 chouser: clojure.zip's implementation is relevent here.

16:04 lpetit: mwoelker: I'm not sure : the key keyword should be a matter of the library provider, something that "tags" the object when created -> so the caller would certainly prefer to use a builder function anyway :)

16:04 hiredman: lpetit: if he doesn't like multimethods, I doubt he will be interested it protocols

16:04 and protocols don't exist yet

16:04 chouser: it manipulates vectors, each of which has a bunch of fns in its metadata

16:04 hiredman: so I don't think bringing them up is helpful

16:05 lpetit: chouser: can you elaborate, I don't know the implementation of clojure.zip very well

16:05 chouser: most of the public api fns simply turn around and call functions stored in the vector's metadata

16:05 Chousuke: chouser: do you think that was a successful approach?

16:05 mwoelker: no I do think multimethods have their uses, but I think in cases like these a different approach might be more viable...

16:05 hiredman: nope

16:06 mwoelker: I actually think protocols might be what I am looking for

16:06 chouser: Chousuke: well, it's immutable, extensible, and seems to have lived up well under a fair amount of use.

16:06 lpetit: hiredman: you seem to have strong thoughts, can you elaborate a little bit more in your answers ?

16:06 hiredman: if you reall want objects I recomend something like http://gist.github.com/209514

16:06 kotarak: chouser: in which way is this better than a multimethod?

16:07 lpetit: chouser: (real question, I don't have the answer) Had he had protocols at the time, would Rich have implemented clojure.zip with them ?

16:07 hiredman: lpetit: protocols apear to be a specialization/optimization on multimethods

16:07 chouser: kotarak: it probably predates multimethods :-P but besides that, it's just a different solution to similar problems.

16:07 lpetit: mwoelker: yes, protocols will give atomicity and cohesion to a set of multimethods

16:08 mwoelker: lpetit: anywhere I can read up on them?

16:09 lpetit: hiredman: not just a specialization, protocol have the added property of grouping multimethods. But a specialization in the sense that they will be (apparently, and certainly with performance and uniformity in mind) less open in the dispatching area

16:09 chouser: lpetit: I don't know, but it would seem reasonable. Had he had protocols he would have implemented much of RT and core in them, too. :-)

16:09 hiredman: handing people things that don't exist is not cool

16:09 Chousuke: mwoelker: scroll up your backlog :)

16:09 mwoelker: protocols don't exist yet and anything anyone says about them is subject to change

16:09 lpetit: clojurebot: protocols

16:09 clojurebot: http://clojure-log.n01se.net/date/2009-10-13.html#12:02

16:09 Chousuke: even the name :P

16:09 kotarak: chouser: yeah, there are a lot of relics in Clojure, like .. (double-dot). I would prefer a simple multimethods approach over a (maybe overly) clever metadata approach.

16:09 lpetit: mwoelker: clojurebot is your best spy/friend :)

16:11 hiredman: clojurebot: what does the world need?

16:11 clojurebot: what the world needs is more higher order functions

16:11 chouser: mwoelker: it seems likely to me that there are use cases where something like clojure.zip's approach, or one like javascript's prototype "inheritence", might fit better than anything else that is more commonly used in Clojure.

16:12 mwoelker: clojurebot: what is the meaning of liff?

16:12 clojurebot: Huh?

16:12 mwoelker: almost

16:12 lpetit: hiredman: I guess mwoelker is on the learning curve, and not trying to solve a real problem at hand, that's why I point him to "topnotch" stuff :)

16:12 chouser: I think one of the features of Clojure (and maybe lisps in general) is that they allow you to easily experiment with alternate solutions to problems like this.

16:13 if you can write three functions and suddenly have a new design option, why not try it out?

16:14 don't expect everyone else to start using it of course, but it if makes your life easier then by all means...

16:14 actually, lots of dynamic languages provide that feature to some level or other.

16:14 mwoelker: lpetit: Learning curve indeed.

16:15 lpetit: chouser: good point. lisps indeed are about freedom. I should not have said "it's wrong". I should have said : it may be a smell that you're trying to reproduce something from your java background. You may miss a better (or more functional or more idiomatic) solution by doing so. But in the end of the day it's only mwoelker who knows his problem domain best.

16:15 chouser: thank you for reminding us to be modest. (I mean it, really)

16:15 chouser: mwoelker: if you're not yet comfortable with multimethods, I would recommend working with them a bit more.

16:15 Chousuke: macros are still my favourite feature of lisp

16:15 hiredman: woa, who is being modest?

16:16 Chousuke: you don't need them all that often really but when you do you'll be very grateful of them :P

16:16 chouser: lpetit: yes, of course you're right as well -- it's easy to reach for what you know and miss something that might be better.

16:16 Chousuke: or rather, when you'd need them in other languages you'll go "graah" and then resign to your fate.

16:17 OR start writing some code-generating preprocessor.

16:17 chouser: mwoelker: multimethods split apart objects type, type inheritence, object data, and behvaior in a way that provides you a lot of power and flexibility.

16:18 Chousuke: also you can dispatch on more than the object's type

16:18 how about the types of all the parameters, for instance?

16:18 hiredman: well

16:18 java does that

16:18 chouser: Chousuke: that's why I listed behavior and object type separately. :-)

16:18 mwoelker: chouser: it's not really that I feel uncomfortablle with them, I just think they solve a different problem. To solve "my problem" with multimethods would mean annotating the data with extra markers so the multimethod can figure out what actual function to call. "Storing" the function in "slots" in the object itself allows for IMHO a neater solution while also sidestepping possible naming collisions

16:18 Chousuke: (and not the object itself :P)

16:19 hiredman: http://www.sics.se/~joe/bluetail/vol1/v1_oo.html <-- "Why OO Sucks"

16:19 rstehwien: chousuke: I learned ANTLR and read code generation in action because of parts of languages that made me go "graah". ActionScript does that to me daily

16:19 lpetit: mwoelker: I currently like to think about it as this from less abstract to more abstract: defn -> higher order functions -> multimethods. But indeed I recon I would still be annoyed if I had to do plain "database driven" programming with clojure. Though in database-driven code I've seen in the past (I mean java code), domain graphs generally were very anemic, and the business functions were...

16:19 ...methods of "static" (or singleton) service layer classes.

16:20 rstehwien: chousuke: so I do Clojure (and ruby) on the side to feel better

16:20 lpetit: mwoelker: of course this was a pity, but it was the reality of what I saw.

16:20 chouser: mwoelker: one of the trade-offs there is that multimethods allow others to add methods on your "types" without touching your objects

16:20 ambient: how do i make (map + [[1 2] [2 4]]) into (map + [1 2] [2 4])?

16:20 hiredman: ambient: apply

16:21 ambient: i've used map too much that i try to now do everything with it :p ty

16:21 rstehwien: chouser: I really like multimethods... maybe too much (sometimes an if statement will do).

16:21 chouser: rstehwien: heh.

16:21 rstehwien: chouser: next up is abuse of macros :)

16:23 chouser: rstehwien: you're allowed to abuse macros as much as you want as long as you never ask for help.

16:25 mwoelker: lpetit: maybe I am looking at it up from too much of an encapsulation and abstraction standpoint

16:25 lpetit: I blame years of C++ and Java ;)

16:27 ambient: how can i know in which line in my source code a runtime error happens?

16:27 raek: (.printStackTrace *e) might be useful...

16:27 kotarak: ambient: look for "caused by" lines. The stacktrace of the bottom one, is near the culprit.

16:27 ambient: raek nil

16:27 chouser: hm... without mutation of something you can't change the behavior of a whole class of existing objects. multimethods keep that mutation at the namespace and (one step down ) at the multimethod.

16:28 kotarak: ambient: look also in clojure.stracktrace/print-cause-trace

16:28 chouser: to do that with prototypes would require mutation at each object that might be used as a prototype, right?

16:28 raek: (doc *e)

16:28 clojurebot: "; bound in a repl thread to the most recent exception caught by the repl"

16:29 raek: ambient: or did it occur in an agent?

16:29 in that case you'll want (agent-errors my-agent)

16:29 and then (clear-agent-errors my-agent)

16:30 ambient: i have nothing but functions inside functoins at the moment

16:30 mwoelker: chouser: well you could do it as far up in the prototype hierarchy as required

16:30 ambient: raek emacs C-c C-k

16:30 mwoelker: chouser: of course this would not work at runtime which may or may not be a good thing

16:31 raek: ambient: I think I use "the other" emacs mode

16:31 C-c C-k is not bound for me

16:31 mwoelker: chouser: of course you can always add another layer of indirection

16:33 hiredman: clojurebot: literal [0] problem

16:33 clojurebot: <reply>"There is no problem in computer programming which cannot be solved by an added level of indirection." -- Dr Maurice Wilkes

16:35 lpetit: hiredman: what did you mean by "java does that" ?

16:36 hiredman: lpetit: java dispatchs on object type and argument type

16:38 lpetit: mwoelker: I also have the samel feeling, something along those lines = If I use clojure on a big project, and follow what 'seems' to be the convention to just use keywords on maps as the sole way to access data slots, wouldn't I, at some point of the project, face a wall for not having encapsulating the slot access ?

16:38 s/encapsulating/encapsulated/

16:39 hiredman: I don't think so ? java dispatches on object type at runtime, but it does not dispatch on argument type at runtime. This one is the stuff of the compiler, isn't it ?

16:39 hiredman: that's why there are books and blog posts about the Visitor pattern, when you can do that so easily with multimethods in clojure or generic functions in CLOS ?

16:40 mwoelker: lpetit: not only big projects, libraries as well. This might be a neat way to hide implementation details (like: is this value stored or computed) and allow for producers of library to perform updates while staying backward compatible

16:41 hiredman: lpetit: in java a method that takes a String is different from a method that takes an Integer

16:42 so, void add (String a) {} and void add (Integer i) {}

16:42 lpetit: hiredman: but the choice of calling void add (String a) {} or void add (Integer i) {} is done at compilation time.

16:42 mwoelker: hiredman: yeah but which method gets called is decided at compile time

16:43 hiredman: so?

16:43 it's still selected via the argument types

16:43 mwoelker: the thing is if you only have an Object at hand (which may be either an Integer or a String) the compiler will complain

16:43 Object=Object reference

16:43 lpetit: hiredman: so if you have A extends B and in a class void something(A a) [} and void something(B b) {} the compiler will choose the method not on the real dynamic type of the arg that is passed, but based on the declared type of the variable definition of the argument that is passed

16:44 hiredman: so?

16:45 dispatch is still via argument type

16:45 lpetit: hiredman: so argument dispatch is not available at runtime in java.

16:45 hiredman: static, dynamic, whichever

16:45 lpetit: hiredman: the difference is big

16:45 hiredman: 13:42 hiredman : lpetit: java dispatchs on object type and argument type

16:46 I understand that the difference is big

16:46 but the fact remains, java dispatches on object type and argument type

16:47 lpetit: hiredman: if you want, I'm bored by this no-end discussion, and it's late here, so 'night

16:48 hiredman: but still, I consider the discussion was not about compilation dispatch, but really about runtime dispatch. You're playing with words

16:49 hiredman: well, nice of him to leave

16:50 ~botsnack

16:50 clojurebot: thanks; that was delicious. (nom nom nom)

16:52 ambient: if d is a sequence this gets a bit difficult: (reductions (fn [y [x1 x2]] (* d (+ y (- x1 x2)))) 0 (partition 2 1 coll)))

16:53 hiredman: (apply * (+ y (- x1 x2)) d)

16:54 (reduce * (+ y (- x1 x2)) d)

16:54 etc

16:54 ambient: it's all lazy

16:54 hiredman: well, * is not lazy

16:54 ambient: that's why it gets difficult

19:12 Dawgmatix: whats the recommended way to parse xml in clojure ?

19:17 hiredman: Dawgmatix: clojure.xml/parse

19:17 Dawgmatix: cool thanks :)

19:22 is there someway to modify the classpath from the slime repl ?

19:22 clojurebot: classpath is (System/getProperty "java.class.path")

19:23 hiredman: Dawgmatix: there is add-classpath, but it is best not to get into the habit of using it

19:23 Dawgmatix: i am coming from a lisp background and just trying to wrap my head around what the development cycle looks like for clojure

19:24 piccolino: Is there something like a 1.0 release of clojure-contrib?

19:24 hiredman: repl -> repl -> repl -> repl -> repl -> store -> repl

19:24 there is a 1.0 compat branch of contrib

19:25 piccolino: But doesn't that change as development happens?

19:25 Dawgmatix: So if i want to use something like compojure, i add the directory to my actual classpath ?

19:25 (in my ~/.bashrc ? )

19:25 hiredman: piccolino: yes

19:25 Dawgmatix: depends

19:26 my classpath is "/home/kpd/*.jars"

19:26 er

19:26 my classpath is "/home/kpd/.jars/*"

19:26 piccolino: Hm. I'm trying to make a portfile for clojure-contrib, but I think I need some sort of zip file I can download for it (total macports amateur, though).

19:26 Dawgmatix: is there a startup file that clojure reads that I can use to set classpaths and do random other inits (for example (use ... ) statements)

19:27 hiredman: by the time clojure loads, the jvm is already running

19:27 you can use some kind of script or what have you

19:27 Dawgmatix: oic - and the classpath isnt thought of as a dynamically changeable entity ?

19:28 hiredman: classpaths are, I belive, a property of ClassLoaders

19:28 Dawgmatix: (sorry if these are dumb questions, i am as much a java noob as i am a clojure one)

19:28 hiredman: and you cannot muck with the system classloader, you can do stuff like spin off your own classloader, but that can lead to issues

19:29 Dawgmatix: i see, so in short its better off to just have a jar folder like yours

19:29 hiredman: technomancy has some setup where he just unpacks the jar files

19:29 *shrug*

19:30 the jar directory approach has some issues to, classpaths with wildcards like only work with 1.6+ jvms

19:30 but you can always just write a bit of code to generate a classpath from a bunch of jar files

19:31 you can also do CLASSPATH="./libs/*" which is hand for a project specific classpath

19:31 Dawgmatix: I see.

20:29 froog: is there a unit testing framework that is still in active development?

20:36 jhawk28: junit?

20:36 define active development

20:37 chouser: froog: clojure.test is in clojure proper now, and all clojure's own tests us it

20:38 used to be test-is

20:41 Dawgmatix: is there any documentation for compojure ? i cant seem to find any on github ?

20:42 froog: jhawk28: it's just that fact states: "no longer in active dev", so that doesn't seem like the right tool to start using :)

20:42 Dawgmatix: alternatively are there other competing web frameworks ?

20:43 froog: chouser: thanks, will look into it

20:44 jhawk28: froog: junit is stable and doesnt need active dev (they did just release 4.7 in august)

20:45 froog: jhawk28: I thought that was for java

20:46 chouser: froog: I have a set of test written in clojure for junit so that they can plug into the junit runner suite at work.

20:47 mrowe: Dawgmatix: there's also conjure, which is pretty much a line-by-line clones of Rails

20:48 Dawgmatix: and I believe there's a newer one, cascade, but I don't know anything about it

20:48 Dawgmatix: I see.

20:50 chouser: how much framework do you want? I'm using (a small part of) ring and like it very much so far.

20:50 Dawgmatix: I just want basic url routing

20:51 froog: chouser: ok, I just wanted something simple, but maybe junit is simple.

20:51 mrowe: Dawgmatix: sounds like compjure is what you want... there's a draft tutorial on the mailing list that should help get you started

20:52 Dawgmatix: http://groups.google.com/group/compojure/browse_thread/thread/3c507da23540da6e

20:52 Dawgmatix: thanks :)

20:53 chouser: froog: I'd recommend you look at clojure.test. I mentioned junit only because it can be used, but it's a bit of a pain -- worth it only if using it buys you something else (like integration)

20:53 froog: jhawk28: thanks for pointing out junit.

20:53 chouser: ring and multimethod gets you very simple url routing. *very* simple

20:58 froog: chouser: yes, clojure.test looks very much like what I want

22:57 tomoj: maybe something is wrong with my brain. I can't figure out how to convert a char to a byte/int/whatever so I can do bit-test on it

22:57 hiredman: ,(int \a)

22:57 clojurebot: 97

22:57 hiredman: ,(-> \a int byte)

22:57 clojurebot: 97

22:57 tomoj: ah

22:57 ,(byte \a)

22:57 clojurebot: java.lang.ClassCastException: java.lang.Character cannot be cast to java.lang.Number

22:57 tomoj: why doesn't that work?

22:58 chars are too big I guess?

22:58 hiredman: a Character cannot be cast to a Number

22:58 nah

22:58 I am pretty sure chars can be cast to ints no problem

22:58 clojurebot: People have a problem and think "Hey! I'll use a regular expression!". Now they have two problems....

22:58 hiredman: clojurebot: everybody!

22:58 clojurebot: everybody looks good in a sheinhardt

22:58 tomoj: yep, just not bytes

22:58 hiredman: well, and int can be cast to a byte

22:59 tomoj: right, but why not straight to byte?

22:59 hiredman: the issue is, bascially, boxing

22:59 tomoj: ah well, int will work fine for me anyway

23:00 thanks

23:03 danlarkin: <3 30 rock

23:04 hiredman: :D

23:10 tomoj: this is profoundly ugly :( http://gist.github.com/223d4f377d4b3e7d6dab

23:10 maybe I need to stop coding and go to sleep

23:11 problem is to convert a (positive) integer to a big-endian two's complement string, so you have to add a 0x00 char if the leftmost bit is 1, and for 0 you're supposed to return 0x00, not just ""

23:11 hiredman: :(

23:12 tomoj: I wonder why the hell they use two's complement when all the integers are positive

23:12 maybe btwoc is a standard function elsewhere?

23:12 hiredman: hmmm

23:13 ,(.getBytes "foo")

23:13 clojurebot: #<byte[] [B@265e47>

23:13 danlarkin: ,(seq (.getBytes "foo"))

23:13 clojurebot: (102 111 111)

23:13 hiredman: ,(-> "foo" .getBytes ((partial map int)))

23:13 clojurebot: (102 111 111)

23:14 danlarkin: I like mine

23:14 :-p

23:14 tomoj: that's backwards

23:14 hiredman: ,(-> "foo" .getBytes ((partial map int)) ((partial map #(Integer/toBinaryString %))))

23:14 clojurebot: ("1100110" "1101111" "1101111")

23:15 tomoj: though I'll have to do that eventually too

23:15 hiredman: ,(-> "foo" .getBytes ((partial map #(Integer/toBinaryString %))))

23:15 clojurebot: ("1100110" "1101111" "1101111")

23:18 danlarkin: ,(map #(Integer/toBinaryString %) (.getBytes "foo")

23:18 clojurebot: EOF while reading

23:19 danlarkin: ,(map #(Integer/toBinaryString %) (.getBytes "foo"))

23:19 clojurebot: ("1100110" "1101111" "1101111")

23:19 hiredman: :(

23:19 danlarkin: so much less complicated

23:19 hiredman: parens are not complicated

23:20 actually

23:20 ,(->> "foo" .getBytes (map #(Integer/toBinaryString %)))

23:20 clojurebot: ("1100110" "1101111" "1101111")

23:20 hiredman: :D

23:31 durka42: (doc ->>)

23:31 clojurebot: "([x form] [x form & more]); Threads the expr through the forms. Inserts x as the last item in the first form, making a list of it if it is not a list already. If there are more forms, inserts the first form as the last item in second form, etc."

23:31 durka42: (doc ->)

23:31 clojurebot: "([x form] [x form & more]); Threads the expr through the forms. Inserts x as the second item in the first form, making a list of it if it is not a list already. If there are more forms, inserts the first form as the second item in second form, etc."

23:41 tomoj: i uinai mi manci na'e jimpe la'oi ->> doi durka

23:44 durka42: tomoj: clojure does that :)

23:45 it makes sense when you look at what hiredman gave ->> as an alternative to

23:45 tomoj: I will have to play around with it sometime

23:47 durka42: i hadn't seen ->> before, is it in the standard core or is it a clojurebot original (tm)?

23:47 hiredman: it was added to the core sometime is last month or so

23:49 rboyd: what's that operator called? arrow operator?

23:53 arbscht_: -> and ->> are 'threading'

23:54 hiredman: 'awesome'

23:54 arbscht_: :)

23:54 hiredman: also the thrush combinator

Logging service provided by n01se.net