#clojure log - Jan 21 2012

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

0:00 jeremyheiler: brehaut: nice, yeah

0:06 technomancy: jeremyheiler: it's only like a hundred lines

0:10 I think it's been spun off without a proper maintainer anyway, since the chances of further changes to it are so slim

0:13 jeremyheiler: technomancy: yeah, im not saying it's difficult to reproduce or anything. my thought was that this stuff was maintained in clojure proper, then it would be easier for libraries to depend on network io code and still be cross platform. im not sure if that's a real goal, though.

0:16 clj_newb: I have a [1.0 2.0] in clojure land. A Java function requires a float []. How do I convert it to a float [] ?

0:17 jeremyheiler: ,(float-array 2 [1.0 2.0])

0:17 clojurebot: #<float[] [F@1e21544>

0:17 jeremyheiler: ,(float-array [1.0 2.0])

0:17 clojurebot: #<float[] [F@4c638b>

0:18 clj_newb: jeremyheiler: worked; thanks.

0:18 jeremyheiler: np

0:18 clj_newb: btw, what is to-array used for?

0:18 I dug to-array up, it didn't work; and now, I'm not sure when to-array is ever useful

0:18 technomancy: jeremyheiler: the question of who maintains a library doesn't really affect how easy it is to depend upon

0:19 unless you mean the question of how easy it is to discover

0:19 jeremyheiler: clj_new: to-array returns an array of objects instead of primitives

0:20 clj_newb: jeremyheiler: Object[] rather than float[] ?

0:20 jeremyheiler: clj_newb: yeah

0:21 clj_newb: understood; thanks

0:23 jeremyheiler: technomancy: i meant if i were creating a clojure library that i wanted to work on both the jvm and clr, having something as basic as net io bundled with the langauge would make developing and distributing the library easier.

0:25 technomancy: ah, inside clojure.jar itself? yes, that's different.

0:25 and very rare

0:28 jeremyheiler: yeah, and it's understandable since interop is so simple.

0:46 muhoo: what does ^: mean, as in (def ^:dynamic *group* []) ?

0:46 i know what :foo is, but what is ^:foo ?

0:47 oakwise: is anyone using lein-cljsbuild?

0:48 jeremyheiler: muhoo: it's the same as saying (meta :foo)

0:48 muhoo: ah, thanks

0:49 one more thing i couldn't easily search for in the language reference:

0:49 what is #(), as in #(str %1 "-" %2) ?

0:50 jeremyheiler: #() is an anonymous function. it's the same as saying (fn [a b] (str a "-" b))

0:51 muhoo: thanks!

0:52 Raynes: &(meta :foo)

0:52 lazybot: ⇒ nil

0:52 Raynes: That is not the same.

0:53 It is the same as saying (def ^{:dynamic true} *group* []), which sets the metadata for the *group* bar to the map you see there, containing :dynamic true.

0:57 muhoo: so, um, #^{:foo "bar"} is the metadata of an anonymous function?

0:58 that one has me stumped

0:59 Raynes: No.

1:02 brehaut: ^ is reader metadata, so its on the form, not the result

1:02 with-meta is how you apply metadata to runtime data

1:02 * brehaut climbs off amalloy's soapbox

1:04 clj_newb: is there a way in java/awt to have the awt application treat Tab as a modifier key?

1:14 franks: any "easy" way to find the process id of your clojure program?

1:24 muhoo: franks: ps fax |grep java ?

1:25 franks: muhoo: understood, but now from within your running clojure program...

1:26 technomancy: franks: I think you can use JMX; it's of obtuse IIRC

1:30 franks: (println "PID:" (:out (clojure.java.shell/sh "bash" "-c" (str "echo -n ${PPID}"))))

1:30 ough...

1:30 muhoo: so what's the difference between #{:foo, :bar} and {:foo, :bar} ?

1:36 duck1123: muhoo: #{:foo :bar} is a set containing 2 items

1:36 the other is a hashmap with 1 pair

3:25 muhoo: cool. so then what is #^{:foo "bar"} ? a set that is metadata?

6:58 jondot1: hey guys. without going into editor wars, what editor is most suitable for clojure? (when i did scheme 6 years ago, i used to use emacs)

7:02 raek: I don't think you can determine which one's the "most suitable" without going into editor wars

7:04 I use emacs myself. clojure-mode has very good Leiningen integration.

7:05 jondot1: well, i'd use emacs as well, just there is a new variable here that i don't really know how to handle - java integration

7:06 raek: also, according to this survey emacs+slime is used by 61%: http://cemerick.com/2011/07/11/results-of-the-2011-state-of-clojure-survey/

7:07 jondot1: you have a Clojure project that needs to interoperate with a Java project? or do you just need to use Java libraries?

7:07 jondot1: mostly, using java libraries for NLP.

7:08 i guess clojure would be the glue language in this case

7:09 raek: ok. the project and library stuff is handled by Leiningen. An IDE that strictly builds on top of Leiningen for its Clojure project support (like Emacs) does not have to deal with these things at all

7:10 jondot1: have you looked at Leiningen?

7:10 jondot1: not really, i have a long list of tabs which i have to read serially about clojure :)

7:10 i'll change the order i guess.

7:10 raek: consuming a Java library is very simple if it exists in the maven central repo

7:11 jondot1: good! the lein tutorial should be very high on the list, IMO. https://github.com/technomancy/leiningen/blob/stable/doc/TUTORIAL.md

7:12 jondot1: great, thanks!

7:12 raek: jondot1: since you're interested in java libs I might as well point you to a search engine: http://jarvana.com/jarvana/

7:13 you usually find Java libs there and Cojure libs on http://clojars.org/

7:13 jondot1: nice, thanks, i guess maven is the de facto build system to use with clojure?

7:14 raek: jondot1: well, both yes and no. it is the de facto dependency system.

7:14 and Leinginen uses those parts of Maven to do its job

7:14 jondot1: yep, ok.

7:14 raek: but the de facto build system would be Leiningen

7:14 though some people use Maven too

7:16 CmdrDats1: jondot1: I use emacs and occasionally eclipse for browsing through java libs when I need to do java integration work

7:17 raek: jondot1: and for emacs integration, this is the only guide you should follow (the official one): https://github.com/technomancy/swank-clojure

7:17 jondot1: thanks

7:33 b6n: Hi guys, whats the most pragmatic way to determine the index of an element in a sequence?

7:48 llasram: b6n: In Clojure that's honestly not a frequently-needed sort of idiom. Why do you need an index?

7:53 b6n: IIasram: I have an vector of keywords and if a keyword occurs at a lower index it has a higher 'value'. and I want to compare those values

7:55 AimHere: Well in that sort of case, perhaps a vector might not be the best data structure

7:57 raek: b6n: you can use the java api of vectors to do this: ##(.indexOf [:a :b :c] :b)

7:57 lazybot: ⇒ 1

7:58 raek: but to do a linear search might not be a very good solution

8:01 b6n: yes maybe picking a vector wasn't a good idea. I have a implementation using keep-indexed which works but feels not quite right :-)

8:03 raek: b6n: what do you want to do with these keywords and "values"?

8:05 the coice of data representation is often determined what kind of information you want to get out of the data

8:07 but if this isn't time-critical at all and is just a script you want to throw together the choice of data structures might not be that important

8:07 b6n: I want to implement a traditional card game in which the color of a card determines if it overtrumps another

8:07 there are only 4 card colors

8:10 raek: where does the vector come into the picture?

8:11 do you have something like [:clubs :diamonds :hearts :spades] ?

8:11 b6n: yes exactly

8:11 raek: ok now I understand!

8:11 b6n: so imagine :clubs overtrumps :diamonds and so forth

8:12 [:clubs > :diamonds > :hearts > :spades]

8:12 raek: since the number of elements is very low and constant, .indexOf is very bad here

8:12 another way could be to use a map from suit to a number

8:12 and constuct that map from the vector

8:13 llasram: s,very bad,not very bad, ?

8:13 raek: llasram: yes :-)

8:13 llasram: Only because I was honestly confused for a sec :-)

8:13 raek: (def suit-order [:clubs :diamonds :hearts :spades])

8:13 AimHere: Still, if he's reinventing bridge, maybe he's doing it to learn to program, so it might be a good plan to teach him the right thing

8:14 raek: (def suit-value (into {} (map vector suit-order (range))))

8:15 then suit-value is {:clubs 0, :diamonds 1, :hearts 2, :spades 3}

8:15 which also works as a function from suit to value

8:16 (defn overtrumps? [suit-a suit-b] (< (suit-value suit-a) (suit-value suit-b)))

8:16 something like this is how I would have done it

8:16 b6n: yes this looks much better than my (first (keep-indexed (fn ....

8:17 raek: the biggest difference from the .indexOf approach is that the mapping from suit to value is only calculated once

8:19 b6n: I see, thanks a lot!

8:29 llasram: When is it necessary to explicitly reference a function by its var in order to for dynamic changes to that var to take effect?

8:34 I thought I had a handle on it, but I'm messing with Processing in Clojure, and am able to re-def functions and have the changes be picked up immediately in the running applet

8:34 It kind of breaks my previous understanding of the compiler :-/

8:35 raek: llasram: whenever 'foo' is used in a function, it will be dereferenced. the cases you need to watch out for are when you keep the value of 'foo' for a long time

8:36 for example if you store it in a data structure or pass it as an argument to a function that runs for a long time

8:38 so, a var #'foo is dereferenced whenever an expression foo is evaluated where foo is a free variable

8:38 llasram: I see. So that function won't be redefined, but anything it references via a var (via the normal implicit namespace resolution) will be

8:38 raek: yes, the function objects themselves are immutable

8:39 AimHere: Hmmm. I'm dead new to this clojure stuff. Why does clojure give me integer overflows a lot sooner in slime/swank/emacs than it does when I run clojure from the command line?

8:40 llasram: I see. Ah! Yes, the situation I'd run into before where I needed to reference vars explicitly, I was generating reify'd objects by passing in function objects directly. Those functions objects were immutable, but their free refs are available for redef

8:40 Thank you, raek :-)

8:40 raek: AimHere: is this for the same project?

8:40 AimHere: Just for a standard recursive factorial function

8:41 raek: AimHere: do you use the same version of clojure in the two setups?

8:42 AimHere: Heh, well I was using different ones and was so confused I dropped the .jar from one into the other to see what happens

8:42 raek: the default behavior of auto-promotion of integers changed from Clojure 1.2 to 1.3

8:42 AimHere: Strangely, it doesn't seem to be recurring

8:42 Ah, yeah, I think that's the thing

8:43 I think there may have been a 1.2 version kicking around at some point

8:44 raek: you can either throw in a BigInt value in the computation (which will cause all partial results to be BigInts as well), or you can use the promoting ops: +', -', *', /', etc

8:44 (factorial 100N) ;; BigInt literal as input

8:44 (in Clojure 1.3)

8:45 AimHere: Thanks. A lisp doesn't feel right if it doesn't spit out the factorial of 2000 in a jiffy

9:30 mindbender: guys, how do you approach a problem space with a functional orientation?

9:40 TimMc: raek: Any idea whether using BigInts all the time is slower than checking every time whether promotion is needed?

9:41 I feel like it would be, unless it is doing the checking itself... and even then, I *think* branch prediction (for BigInt-always) wouldn't be as advantageous.

9:43 raek: TimMc: no, I haven't studied how all this is implemented

9:44 but I would guess that a BigInt op is slower than a overflow check followed by a primitive op

9:47 dnolen: mindbender: that's a big question :)

9:47 mindbender: dnolen: I agree

9:47 dnolen: mindbender: but generally I find there's less to think about

9:47 mindbender: pick a data structure, write some functions

9:48 mindbender: dnolen: some functions to interact with the data structure

9:49 dnolen: mindbender: yeah

9:50 mindbender: dnolen: can such an approach be used to build a full blown solution?

9:50 dnolen: mindbender: yep

9:52 mindbender: dnolen: I tend to put all code I look at within that frame. But most attimes the authors are not too kind to talk about why they chose such a structure and the need for the fuctions that accompany them

9:52 TimMc: raek: Sorry, I messed up my question... imagine an AutoPromoteInteger that kept a long and a BigInt under the surface.

9:53 dnolen: mindbender: well I find that it's usually obvious from the code

9:54 mindbender: Clojure people tends to rely heavily only on maps, sets, vectors, lists. so few surprises

9:55 mindbender: dnolen: what about the point for higher order functions, first class functions and macros, can they be put into any kind of simple perspective?

9:57 dnolen: mindbender: higher fns, first class fn already part of a simple perspective.

9:57 jonasen: If I understand the ClojureScript One sample application correctly, there are two 'Views': form and greeting.

9:57 Is there an easy way to add another view based on a new template?

9:58 dnolen: mindbender: macros take a while to understand but they solve a fairly common place problem.

9:58 jonasen: I'm probably missing something obvious

9:58 I've created a template myview.html (based on greeting.html) and now I don't really know what to do next.

9:59 mindbender: dnolen: can you try to put it into some perspective with regard to the structure we talked about i.e macros

9:59 dnolen: mindbender: simplest use case for macros is removing boilerplate.

10:00 mindbender: but it scales up to writing compiler extensions without needing to actually change the compiler

10:02 jonasen: looks like you need to add some code to view.cljs

10:03 jonasen: then add a render method for that particular state

10:03 jonasen: dnolen: I've added a new render method (defmethod render :myview ...)

10:03 dnolen: jonasen: but you also need to load it in the render :init method I think

10:05 jonasen: dnolen: you mean in (fx/initialize-views ..)?

10:05 dnolen: jonasen: I think so

10:06 jonasen: it looks like you need to change the one.sample.snippets/snippets macro as well

10:07 jonasen: dnolen: Looking at the definition for initialize-views it seems to be hard-wired for form and greeting

10:07 dnolen: jonasen: it definitely is

10:07 jonasen: dnolen: I'll take a look at snippets

10:18 dnolen: No luck yet, I'm new to "single page apps" so it's quite challenging.

10:19 but they seem to just move greeting out of view, so I guess I shoud do the same with myview

10:20 dnolen: jonasen: the way they manipulate views is not particularly generic or reusable.

10:20 jonasen: remember one is just supposed to illustrate how a ClojureScript application might be constructed

10:20 probably makes sense to improve on the design

10:21 jonasen: dnolen: Yes, maybe I should just edit the views that are already there for now. Until I understand the whole design better

10:49 uberhanz: Any pointers for someone wanting to learn clojure that knows (too) much java and loves haskell?

10:51 Scriptor: uberhanz: if you already know haskell you'll have a head start thinking of functional solutions for the exercises in http://www.4clojure.com/

10:52 uberhanz: thanks alot. looks like fun!

11:26 phil__: should i use clojure.contrib.trace or clojure.tools.trace?

11:26 llasram: ~contrib

11:26 clojurebot: Huh?

11:26 llasram: Damn it

11:26 dnolen: phil__: you should not use anything from clojure.contrib

11:27 phil__: dnolen: is it outdated?

11:27 dnolen: phil__: yes

11:29 phil__: ok, any pointers on how i should set up https://github.com/clojure/tools.trace with lein? or should i just pull the source and stuff it into my project?

11:29 but this seems messy :/

11:30 or is there just a better way to trace function execution?

11:31 llasram: phil__: using `lein search' will search your configured repos for artifacts

11:32 searching for tools.trace shows be that it's [org.clojure/tools.trace "0.7.1"]

11:32 phil__: ooh

11:33 i see, this is awesome

11:33 thanks a lot :)

11:34 llasram: Np :-) It does seem like something that you'd just want to slurp in to any random project, without needing to explicitly make it a dependency. Maybe a lein plugin?

11:39 phil__: llasram: why, is it bad to have extra dependencies on packages like tools.trace?

11:41 llasram: Just stuff you don't need. You can make it a dev-dependency, and then it isn't included in deployments etc, but it's still unnecessary if the committed code doesn't actually trace anything

11:43 There doesn't seem to be a better way of referencing it ATM though, so a dev-dependency is probably the way to go

11:53 devn: &(= [1 4 9 16] '(1.0 4.0 9.0 16.0))

11:53 lazybot: ⇒ false

11:55 llasram: Or more simply: ##(= 1.0 1)

11:55 lazybot: ⇒ false

11:56 dnolen: ##(== 1.0 1)

11:56 lazybot: ⇒ true

12:41 tufflax: Hm, the docs say that = is supposed to compare numbers in a type-independent manner. ##(= 1.0 1) does not give that impression.

12:41 lazybot: ⇒ false

12:41 dnolen: tufflax: docs are out of date, == does that now

12:42 tufflax: ok :p

12:43 AimHere: Well (/ 1/6 (/ 1.0 6.0)) is still false, note!

12:44 ##(== 1/6 (/ 1.0 6.0))

12:44 lazybot: ⇒ false

12:46 Luyt: Interesting, there is a 'first' and 'second', but not a 'third' or 'fourth'. I guess you have to draw the line somewhere ;-)

12:46 tufflax: AimHere that's expected, at least by me :p

12:46 TimMc: Not by me.

12:46 tufflax: TimMc why not

12:46 AimHere: ##(== 1/3 (/ 1.0 3.0))

12:46 lazybot: ⇒ true

12:47 tufflax: hm

12:47 :p

12:47 AimHere: I guess it doesn't like rounding up

12:48 Luyt: Floating point is only an approximation. And ##(type 1/3) is not the same as ##(type (/ 1.0 3.0))

12:48 lazybot: (type 1/3) ⇒ clojure.lang.Ratio

12:48 (type (/ 1.0 3.0)) ⇒ java.lang.Double

12:49 TimMc: AimHere: Oh, what the...

12:49 Luyt: So? ##(== 1 1.0)

12:49 lazybot: ⇒ true

12:50 Luyt: Apparently 1.0 is a value that can be represented exactly in floating point.

12:50 AimHere: But neither 1/3 nor 1/6 can be represented exactly

12:50 Luyt: But 1.0/3.0 is 0.3333333333333333 and where does the 333333333 end?

12:50 AimHere: Well unless you're taking a base with 3 (and/or 2) as the factor

12:51 tufflax: So why the difference in 1/6 and 1/3 results?

12:51 in the

12:51 as above :YP

12:51 AimHere: Maybe the internal representation of clojure doubles is in base 81

12:52 Luyt: I think it's caused by the floating point implementation of the machine on which the code executes.

12:52 The same problem crops up in any other program language which uses floating point.

12:53 tufflax: Most (?) other languages don't have ratios though

12:53 AimHere: Well what other languages manage to compare double floats to inbuilt integer rational types?

12:53 I mean, it's nice that it even works some of the time

12:54 tufflax: Hehe, I don't know about that :)

12:56 TimMc: I'd prefer consistency.

12:56 I don't see any tickets on this; filing one.

12:56 dnolen: TimMc: ticket about what?

12:57 AimHere: The == operator isn't overly consistent when comparing number types that were never meant to be compared in the first place !

12:58 It's a lucky day in most languages if your floating point type manages to equate 1/3 and 2/6

12:58 TimMc: dnolen: (== ratios floats) being inconsistent

12:58 AimHere: Never mind casting to rationals

12:59 TimMc: dnolen: (== 1/x (/ x.0)) false for x = 6, 7, 13, true for x = 2, 3, 4, 5, 8, 9, 10, 11, 12, 14

13:00 $javadoc clojure.lang.Ratio

13:00 lazybot: http://download.oracle.com/javase/6/docs/api/clojure/lang/Ratio.html

13:00 TimMc: bah

13:07 AimHere: ##(#(if (= %2 0) 1 (*' %2 (%1 %1 (- %2 1)))) #(if (= %2 0) 1 (*' %2 (%1 %1 (- %2 1)))) 200)

13:07 lazybot: ⇒ 788657867364790503552363213932185062295135977687173263294742533244359449963403342920304284011984623904177212138919638830257642790242637105061926624952829931113462857270763317237396988943922445621451664240254033291864131227428294853277524242407573903240321257405579568... https://refheap.com/paste/369

13:07 AimHere: Oh sweet

13:09 TimMc: AimHere: Is that Ackerman?

13:09 AimHere: Nah, just a Y combinator on 200!

13:10 (#(%1 %1) #(%1 %1))

13:10 ##(#(%1 %1) #(%1 %1))

13:10 lazybot: java.lang.StackOverflowError

13:10 AimHere: Just have to stresstest the bot ;)

13:10 TimMc: ,(#(% %) #(% %))

13:10 clojurebot: #<RuntimeException java.lang.RuntimeException: java.lang.StackOverflowError>

13:16 TimMc: dnolen: Never mind, not filing a ticket.

13:16 AimHere, tufflax: ##(double 1/6)

13:16 lazybot: ⇒ 0.1666666666666667

13:16 TimMc: ##(/ 6.0)

13:16 lazybot: ⇒ 0.16666666666666666

13:17 TimMc: Inverting the float munges it enough to make it inequal with the ratio.

13:17 tufflax: why not? :p After thinking some more about it I think I have changed my view. I would expect ##(= 1/x (/ x.0)) to be true for all x, and that would, I think, be more useful. :P

13:18 Even if not totally true

13:18 TimMc: ##(3.0 (/ (/ 3.0)))

13:18 lazybot: java.lang.ClassCastException: java.lang.Double cannot be cast to clojure.lang.IFn

13:18 TimMc: ##(== 3.0 (/ (/ 3.0)))

13:18 lazybot: ⇒ true

13:19 TimMc: ##(== 6.0 (/ (/ 6.0)))

13:19 lazybot: ⇒ true

13:19 TimMc: huh

13:19 tufflax: I mean, if you think of (/ x.0) as the double that results

13:21 TimMc: &(== 1/6 0.1666666666666667)

13:21 lazybot: ⇒ true

13:22 TimMc: I'm just chalking this up to floating-point jitter and leaving it be.

13:32 chewbranca: anyone have any recommendations for error handling with clutch and couchdb? right now the default is to throw an io exception with a string containing the http error code, but I would like to be able to react appropriately to different errors, specifically in this case, 409 conflict errors

13:44 raek: chewbranca: I would recommend slingshot in general for clojure programs. https://github.com/scgilardi/slingshot

13:46 chewbranca: raek: nice, I've been meaning to look more into slingshot, time to dive in

13:54 zilti: How do I add a leiningen dependency which has a classifier? Where do I write the classifier?

13:54 chewbranca: raek: cool, switched over to slingshot, looks like a nice approach to error handling. Won't help with dealing with string status messages, but overall using slingshot looks nice

13:57 jkkramer: zilti: [group/artifact "version" :classifier "foobar"]

13:57 zilti: per https://github.com/technomancy/leiningen/blob/master/sample.project.clj

13:57 zilti: oh, thanks!

14:06 Luyt: How do I do 'argument splatting' in Clojure? Like that (println 1 (splat [2 3]) 4) means the same as (println 1 2 3 4) ?

14:08 brehaut: ,(apply println 1 (conj [2 3] 4))

14:08 clojurebot: 1 2 3 4

14:10 Luyt: is there no function that will unpack a collection so that the items can be passed individually instead of inside a collection?

14:10 brehaut: Luyt: apply ^

14:10 Luyt: (conj [2 3]) doesn't expand into two arguments, 2 and 3.

14:10 Ow moment, I'll look up apply

14:11 brehaut: Luyt: build one seq, and use apply to pass it to the fn

14:11 no need for jiggery pokery voodoo

14:12 Luyt: I was trying (disj a b) where both a and b are sets, but that didn't work as expected, but (disj a b1 b2 b3 ... bn) where bi are elements of set b

14:12 did work.

14:12 Raynes: &(apply + [1 2 3])

14:12 lazybot: ⇒ 6

14:13 raek: Luyt: have you seen clojure.set/difference?

14:13 Luyt: raek: Yes, the tutorial mentiones that, but I was wondering whether there is a splat operator/function in Clojure.

14:14 raek: Luyt: you could use apply there: (apply disj a b) = (apply disj (cons a b)) = (disj a b1 b2 b3 .. bn)

14:14 Luyt: Hmmm, food for thought ;-) Thanks for all your tips, I'll figure something out ;-)

14:14 raek: the variadic version of apply takes all elements between the first and the last and concats them to the last

14:15 and then applies the function with those as the arguments

14:24 uberhanz: best page when trying to learn clojure : http://clojure.org/cheatsheet

14:28 Luyt: I'm currently working through http://java.ociweb.com/mark/clojure/article.html

14:30 I sometimes have to turn my brains inside-out ;-)

14:31 uberhanz: I usually like static (and strong) typed languages, but clojure is fun!

14:31 Luyt: I was surprised that you can use a set or hashmap as a function to test for membership. Image the power that'd be unleashed if you could pass functions around!

14:32 uberhanz: haha. new to functional programming?

14:32 or am I missing the irony?

14:33 Luyt: I was a bit charging there ;-) I come from a C/C++/Python background. In Python, functions are first class citizens, like in Clojure. But I already passed around function pointers in C, so...

14:34 brehaut: function pointers dont have any lexical context though

14:35 AimHere: I think his point is that he did the closest that he could to that sort of stuff in C

14:35 Luyt: Good point. But when they don't use globals or have any side effects, that wouldn't be a limitation, would it?

14:36 brehaut: its a huge limitation!

14:36 Luyt: No closures, indeed

14:36 No fancy python decorator stuff

14:37 brehaut: no super expressive combinators

14:37 uberhanz: think about us poor ppl that have to use Java at work and have to keep their functional programming for home projects. weep for us!

14:37 Luyt: Are you one of them?

14:37 uberhanz: yeah

14:38 Luyt: The problem is that corporations want to standardize on Java instead of just the JVM.

14:38 In the latter case, you could use anything that produces java bytecode.

14:38 uberhanz: yeah

14:39 Luyt: Corporations see "Java Programmers" as a commodity

14:39 semperos: using clojurescript, working with a JavaScript library function that expects a JS object as a parameter

14:39 uberhanz: Its easier to start to write tools in other JVM based languages

14:39 semperos: what's the "right" way to go about this common task?

14:39 TimMc: Luyt: s/"Java Programmers"/people/

14:40 semperos: TimMc: s/people/walking-money-bags-with-no-life-outside-work/

14:40 uberhanz: haha

14:43 Luyt: I already suspected it'd be better to learn some Clojure instead of doing Java from 9 to 5 and couchpotato for the TV with a few beers at evening.

14:43 AimHere: Couchpotato with the TV and beer from 9 to 5, then learn some Clojure in the evening

14:44 Clearly the lifestyle of champions

14:44 uberhanz: Well, I actually not only do Java, but do email also! on the otherhand, I dont do couchpotato. not my thing

14:44 wiseen: is there a clojure parser library - something that would help parse macro grammars ?

14:45 brehaut: wiseen: you mean something that deals with sexps?

14:45 Luyt: I usually do Python during the day, but one has to keep on learning more powerful blob languages, no? http://paulgraham.com/pypar.html http://www.paulgraham.com/avg.html

14:46 zilti: My life's Clojure and Army, right now

14:46 wiseen: brehaut, well something that will help me parse macro body, eg. I have a macro that can contain (message ...) (catch ...)* (close ...) (finally ...)

14:46 catch can appear multiple times, others are optional

14:47 parsing that from lists is tedious

14:47 ideally I could have some declarative way to specify the grammar ?

14:47 Raynes: I do exactly that in lazybot's plugin dsl. I use keywords for the names though, which make it clearer that you're not calling things by are supplying directives instead.

14:48 s/by/but/

14:49 wiseen: Raynes, link ?

14:50 Raynes, do you do it manually or did you write a DSL for it ?

14:50 Raynes: Manually.

14:51 https://github.com/flatland/lazybot/blob/develop/src/lazybot/registry.clj#L121 Now, this is all probably pretty insane (this has been only marginally modified since originally created and was some of my first Clojure code), but the actual parsing stuff (I think) is fairly recently rewritten and isn't all that wild.

14:53 phil___: can somebody please tell me if this is considered bad form: https://gist.github.com/1653743, as opposed for example to this: https://gist.github.com/1653746

14:54 i prefer to use as few ifs and conds and cases as possible and let the language handle the test cases vie apply

14:54 wiseen: yeah the gorey internals of writing a parser manually, I'm suprised someone hasn't written a declarative parsing library - I'm guessing it would simplify writing macros a lot, and functional PLs usually have cool parsing libs (eg. FParsec F#)

14:55 Raynes: The first example is much clearer, but I think that might because of the insane indentation in the second one.

14:55 Er, reverse that.

14:55 I clicked the links in the wrong order. :P

14:55 Yeah, closer inspection tells me that the second one is definitely the clearer of the two.

14:56 phil___: :D so the second is considered good practice? isnt it much clearer to have all edge cases layed out in front of you as in the first example?

14:58 it certainly looks much cleaner, but the explicit tests kind of conceal the intent i think

15:02 wiseen: just yesterday i read about a parsec like monadic parser in clojure: http://intensivesystems.s3-website-us-east-1.amazonaws.com/tutorials/monads_101.html?from=@

15:02 gotta scroll down a bit

15:03 raek: there's also fn-parse: https://github.com/joshua-choi/fnparse

15:03 tavis`: Roman Gonzalez is about to release his port of attoparsec to clj

15:04 it should be up on https://github.com/roman/ sometime soon

15:04 zettaparse

15:08 muhoo: hmm, kind of annoying (.split "foo bar baz" " ") doesn't give me a list of strings, it gives me a #<String[] [Ljava.lang.String;@10241ae>

15:08 instead of ("foo" "bar" "baz") which i kind of expected

15:08 Raynes: muhoo: That's a Java array of strings. It is seqable, so you can treat it essentially as what you want.

15:09 &(seq (.split "foo bar baz" " "))

15:09 lazybot: ⇒ ("foo" "bar" "baz")

15:09 Raynes: &(map #(str % " hi") (.split "foo bar baz" " "))

15:09 lazybot: ⇒ ("foo hi" "bar hi" "baz hi")

15:10 raek: ,(clojure.string/split "foo bar baz" #" ")

15:10 tavis`: &(clojure.string/split "foo bar baz" #" ")

15:10 lazybot: ⇒ ["foo" "bar" "baz"]

15:10 clojurebot: #<ExecutionException java.util.concurrent.ExecutionException: java.lang.RuntimeException: java.lang.ClassNotFoundException: clojure.string>

15:10 * Raynes sighs

15:10 Raynes: I wish people wouldn't use that as an opportunity to avoid explaining the difference between Java arrays and Clojure seqs and how you can use them in Clojure.

15:11 muhoo: uberhanz: could be worse, you could be force to use PHP at work

15:11 Raynes: thanks!

15:11 Raynes: raek: Not that you are guilty of such acts.

15:12 I occasionally see people with muhoo's query get shown an example of clojure.string/split and told "See! This does it!" and a fantastic opportunity for them to learn about Java collections is missed.

15:12 It's tragic, really.

15:13 muhoo: i am very thrilled to be able to use seq to turn some nonsense #<BS[] [Ljava.lang.BS into a nice lispy list

15:14 raek: exactly :-)

15:14 Raynes: muhoo: Keep in mind that, unless you're trying to print the array, you don't usually have to call seq on it.

15:14 muhoo: it's just repl sugar for me, but it makes me happy :-)

15:15 Raynes: muhoo: Most of Clojure's functions do that implicitly. Like my map example.

15:15 :)

15:18 muhoo: housekeeping question, the bot is & or ##?

15:18 &"foo"

15:18 lazybot: ⇒ "foo"

15:18 muhoo: ##"foo"

15:18 hmm

15:18 brehaut: both of those are lazybot

15:18 raek: blahblah ##"foo"

15:18 brehaut: clojurebot is prefixed with a comma

15:18 muhoo: ,"foo"

15:18 clojurebot: "foo"

15:18 raek: blahblah ##(identity "foo")

15:18 lazybot: ⇒ "foo"

15:18 muhoo: wait, there are two bots?

15:19 brehaut: ,(inc 1)

15:19 clojurebot: 2

15:19 brehaut: &(inc 1)

15:19 lazybot: ⇒ 2

15:19 brehaut: theres also hsbot

15:19 muhoo: !

15:19 tavis`: hsbot?

15:19 cold_gopher: Hi all. I have just installed SWANK and I am launching it from emacs. When I'm in the REPL and perform a doc such as (doc map), I get an exception. Anyone come across this before?

15:20 brehaut: haskell bot i think

15:20 tavis`: what's it doing here? ;)

15:20 brehaut: cold_gopher: the swank repl is different to the normal repl

15:20 cold_gopher: you need to use clojure.repl if you want the normal tools. however, slime provides alternatives through emacs that you can use

15:21 cold_gopher: ok thanks

15:21 brehaut: cold_gopher: C-c C-d C-d for docs

15:21 (on a var)

15:21 works in the repl and editor

15:21 cold_gopher: nice

15:24 wjlroe: brehaut: oh man, I didn't know that and was looking for that yesterday - thanks!

15:24 Could not find it in the C-h b listing for some reason

15:26 brehaut: i cant find the one for looking up the source of a var

15:27 tavis`: eldoc is also quit handy with slime: https://gist.github.com/1551858

15:29 wjlroe: Also useful - break points in swank - http://hugoduncan.org/post/2010/swank_clojure_gets_a_break_with_the_local_environment.xhtml

15:29 Raynes: brehaut: lazybot evals Haskell too.

15:29 &he 3 + 3

15:29 lazybot: java.lang.RuntimeException: Unable to resolve symbol: he in this context

15:29 Raynes: Duh.

15:29 $he 3 + 3

15:29 lazybot: ⇒ 6

15:29 brehaut: Raynes: thats good, becuase i cant remember the hsbot commands :P

15:30 Licenser: heh

15:30 tavis`: $he take 6 (cycle [1,2,3])

15:30 Raynes: muhoo: ##(println "is for evaluation of code embedded inside of a message (when you can't begin the message with &)")

15:30 lazybot: ⇒ is for evaluation of code embedded inside of a message (when you can't begin the message with &) nil

15:30 ⇒ [1,2,3,1,2,3]

15:30 raek: this is interesting: http://skife.org/java/unix/2011/06/20/really_executable_jars.html

15:32 brehaut: $he let fib = 1 : 1 : zipWith (+) fib (tail fib) in take 10 fib

15:32 lazybot: ⇒ [1,1,2,3,5,8,13,21,34,55]

15:32 Raynes: $ht "you can even check types!"

15:32 lazybot: ⇒ Type: "you can even check types!" :: [Char]

15:32 Licenser: wow that is the most terse definition of fib I've ever seen o.O

15:32 Raynes: I wonder why i prefix that with 'type'.

15:32 Licenser: Welcome to Haskell. May I take your coat?

15:33 Licenser: Raynes that is astonishing

15:33 brehaut: Licenser: its the canonical 'i have lazy values!' version

15:33 Licenser: so I have a real hard time to understand it

15:33 so you should be able to do about the same in clojure shouldn't you?

15:33 brehaut: you can…

15:34 you probably need to use a delay or a promise to tie the knot though

15:34 or use a def, which is a potential space leak ;)

15:34 Licenser: so let … in … is like (let [..] …) right?

15:34 brehaut: correct

15:35 Licenser: so the definition of fib is 1 for 1 or zipWith (+) fib tail fib for all others?

15:35 brehaut: (concat [1 1] (map + …))

15:35 tavis`: what would lazybot do with an infinite list?

15:35 Raynes: : is cons

15:35 tavis`: Try it out.

15:35 Licenser: ah

15:35 brehaut: or (list* 1 1 (map + … i guesss

15:35 Licenser: $(range)

15:36 tavis`: $ht [1..]

15:36 lazybot: ⇒ Type: [1..] :: (Num t, Enum t) => [t]

15:36 Licenser: ,(range)

15:36 clojurebot: (0 1 2 3 4 ...)

15:36 Licenser: clojurebot is a sneaky bastard &&

15:36 &(range)

15:36 lazybot: java.lang.OutOfMemoryError: Java heap space

15:36 Licenser: lazybot will post the infinit list to github? :P

15:37 Raynes: Haha, well, normally he would stop after so many seconds and print an error message saying he timed out.

15:37 Licenser: but this is too fast ^^

15:37 Raynes: In this case, he has reached the memory limitations I've set for him.

15:37 No, that would usually be fine.

15:37 Licenser: Raynes can't you test for lazy lists and make it print it like clojurebot ?

15:37 Raynes: Licenser: I'm pretty sure he just sets *print-length*, and yes, I could do that too.

15:38 Licenser: print-length is cheating

15:38 Raynes: I agree.

15:38 Licenser: you could build your own pr-str to be smrt

15:38 Raynes: &(range)

15:38 lazybot: java.lang.OutOfMemoryError: Java heap space

15:38 Raynes: Huh. I guess I've got the timeout set too high.

15:38 Licenser: or create a clojure version that has infinit memory space

15:38 and internet bandwith

15:39 well range will fill your memory quite quick I guess

15:39 Raynes: Yeah, but that didn't always blow the heap. Don't think we tried that since we changed the memory settings.

15:39 Anyways, ##(+ 3 3)

15:39 lazybot: ⇒ 6

15:39 Raynes: He's still okay.

15:40 tavis`: and he can't be tricked to flood the channel?

15:40 Raynes: With code? No.

15:40 muhoo: &(range 20)

15:40 lazybot: ⇒ (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19)

15:40 Raynes: &(range 500)

15:40 lazybot: ⇒ (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 ... https://refheap.com/paste/371

15:40 tavis`: nice

15:40 muhoo: ooh, nice

15:40 brehaut: &(let [fib (promise)] (deliver fib (concat [1 1] (map + @fib (rest @fib))))) (take 10 @fib))

15:40 Raynes: You can, of course, spam him with eval requests which would make him flood, but you'd be flooding the channel too and it wouldn't be much of a trick.

15:41 lazybot: Execution Timed Out!

15:41 brehaut: rats

15:41 Raynes: ^ is what it is supposed to do rather than blow the heap.

15:41 brehaut: i have clearly forgotten how to use the promise trick

15:41 Raynes: brehaut: Promise you've forgotten.

15:41 Licenser: &(println "bla")

15:41 lazybot: ⇒ bla nil

15:42 Licenser: &(println "bla\nblubb")

15:42 lazybot: ⇒ bla blubb nil

15:42 Licenser: aww he strips line breaks :P

15:42 &(println "bla\nrblubb")

15:42 lazybot: ⇒ bla rblubb nil

15:42 Licenser: &(println "bla\nrblubb")

15:42 lazybot: ⇒ bla rblubb nil

15:42 Licenser: &(println "bla\rblubb")

15:42 lazybot: ⇒ blablubb nil

15:42 Licenser: :(

15:42 raek: %(println "foo\u0000bar")

15:42 &(println "foo\u0000bar")

15:42 lazybot: ⇒ foo

15:42 Raynes: ,(println "foo\nbar\nbaz")

15:42 clojurebot: foo

15:43 bar

15:43 baz

15:43 muhoo: what is this, bot torture?

15:43 Raynes: muhoo: This is spam that you've instigated.

15:43 tavis`: ,(print "&(print 1234)")

15:43 clojurebot: &(print 1234)

15:43 lazybot: ⇒ 1234nil

15:43 Raynes: Now feel guilty about it.

15:43 muhoo: Raynes: i do indeed.

15:43 brehaut: ,(print "(dec Raynes)")

15:44 clojurebot: (dec Raynes)

15:44 lazybot: ⇒ 12

15:44 Raynes: clojurebot is not my biggest fan.

15:44 tavis`: so lazybot is a bit smarter than clojurebot about preventing the other bots from listening

15:44 Licenser: ,(println "&(println \"&(+ 1 1)\")")

15:44 clojurebot: &(println "&(+ 1 1)")

15:44 lazybot: ⇒ &(+ 1 1) nil

15:45 Licenser: ,(println "&(println \"##(+ 1 1)\")")

15:45 now that didn't work

15:45 lazybot: ⇒ 2

15:45 clojurebot: &(println "##(+ 1 1)")

15:45 lazybot: ⇒ 2

15:45 Licenser: oh it did

15:45 muhoo: a bot as a macro expander

15:45 Licenser: now I wonder if you make them ping pong

15:45 so to say a quine :P

15:45 Raynes: No, you can't.

15:45 Licenser: Raynes are you sure?

15:45 Somelauw: &(def fib (lazy-cat [0 1] (map + fib (rest fib))))

15:45 Bronsa: ,(let [fib (promise)] (deliver fib (lazy-cat [1 1] (map + @fib (rest @fib)))) (take 10 @fib))

15:45 clojurebot: (1 1 2 3 5 ...)

15:45 lazybot: java.lang.SecurityException: You tripped the alarm! def is bad!

15:45 tavis`: ,(print ",(print 1234)")

15:45 clojurebot: ,(print 1234)

15:45 Raynes: Yes.

15:45 Licenser: oh I guess lazybot ignores himsef?

15:46 Raynes: lazybot has to ignore himself -- the IRC server doesn't send you your own messages.

15:46 But that isn't the problem.

15:46 Licenser: ut?

15:46 but?

15:46 Raynes: lazybot can't invoke clojurebot because he prefixes eval results with an arrow.

15:46 Licenser: but lazybot can invoke lazybot ##(str "##(+ 1 1))

15:46 lazybot: ⇒ 2

15:47 Licenser: but lazybot can invoke lazybot ##(str "##(+ 1 1)")

15:47 lazybot: ⇒ 2

15:47 Licenser: hmm seems it can't

15:47 but lazybot can invoke lazybot ##(str "#" "#(+ 1 1)")

15:47 lazybot: ⇒ "##(+ 1 1)"

15:47 Raynes: It can't because that is a limitation of the IRC protocol.

15:47 Licenser: ah yeas he does not see himself

15:47 hah

15:47 sneaky we have to con clojurebot into having something like ## ^^

15:47 then we can make them do a bot war

15:47 ordnungswidrig: Licenser: don't feed the bots! :-)

15:48 Licenser: ^^

15:48 but it would be fun

15:48 muhoo: "fun" in the sense that setting old xmas trees on fire is fun

15:48 Licenser: muhoo yes

15:48 muhoo: not very productive though.

15:49 Licenser: productive is for once overrated and then it is relative

15:49 breaking clojurebot in the beginning was quite productive ^^

15:49 Somelauw: Seems like promise makes a variable and deliver sets that variable

15:49 Licenser: if it hand't been done there would never have been the whole jailing thing

15:49 Raynes: clojurebot is still pretty easy to break.

15:49 The jail at least.

15:50 But I'm not sure he is going for safe with that one.

15:50 Licenser: Raynes just because it is not using clojail or clj-sandbox :P

15:50 Somelauw: So, that's how you make non-global recursive lists. I asked before but nobody knew.

15:50 Raynes: Well, lazybot's clojure plugin has essentially been a battleground for testing clojail.

15:51 tavis`: have you played with running clojurescript in jailed env?

15:51 Raynes: tavis`: Sure, we call that 'your browser'.

15:51 ;)

15:52 tavis`: bot style I mean

15:52 Raynes: No. I'd be tempted to refheap the compiled javascript and tell you to run it your damn self. :p

15:52 tavis`: hehe

15:53 'your browser' isn't really a safe jail though

15:53 Raynes: It's safe for me though.

15:53 tavis`: very true

15:55 ordnungswidrig: anyboy else having problems with slime-edit-definition? When invoking on a function defined in a protocol I get NPE in File/init called by slime-find-file

15:56 tavis`: yeah, it doesn't work yet

15:56 I'm working on that

15:56 ordnungswidrig: nice.

15:57 tavis`: if you move your point to the protocol itself you'll get pretty close to it

15:57 ordnungswidrig: I wonder if we can have jump it to the function implementation, not the protocol definition.

15:57 tavis`: metapoint works on protos but not proto funcs

15:58 technomancy_: nice to have someone helping with slime who actually cares about protocols

15:58 tavis`: I saw you prefer multimeths

15:59 Somelauw: Would it be possible to write a letrec macro in clojure using the promise/deliver primitives?

16:00 technomancy_: tavis`: a better way to say it would be that I don't work on any problems myself for which the speed of protocols is valuable enough to outweigh the inconveniences =)

16:05 Somelauw: How to STOP clojure in emacs

16:05 before my stack explodes?

16:06 I need to stop it quickly?

16:06 tavis`: slime-interrupt might

16:06 ordnungswidrig: Somelauw: kill the java process.

16:06 Somelauw: alt+x not working

16:07 Something like ctrl-c?

16:07 tavis`: then kill -9 java

16:07 Somelauw: Okay, I killed everything.

16:09 Thanks. Can't slime be stopped by ctrl-c or something?

16:09 Raynes: It can be stopped by force killing your Emacs.

16:09 ;)

16:09 technomancy_: tavis`: I think it would be perfectly acceptable to skip byte compilation of the .el payload files are remote

16:09 Somelauw: That's what I did. I force killed emacs

16:10 technomancy_: as long as they get loaded; the byte compilation is nice for everyday speed, but it's an optimization. using jack-in remotely seems like not an everyday task.

16:10 muhoo: is there a way to deref something where all i have is the text printout of the reference, i.e. #<Server Server@160bf50> ?

16:10 technomancy_: tavis`: of course if you intend to use it as part of normal development then maybe not; depends on your plans for it

16:10 muhoo: is there any way to turn that text into the object that it sort-of-describes?

16:13 ordnungswidrig: tavis`: is hte npe fixed in swank clojure head?

16:14 tavis`: do worry. It is. just found it.

16:18 raek: muhoo: not in general. you can use the *1, *2, and *3 variables though if you evaled it recently

16:36 Bronsa: https://github.com/clojure/clojure/blob/master/src/clj/clojure/repl.clj#L124

16:36 shouldnt it be a set?

16:37 arkh: how do I tell what version of clojure I'm running at a repl? I'm not sure if my emacs setup is using my project clojure of 1.3 or the 1.2 it installed with "lein plugin install swank-clojure 1.3.4"

16:37 Bronsa: oh, i see, i misunderstood

16:37 ,(clojure-version)

16:37 clojurebot: "1.3.0"

16:38 arkh: Bronsa: thank you

16:39 dnolen: ,*clojure-version*

16:39 clojurebot: {:major 1, :minor 3, :incremental 0, :qualifier nil}

16:43 tavis`: technomancy_: we could also just copy the remote files to local and then byte-compile locally

16:44 any thoughts on a security warning first?

16:52 zilti: Is it a bug or a feature that things like (. (new Foo) (bar x)) aren't possible?

16:52 nodename: Hi, I have an app built as a Counterclockwise project. I've been asked "Where's the project.clj?" How can I make my project runnable outside Eclipse?

16:53 ibdknox: zilti: huh? that is possible

16:54 ,(. (Integer. "2") (toString))

16:54 raek: &(. (new Object) (toString))

16:54 lazybot: ⇒ "java.lang.Object@1139c27"

16:54 clojurebot: "2"

16:54 zilti: ibdknox: I have the problem that it isn't possible - but it's possible if I first store it in a variable and then do a (. foo (bar x))

16:56 ibdknox: that seems unlikely

16:56 what's the exception?

16:56 and the exact code

16:59 zilti: It's a simple NullPointerException

16:59 ordnungswidrig: nodename: you can package it as a jar

16:59 ibdknox: ordnungswidrig: I think he's asking how to take a CCW project and make a project.clj from it so it'll work in lein

17:00 nodename: ordnungswidrig: yes, what ibdknox said

17:00 ordnungswidrig: I see.

17:00 zilti: I've already changed the code... Actually I used the .. macro. I had to change the whole thing because the .. macro seems to have problems with mutable java classes anyway. But I wanted to ask if that's a known problem

17:04 dnolen: zilti: there's no problem. many mutating methods return void instead of a value.

17:11 ishkabibl: wow this is a big irc channel

17:12 is Raynes here?

17:12 Raynes: Yep.

17:13 ishkabibl: I saw your "try coljure" interactive web appliction(at first I didn't realize you made it)

17:17 Raynes: ishkabibl: Yup, that'd be me.

17:18 ishkabibl: hows your book comming?

17:18 Raynes: At least partially. I didn't do much of the design portion.

17:18 Slowly but surely.

17:18 ishkabibl: well it has your name on it(try clojure)

17:20 Raynes: ishkabibl: I wrote the majority (all?) of the backend and the initial design. Other people came along and streamlined it, because I wasn't fantastic at web design.

17:20 ishkabibl: I see

17:21 are maps persistent?

17:22 Raynes: Yep.

17:22 ordnungswidrig: ishkabibl: everthing it but refs, atom and agent.

17:22 Raynes: &(type {:foo 0})

17:22 lazybot: ⇒ clojure.lang.PersistentArrayMap

17:22 ordnungswidrig: ishkabibl: and java classes

17:22 Raynes: http://clojure.org/data_structures

17:24 phil___: is it possible to simplify the following code in some way? https://gist.github.com/1654274

17:26 ishkabibl: maps must use vectors to store their buckets

17:27 dnolen: ishkabibl: object arrays more likely

17:28 ishkabibl: are object arrays just java arrays?

17:28 ordnungswidrig: phil___: (if (symbol? a) [a (cons a b)] [a b]) can be simplified to [a (if (symbol? a) (const a b) b))]

17:29 phil___: i.e. you can inline the if into the vector creation

17:30 ishkabibl: wait, there are 2; sorted and hashed. the sorted one makes sense(it's just a tree like haskell's map) but the hashed one makes less sense

17:30 tauntaun: Does Clojure have a standard library for the basic combinators (S, K, etc.)?

17:30 phil___: ordnungswidrig: oh yes, thx :)

17:31 ishkabibl: tauntaun: if not you can use fn for lambda clalcules to implment it

17:33 tauntaun: ishkabibl: I'm quite aware of that :) I prefer not to reimplement even small simple things.

17:33 ishkabibl: ya, me too :)

17:39 tavis`: tauntaun: http://www.thelastcitadel.com/blag/combinator

17:40 technomancy_: tavis`: that would work too; depends on how much effort you want to put into it. either approach is valid.

17:43 chewbranca: what do you guys use for web request loggin? more specifically with noir?

17:47 tauntaun: Wow, I must be communicating really poorly :)

17:47 tavis`: same, that was my way of saying I can't find one

17:50 tauntaun: there's various parser combinator libs, but I can't see anything packaged up for S K I,etc.

17:52 ordnungswidrig: chewbranca: ngnix or apache in front of it

17:54 chewbranca: ordnungswidrig: I'm looking for something in the app itself

17:54 I found an example logging ring middleware that looks like it will get me going: http://techbehindtech.com/2011/01/19/introduction-to-clojure-web-development-using-ring-compojure-and-sandbar/

17:55 ordnungswidrig: chewbranca: never thought of it but writing a ring middleware to log looks trivial

17:55 chewbranca: yeah much simpler than I expected

17:55 ordnungswidrig: chewbranca: that's clojure!

17:56 chewbranca: ordnungswidrig: ?

17:56 ishkabibl: i belive he is saying that clojure makes everything easy

17:56 ordnungswidrig: chewbranca: clojure makes it easy :-)

17:56 the rest is written here: http://en.wikipedia.org/wiki/Common_Log_Format

17:57 chewbranca: oh lol, yeah I agree, been astonished with how powerful and concise clojure is

17:57 I'm honestly less interested in using the commong log format as I would much rather use actual machine readable logs, either as raw clojure data structures or json

17:58 but that depends on whether you're more interested in processing logs with shell utils or something higher level

18:00 nice, and logging is working

18:54 clj_newb: why is (type (doall (map identity '(1 2 3)))) a lazy seq? doens't doall force exection of the list?

18:56 hiredman , amalloy_ : ping ^

19:01 why is (type (doall (map identity '(1 2 3)))) a lazy seq? doens't doall force exection of the list?

19:02 tmciver: ,(doc doall)

19:02 clojurebot: "([coll] [n coll]); When lazy sequences are produced via functions that have side effects, any effects other than those needed to produce the first element in the seq do not occur until the seq is consumed. doall can be used to force any effects. Walks through the successive nexts of the seq, retains the head and returns it, thus causing the entire seq to reside in memory at one time."

19:02 Xorlev: Clojure always surprises me. I cringe thinking how hard something will be, then end up being (usually) pleasantly surprised.

19:02 clj_newb: tmciver: so it executes the entire list ... and then why is it still lazy?

19:03 tmciver: clj_newb: That's a great question and I'm not positive about the answer but it looks like doall walks the sequence then returns the head so the type is whatever was passed to doall.

19:04 clj_newb: tmciver: (source doall) agrees with you. I'm now baffled on how clojure handles laziness.

19:06 tmciver: clj_newb: the return type of map is a lazy sequence; this fact does not change just because the sequence has been realized.

19:06 it's a realized sequence of type LazySeq

19:07 clj_newb: I think I get it now

19:07 dorun can be run _multiple_ times

19:07 so the side effects can happen multiple times

19:07 I had thought dorun ran it _once_ if it was lazy + then cached the results

19:08 instead, dorun will happily do the sid effects multiple times

19:09 tmciver: ,(doc dorun)

19:09 clojurebot: "([coll] [n coll]); When lazy sequences are produced via functions that have side effects, any effects other than those needed to produce the first element in the seq do not occur until the seq is consumed. dorun can be used to force any effects. Walks through the successive nexts of the seq, does not retain the head and returns nil."

19:09 clj_newb: sorry, s/dorun/doall

19:09 tmciver: yeah, it looks like dorun is like doall except it does not retain the head of the sequence.

19:09 Ah

19:09 clj_newb: tmciver: anyway, this is clear to me now; thanks for helping me debug my understanding

19:10 tmciver: np, it helped me too.

19:10 clj_newb: the example I was getting at is that (doall (doall (doall blah))) would do the side effects of blah 3 times

19:10 whereas in my mental model, the first doall would execute it; cache the results, and the latter 2 do alls would do nothing

19:10 clearly I was wrong

19:11 wait

19:11 tmciver: Yes, looks like the sequence is realized and kept in memory but side effects are reproduced.

19:11 clj_newb: ,(doall (doall (doall (map (fn [x] (println x)) '(1 2 3)))))

19:11 clojurebot: 1

19:11 2

19:11 3

19:11 (nil nil nil)

19:11 clj_newb: it's only executed once, not 3 times

19:12 brehaut: clj_newb: doall just realizes the seq. once its realised, the thunks are not called again

19:12 TimMc: clj_newb: A lazy seq caches the results of the computations.

19:12 clj_newb: brehaut: I'm baffled. Why is the return value of a doall a lazy sequence then?

19:12 brehaut: clj_newb: because thats its type.

19:13 clj_newb: is my brain weird; or do others also find this counterintutivie?

19:13 brehaut: clj_newb: a lazy seq is either an empty seq, or a head, and another lazy sequence that will be computed by need

19:13 clj_newb: if the list is executed + caught; why is it lazy rather than a normal list?

19:13 tmciver: clj_newb: the println is called in map's function; that function is not called when doall executes.

19:13 brehaut: clj_newb: lazy sequences are a flow control construct, not a data structure

19:14 TimMc: clj_newb: When I do (let [t (range)] (take 20 t)), that forces range to produce the first 20 elements, but the rest are not produced. The result is still a seq, but the head is realized and the tail is not.

19:14 brehaut: clj_newb: what programming languages did you use prior to clojure?

19:14 clj_newb: brehaut: scheme + clojure

19:14 err, scheme + haskell

19:15 brehaut: clj_newb: im baffled. this is exactly the same as it is in haskell, and im pretty sure scheme has an equivalent

19:15 clj_newb: brehaut: scheme, iirc, isn't lazy, though chapter 3 of sicp implements lazy cons

19:15 TimMc: $seen zmaril

19:15 lazybot: zmaril was last seen quitting 1 week and 2 days ago.

19:15 brehaut: clj_newb: scheme has laziness via delays and there are lazy streams available

19:16 clj_newb: clojure isnt lazy either

19:16 TimMc: not as a language

19:16 (that was ambiguous -- I was agreeing with brehaut)

19:16 tmciver: ? Clojure not lazy? Now I'm confused.

19:16 clj_newb: here, can we walk through this example (doall (doall (map (fn [x] (println x)) '(1)))) ? I thin this is the simplest test case that demonstrates m confusion

19:17 brehaut: tmciver: clojure is a strict language with some lazy datastructures (notably lazy seqs and delays)

19:17 TimMc: tmciver: Haskell is inherently lazy. Clojure is eager, but has a tricky construct for laziness.

19:17 brehaut: technically haskell is not lazy either, its non-strict ;)

19:17 TimMc: hmm

19:17 tmciver: But many functions return lazy seqs, e.g. map, yes?

19:17 brehaut: tmciver: yes

19:19 tmciver: So for a language to be considered lazy, all of it's data structures should exhibit laziness?

19:19 clj_newb: ,(do (def b (map (fn [x] println x)) '(1 2 3))) (doall b) (doall b))

19:19 clojurebot: #<Exception java.lang.Exception: SANBOX DENIED>

19:19 TimMc: clj_newb: You'll want to use let there.

19:19 tmciver: No def for you!

19:19 TimMc: being a shared environment

19:19 clj_newb: ,(let [b (map (fn [x] (println x)) '(1 2 3))] (doall b) (doall b))

19:19 clojurebot: 1

19:19 2

19:19 3

19:20 (nil nil nil)

19:20 clj_newb: why is it only printed once?

19:20 I had two (doall b)'s

19:20 brehaut: tmciver: its to do with the calling convention as much as it is by the datastructures. haskell can have strict datastructures too

19:20 clj_newb: why are the thunks only executed once?

19:20 and if the results are cached, then why is the list still lazy?

19:20 Somelauw: Because map remembers the results.

19:20 tmciver: clj_newb: the fn is called when map executes - not when the doall's do.

19:20 brehaut: clj_newb: because once a lazy seq cons cell has been realized, attempting to realize it again is a no-op

19:20 Somelauw: Use doseq instead of map if the side effects matter

19:21 clj_newb: tmciver: map is lazy; it doens't execute it until the doall

19:21 ,(let [b (map (fn [x] (println x)) '(1 2 3))] (println "after map") (doall b) (doall b))

19:21 tmciver: Ah, yes, you're right.

19:21 clojurebot: after map

19:21 1

19:21 2

19:21 3

19:21 (nil nil nil)

19:21 clj_newb: brehaut: so the results are cached in a _lazy_ list?

19:21 brehaut: clj_newb: yes

19:22 clj_newb: I find this counterintutiive, but I accept it.

19:22 brehaut: clj_newb: why would it be counter intuitive?

19:22 clj_newb: because I feel the return type of a doall should be a normal list

19:22 it's no longer lazy, i have executed all the p[arts of it, and I have the results

19:23 in my mind, (doall x) = (apply list x)

19:23 brehaut: clj_newb: whats the difference between a realized lazy sequence and a 'normal list'?

19:23 clj_newb: but clealry that is NOT the case

19:24 tmciver: brehaut: the type!

19:24 Somelauw: I am not sure if the realized lazy sequence might need less memory

19:24 clj_newb: , (println (str (doall (map identity '(1 2 3))))) (println (str (apply list (map identity '(1 2 3)))))

19:24 clojurebot: clojure.lang.LazySeq@7861

19:24 clj_newb: (println (str (apply list (map identity '(1 2 3)))))

19:24 ,(println (str (apply list (map identity '(1 2 3)))))

19:24 clojurebot: (1 2 3)

19:24 clj_newb: ,(println (str (doall (map identity '(1 2 3)))))

19:24 clojurebot: clojure.lang.LazySeq@7861

19:24 clj_newb: that is the difference

19:24 (I'm doing file serialization, and lazyseqs are screwing me up)

19:25 brehaut: clj_newb: clojure is heavily oriented toward interfaces over concrete types.

19:25 TimMc: clj_newb: Here it is: A seq is either a generator or a cons cell. A cons cell is a pair of a realized value ("first") and a seq ("next"). When you ask for the first of a generator seq, it is converted into a cons cell with the computed value, and a "next" of a new generator. Ignore the name "LazySeq" here, it is an implementation detail.

19:26 brehaut: clj_newb (and tmciver): so saying 'the type of X is T' is non-idiomatic

19:27 if i recall correctly the biggest difference between list and lazy seq is that list is counted and seqs are not

19:27 (map counted? [(list 1 2 3) (map identity 1 2 3)])

19:27 ,(map counted? [(list 1 2 3) (map identity [1 2 3])])

19:27 clojurebot: (true false)

19:27 Somelauw: vector is counted, i don't know about list, but it probably isn't

19:28 brehaut: Somelauw: ^

19:28 tmciver: brehaut: 'type of X is T' may be non-idiomatic but it's still true.

19:29 TimMc: but not always useful

19:29 brehaut: tmciver: of course its still true

19:29 tmciver: I would say it's useful in learning the inner workings of Clojure.

19:30 brehaut: tmciver: sure

19:31 tmciver: Thanks to clj_newb, brehaut and TimMc: I learned something! :)

19:33 clj_newb: I'm soem awesome people learn things from answering my qeustions.

19:33 I should charge people tuition to teach me.

19:35 ,(read "({})")

19:35 clojurebot: #<ClassCastException java.lang.ClassCastException: java.lang.String cannot be cast to java.io.PushbackReader>

19:35 clj_newb: why can't I read that as an list of a empty hash?

19:35 brehaut: ,(read-string "({})")

19:35 clojurebot: ({})

19:35 TimMc: Hmph, where did Somelauw go? I wanted to show them the diagram on http://www.brainonfire.net/files/seqs-and-colls/main.html

19:35 clj_newb: brehaut: thanks!

19:36 brehaut: clj_newb: be aware that the reader evals by default

19:36 TimMc: see *read-eval*

19:37 brehaut: ,(read-string "#=(inc 1)")

19:37 clojurebot: #<RuntimeException java.lang.RuntimeException: EvalReader not allowed when *read-eval* is false.>

19:37 brehaut: ah of course the bot has it the other way round

19:37 TimMc: even clojurebot has it disabled

19:37 tmciver: meaning they don't eval by default?

19:38 TimMc: tmciver: at all

19:38 The default is true, they have it set to false.

19:38 brehaut: ,(eval ":noluck!")

19:38 clojurebot: #<Exception java.lang.Exception: SANBOX DENIED>

19:38 clj_newb: hang on: (1) read-eval does NOT evalute the sexp it returns (2) read-eval will evaluate _special_ reader-eval forms #=. Are both statements correct?

19:38 brehaut: clj_newb: correct

19:39 tmciver: brehaut: kindly tell me what the #= is.

19:39 brehaut: clj_newb: you need #=… reader macro expressions to get read eval

19:39 TimMc: ,(let [evil (resolve (symbol "eval"))] (evil `(+ 2 2))) ; brehaut

19:39 clojurebot: 4

19:39 brehaut: &(read-string "#=(inc 1)")

19:39 lazybot: java.lang.RuntimeException: EvalReader not allowed when *read-eval* is false.

19:39 brehaut: TimMc: haha its much easier in clojurebot than lazybot apparently :)

19:39 TimMc: Right, lazybot is actually locked down pretty well.

19:40 tmciver: TimMc: that gets by clojurebot because it's looking for the symbol eval?

19:40 TimMc: A bit overly so at the moment. ##(binding [*out* 4] *out*)

19:40 lazybot: java.lang.SecurityException: You tripped the alarm! pop-thread-bindings is bad!

19:40 tmciver: and not the string?

19:40 TimMc: tmciver: Yeah, clojurebot is a dunce.

19:40 clj_newb: just so we are clear; suppose my sworn enemy sends me a read-this.clj , I should read it with *read-eval* set to false?

19:40 TimMc: clj_newb: Right.

19:40 tmciver: Shh, he might hear you!

19:41 TimMc: clojurebot: Are you offended?

19:41 clojurebot: Huh?

19:41 TimMc: See, no problem.

19:41 tmciver: wow, he IS a dunce! :)

19:41 Or he's hard of hearing.

19:41 clj_newb: clojurebot: Have you been so offended you can't think clearly?

19:41 clojurebot: Pardon?

19:42 TimMc: Might just be deaf.

19:42 brehaut: xml rpc api's seem to be universally poorly specced out

19:42 TimMc: lazybot, would you stand for such treatment??

19:42 lazybot: TimMc: Uh, no. Why would you even ask?

19:45 clj_newb: we should give the bot ops

19:45 then whenver anyone asks it a question or uses it

19:45 with a certain probability they get kicked

19:45 it'd be hilarious

19:45 TimMc: We should have someone with ops at all. -.-

19:46 although I've only ever seen 3 people in here that needed kicking.

19:46 clj_newb: or ... suppose you tell cojurebot to evaluate something; and it throws an exceptino ==> kicked; it times out ==> silenced; etc ...

19:47 jayunit100: SCIP is wayyyyy too long has someone abridged the good parts

19:47 TimMc: I think stack overflow -> kick was proposed at one point.

19:47 tmciver: why was the #= reader macro needed in the examples above?

19:47 TimMc: tmciver: For demonstration.

19:47 tmciver: ,(read-string "#=(inc 1)")

19:48 clojurebot: #<RuntimeException java.lang.RuntimeException: EvalReader not allowed when *read-eval* is false.>

19:48 clj_newb: jayunit100: when I read a book that I feel is too basic; I read the hardest chapters first

19:48 tmciver: ,(read-string "(inc 1)")

19:48 clojurebot: (inc 1)

19:48 lazybot: ⇒ 5

19:48 clj_newb: then I read the others as necesary to understand the hard chapters

19:48 TimMc: tmciver: Clojure uses it internally for some stuff.

19:48 tmciver: Try it in your repl.

19:49 tmciver: ##(binding [*print-dup* true] (pr-str {:a 3}))

19:49 lazybot: java.lang.SecurityException: You tripped the alarm! pop-thread-bindings is bad!

19:49 TimMc: bah

19:49 ,(binding [*print-dup* true] (pr-str {:a 3}))

19:49 clojurebot: "#=(clojure.lang.PersistentArrayMap/create {:a 3})"

19:49 jayunit100: wait how do you "run" the "inc 1" closure that is returned

19:49 tmciver: TimMc: hmm, *read-eval* is true but (read-string "(inc 1)") returns (inc 1)

19:49 TimMc: I expected it to eval it.

19:50 TimMc: You're misunderstanding #=

19:50 jayunit100: oh duh eval

19:50 tmciver: yes

19:50 TimMc: #= says "read this next form, eval it, and substitute that as the form"

19:50 tmciver: I'm not even sure what it does, I don't believe it's documented.

19:50 TimMc: It's not really documented, and that's a security problem. I've opened a ticket for it.

19:51 tmciver: TimMc: OK, but I thought read-string eval'd too.

19:51 TimMc: yep

19:52 Oh, only with #= forms

19:52 tmciver: Ahh.

19:52 So read-string returns an un-eval'd form, but prefixed with #= it gets eval'd

19:53 (if *read-eval* is true)

19:55 TimMc: http://dev.clojure.org/jira/browse/CLJ-904 <-- there's the ticket, feel free to vote for it!

19:56 Right, so (first (read-string "[a b #=(+ 1 3)]")) => 'a

19:56 There's no "unbound symbol a" problem, because eval is restricted to that one little thing.

19:57 #= has some limitations, too. (read-string "#=(type (+ 1 2))") => clojure.lang.PersistentList -- only the top layer is "unquoted"

19:58 tmciver: TimMc: I think I got it but what do you mean by "eval is restricted to that on little thing"?

19:59 ,(first [a b c])

19:59 clojurebot: #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: a in this context, compiling:(NO_SOURCE_PATH:0)>

20:00 jayunit100: best way to learn clojure is to code w/ a broken parenthesis key.

20:00 forces you to read the docs before typing stuff.

20:01 TimMc: tmciver: What would you expect (type (+ 1 2)) to produce if it were eval'd?

20:02 tmciver: TimMc: without looking . . . Integer?

20:02 TimMc: Long, in 1.3, but yeah.

20:02 tmciver: Right

20:02 brehaut: im not sure if type is a sensible function these days. havent we moved away from :type metadata?

20:02 TimMc: So why didn't read-string produce java.lang.Long?

20:02 tmciver: TimMc: I'm just wondering why you mentioned the unbound symbol problem.

20:03 TimMc: brehaut: Right, I should use class there.

20:03 tmciver: TimMc: ttyl, supper time!

20:03 TimMc: tmciver: Because of something you said earlier -- I think you've removed that misconception by now. :-)

20:15 The default bindings for starting and stopping a macro recording in Emacs are C-x ( and C-x )? That's *so cute*!

20:16 brehaut: haha :)

20:18 tavis`: so why does #= need to exist in the first place?

20:32 seancorfield: slime/swank startup problem: Unable to resolve symbol: pst-elem-str in this context, compiling:(swank/core.clj:128) -- what's the likely cause?

20:32 i saw this mentioned the other day here and have forgotten the cause/solution sorry :(

20:33 tavis`: it's a clj-stacktrace version issue

20:33 seancorfield: yup, not sure where to look to track it down

20:33 tavis`: if you're using swank-clojure as a plugin rm clj-stacktrace from your lib/

20:34 seancorfield: i did have it installed as a global plugin and just deleted that but it's still giving me the error

20:34 tavis`: put it back as a plugin and get rid of your project's clj-stacktrace jar

20:35 swank-clojure unfortunately depends on a newer version of clj-stacktrace than what a lot of libs pull in

20:36 seancorfield: ah, looks like it's the lein-cljsbuild plugin... time to switch from global to dev-dependency!

20:36 tavis`: ah, I hit that yesterday as well

20:37 :exclusions in ~/.lein/init.clj might work

20:38 btw, do you have any idea why running the sample projects in lein-cljsbuild pops up a java window?

20:39 seancorfield: haven't tried that... i've just been using lein cljbuild auto

20:40 TimMc: tavis`: Lookat my message @ 19:52 (20:42 here now)

20:42 actsasgeek: hello clojurians. I'm trying to do something I think should be easy but apparently not. I want to have the user (me) input a string "plane flies-to paris" and have it evaluated as (plane flies-to paris game-state). plane is a function as is flies-to. paris resolves to a keyword. game-state is a parameter to method that's doing this.

20:43 I've tried all kinds of crazy combinations of eval and apply and I just can't quite get it to work.

20:44 TimMc: actsasgeek: Make a lookup map like {'plane plane}.

20:44 You really don't want to be using eval for this...

20:45 brehaut: ,(let [[fname & args] (.split "plane flies-to paris" " ")] [fname args])

20:45 clojurebot: ["plane" ("flies-to" "paris")]

20:45 tavis`: TimMc: yeah, I saw that. I get what it does, but I'm curious what problems it was invented to solve.

20:46 TimMc: tavis`: Exactly that -- preserving types. (records were involved, I think...)

20:46 tavis`: oh, I think I get it now

20:46 actsasgeek: brehaut: I tried something similar. let me give that version a go.

20:46 TimMc: actsasgeek: Oh, symbol and resolve might be what you're after, but I still recommend the explicit lookup table.

20:47 actsasgeek: TimMc: it seems to be the arguments that cause the difficulty.

20:47 brehaut: actsasgeek: TimMc's explicit table look up is smart

20:47 TimMc: brehaut: I just used that for a CLI application. :-)

20:48 brehaut: ,(let [table {:plane (fn [action target] (prn "the plane" action target))} [fname & args] (.split "plane flies-to paris" " +")] (apply (table (keyword fname)) args))

20:48 clojurebot: "the plane" "flies-to" "paris"

20:48 actsasgeek: yeah, I've done that in Python.

20:48 TimMc: actsasgeek: Have you gotten to the point where you have the name resolved to a function?

20:48 brehaut: TimMc: necessary-evil does similar for xml rpc ;)

20:48 actsasgeek: for that particular attempt, I was mapping symbol over the splitted string.

20:49 https://gist.github.com/1655048 is the latest...I just need to figure out the right thing to do to args.

20:50 TimMc: actsasgeek: Symbols need to be resolved before they can be used.

20:50 actsasgeek: so (resolve (symbol function))?

20:52 brehaut: correct

20:52 TimMc: ,(let [c (map (comp resolve symbol) (.split "comp - inc" " "))] c)

20:52 clojurebot: (#'clojure.core/comp #'clojure.core/- #'clojure.core/inc)

20:53 TimMc: ,((let [c (map (comp resolve symbol) (.split "comp - inc" " "))] (apply (first c) (rest c))) 8)

20:53 clojurebot: -9

20:54 TimMc: Trying to simplify that apply...

20:56 brehaut: TimMc: if you make the split string " +" then it splits on 1 or more spaces

20:56 ,((juxt #(seq (.split % " ")) #(seq (.split % " +"))) "a b")

20:56 clojurebot: [("a" "" "" "b") ("a" "b")]

21:00 TimMc: &(filter seq (.split " a b c " " +")) ;; leading and trailing too

21:00 lazybot: ⇒ ("a" "b" "c")

21:00 TimMc: although that's not the only way

21:00 actsasgeek: the annoying thing is that if I insert the literal for what I want, it works. but I can't seem to get the "args" part to work correctly. more specifically, the "game-state" symbol doesn't want to resolve correctly because it is a closure over a method parameter.

21:01 seancorfield: tavis`: thanx for you help - i have swank back up and running and i still have lein cljsbuild auto running on my other project! :)

21:01 TimMc: actsasgeek: Is game-state a local?

21:01 actsasgeek: TimMc: yes.

21:02 TimMc: Then you're screwed (for this approach) -- Clojure does not have reified environments.

21:02 actsasgeek: ah.

21:02 TimMc: eval, resolve, etc. -- none of those can see locals

21:02 seancorfield: now of course my question is how to get swank up and running on a project that has lein-cljsbuild as a dev dependency :)

21:02 you mentioned something about exclusions

21:02 actsasgeek: I guess I'll have to give up on a purely functional approach then.

21:03 TimMc: actsasgeek: eval and resolve aren't really staples of a functional approach anyhow

21:04 actsasgeek: TimMc: yeah, but I need some sort of interface.

21:04 TimMc: Lookup tables are a fine approach.

21:04 actsasgeek: but I still can't send the arguments to it.

21:05 TimMc: You'd have to explain the larger picture -- why does the user need to know the internal names of your functions?

21:05 actsasgeek: I think the lookup tables is fine but those functions will need to modify global game state in the simulation since it can't be passed around.

21:05 TimMc: You can special-case 'game-state

21:05 actsasgeek: well, they don't...there is a vocabulary for controlling the game.

21:07 jessetrimble: new to clojure - having some trouble wrapping my head around java regex and newlines

21:07 TimMc: And that's what the lookup maps are for -- connecting game vocabulary to internal var names.

21:07 actsasgeek: what really happens is that "plane flies-to paris" calls a (plane flies-to paris game-state) and plane calls the method (flies-to paris plane-game-state) so the subject determines what game state gets changed.

21:08 jessetrimble: (re-matches #"(foo)" "foo") will match foo

21:08 actsasgeek: right but I was trying to avoid any global variables.

21:08 TimMc: actsasgeek: You don't need any, that's what I'm telling you.

21:08 jessetrimble: but (re-matches #"(foo)" "foo\n") doesn

21:09 1. is this the right place to be asking these types of questions, and 2. if so, anyone have any suggestions?

21:09 TimMc: jessetrimble: ##(re-matches #"foo" "foox") it's not about newlines

21:09 lazybot: ⇒ nil

21:09 actsasgeek: TimMc: but you can do other things with plane...you can do "plane refuels"

21:09 I don't want to have to look up every possible string combination.

21:09 seancorfield: nm, i add :exclusions [clj-stacktrace] to the lein-cljsbuild dev-dependencies entry and everything is working fine now - yay!

21:10 actsasgeek: unless I'm missing something obvious. I'm used to doing things like { "name" : function}[ "name"]( args) in Python.

21:11 jessetrimble: TimMc: I see. Coming from regular expressions in the Ruby world…I see I have some research to do. Thanks

21:12 TimMc: jessetrimble: re-matches is a whole-string match

21:12 seancorfield: i spoke too soon... i obviously don't have the syntax right on the exclusion

21:13 TimMc: jessetrimble: look at re-seq and re-find as well: (find-doc #"^re-")

21:13 jessetrimble: awesome, will do. thanks for pointing me in the right direction

21:14 TimMc: NB: re-seq behaves differently w/ and w/o groups

21:24 tavis`: seancorfield: put it at the top level of the project def

21:24 (defproject ... :exclusions [clj-stacktrace])

21:24 at least that's what worked for me

21:24 seancorfield: tavis`: oh, i didn't even know it could go there? i realized i had a regular dependency that also pulled it because of ring or something...

21:24 let me try that

21:25 tavis`: I'm tem

21:25 pted to fix swank-clojure to work with older versions of it

21:28 clj_newb: A = (java.awt.Color. 0.8 0.8 0.8) ; B = ((fn [x] (java.awt.Color. x x x)) 0.8) . A works fine. B throws an exception. Why?

21:29 ,(java.awt.Color. 0.8 0.8 0.8)

21:29 clojurebot: #<Color java.awt.Color[r=204,g=204,b=204]>

21:29 clj_newb: ,((fn [x] (java.awt.Color. x x x)) 0.8)

21:29 clojurebot: #<IllegalArgumentException java.lang.IllegalArgumentException: No matching ctor found for class java.awt.Color>

21:30 TimMc: Hmm, maybe a promotion issue.

21:30 Does it take floats?

21:31 clj_newb: ##(#(java.awt.Color. % % %) (float 0.8))

21:31 lazybot: ⇒ #<Color java.awt.Color[r=204,g=204,b=204]>

21:32 augustl: how do I get query parameters on pages in noir?

21:32 doing a /search?q=foo type thing

21:32 clj_newb: TimMc: brilliant debuggin. Thanks!

21:33 seancorfield: tavis`: thanx man - perfect!

21:37 actsasgeek: TimMc: thanks for your help. I got a lookup table version to work...so far. slainte.

21:39 seancorfield: anyone know if lein-cljsbuild pulls in enough dependencies to start a clojurescript repl?

21:40 cljs.repl.rhino doesn't seem to have everything it needs... some org.mozilla.context stuff is missing... not a biggie but it would be nice to get it running

21:41 augustl: is it just me, or is noir very unfunctional? https://github.com/ibdknox/noir/blob/master/src/noir/request.clj for example

21:41 global state? :S

21:42 TimMc: clj_newb: I remember the last time I used Color, it was annoying to call 'float on all the args.

21:42 tavis`: seancorfield: I think it does

21:42 seancorfield: augustl: it's a pragmatic choice to make the web semantics easier to work with

21:43 i took a functional approach in fw/1 but it makes session and cookie stuff a bit stranger to work with

21:43 tavis`: hmm, i guess i'm just trying the wrong thing to get a cljs repl running then

21:44 tavis`: it won't work in swank

21:44 see this http://p.hagelb.org/lein-cljs-swank.html

21:44 TimMc: augustl: It's not as bad as unchecked mutable globals -- that's a dynamically scoped var.

21:44 tavis`: phil's trick to start a cljs repl alongside swank

21:44 augustl: TimMc: I see, I guess noir is more clever than I am :) Especially since I'm new to clojure.

21:45 seancorfield: tavis`: thanx - i'm in your debt tonight

21:45 signing off for dinner... back later maybe :)

21:46 tavis`: also out of here, that's enough geeking for a day

21:46 TimMc: augustl: That (binding ...) just introduces a thread-local value for *request*, it doesn't affect global state.

21:47 augustl: TimMc: ah I see

21:59 what's the best way to create a method that has one optional argument?

21:59 function, sorry :)

21:59 I have a function that returns vectors for a search form, and it may or may not have a prefilled value

22:01 doh, I can just pass nil when calling the function

22:05 TimMc: augustl: Sometimes you'll see (fn foo ([x] (foo x default)) ([x opt] ...))

22:08 There's also the ugly trick ##((fn [x & [opt]] (list x opt)) 4), but that doesn't even let you specify a non-nil default.

22:08 lazybot: ⇒ (4 nil)

22:39 apwalk: augustl: This might be what you're after - https://gist.github.com/1655342

22:48 alexbaranosky: what do you all think of using (defn ^:private foo ...) instead of (defn- foo ...) ? I'm starting to feel partial to the consistency of using ^:private everywhere instead of having a special case for defn- (as well as thinking the '-' is not a very readable way to distinguish the two visually)

22:54 leo2007: how does flightcaster.com predict flight delays?

22:55 TimMc: alexbaranosky: Sounds good to me.

22:56 Raynes: alexbaranosky: I'm in favor because defn- shouldn't exist in the first place.

22:57 alexbaranosky: are you guys doing this in your projects?

23:01 TimMc: I probably should.

23:01 I still don't know how I feel about private vars in the first place.

23:01 alexbaranosky: what are your concerns?

23:01 do you think they should be letfns ... or do you just think everything should be public?

23:03 I tend to avoid private vars, but use letfns... the var in question is tested (in another file) so it can't become a letfn without me changing tests around, which I don't feel is worth the time

23:04 TimMc: What's your use-case for private vars?

23:04 alexbaranosky: can still be tested

23:04 TimMc: No, I mean hiding stuff in the first place.

23:05 OCD, implicit non-API, cleaner use-alls...

23:05 alexbaranosky: in my opinion too many public functions make understanding the intended usage of a ns harder

23:06 TimMc: That's where a well-documented public API comes in handy... -.-

23:06 alexbaranosky: if the private stuff builds up to be too much, then it might graduate to its own NS

23:06 TimMc: I really don't like this "docs are optional" mentality the community seems to have.

23:07 alexbaranosky: I guess I come from a school of thought that code should be as readable as possible first, then the documentation is icing on the cake

23:07 docs are not optional for users, I agree

23:08 TimMc: Meh.

23:08 alexbaranosky: I more mean for developer readability

23:08 technomancy_: TimMc: a public var implies a promise to not change it until a major version bump

23:08 that's ... huge.

23:08 alexbaranosky: that too :)

23:08 TimMc: technomancy_: You see a public var as implicitly part of the API?

23:08 alexbaranosky: I absolutely do

23:08 TimMc: That makes sense from my Java background, I guess.

23:09 technomancy_: TimMc: in the absence of explicit documentation stating "the public API consists only of the vars in the foo.bar" namespace, absolutely

23:09 I've started using ^:internal metadata to signify stuff that's not part of the public API but still subject to change if I can't make it private for whatever reason

23:10 alexbaranosky: technomancy_, what is a reason you might not be able to make something private?

23:10 TimMc: :private seems... *complected* :-P

23:10 alexbaranosky: with what?

23:11 technomancy_: alexbaranosky: plenty of places where just because another namespace needs access to it doesn't mean I'm ready to commit to the function sticking around.

23:11 alexbaranosky: not using seems to me, to complect that which is meant for user consumption and that which is implementation detail

23:12 TimMc: alexbaranosky: It is used to determine both refers and the default API

23:12 alexbaranosky: technomancy_, yup. I'd usually put that function in a shared internal ns, but I think I tend to use more NSs than most

23:12 technomancy_: :private complects the act of communicating to the consumer and whether a var will show up in ns-publics

23:12 TimMc: but mostly I just wanted to use that word.

23:12 phil: is it faster to just reverse a list or to (concat list element) instead of (cons element list)?

23:12 TimMc: technomancy_: You're not willing to use the #' hack?

23:12 alexbaranosky: but not using private also has issues... hence adding the idea of ^:internal

23:13 technomancy_: TimMc: I'll use it for tests, but not for implementation

23:13 alexbaranosky: most languages have more than just private and publics, so internal seems to make sense

23:14 TimMc: technomancy_: Do you intend ^:internal to be machine-readable?

23:14 llasram: Ranting: what needs to be done to fix things such that the Clojure website tells you to use Leiningen?

23:14 technomancy_: TimMc: no

23:14 TimMc: I guess it would be cool if marg and friends honored it though

23:14 TimMc: sure

23:15 llasram: Was out with friends tonight. Brought up Clojure. One had tried to try it, but installed "clojure" package from homebrew (I believe?), got a REPL with no readline support, got no help from clojure.org, and gave up in disgust

23:16 technomancy_: llasram: some of the folks in Core have no idea how lein works. one of them told me they don't use it because they don't want all their libraries to have AOT applied to them.

23:16 (which was how it worked back in 1.0.0; late 2009)

23:17 dnolen: llasram: someone should try to get clojure removed from homebrew, apt-get, etc

23:17 technomancy_: it has to be in apt-get because it's a dependency of lein and debian won't ship uberjars

23:17 alex_baranosky: llasram, more complaining / more helping make it happen?

23:17 technomancy_: but the shell script wrapper should probably be removed from the apt-get package

23:18 TimMc: phil: You want to reverse a list, or you want to add something to the end?

23:18 If the latter, you might want to use vectors instead.

23:18 Raynes: alex_baranosky: No, because I hadn't thought of it before. I assure you that I will from now on.

23:19 alex_baranosky: Raynes: I've got my fingers poised for a global search and replace of Midje over here :)

23:19 Raynes: alex_baranosky: Do my projects afterwards for a cookie.

23:19 alex_baranosky: what kind?

23:19 Molasses and I'll do it

23:20 dnolen: alex_baranosky: just to throw in my vote, I'm against defn- and :private as well

23:20 llasram: alex_baranosky: But where? Telling people that clojure.org is useless and they should be looking at some random (to them) github project is hard

23:20 alex_baranosky: dnolen, so no letfns either?

23:20 dnolen: alex_baranosky: I like letfn

23:21 TimMc: dnolen: What are your reasons for hiding fns?

23:21 dnolen: TimMc: not hiding, clarity, readability

23:21 alex_baranosky: ok, then I agree. tend to use letfn for all new stuff

23:21 llasram: technomancy_: Yeah, down with the shell script wrapper. I need to try the Debian package again... Last time I gave it a whirl, ant compat issues made it explode, but I assume that was transitory (or at least totally solvable)

23:22 dnolen: How?

23:22 dnolen: llasram: how?

23:22 TimMc: llasram: I think replaca handles clojure.org -- but you'd have to get Clojure/core as a whole to agree to make lein an official tool, if they haven't already.

23:22 alex_baranosky: llasram, have you brought it up on the mailing list? If I had enough excitement for that particular cause that is where I would start

23:22 TimMc: alex_baranosky, dnolen: Doesn't letfn make testing hard?

23:23 llasram: dnolen: Sorry. How to get the package removed from homebrew? I mean, I have no connection to the Mac community. I assume it was created by a Clojure enthusiast?

23:23 TimMc: Or are you more focused on integration-style testing?

23:23 alex_baranosky: I tend to only write tests of public things. Just like I would in an OO language

23:23 dnolen: TimMc: depends, but I'm not a big tester. I test high level functionality, no patience for testing small fns.

23:23 alex_baranosky: but like other most things, it depends

23:23 TimMc: There's something to be said for that -- tests are often treated as API demos.

23:24 llasram: alex_baranosky: That's probably a constructive way to start

23:24 TimMc: alex_baranosky: You tend to do top-down testing anyway, right?

23:24 alex_baranosky: TimMc, that's not a bad thought

23:24 llasram: TimMc: Useful info (re: replaca). Mostly just ranting now, but I'll look back at the log tomorrow morning and contemplate

23:25 Anyway, </rant>

23:25 TimMc: I know s/he does the autodocs.

23:25 alex_baranosky: there are a lot of things I thinkshould be letfns but instead private vars in Midje that aren't because of how they are tested

23:25 phil: TimMc: im adding elements to a list in a recursive function but need to reverse it at the end, or alternatively (concat e2 e1) instead of (cons e1 e2) at every step

23:25 and im wondering which is faster

23:26 is concat of 2 lists O(1)? it should be i guess

23:27 dnolen: phil: concat is linear in the first list, but it's lazy.

23:27 first seq I should say

23:28 TimMc: phil: You could build a vector and give back an (rseq ...) on it, if the consumer only needs a seq.

23:30 phil: but consing to a vector must be must slower than consing to a list right?

23:30 TimMc: phil: conjing, actually. It's complicated, since vectors are 32-way trees under the surface

23:32 phil: yea i read about the implementation somewhere - basically when just conjing data is copied once every 32 conjs right?

23:32 else just add to the current 32 element vector

23:33 TimMc: phil: You might also look at transients.

23:33 Ultimately... it comes down to profiling. :-/

23:33 phil: unfortunately it needs to be compatible to clojurescript

23:34 yea i guess :/ so concat is linear but lazy?

23:34 TimMc: Same algorithm running in both languages?

23:34 phil: yea

23:34 TimMc: You should know that CLJS doesn't really have persistents yet.

23:35 phil: exactly :)

23:35 dnolen: phil: clojurescript doesn't have efficient persistent data structures

23:35 phil: dnolen: i know, i looked at the implementation, right now vectors are just copied on right if i understand correctly

23:35 but porting the java version to javascript should be relatively easy

23:36 dnolen: phil: yup. if efficiency is a concern you've always got arrays and loop/recur

23:36 phil: im planning on doing it somewhen

23:38 dnolen: i understand... im not really writing very performance sensitive code right now, just trying to understand the "best practices" since im new to clojure

23:38 basically, when to use what data structure, what are the implications etc etc

23:39 dnolen: phil: best practice - don't worry about it. stick to the abstractions.

23:39 TimMc: Vectors are usually the right answer for random access.

23:39 dnolen: phil: CLJS doesn't have any data structures that you can update quickly, except for lists.

23:39 phil: so just (cons) to list and then (reverse)?

23:40 dnolen: phil: if reverse is the important bit, conj on to vector then reverse

23:40 TimMc: phil: If you cons to list, it will be the same as conjing onto a vector.

23:41 phil: yea but still, right now conjing to a vector is basically linear in cljs

23:41 TimMc: &(cons 1 (cons 2 (cons 3 ())))

23:41 lazybot: ⇒ (1 2 3)

23:42 TimMc: phil: Sure, but that will change by the time you have to care.

23:42 phil: which is then gonna turn into O(n^2) when conjing at every step

23:42 TimMc: are the data structures gonna be ported soon?

23:42 TimMc: No idea.

23:43 Development seems to have ramped up, though.

23:43 dnolen: phil: keep something in mind, mutability aint so bad if you don't let it escape.

23:43 phil: ok, thats good, but it shouldnt be that hard i guess

23:43 dnolen: but there are no transients in cljs anyway right?

23:44 dnolen: if you don't need to constantly add to something you can construct a mutable array but return something that only supports a functional interface

23:44 phil: how is a mutable array constructed?

23:45 dnolen: phil: I doubt they will be ported anytime soon, I don't think the JS engines generally have the kind of perf you need

23:45 phil: i mean in cljs

23:45 dnolen: maybe V8 is getting close

23:45 (array)

23:45 phil: dnolen: but copy on write must be must slower than a ported PersistentVector??

23:45 lazybot: phil: Definitely not.

23:46 TimMc: Oh, lazybot...

23:46 Raynes: Hahaha

23:47 phil: and tbh i dont think theyre that slow in js tbh

23:47 dnolen: phil: not for small data structures. Clojure data structures rely on some hard core things - fast bit twiddling, machine representation of JVM arrays etc

23:47 phil: i took the java version and put it through gwt

23:47 100k conjs in 2secs on safari on an old macbook

23:47 dnolen: that's crazy slow.

23:48 phil: well it depends on what you wanna do

23:48 i mean yea, if you wanna do machine learning in the browser its slow

23:48 dnolen: phil: sure, but you could also 100k push onto an array and return a functional thing and save yourself the trouble.

23:49 phil: if you want to do some ui with clean immutable data structures its more than enough

23:49 dnolen: phil: definitely, but what's there now is good enough for that as well.

23:50 phil: dnolen: also true :) but cant see any disatvantage in porting them to js

23:51 i mean the only thing i saw thats kinda harder in js is counting bits in an integer

23:51 and there are some black magic O(1) algorithms for that without having to rely on a cpu instruction

23:51 alex_baranosky: hmmm it looks like defn ignores its attr-map? parameter

23:52 dnolen: phil: it would be fantastic for someone to try to port them and do some benchmarks

23:52 TimMc: phil: like log2

23:52 dnolen: phil: as you say for large amounts of data they pay their way

23:52 TimMc: alex_baranosky: Depends on the form you use, i think.

23:52 dnolen: but storing 100,000 in a client side JS app seems like a waste of memory.

23:52 alex_baranosky: looking at the source, and I don't see the param used

23:53 oh durrrrr

23:53 TimMc: alex_baranosky: Which attr-map? There are 3...

23:53 phil: dnolen: yea, i cant imagine what youd need 100k elements for client side

23:54 but 10k i can imagine

23:54 alex_baranosky: TimMc, I see now

23:55 phil: and copying 10k elements every time you update that vector cant be good

23:55 alex_baranosky: TimMc, so what is wrong with this?: (defn as-validation-error ^:private [form] ...)

23:56 TimMc: alex_baranosky: You've put the meta on the args.

23:57 ^:private foo gives you a symbol foo with metadata, and the defn macro should pick that up. An explicit arglist is different.

23:57 dnolen: phil: anyways, not saying it wouldn't be interesting to pursue!

23:58 phil: some one should do it and report back with benchmarks in various browsers, Node.js etc.

23:58 phil: also might be interesting if TypedArrays offer any perf advantage

23:58 alex_baranosky: TimMc: this fails too: (defn ^:private as-validation-error [form] ...)

23:59 * TimMc doubts

Logging service provided by n01se.net