#clojure log - May 21 2011

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

0:59 wastrel: i'm stuck on a 4clojure problem

1:00 offby1: is that a sort of puzzle site?

1:00 ooh, I need to study that! thanks for the tip

1:00 (and no, I can't help you with your problem; I'm too n00b)

1:08 wastrel: it's cute

1:08 but evil

1:09 do you have programming experience in another language?

1:09 computer science background?

1:09 offby1: yep

1:10 which problem is it? Maybe it's easier than I think

1:10 I'm on problem 7 right this second :-)

1:10 wastrel: it is an embarrasingly early one

1:10 offby1: well!

1:10 as early as 7

1:10 ?

1:10 wastrel: the one i'm stuck on is past 7 but not by much

1:10 i think it took me 3 days to get to prob 7 ;]

1:10 offby1: well if you don't tell me which it is, I can't help.

1:11 wastrel: sec i'm looking it up

1:11 offby1: I think I know you from #emacs

1:11 wastrel: i was there briefly, failing to get emacs setup

1:11 offby1: aw

1:11 wastrel: it is problem 22

1:11 offby1: well, emacs is a lot to learn all at once.

1:12 wastrel: http://www.4clojure.com/problem/22

1:12 offby1: yeah, I don't know Clojure enough to just write that immediately.

1:12 wastrel: at this point i might be expected to start reading up on the language

1:13 i was trying to delay as long as possible :]

1:13 offby1: But I assume it'll look something like this (modulo my getting the syntax wrong): (def my-count [x] (if (empty-list? x) 0 (+ 1 (my-count (all-but-the-first-element x)))))

1:13 that's more or less how you'd do it in (say) scheme

1:13 wastrel: you're not allowed to use def i think

1:13 it yelled at me

1:15 empty-list? is a good trick though, i've been using (= x ())

1:15 offby1: that'd work too, but I assume there's a built-in function that does the equivalent. (I doubt it's called "empty-list?"; I just made that up)

1:15 probably "null" or something

1:17 wastrel: empty?

1:17 works on collections (per the cheatsheet)

1:17 offby1: sounds reasonable

1:17 I'm surprised you can't use def

1:20 wastrel: hrm

1:20 you can make anonymous functions with (fn

1:20 so that woulde work actually

1:20 i don't understand how it works but i see what you're doing.

1:21 i'll have to draw it out

1:22 offby1: I've got an answer, but it's probably more complex than it needs to be

1:22 given the simplicity of the problems that precede 22

1:23 wastrel: http://ix.io/1Hd

1:23 lemme try it in the web page

1:23 Yamazaki-kun: hm.

1:23 wastrel: offby1: see it will object to the inner def

1:23 offby1: that's exactly what i did

1:24 offby1: heh

1:24 Yamazaki-kun: can't use defn... what?

1:24 I did a loop.

1:24 wastrel: you use fn to make an anonymous func

1:24 it shows you how in an earlire problem.

1:25 offby1: http://ix.io/1Hf works

1:26 I still suspect there's a much simpler way

1:28 wastrel: ah i thought i needed to name the inner func because i didn't know about recur

1:28 coolycool

1:29 offby1: yeah, I read about that somewhere. Probably my Clojure book; who'd'a thunk

1:30 actually, "recur" hasn't been mentioned in any of the previous problems, which makes me think it's the wrong solution.

1:30 Yamazaki-kun: gotcha

1:30 * thunk gets growled at

1:30 offby1: but if I can't use "def", then I don't know how to recur (I am far too lazy to write the Y combinator :-)

1:30 thunk: I was just thunking about you

1:30 * offby1 slaps thigh

1:30 thunk: i'm all thunk out

1:30 * offby1 invokes thunk with no arguments

1:31 Yamazaki-kun: http://paste.lisp.org/display/122173

1:31 offby1: Yamazaki-kun: loop sounds better -- particularly if a previous problem introduced it

1:31 Yamazaki-kun: you cheated -- you used your experience :)

1:31 I was looking for "fold" :-)

1:31 Yamazaki-kun: ah.

1:32 er, that's a Haskell function.

1:32 offby1: sure

1:32 wastrel: your first one works fyi

1:32 offby1: I know mine works; I tested it.

1:32 it's just ugly.

1:34 rudybot: (foldl + 0 (list 1 2 3))

1:34 rudybot: *offby1: your scheme sandbox is ready

1:34 *offby1: ; Value: 6

1:34 offby1: that's how we do it in Scheme

1:34 (racket, anyway)

1:34 oops, wrong function

1:34 Yamazaki-kun: yeah.

1:34 anyhow, I think I need to (bed)

1:37 seancorfield: another java interop Q... from java, i want to compile a clojure namespace...

1:38 RT.Var( "clojure.core", "compile" ).invoke( "my.test.ns" ); // should work but...

1:38 it complains that *compile-path* is not set

1:38 ok... so how do i set that from java?

1:54 solved that part with this ugly monstrosity: RT.var( "clojure.core", "alter-var-root" ).invoke( RT.var( "clojure.core", "*compile-path*" ), RT.var( "clojure.core", "constantly" ).invoke( "classes" ) );

1:54 symbole: I have a macro (defmacro foo [x]), which is called like so (foo (bar baz)). How can I force x to evaluate (bar baz)? I've only been able to do it with eval.

1:55 seancorfield: now i'm stuck trying to figure out the correct incantation for compile

1:56 symbole: doesn't (defmacro foo [x] x) work?

1:57 (foo (inc 1)) produces 2

1:57 or didn't you mean that?

1:59 symbole: Seems my toy example is not the same as what I'm doing. I'll show you, one sec.

2:03 (defmacro foo [x] (:key x)), (defn a [] {:key "bob"}), (foo (a)).

2:04 This returns nil, because I assume that when x is evaluated, it evalutes to a list with one symbol, 'a.

2:07 Correct me if I'm wrong. The first case (with (inc 1)) worked, because what was returned is '(inc 1).

2:09 I guess it's a bad form to try an evaluate the parameters, because it's not always the guess that what is being evaluated is available during macro expansion time.

2:09 try and evaluate...

2:34 seancorfield: symbole: (defmacro foo [x] `(:key ~x))

2:35 ,(defmacro foo [x] `(:key ~x))

2:35 clojurebot: DENIED

2:35 seancorfield: &(defmacro foo [x] `(:key ~x))

2:35 sexpbot: java.lang.SecurityException: You tripped the alarm! def is bad!

2:35 seancorfield: *sigh*

2:36 anyways, given that macro, (macroexpand-1 '(foo (a))) expands to (:key (a)) which is what you want

2:36 symbole: seancorfield: Actually I want to evaluated (a) before (:key) is applied.

2:37 evaluate*

2:39 seancorfield: but (:key (a)) will give you that value... so i'm not sure what you're asking now

2:40 symbole: I want the return value of (a) to be available while the macro is running.

2:41 I came up with (defmacro foo [x] (:key (eval x)))

2:51 jarpiain: symbole: it's not going to work if you need to use it like (let [a {:key 1}] (foo a))

2:52 why do you (think you) need the value at macroexpansion-time?

2:53 symbole: jarpiain: It's something I came across while creating my macro. I suspect it's due to a bad design on my part. So I was just very curious.

4:32 cljnewb: hello, I'm trying the "fasttrackclojure" tutorial, and I can't seem to get past (use 'clojure.contrib.prxml) .. I get a filenotfoundexception. I cannot figure out why though. I am in class path hell :(

4:33 in my .bashrc, I'm exporting CLOJURE_EXT containing the clojure 1.2 directory, and the clojure-contrib 1.2 directory

4:34 pepijndevos: link?

4:34 clojurebot: your link is dead

4:34 cljnewb: for no reason other than I don't know what I'm doing and there's very little online help concerning these matters, I've also exported the CLASSPATH variable to point to the same directories

4:34 http://fasttrackclojure.blogspot.com/2010/09/lesson-3-user-defined-functions-in_25.html

4:35 I'm using the 'clj-env-dir' script from my clojure-contrib directory

4:36 fliebel: I'm trying to avoid all these issues, by using my package manager or lein to manage it.

4:37 cljnewb: fliebel: if I run 'lein repl', and try (use 'clojure.contrib.prxml), I get the same thing :(

4:38 if ubuntu's clojure package weren't so old, I'd try going that route

4:39 fliebel: cljnewb: That is because the global lein does not include it. I'm no sure how you can control that… How old are ubuntu's?

4:39 cljnewb: ubuntu's clojure is 1.1.0

4:39 fliebel: :(

4:40 You could try cljr or cake maybe. Or just create a new lein project that has contrib as a dep.

4:41 cljnewb: I could I guess, but it just seems silly. I'm just playing around.. why create a new lein project?

4:41 But if I don't figure out anything else, yeah, I'll do that

4:42 fliebel: cljnewb: try ##(System/getProperty "java.class.path")

4:42 sexpbot: java.security.AccessControlException: access denied (java.util.PropertyPermission java.class.path read)

4:45 cljnewb: fliebel: I get about a page worth of classpath stuff... looks like all the files from clojure dir and clojure-contrib dir

4:47 fliebel: cljnewb: well, if prxml is in there, it should work :(

4:48 cljnewb: fliebel: well, prxml.jar is in there (under clojure-contrib-1.2.0/src/main/clojure/clojure/contrib of course)

4:48 but yeah, I think it should work too

5:08 so I'm trying http://www.learningclojure.com/2010/08/clojure-emacs-swank-slime-maven-maven.html now, but after creating a pom.xml file, and trying 'mvn clojure:repl', I get a fatal error.. reason: not a v4.0.0 POM

5:08 why are there a million ways to get clojure, but none of them work?

5:09 maybe I should just install windows and use clojurebox :P

5:21 well I created a lein project and added contrib as a dep, works fine

5:21 seems like I shouldn't have to do that, but whatever, if it works, it works I guess

5:21 thanks fliebel! :)

7:40 pauldoo: just spent 20 mins wondering how you'd implement a C# style yield construct in Clojure. But of course it's just a lazy-seq. Easy

7:44 churib: Is there a code walker written in clojure?

7:45 pauldoo: code walker?

7:46 churib: http://dictionary.reference.com/browse/codewalker

7:47 chouser: clojure.walk

7:47 that's a namespace with a few related useful functions

7:48 churib: but nothing more than just walking through sexps...

7:49 what about the plans of writing the clojure compiler in clojure - is there some code yet?

8:01 chouser: churib: there's no official clojure-in-clojure compiler components yet

8:02 but there's an unofficial one here: https://github.com/jarpiain/cljc

8:03 and you can use Clojure's in-Java compiler's analyzer to some extent, like this does: http://clojure.github.com/clojure-contrib/repl-utils-api.html#clojure.contrib.repl-utils/expression-info

8:14 fliebel: pauldoo: I don't think you can implement coroutines with lazy seqs though, like you can in Python.

8:16 pauldoo: fliebel: hm - aren't lazy-seqs doing something extremely similar to coroutines?

8:16 ie, returning closures representing the rest of the computation (the remaining list)

8:17 fliebel: Yea, it's very similar.

8:19 So using interleave and trampoline you could consume lazy seqs of fns, but you can't yield in the middle of some imperative action like you do in Python.

8:23 pauldoo: Buggy example: http://pepijndevos.nl/cooperative-concurrency-in-clojure

8:24 pauldoo: fliebel: right yeh - it wouldn't look like yield in the c# sense of a statement that pauses execution. but the idomatic equivelant still exists in clojuse as a lazy-seq

8:25 I guess a closer match to c# yield would involve a thread or something to store the continuation. 'yield' would be like passing a single value to another thread

8:26 fliebel: hmmmm http://download.oracle.com/javase/6/docs/api/java/util/concurrent/Exchanger.html

8:29 pauldoo: fliebel: perfect - yup.. one of those :)

8:29 fliebel: I'm going to cook up an iseq impl for that :)

8:30 pauldoo: might be a PITA to dispose of the thread if the caller stops iterating mind you

8:30 fliebel: hmph, I'll ignore that for now.

8:31 pauldoo: so long as each side of the exchanger only has a weak ref to the other side, it could determine when the other side has been garbage collected. would work fine

8:31 fliebel: pauldoo: What? Weak refs? Explain.

8:32 pauldoo: so the thread calling into 'yield' should give up if the caller ever stops iterating

8:33 so.. if it had a weak reference (http://download.oracle.com/javase/1,5.0/docs/api/java/lang/ref/WeakReference.html) to the exchanger object, it could perhaps determine when the calling thread has decided to stop iterating

8:33 fliebel: btw, can anyone give me a list of things to implement for a proper seq? I remember just first and next not being enough.

8:47 So, I need first, rest, more, cons. I though I needed seq as well, but I'm not sure why.

9:01 hiredman: fliebel: thats ridiculous, why would you need cons?

9:01 anyway, just look at the interface

9:01 fliebel: hiredman: Don't know, It's part of ISeq, which extends IPersistenColection, which implements Sequable.

9:02 So I even have to implement things like count and all...

9:30 robonobo: how would I check if a given argument is a function?

9:37 fliebel: robonobo: (fn? f)

9:38 robonobo: fliebel: thanks

10:12 fliebel: amalloy_: I found your take-shuffled. Any idea how fast it is compared to the ones I collected before? http://pepijndevos.nl/take-n-distinct-random-items-from-a-vector

11:23 no_mind: Is there a way to verify if the code is idiomatic clojure or not ? (or the question is stupid ?)

11:24 offby1: sure. show it to a clojure whiz (or a group of them) and ask

11:24 mids: no_mind: 1) put your code up on pastebin 2) paste the link here 3) ask for feedback

11:24 mefesto: the mailing list is a good place too

11:25 no_mind: hmm so is there a definition for idiomatic code ?

11:25 offby1: of course not

11:26 it's as much aesthetic as anything else

11:26 no_mind: I cant paste code in paste bin... too much for pastebin... will checkin to github

11:26 offby1: sure

11:26 gfrlog: I don't think it'd be impossible to have an automated solution for that...

11:26 mids: no_mind: it is less likely that someone will review your entire codebase... just focus on a snippit and paste that

11:26 gfrlog: quasi-solution...

11:43 * gfrlog did not know about the :or construct

11:44 mefesto: dnolen: no, i mean how would an idiomatic clojure code tool figure out that you should be following that pattern.

11:45 gfrlog: well, it would first set P = NP, and then search for the shortest piece of code that provably does the same thing

11:45 then it would use machine-learning algorithms to decide if the result is "readable" or not

11:46 ,(binding [P NP] (write-shakespeare))

11:46 clojurebot: java.lang.Exception: Unable to resolve var: P in this context

11:47 mefesto: i'm guessing those algorithms will need access to the results of idiomaticornot.com :)

11:48 gfrlog: idiotic-corn.com

11:48 my apologies if that's an actual site

11:50 robonobo: is NumberFormat.parse significantly slower than Integer.parseInt?

11:51 gfrlog: ,(time (doall (map #(NumberFormat.parse (str %)) (range 10000))))

11:51 clojurebot: java.lang.ClassNotFoundException: NumberFormat.parse

11:51 gfrlog: ,(time (doall (map #(NumberFormat/parse (str %)) (range 10000))))

11:51 clojurebot: java.lang.Exception: No such namespace: NumberFormat

11:51 gfrlog: I give up

11:52 TimMc: robonobo: A) Benchmark it. B) Check the source. C) Which is clearer to a reader of your code?

11:52 no_mind: If the process of writing idiomatic code is not repeatable (hence not testable by a tool), then it is not a scientific process. Even in art and aesthetics, the process is replicable...

11:52 gfrlog: no_mind: why would it be "not repeatable"?

11:53 no_mind: gfrlog: from what I infer from the discussion, idomatic or not requires human judgement...

11:53 mefesto: no_mind: i think it's definitely a subjective thing but as a community there are certain things that are accepted as "a good way" to do things

11:53 churib: chouser: sorry, was away - thanks for your pointers, they helped me!

11:54 TimMc: offby1: I suspect that while there may be a decently long tail of non-idiomaticness, the vast bulk of non-idiomatic stuff you see in this channel will be very similar.

11:55 Trying to write {Java,Python,JS} using Clojure.

11:55 gfrlog: I don't know if this falls into the same category, but there's a lot of "not knowing there was a function for that" you could catch

11:56 TimMc: definitely

11:56 gfrlog: e.g., (swap! a (constantly b)) => (reset! a b)

13:45 devn: Given a list '(2.0 3.14 4.8 9.0)

13:45 how can I convert 2.0 and 9.0 to 2 and 9, but not convert 3.14 and 4.8

13:46 &(map int [9.0 4.25])

13:46 sexpbot: ⟹ (9 4)

13:46 devn: should instead return ##'(9 4.25)

13:46 sexpbot: ⟹ (9 4.25)

13:46 gfrlog: ,(= 7.0 7)

13:46 clojurebot: true

13:46 devn: gfrlog: heh, woops!

13:47 gfrlog: actually my problem still stands

13:47 gfrlog: &(map #(let [n (int %)] (if (= n %) n %)) [9.0 4.25])

13:47 sexpbot: ⟹ (9 4.25)

13:47 devn: because i need to convert these back to strings

13:47 gfrlog: &(map #(str (let [n (int %)] (if (= n %) n %))) [9.0 4.25])

13:47 sexpbot: ⟹ ("9" "4.25")

13:47 devn: gfrlog: not ideal, but that will work

13:47 kind of verbose just to go from n.0 to n

13:47 gfrlog: alternatively, start with strings and remove any #"\.0+$"

13:48 devn: it is.

13:49 devn: I guess this is for display purposes?

13:49 I was about to assert that this couldn't possibly be a common thing, but maybe it would be

13:50 ,(format "%f %f" 3.8 3.0)

13:50 clojurebot: "3.800000 3.000000"

13:51 gfrlog: yeah there oughta be a formatter flag for it

13:51 not "oughta" like there probably is but "oughta" like "why isn't there?"

13:53 ,(format "%f %f" 3.8 3)

13:53 clojurebot: java.util.IllegalFormatConversionException: f != java.lang.Integer

13:53 gfrlog: ,(format "%f %f" 3.8 3.)

13:53 clojurebot: "3.800000 3.000000"

13:54 gfrlog: funny the java docs seem to imply this ought to work

13:54 and that the "#" flag is used to force a decimal point

13:54 $google "The decimal separator will only appear if a digit follows it"

13:54 sexpbot: First out of 2 results is: Formatter (Java 2 Platform SE 5.0)

13:54 http://download.oracle.com/javase/1.5.0/docs/api/java/util/Formatter.html

13:54 gfrlog: I wash my hands of the matter

13:57 robonobo: how would I set a variable that is not in my namespace? clojure-csv needs csv/*delimiter* to be set for the parsing to work.

13:58 gfrlog: robonobo: I suspect (binding) was intended?

13:58 which of course only "sets" the var thread-locally for the code that you pass in

13:59 robonobo: it sets the delimiter for a csv parser

13:59 do i have to use (use) instead of require?

13:59 gfrlog: sure; I mean that you would use the (binding) macro to set it

13:59 no

13:59 you would use it like this:

13:59 assuming the entry-point to your code is the function (run-my-code)

14:00 then you could call (binding [csv/*delimiter* ";"] (run-my-code))

14:00 robonobo: cool, thanks

14:00 gfrlog: sure

14:07 devn: gfrlog: sorry, was taking a shower, but yeah, it's basically that ##(Math/sqrt 4) will return a double

14:07 sexpbot: ⟹ 2.0

14:08 gfrlog: devn: on the off-chance that the only thing you're doing is taking the square roots of squares, I think there's a function in contrib

14:08 devn: I may no longer care about sqrt though, thinking about using bit-and to check if something is a square instead ##(= 0 (bit-and 9 2))

14:08 sexpbot: ⟹ true

14:08 devn: &(= 0 (bit-and 9 5))

14:08 sexpbot: ⟹ false

14:08 gfrlog: devn: if you're checking squareness, I'd use the integer-square-root function in contrib

14:09 devn: gfrlog: nod -- this is for a 4clojure problem actually

14:09 so im working down my stroke count :)

14:09 gfrlog: does that mean you can't use contrib?

14:09 devn: gfrlog: i can use contrib, but it will mean calling it like clojure.contrib.lib/foo

14:10 which kills my score a bit

14:10 TimMc: Oh no, does 4clojure encourage golfing?

14:10 gfrlog: I say character count is a bad metric

14:10 devn: TimMc: it's an option

14:10 gfrlog: should be symbol count or such

14:10 they should just flatten the code and count that

14:10 TimMc: gfrlog: point count :-P

14:10 devn: gfrlog: it actually might be -- here i am a contributor on 4clojure and im not even sure how amalloy decided to measure it

14:11 * devn peers at code

14:11 bendlas: hi folks

14:11 gfrlog: hi bendlas

14:11 devn: hola bendlas

14:11 bendlas: Quick question

14:11 TimMc: hey bendlas

14:11 bendlas: is the following intended?

14:11 ,(boolean 'nil)

14:11 clojurebot: false

14:11 gfrlog: devn: (def square? (comp zero? last clojure.contrib.math/exact-integer-sqrt))

14:12 TimMc: (doc boolean)

14:12 clojurebot: "([x]); Coerce to boolean"

14:12 gfrlog: bendlas: totally intended

14:12 devn: gfrlog: not bad -- i like the use of comp there

14:12 bendlas: why?

14:12 clojurebot: http://clojure.org/rationale

14:12 gfrlog: bendlas: um.

14:12 bendlas: i mean

14:12 gfrlog: in a lot of languages, "false" and "nil" are considered falsy, and everything else is considered truthy

14:12 bendlas: that's my point

14:12 gfrlog: why would you do it differently?

14:13 TimMc: bendlas: Are you familiar with the concept of "logical truth/falsity"?

14:13 bendlas: note, that 'nil is a symbol

14:13 gfrlog: ,(boolean 'nil)

14:13 bendlas: not nil itself

14:13 clojurebot: false

14:13 gfrlog: oh wait okay

14:13 TimMc: ,(type 'nil) # bendlas

14:13 clojurebot: nil

14:13 gfrlog: then forget everything I said and consider me befuddled

14:13 TimMc: ,(type 'foo)

14:13 clojurebot: clojure.lang.Symbol

14:13 gfrlog: TimMc: WHY!?

14:13 ,(type (symbol "nil"))

14:13 clojurebot: clojure.lang.Symbol

14:14 gfrlog: ,(boolean (symbol "nil"))

14:14 clojurebot: true

14:14 gfrlog: okay so there is a 'nil but it is hard to get to

14:14 TimMc: bendlas, gfrlog: Quoting is for names. nil is not a name you'd want to use. :-)

14:14 gfrlog: ,(type (quote nil))

14:14 clojurebot: nil

14:14 TimMc: ,(map type '[1 foo nil])

14:14 clojurebot: (java.lang.Integer clojure.lang.Symbol nil)

14:14 bendlas: mhmm

14:14 gfrlog: TimMc: most of my variables are called nil

14:15 ,(let [nil 12] (+ 13 nil))

14:15 clojurebot: java.lang.Exception: Unsupported binding form:

14:15 TimMc: Common Lisp does this with T, I think.

14:15 ,(type 'true)

14:15 clojurebot: java.lang.Boolean

14:15 devn: "nil pun with care"

14:15 ^--Joy of Clojure

14:15 bendlas: ,(type :nil)

14:15 clojurebot: clojure.lang.Keyword

14:15 gfrlog: TimMc: what witchcraft is this?

14:15 bendlas: ok

14:16 TimMc: bendlas: keywords are pure labels

14:16 ("labels" is not the best word here, but it's what I could come up with)

14:16 bendlas: TimMc: yes, my concept of symbols was, that they are too

14:16 till now

14:16 gfrlog: ,(= (quote true) (symbol "true"))

14:16 clojurebot: false

14:17 TimMc: bendlas: That's something I stumbled over coming from PLT Scheme as well. :-)

14:17 In PLT Scheme, boolean literals use a reader macro: #t, #f

14:17 bendlas: the only difference i was aware of, is that syms wouldn't get interned

14:17 gfrlog: they don't??

14:17 TimMc: ...and thus 'true and 'false are symbols, while true and false are names bound to #t and #f.

14:18 gfrlog: why would you not intern a symbol?

14:18 TimMc: In Clojure, nil, true, and false are compiler literals or something.

14:18 bendlas: gfrlog: because that's what keywords are for

14:18 gfrlog: ,(type '438)

14:18 clojurebot: java.lang.Integer

14:19 bendlas: TimMc: like fn*, ...?

14:19 gfrlog: bendlas: is there no interest in comparing the equality of symbols?

14:19 TimMc: bendlas: Yeah.

14:19 hmm...

14:19 gfrlog: ,(identical? 'timmy 'timmy)

14:19 clojurebot: false

14:19 gfrlog: golly!

14:19 TimMc: ,(type 'fn*)

14:19 clojurebot: clojure.lang.Symbol

14:19 TimMc: hrm

14:19 So, treated a bit differently, of course.

14:20 gfrlog: ,(type 'fn)

14:20 clojurebot: clojure.lang.Symbol

14:20 TimMc: This all makes macro writing much easier, of course.

14:21 bendlas: TimMc: I indeed stumbled upon it while reading macros

14:21 TimMc: (if you need to recognize literals)

14:22 bendlas: wondering why (when-let [x# '~(stuff evaling to nil)] ..) worked

14:22 TimMc: bendlas: I assume you have looked up the difference between ' and `?

14:22 bendlas: TimMc: yes

14:22 TimMc: good

14:22 bendlas: wouldn't make a difference for false, nil, ints ...

14:23 though

14:23 gfrlog: let's add a reader macro for left-curly-quotes and right-curly-quotes

14:23 TimMc: oh no

14:23 gfrlog: oh would be some macro sorcery

14:23 /^oh/it

14:23 s/oh/it

14:23 sexpbot: <gfrlog> /^it/it

14:23 TimMc: haha

14:24 bendlas: ok, true, false, .. literals are already handled in the reader

14:24 try (type (second (read-string "(quote false)")))

14:24 gfrlog: ,(type (second (read-string "(quote false)")))

14:24 clojurebot: java.lang.Boolean

14:25 bendlas: oh, i wasn't aware clojurebot supported read-string

14:25 gfrlog: try first, assume later

14:25 read-string is not any kind of danger

14:25 it's a pure function that has nothing to do with the environment

14:26 bendlas: it does

14:26 gfrlog: what meanest thou?

14:26 bendlas: clojure has an undocumented reader macro

14:26 gfrlog: the reader-eval you mean?

14:26 bendlas: which allows arbitrary evaluation at read time

14:26 yep

14:26 gfrlog: let's try it

14:27 TimMc: *read-eval* is bound to false

14:27 gfrlog: ,(read-string "=(+ 3 4)")

14:27 clojurebot: =

14:27 * TimMc pokes gfrlog with a #

14:27 gfrlog: ouch

14:27 ,(read-string "#=(+ 3 43)")

14:27 clojurebot: java.lang.RuntimeException: java.lang.Exception: EvalReader not allowed when *read-eval* is false.

14:27 bendlas: k

14:28 gfrlog: so we were both right

14:28 TimMc was also right

14:28 bendlas: nice :)

14:29 anyway, makes sense that the reader recognizes data literals

14:29 and that quote just passes them

14:29 TimMc: Maybe they even use the same code.

14:30 gfrlog: you could write a quote* macro that would transform all literals back to symbols

14:30 TimMc: ,#=(+ 3 4) # try that in your repl

14:30 clojurebot: EvalReader not allowed when *read-eval* is false.

14:30 gfrlog: ,(print-dup (symbol "83"))

14:30 clojurebot: java.lang.IllegalArgumentException: Wrong number of args (1) passed to: core$fn--3893$fn

14:30 gfrlog: wtf

14:30 bendlas: TimMc: not the same code

14:30 ,(quote (symbol "false"))

14:30 clojurebot: (symbol "false")

14:31 bendlas: srry

14:31 TimMc: ,(quote ~(symbol "false"))

14:31 clojurebot: (clojure.core/unquote (symbol "false"))

14:31 TimMc: hrmf

14:31 gfrlog: ,(print-dup (symbol "okay"))

14:31 clojurebot: java.lang.IllegalArgumentException: Wrong number of args (1) passed to: core$fn--3893$fn

14:31 TimMc: I don't think that demonstrates anything.

14:31 bendlas: (type (quote #=(symbol "false")))

14:32 evals to clojure.lang.Symbol

14:32 TimMc: comma in front

14:32 Oh right, restrictions.

14:32 bendlas: no ;)

14:32 so it's purely the reader

14:32 which definitely is the sane way to do it

14:33 gfrlog: ,(print-dup :what)

14:33 clojurebot: java.lang.IllegalArgumentException: Wrong number of args (1) passed to: core$fn--3893$fn

14:33 gfrlog: clearly I don't know how to use that function

14:33 TimMc: ,(doc print-dup)

14:33 clojurebot: "; "

14:33 TimMc: !

14:33 gfrlog: I saw that the other day

14:33 TimMc: Ah, a defmulti.

14:33 gfrlog: ,(doc *print-dup*)

14:33 clojurebot: "; When set to logical true, objects will be printed in a way that preserves their type when read in later. Defaults to false."

14:34 gfrlog: ,(binding [*print-dup* true] (prn :what)))

14:34 clojurebot: :what

14:34 gfrlog: oh good

14:34 ,(binding [*print-dup* true] (prn (symbol "284")))

14:34 clojurebot: 284

14:34 gfrlog: oooh

14:34 that doesn't look good

14:34 ,(type (symbol "283"))

14:34 clojurebot: clojure.lang.Symbol

14:34 TimMc: That's cuz you're trying to fool it.

14:35 gfrlog: well, it could at least throw an error

14:35 TimMc: That would be... unidiomatic. :-P

14:35 * gfrlog pokes TimMc with a &

14:35 TimMc: eep

14:36 bendlas: what about

14:36 ,(binding [*print-dup* true] (prn (symbol "284"))),(binding [*print-dup* true] (prn 'foo))

14:36 clojurebot: 284

14:36 bendlas: ,(binding [*print-dup* true] (prn 'foo))

14:36 clojurebot: foo

14:37 bendlas: sry

14:37 no quote either

14:37 gfrlog: not supposed to have one

14:37 the expectation is that calling ##(read-string "foo") will return the same object

14:37 sexpbot: ⟹ foo

14:37 gfrlog: which it does -- a symbol

14:37 TimMc: gfrlog: So how can you tell that 284 isn't '284?

14:38 gfrlog: amalloy said the other day that this was a good use case for reader eval

14:38 bendlas: gfrlog: see

14:38 gfrlog: thus it should output "#=(symbol \"284\")"

14:38 dnolen: core.logic tabling fixed, got a tiny bit faster, now back to predicate dispatch

14:38 gfrlog: ,(type (symbol 284))

14:38 clojurebot: java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String

14:38 fliebel: dnolen: yay!

14:40 dnolen: Right now I use it for the score function of my crappy genetic algorithm. It tries to do some weird variant of the traveling salesman problem.

14:40 TimMc: ,(binding [*print-dup* true] (pr-str '(foo)))

14:40 clojurebot: "(foo)"

14:40 gfrlog: the Traveling Salesturtle Problem?

14:42 ,(let [well-behaved? (fn [ob] (= ob (read-string (binding [*print-dup* true] (prn ob)))))] (map well-behaved? ['tommy nil false 388 :what]))

14:42 clojurebot: java.lang.NullPointerException

14:42 gfrlog: crud

14:42 ,(read-string nil)

14:42 clojurebot: java.lang.NullPointerException

14:43 gfrlog: (prn nil)

14:43 ,(prn nil)

14:43 clojurebot: nil

14:43 gfrlog: golloshums

14:43 TimMc: gfrlog: read-*string*

14:43 fliebel: gfrlog: haha, actually, trying to get the best route for this: http://www.google.com/search?q=ticket+to+ride&tbm=isch

14:43 TimMc: wait

14:43 I see

14:44 gfrlog: oh whoops

14:44 ,(let [well-behaved? (fn [ob] (= ob (read-string (binding [*print-dup* true] (pr-str ob)))))] (map well-behaved? ['tommy nil false 388 :what]))

14:44 clojurebot: (true true true true true)

14:44 gfrlog: ,(let [well-behaved? (fn [ob] (= ob (read-string (binding [*print-dup* true] (pr-str ob)))))] (map well-behaved? ['tommy nil false 388 :what (symbol "388")]))

14:44 clojurebot: (true true true true true false)

14:44 gfrlog: there it is

14:44 TimMc: hrm

14:45 gfrlog: ,(let [well-behaved? (fn [ob] (= ob (read-string (binding [*print-dup* true] (pr-str ob)))))] (map well-behaved? ['tommy nil false 388 :what (symbol "388") (symbol "foo bar")]))

14:45 clojurebot: (true true true true true false false)

14:45 gfrlog: there's another case

14:45 was discussing this a few days ago

14:45 somebody (chouser?) said this was an acknowledged syntactical shortcoming that could be fixed in the future

14:45 TimMc: Unnatural symbols, right.

14:46 PLT Scheme uses '|foo bar|

14:46 gfrlog: but certainly "#=(...)" would be a palatable solution in the meantime

14:46 yeah, that's what he mentioned

14:46 TimMc: or something similar (also it is called "Racket" now I guess)

14:46 gfrlog: also :|foo bar| for keywords

14:47 no_mind: some days ago, someone pointed me a source code on github that will search files in a directory and load namespaces. I cant find that link... any pointers ?

14:47 gfrlog: so in that cause would you think '|nil| evals to nil or a symbol?

14:48 TimMc: gfrlog: I would say that '|...| indicates an intention to use a weird symbol name... so symbol.

14:48 bendlas: adree

14:48 gfrlog: I also adree

14:48 bendlas: :D

14:49 TimMc: ,'|

14:49 clojurebot: |

14:49 TimMc: '|ohno|

14:49 ,'|ohno|

14:49 clojurebot: |ohno|

14:49 TimMc: I recall that Racket uses backslashes as well.

14:49 gfrlog: awesome, it'd be backwards incompatible

14:49 bendlas: better be

14:50 TimMc: gfrlog: Hasn't stopped Clojure before... >:-(

14:50 gfrlog: ,:|haha-what|

14:50 clojurebot: :|haha-what|

14:50 bendlas: what else to do with ,(symbol "||")

14:50 gfrlog: that'd be '|\|\||

14:51 bendlas: ... when allowing backslash escapes

14:51 gfrlog: yes

14:51 which we would want

14:51 which is your point

14:51 bendlas: indeed

14:51 gfrlog: so once again we are in adreement

14:51 bendlas: vrry mchu adree

14:52 arohner: no_mind: c.c.find-namespaces

14:52 bendlas: ;)

14:53 gfrlog: BOO: ##(< \A \Z)

14:53 sexpbot: java.lang.ClassCastException: java.lang.Character cannot be cast to java.lang.Number

14:53 no_mind: arohner: it wants find-namespaces . IThe code will look for clj files in a directory path and load namespaces

14:54 chegibari: Hello.

14:54 gfrlog: how do I check if a char is between \a and \z without typing too much?

14:54 hi chegibari

14:54 TimMc: gfrlog: I suppose that depends on your encoding. :-)

14:54 gfrlog: I wants me the ascii

14:54 chegibari: Does clojure have type annotations and static type-checking?

14:54 gfrlog: chegibari: I'm going to say no and then somebody will contradict me

14:54 raek: gfrlog: ##(<= (int \a) (int \p) (int \z))

14:54 sexpbot: ⟹ true

14:55 bendlas: chegibari: only annotations

14:55 gfrlog: raek: you have my gratitude

14:55 raek: TimMc: strings do not have encodings

14:55 sequences of bytes do

14:55 TimMc: raek: I suppose I meant "collation" then.

14:56 gfrlog: I once used a sequence of bites to consume a cake

14:56 raek: TimMc: indeed important

14:56 TimMc: Of course, I doubt there are an collations that change the ordering of a-z

14:57 raek: when you turn a character into an int, you get its unicode code point number

14:57 chegibari: bendlas: what are they used for?

14:57 raek: so snippet of code only works for character ranges that happens to be ranges in unicode

14:57 ^ my

14:58 gfrlog: incidentally, I refactored to ##(apply <= (map int [\a \p \z]))

14:58 sexpbot: ⟹ true

14:58 gfrlog: because I am stupid.

14:58 * TimMc adrees

14:58 gfrlog: I like my code dry and unreadable

14:58 I use -> and ->> whenever it is syntactically possible

14:59 TimMc: (map \ [a p z]) :-P

14:59 oh!

14:59 ,(apply <= (map int "apz"))

14:59 clojurebot: true

15:00 gfrlog: anybody up for a Fun CS Theorem?

15:00 TimMc: yes but that doesn't help when \p is not hard-coded

15:01 raek: ,(<= \a \z)

15:01 clojurebot: java.lang.ClassCastException: java.lang.Character cannot be cast to java.lang.Number

15:01 gfrlog: raek: that's how it all started

15:02 bendlas: chegibari: typecasts instead of reflection => faster

15:03 so .. pure optimization hints

15:03 except when you mean java annotations

15:03 those can be used too, for compat

15:03 gfrlog: when you add type hints, does it just add a second method signature+implementation?

15:04 i.e., one with specific types and one with Objects?

15:04 bendlas: no, always objects

15:04 but ((TargetType) x).targetMethod()

15:04 gfrlog: will that not file if x is not a TargetType?

15:04 fail*

15:05 bendlas: instead of x.getClass().getMethod("targetMethod") ...

15:05 it will

15:05 gfrlog: I thought type hints didn't change the functionality

15:05 bendlas: that was a lie

15:05 ;)

15:05 gfrlog: ,(let [foo (fn [^Integer x] (+ 3 x))] (+ 5))

15:05 clojurebot: 5

15:05 gfrlog: ,(let [foo (fn [^Integer x] (+ 3 x))] (foo 5))

15:05 clojurebot: 8

15:05 gfrlog: ,(let [foo (fn [^Integer x] (+ 3 x))] (foo 5.0))

15:05 clojurebot: 8.0

15:06 gfrlog: what's that then?

15:06 probably not a typehint

15:06 I don't know how to make one

15:06 bendlas: it's just used when reflection had to be used otherwise

15:06 gfrlog: kay so how can me create an example?

15:06 s/me/we

15:06 sexpbot: <gfrlog> kay so how can we create an example?

15:06 gfrlog: s/example/elephant

15:07 * gfrlog hrmphs

15:07 dnolen: gfrlog: type hints have nothing to do w/ signatures. they are expression oriented.

15:07 TimMc: s/./*/

15:07 sexpbot: <TimMc> ***************************

15:07 bendlas: gfrlog: ((fn [s] (.length s)) "")

15:08 ,((fn [s] (.length s)) "")

15:08 clojurebot: 0

15:08 * chegibari is more confused than before :)

15:08 gfrlog: bendlas: is there a second half of that example forthcoming?

15:08 bendlas: ,((fn [s] (.length s)) 5)

15:08 clojurebot: java.lang.IllegalArgumentException: No matching field found: length for class java.lang.Integer

15:09 bendlas: ,((fn [^String s] (.length s)) 5)

15:09 clojurebot: java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String

15:09 bendlas: there you have it

15:09 dnolen: in 1.3.0, type hinting support for primitives does allow actually defining fn signatures.

15:10 bendlas: the only real difference comes into play, when you'd pass an object with a .length method

15:10 other than a string

15:10 chegibari: http://stackoverflow.com/questions/4204629/clojure-static-typing-part-2

15:10 Now I got what you meant

15:10 gfrlog: ,(.length [])

15:10 clojurebot: 0

15:11 gfrlog: ,((fn [^String s] (.length s)) [:okay :this :makes "Sense but I'm still surprised"])

15:11 clojurebot: java.lang.ClassCastException: clojure.lang.PersistentVector cannot be cast to java.lang.String

15:11 gfrlog: I think "type hint" is a poor name

15:12 TimMc: ,5 gfrlog: Only the first form is read

15:12 clojurebot: 5

15:12 dnolen: gfrlog: what would you call it instead?

15:12 gfrlog: TimMc: Only the first form is red

15:12 dnolen: I'm not sure. Is there any reason "type declaration" would be inappropriate/misleading?

15:13 dnolen: gfrlog: that is exactly what it is not.

15:13 gfrlog: oh that does mean a different thing doesn't it

15:13 well then what means what I'm thinking of?

15:14 "type assertion"? "type restriction"? "type party"? "typewriter"?

15:17 "hints" just don't sound like something that changes the meaning of the code

15:17 TimMc: gfrlog: Nevermind, misread your example.

15:17 Anti-reflection assertions.

15:17 bendlas: gfrlog: it's really a hint. It's like saying to the compiler: "Hey, I know about the thing with dynamic typing and such, but when you get speed out of it, you can safely assume x being a String"

15:17 TimMc: Dispatch explicitizers.

15:18 gfrlog: :-/

15:20 TimMc: Spline reticulators.

15:20 bendlas: lol wut?

15:21 TimMc: $google reticulating splines

15:21 sexpbot: First out of 513 results is: SimCity 2000 - Wikipedia, the free encyclopedia

15:21 http://en.wikipedia.org/wiki/SimCity_2000

15:22 gfrlog: I hope that sounds familiar for a reason

15:23 article does not explain how the phrase was used

15:23 * chegibari takes note: never ask about type hints in the #closure channel. underlined in red. twice

15:23 chegibari: :)

15:23 TimMc: nor in the #clojure channel, for that matter

15:23 gfrlog: dang

15:23 chegibari: opss... sorry for the mispelling

15:23 gfrlog: beat me to it

15:24 doesn't look like there's anybody in the #closure channel

15:25 bendlas: what a shame, that should be a first-class channel on freenode

15:26 chegibari: it was just a mispelling, I meant #closure

15:26 TimMc: hee

15:26 bendlas: seems more like an anonymous inner channel

15:27 gfrlog: if this sentence is true, then santa clause exists

15:28 * TimMc suffers StackOverflowError in expand-predicate.clj

15:34 bendlas: quick poll: which lib would you use for rewriting java source code

15:34 bytecode instrumentation would be acceptable too, if it's more convenient

15:39 no_mind: why searching #clojure log is not showing results after feb 2011 ?

15:40 stuartsierra: maybe its indexer is broken?

15:41 no_mind: stuartsierra: but the search box says "google custom search"

15:41 stuartsierra: oh

15:42 gfrlog: golly. writing an elegant function to unlabel a sequence is not easy.

15:43 (lazily)

15:43 stuartsierra: unlabel?

15:43 gfrlog: yeah. I want to map a sequence such that (2 3 2) = (3 1 3) != (2 3 3)

15:43 so the first two would become (0 1 0) while the last becomes (0 1 1)

15:44 stuartsierra: not sure I follow.

15:45 gfrlog: the goal is to be able to say, given two sequences, whether once can have its elements mapped to become the other

15:45 (2 3 2) can become (3 1 3) if we change do (map {2 3, 3 1} coll)

15:45 s/change//

15:45 sexpbot: <gfrlog> (2 3 2) can become (3 1 3) if we do (map {2 3, 3 1} coll)

15:45 stuartsierra: I see

15:45 gfrlog: so to check this effeciently I am normalizing the sequences

15:46 then just check if the normalized versions match

15:46 it would be easy to do with (loop), which I don't believe is lazy

15:46 stuartsierra: no it's not

15:46 gfrlog: so I am using (iterate) and it is getting clunky

15:47 stuartsierra: I guess I'd reduce over both sequences, building up a map of translations. If there's a contradiction, stop & return false.

15:47 gfrlog: in reality I don't have just two sequences

15:47 raek: bendlas: objectsweb asm can be used for transforming classes on bytecode level (http://asm.ow2.org/)

15:47 gfrlog: I have a huge collection that I'm trying to index so I can search against it

15:48 raek: bendlas: this blog compares some bytecode libs (look for the Generating JVM bytecode articles) http://elliotth.blogspot.com/search?updated-max=2008-04-06T03%3A14%3A00Z&max-results=10

15:49 gfrlog: thus the normalization tactic

15:49 I'll probably just use (lazy-seq)

15:50 bendlas: raek: thanks, I'll try it

15:50 depends if asm can read not-quite-legal java bytecode

15:51 i.e. classes with "native" constructors, which don't exist per standard

15:51 raek: not-quite-legal? does it go through the validator?

15:51 bendlas: guess not

15:51 the normal class loading mechanism pukes on it

15:52 let me explain

15:52 RIM doesn't think they need to conform to java in order to implement it

15:53 so their API jar for blackberries contains classes with said constructors

15:53 i want to use it with aspectME

15:54 which already uses objectweb asm

15:54 stuartsierra: bendlas: could you stub out those classes with valid Java bytecode?

15:54 bendlas: I could

15:54 that's what i want to do

15:55 but not manually

15:55 i already have decompiled java files

15:55 so I could use a pure source transforming lib

15:55 or bytecode rewriting

15:56 the latter given a lib which doesn't puke

15:58 gfrlog: any easy way I can check that a seq is longer than 3 elements without consuming the whole thing?

15:58 stuartsierra: gfrlog: (> 3 (count (take 4 the-seq))) ?

15:58 gfrlog: ,(take 4 [])

15:58 clojurebot: ()

15:59 gfrlog: heck yes that's it.

15:59 bendlas: ,(nth [1 2] 2 nil)

15:59 clojurebot: nil

15:59 bendlas: ,(nth [1 2 3] 2 nil)

15:59 clojurebot: 3

15:59 gfrlog: bendlas: that is also the correct answer

15:59 forgot that nth had an extra arg

15:59 stuartsierra: ,(nth [1] 3 nil)

15:59 clojurebot: nil

15:59 stuartsierra: ok

15:59 that's better

16:00 bendlas: thx

16:04 a_robbins: trying to use appengine-magic. Getting java.lang.NoClassDefFoundError: Could not initialize class seo_analyzer.app_servlet . I already added an :aot [seo_analyzer.app_servlet] directive in my project.clj file. What else needs to happen?

16:04 stuartsierra: that should probably be :aot [seo-analyzer.app-servlet]

16:05 a_robbins: stuartsierra: Compiling blows up after that change. Caused by: java.lang.Exception: namespace 'seo-analyzer.app-servlet' not found after loading '/seo_analyzer/app_servlet'

16:06 stuartsierra: then there's probably something wrong with the source file app_servlet.clj

16:07 like the `ns` declaration

16:07 a_robbins: stuartsierra: http://paste.pocoo.org/show/392855/ See anything?

16:07 That code was autogenerated by appengine-magic

16:07 stuartsierra: ns seo-analyzer.app_servlet is wrong, should be ns seo-analyzer.app-servlet

16:08 In Clojure code, always use hyphens. In file/directory names, always use underscores.

16:13 bendlas: hey stuartsierra, how is cljque coming along?

16:14 stuartsierra: slowly

16:14 a_robbins: stuartsierra: That fixed the compile step. Thanks!

16:14 stuartsierra: a_robbins: 'welcome

16:15 bendlas: You can see some of my discussions with Rich here: http://dev.clojure.org/display/design/Asynchronous+Events

16:15 fliebel: how can I force lein to check deps?

16:15 bendlas: thanks

16:15 I really liked the idea, when I saw your presentation

16:16 stuartsierra: thanks. Then challenge which Rich put me on was to make it more purely function, less side-effectful.

16:16 s/function/functional/

16:16 sexpbot: <stuartsierra> thanks. Then challenge which Rich put me on was to make it more purely functional, less side-effectful.

16:19 gfrlog: why is 3 the wrong number of args to pass to if-let?

16:21 bendlas: I see

16:21 gfrlog: nevermind. still don't get the error message though...

16:21 ,(if-let [x 10])

16:21 clojurebot: java.lang.IllegalArgumentException: Wrong number of args (3) passed to: core$if-let

16:22 bendlas: ,(if-let [x 10] 'then 'else)

16:22 clojurebot: then

16:22 gfrlog: bendlas: right, I know how to use it -- it's just a strange error message

16:22 I guess core$if-let probably doesn't refer to the macro

16:23 bendlas: ,`if-let

16:23 clojurebot: clojure.core/if-let

16:23 bendlas: hmm ..

16:23 fliebel: :( I'm slowly running out of heap space.

16:23 gfrlog: ,core$if-let

16:23 clojurebot: java.lang.Exception: Unable to resolve symbol: core$if-let in this context

16:24 bendlas: ,clojure.core$if_let

16:24 clojurebot: clojure.core$if_let

16:25 gfrlog: ,(type clojure.core$if_let)

16:25 clojurebot: java.lang.Class

16:26 gfrlog: (sort clojure-conj strange-loop)

16:34 bendlas: gfrlog: that seems to be the standard message when calling a macro with false arity

16:34 ,(let)

16:34 clojurebot: java.lang.IllegalArgumentException: Wrong number of args (2) passed to: core$let

16:34 gfrlog: not clear where the number comes from

16:34 bendlas: with (-> args count (+ 2))

16:36 maybe &form and what's the other magic arg called for macros?

16:36 gfrlog: &form is not a magic arg

16:36 sexpbot: java.lang.Exception: Unable to resolve symbol: form in this context

16:37 bendlas: right

16:37 but there are two magic parameters available inside a (defmacro ..)

16:37 gfrlog: that's news to me

16:39 bendlas: hmm, forgot how they were called

16:39 stuartsierra: &env and &form

16:39 sexpbot: java.lang.Exception: Unable to resolve symbol: env in this context

16:40 gfrlog: the best way to learn is to assert something and wait till you're contradicted

16:40 bendlas: thanks

16:47 gfrlog: something to play (defmacro silly [x] `(with-meta ~x {:form '~&form :env '~(keys &env)}))

16:48 gfrlog: bendlas: I am going to play with that. And then I will be a more knowledgable person.

16:53 bendlas: maybe those get passed to the compiled macro as first and second arg, with any explicit arguments last

19:06 ChristianMarks: More noob code -- generation of a random permutation and computation of its order in clojure: http://paste.lisp.org/+2M9K

19:11 gfrlog: ChristianMarks: what is a permutation's order?

19:11 ChristianMarks: The order of a permutation p is the least positive integer n such that p^n = 1

19:12 gfrlog: how is p^n defined?

19:12 ChristianMarks: Examples: the identity permutation has order 1 and a transposition has order 2

19:12 This is functional composition

19:12 gfrlog: so p^n is also a permutation?

19:12 ChristianMarks: Yes

19:13 for any n

19:13 gfrlog: so when you said p^n = 1 you're using 1 as shorthand for the identity permutation?

19:13 ChristianMarks: Yes

19:13 gfrlog: I am now tracking.

19:13 what is the maximum order for a permutation?

19:14 tomoj: ChristianMarks: what for?

19:14 ChristianMarks: For a permutation of length n, n!

19:15 gfrlog: hm

19:15 tomoj: I mean, are you doing anything with random permutations, or was this just an exercise?

19:15 gfrlog: his namespace is knuth, so I'm betting an exercise

19:15 ChristianMarks: The order of an element of a group divides the order of the group. The symmetric group on n elements has order n!

19:16 It's from an article that Knuth wrote, based on an algorithm of Gower

19:16 It's not a homework exercise

19:16 gfrlog: I meant exercise more generally

19:16 as in "not headed for production"

19:16 ChristianMarks: just a translation of code

19:16 Well, I guess if it were headed for production it would need work

19:17 gfrlog: so apparently most permutations have a small order, nowhere near n!

19:17 tomoj: I'm trying to get random permutation code into production

19:17 ChristianMarks: Really

19:17 gfrlog: tomoj: shuffle?

19:17 ChristianMarks: Well, you saw the paste

19:17 http://paste.lisp.org/+2M9K

19:17 shuffle does this trivially. Returns a vector, apparently

19:18 (shuffle (range 10))

19:18 gfrlog: ChristianMarks's code wasn't about generating permutations -- he used shuffle directly. he was computing the order.

19:18 ChristianMarks: Right

19:18 tomoj: I have no loops in the functions I use because I apply the permutations on sparse "vectors" in maps

19:18 gfrlog: maps from ints to objectsL

19:18 tomoj: but I don't need to compute order, and don't see how I could with my ->> and seq fns

19:18 gfrlog: ?

19:19 ChristianMarks: I used the associativity of the least common multiple -- well, maybe I could eliminate the loop/recur pairs

19:19 gfrlog: ChristianMarks: I'm still wondering what kind of permutation has order n!

19:19 tomoj: I'm still a bit iffy on what you're doing

19:20 tomoj: https://gist.github.com/086a50ba2a402fb6ea2e

19:20 but the properties of random permutations interests me, too bad I forgot group theory

19:21 ChristianMarks: So am I

19:21 :)

19:22 gfrlog: tomoj: is it doing what you want it to?

19:23 tomoj: I think so

19:24 gfrlog: tomoj: your random-permutation function could be abbreviated as (shuffle (range n)), no?

19:24 tomoj: then how do you apply a permutation?

19:24 oh, stick that into a vector?

19:24 gfrlog: same way -- vectors are also fns

19:24 oh right

19:24 so (-> n range shuffle vec)

19:25 or (comp vec shuffle range)

19:25 tomoj: :D

19:26 gfrlog: still trying to figure out the permute function

19:26 tomoj: ouch, don't pass zero args to that!

19:26 gfrlog: to what?

19:26 tomoj: (comp vec shuffle range)

19:26 gfrlog: no, I wouldn't think you'd want to

19:27 ,((comp vec shuffle range) 10)

19:27 clojurebot: [9 3 4 5 1 6 8 7 0 2]

19:27 ChristianMarks: I'm sorry, the maximal order of an element of the symmetric group depends on the least common multiple of all partitions of the numbers from 1 to n, by definition oF the cycle decomposition

19:27 http://mathworld.wolfram.com/LandausFunction.html

19:27 gfrlog: ChristianMarks: woo hoo. I did a buncha your random perms for n=12 and the biggest order I got was 60.

19:27 ChristianMarks: That's the reason

19:28 gfrlog: so 60 is probably the max then?

19:28 ChristianMarks: Yes

19:28 gfrlog: tomoj: I'm gonna say that your permute function is equivalent to:

19:29 (fn permute [_ v] (zipmap (shuffle (range (count v))) (vals v)))

19:29 or (fn permute [p v] (zipmap p (vals v))), where p can just be a seq

19:30 for that matter, if you're just going to reading the result, you could just do (-> v vals shuffle vec) and be done with it

19:30 ChristianMarks: gfrlog: it's exactly 60, according to the Online Encyclopedia of Integer Sequences: http://oeis.org/A000793

19:31 gfrlog: what a swell encyclopedia that is

19:31 ChristianMarks: I'm combinatorially rusty!

19:31 tomoj: gfrlog: I don't understand how that works yet, how do you represent the permutation as a seq?

19:32 gfrlog: tomoj: you don't really need a permutation -- all you're doing is rekeying your map with random nums in (range n)

19:32 tomoj: (I also need to use my shuffle-rand which accepts a Random to use)

19:32 right, but I need reusable permutations

19:32 gfrlog: okay, then (shuffle-rand (range n)) will work

19:32 i.e., doesn't have to be a vec

19:33 because you use zipmap

19:33 which just uses it as a seq

19:33 tomoj: what is the representation of your v above?

19:33 mine are maps from indices to values for sparse high-dimensional vectors

19:33 gfrlog: ,(let [m {:hoo 38, :boy 12, :yeah 384, :okay 49}] (zipmap (shuffle (range (count m))) (vals m)))

19:33 clojurebot: {3 49, 0 384, 1 12, 2 38}

19:34 gfrlog: tomoj: v is a map, I assume. the second argument to permute

19:34 tomoj: right, but I need the permutation to be independent of the order of the vals in the map

19:34 I may still not understand the zipmap approach

19:34 gfrlog: ,(let [m {:hoo 38, :boy 12, :yeah 384, :okay 49}] (zipmap (shuffle (range (count m))) (vals m)))

19:34 clojurebot: {1 49, 3 384, 0 12, 2 38}

19:35 gfrlog: ,(let [m {:hoo 38, :boy 12, :yeah 384, :okay 49}] (zipmap (shuffle (range (count m))) (vals m)))

19:35 clojurebot: {2 49, 0 384, 1 12, 3 38}

19:35 tomoj: would I need a sorted map for the vectors?

19:35 gfrlog: no vectors involved

19:35 tomoj: the "vectors" I mean.. the maps, v

19:35 or m

19:35 gfrlog: no, don't need sorted map

19:36 what're you doing with the output of this?

19:38 ChristianMarks: I see -- zipmap creates an "assholeciation" list

19:38 gfrlog: wtf

19:38 tomoj: huh, it seems to work

19:38 ChristianMarks: (pardon my scatalogical mnemonics)

19:39 ,(zipmap [0 1 2] ['a 'b 'c])

19:39 clojurebot: {2 c, 1 b, 0 a}

19:39 gfrlog: you mean it creates a map?

19:39 ChristianMarks: Yes

19:39 tomoj: https://gist.github.com/9fd979fdaef47ea67da0

19:39 wait

19:39 that uses the random up twice

19:40 coincidence that the answers matched :)

19:40 ChristianMarks: ,(vals (zipmap [0 1 2] ['a 'b 'c]))

19:40 clojurebot: (c b a)

19:41 gfrlog: tomoj: I asked what you're going to do with the result because any map from (range n) to stuff is equivalent to a vector of stuff

19:41 at least when you're reading it

19:41 so you could have (def permute (comp vec shuffle-rand))

19:42 tomoj: https://gist.github.com/35f2c6854ad0e721cf89

19:43 gfrlog: i.e., {1 3, 0 1} is the same as [1 3]

19:43 tomoj: these maps represent sparse high-dimensional vectors of integers, which will be added together and compared with cosine similarity

19:43 right

19:43 ChristianMarks: Well, at least no one said my code was utter crap

19:44 gfrlog: ChristianMarks: your code worked

19:44 like utter crap

19:44 tomoj: but the dimension could be 2000 or 5000 or 10000 or maybe even the entire range of the longs, say...

19:44 gfrlog: tomoj: so that means that the keys in the map are like the indices of the vector?

19:44 ChristianMarks: I guess it could be vastly improved

19:44 tomoj: gfrlog: right

19:44 gfrlog: ChristianMarks: I have no idea really, I didn't look at it too close :)

19:45 ChristianMarks: my guess is that you don't need (loop) though.

19:45 ChristianMarks: Oh, the diss was obligatory.

19:45 gfrlog: I overused loop all the time when I was first learning

19:45 first places to look for replacing it are (for) and (reduce)

19:45 ChristianMarks: Trying to do it in constant space

19:46 gfrlog: tomoj: so is the output expected to have the same keys as the input?

19:46 e.g., {100 "hey", 8323 "yeah"} => {100 "yeah", 8323 "hey"} ?

19:46 tomoj: the output of permute probably won't, unless the permutation is the identity

19:47 gfrlog: cuz the way you have it, the map goes in sparse but comes out dense

19:47 tomoj: but a call to shuffle-rand with two randoms with the same seed should dtrt with respect to the keyspace no matter which keys happen to be filled in the maps

19:47 gfrlog: tomoj: you're ignoring the keys of the input maps

19:48 do you want to reuse the keys?

19:48 tomoj: ah, I see

19:48 gfrlog: sounds like we want to go back to zipmap

19:48 tomoj: this seemed to work https://gist.github.com/2557adecf75110bbee22

19:49 gfrlog: tomoj: did you try it on a sparse map?

19:49 I think what you want is:

19:49 tomoj: yes, the keys come out different

19:50 but it is still a sparse map

19:50 each key in the input is permuted to get the key in the output, but you still have the same number of keys, and the order of the keys in the input/output never matters

19:50 gfrlog: aren't the keys in the output (range n)?

19:51 tomoj: no, v there is a vector like {1781 -1, 1488 1, 195 -1, 1094 1, 1799 -1, 518 1, 560 -1, 547 1}

19:51 er, a map..

19:51 gfrlog: and the output map also has (1781 1488 195 1094 1799 518 560 547) as its keys?

19:52 tomoj: no, p is applied to each input key

19:52 gfrlog: so you're not permuting within the keys of that map, you're permuting within the whole space of keys?

19:53 does that mean your permutation vector is huge rather than ~7 elements?

19:53 tomoj: yes, 1800 elements

19:53 gfrlog: you said earlier that the keyspace could be the whole range of Longs

19:53 tomoj: maybe..

19:53 haven't figured out how to implement that yet

19:54 gfrlog: presumably if it is the whole range of longs, the space of keys that you're actually using would be much smaller right?

19:54 tomoj: but even at 10000 dimensions, it'll be OK

19:54 yeah

19:55 gfrlog: so are you interested in a lazy permutation that would work for that case?

19:55 tomoj: so there the trick would have to be, I think, to use a skippable rng to compute the elements of the permutation you need

19:55 gfrlog: what is a skippable rng?

19:56 tomoj: there are tricks you can use with certain kinds of pseudorandom number generators to 'skip' forwards in the randomness

19:56 so say you're using java.util.Random to generate random longs

19:56 gfrlog: oh I see

19:56 tomoj: and you want the billionth

19:56 gfrlog: and you're hoping that's a quick operation instead of O(billion)?

19:56 tomoj: it actually has to crank through, but there is at least one java implementation which can do it in constant time

19:57 gfrlog: I'm thinking you can do something else with a memoized function

19:57 tomoj: problem is... the whole basis of this is compression and using the longs amounts to virtually no compression

19:58 gfrlog: I'm not sure what you mean by that

20:01 I bet you could use an atom instead of a random seed...

20:01 tomoj: the idea is you can compress observations in a high dimensional space (say, the size of the vocabulary of a language) to a lower dimensional space (say, 1-10 thousand) by using random sparse vectors

20:01 then you can represent ordered/structured composites of observations using random permutations

20:02 gfrlog: what's a composite of observations?

20:02 tomoj: like "the dog runs"

20:02 gfrlog: ah ha

20:03 so a vector then is...a bag of words?

20:03 ChristianMarks: You map back into the higher dimensional space by creating a random permutation of elements of the lower dimensional space?

20:04 tomoj: I never really map back into the higher dimensional space

20:05 ChristianMarks: But you create composites from elements of the lower dimensional space

20:05 tomoj: it's like the vector space model for cosine similarity based queries, where there they use the high-dimensional space and reduce everything by matrix operations to a low dimensional space

20:06 gfrlog: if you're using sparse vectors anyhow, why are lower dimensions better?

20:06 tomoj: except I just run those vectors through a random mapping into the low dimensional space to begin with

20:06 right

20:06 if you add enough sparse vectors together it starts not to look sparse

20:07 ChristianMarks: Well, gotta hit the wikipedia for the cosine similarity measure

20:07 tomoj: so if my dimensionality is too small, they fill up and could be better implemented as vectors anyway

20:07 clojurebot: Ik begrijp

20:08 ChristianMarks: Oh, this is obvious

20:08 gfrlog: so how do "random sparse vectors" help you reduce the dimensions?

20:09 tomoj: http://en.wikipedia.org/wiki/Johnson%E2%80%93Lindenstrauss_lemma

20:10 if you map the high-dimensional space through a random projection using a matrix with a certain distribution, the projection preserves pairwise distance with bounded error

20:10 in the case of the vector space model for language where the high-dimensional space has an axis for each word, this is equivalent to generating a random sparse vector for each word

20:11 gfrlog: which is a lot of random sparse vectors

20:11 lazy matrix multiplication is an interesting idea

20:12 you said mapping down to 1000-10000 dimensions -- I didn't think natural languages had many more words than that anyhow

20:14 ChristianMarks: That's a cool embedding theorem

20:15 tomoj: well, SVD is popular here, so I guess the vocabulary size is too big to be practical

20:16 ChristianMarks: You take a random orthogonal projection, or just any projection

20:16 gfrlog: I have this good idea for a lazy permutation function, but it would require a tree algorithm, which makes my head hurt

20:16 tomoj: I haven't actually done much of anything with any of these vectors, but there is research on using random 1000-10000 dimensional spaces

20:18 gfrlog: if only vectors had constant insertion time then that would work

20:19 maybe a sorted set... hmmm

20:19 ,(doc sorted-set)

20:19 clojurebot: "([& keys]); Returns a new sorted set with supplied keys."

20:19 gfrlog: (nth (sorted-set 1 3 58 348 3 4) 3)

20:19 ,(nth (sorted-set 1 3 58 348 3 4) 3)

20:19 clojurebot: java.lang.UnsupportedOperationException: nth not supported on this type: PersistentTreeSet

20:19 gfrlog: ew

20:20 what good is that?

20:22 ataggart: ,(nth (vec (sort [1 3 58 348 3 4])) 3)

20:22 clojurebot: 4

20:22 gfrlog: ataggart: but I can't insert with a vector

20:23 ataggart: ya, I missed what you were trying to do

20:30 gfrlog: ,(get (sorted-set 38 39 40 41) 2)

20:30 clojurebot: nil

20:37 ataggart: ,(get (sorted-set 38 39 40 41) 41)

20:37 clojurebot: 41

21:02 TimMc: gfrlog: Did you ever figure out why your computer was runnng at THz speeds?

21:03 gfrlog: TimMc: I just assumed it was the JVM optimizing the loop out of existence

21:04 I bet if we used a (reduce) instead of (doseq) we'd get accurate measurements

21:04 * gfrlog starts whipping something up

21:07 gfrlog: ,(time (doseq [_ (range 10000)] (get {} :What)))

21:07 clojurebot: "Elapsed time: 10.169 msecs"

21:07 gfrlog: ,(time (doseq [_ (range 100000)] (get {} :What)))

21:07 clojurebot: "Elapsed time: 80.422 msecs"

21:07 gfrlog: ,(time (doseq [_ (range 100000)] (get {} :What)))

21:07 clojurebot: "Elapsed time: 82.343 msecs"

21:07 gfrlog: actually it might not be optimizing there

21:17 TimMc: https://gist.github.com/985075

21:17 so it might be that calling the field is a tiny bit faster

21:17 or maybe the overhead of the test is getting in the way

21:17 but regardless, the computer is no longer running at THz speeds

21:49 TimMc: gfrlog: Ah, right.

21:51 technomancy: ~clojurebot

21:51 clojurebot: clojurebot is not a benchmarking platform

21:51 technomancy: just throwing that out there =)

21:52 gfrlog: `(list ~clojurebot)

22:06 danbell: anyone in SF area just feel an earthquake?

22:07 gregh: maybe that was the same one I felt half an hour ago in new zealand? :)

22:11 TimMc: $google did you feel it

22:11 sexpbot: First out of 24900000 results is: Did You Feel It?

22:11 http://earthquake.usgs.gov/earthquakes/dyfi/

22:11 TimMc: danbell: ^

22:12 gfrlog: ^ you too

22:12 grah

22:12 gregh, actually

22:13 gregh: yeah, we have one of those here in NZ too, but the recent one was just a 3.0 and after six months of that people don't bother to fill it in :)

22:14 TimMc: haha

22:14 gregh: http://quake.crowe.co.nz/

22:14 gfrlog: TimMc: what do you mean me too? What do I do there? I've never felt an earthquake in my life.

22:15 TimMc: gfrlog: mis-complete

22:15 * gfrlog only got confuseder

22:15 gfrlog: oooh

22:15 oh there okay I see

22:16 that's funny cause I'd think a more common mis-complete would be to start my nick with 'gr'

23:06 kduality: ls

Logging service provided by n01se.net