#clojure log - Oct 17 2010

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

0:17 LauJensen: Good morning guys

0:37 amalloy: hi LauJensen

4:05 notsonerdysunny: why should " (def (symbol "hello") 10) " work .. does anybody have an insight into this?

4:05 why shouldn;t " (def (symbol "hello") 10) " work .. does anybody have an insight into this?

4:06 amalloy: notsonerdysunny: def requires a symbol literal

4:07 ,[(symbol "hello") 'hello]

4:07 clojurebot: [hello hello]

4:08 amalloy: (symbol "hello") is the same as 'hello, and it seems pretty reasonable that (def 'hello 10) shouldn't work, right?

4:10 LauJensen: user> `(def (symbol "hello") 5)

4:10 (def (clojure.core/symbol "hello") 5)

4:10 user> `(def 'hello 5)

4:10 (def (quote user/hello) 5)

4:10

4:11 amalloy: yes?

4:11 LauJensen: In either case its clear they wont work, since neither are a literal symbol

4:11 notsonerdysunny: amalloy: hmm...

4:11 so we cannot programmatically generate the symbols..

4:12 amalloy: you can, but you have to do it in a macro

4:13 notsonerdysunny: amalloy: the other day you had suggested that I use apply-macro to make sure that the arguments of a macro get evaluatated before the macro expansion .. but I couldn't figure out how to use it

4:13 have you used it before?

4:15 amalloy: i wouldn't go so far as to say i *suggested* it...i think you are trying to do things at compile time that you can't do until runtime, and apply-macro lets you get close to that sometimes

4:15 notsonerdysunny: ok sorry for misrepresenting you.. :)

4:15 amalloy: if you really want to create code based on the execution of code, why not just have your clojure program generate a new .clj file

4:15 notsonerdysunny: but I was not able to figure out how to use it in any case ..

4:15 amalloy: and ship that to the user

4:17 notsonerdysunny: :) good point .. but was hoping I needn't have to do that ..

4:18 I think we are trying to make an argument like people using languages who don't have macros would .. :)

4:18 amalloy: if you want the user to be able to run the same program that you do, unmodified, then you have to ship them mathematica. i don't know how it can possibly work otherwise

4:18 notsonerdysunny: I would do to Ahead Of Time compilation

4:19 so all the macros would be expanded in the resultant code ..

4:19 well atleast that was the theory based on which I was working ...

4:20 amalloy: right, i always forget AOT is an option

4:26 okay. here is an idea that i think i have tried a few times but i don't think i've really communicated it to you. one sec while i put together a gist

4:27 notsonerdysunny: http://gist.github.com/630662

4:29 here ask-mathematica is a function, which helps solve-pde generate code

4:31 notsonerdysunny: thanks amalloy .. Let me try to use your idea and come up with something..

4:31 :)

4:32 amalloy: the general point here is you very rarely want to define a macro that uses another macro you define - the second level and below usually want to be functions

4:34 fwiw, (solve-pde x y) really does macroexpand to (+ y (* x 10)) there - the reference to ask-mathematica has vanished

4:50 notsonerdysunny: :) ... but as a side-note.. It would be nice if we had a set of macros which would wrap the special forms and be able to handle non-literal values.. be it macro or just regular code .. just wishfull thinking .. I don't know enough even to evaluate the feasibility of such macros .. :)

4:57 amalloy: notsonerdysunny: well, for (def) you don't need such a macro

4:59 (intern (symbol "test") 'size 10)

4:59 can't do that in clojurebot obviously, but it should work at your repl

5:00 anyway, i'm off to bed. good luck, i hope to see how it all turns out

5:36 _ulises: morning all

7:22 serabe: hi

7:23 raek: hello

8:02 serabe: just released rinzelight, an image library for clojure, http://github.com/Serabe/rinzelight

9:58 shanmu: Hi, What options would I have if I want to run a long running process/daemon in clojure (which has to do some periodic activity)?

9:59 my thought is to have a compojure app, to which I do wget from cron...

10:00 or another option is to write a quartz job but I am not sure how to integrate in clojure...

10:02 or yet another option would be invoke the cljoure script/compiled class direct from shell script/cron but pay jvm startup cost everytime

10:13 LauJensen: shanmu: jvm startup cost is typically < 1 second with the -client option. It would be trivial to write a program which ran a future every x seconds though. Its a tradeoff between startup time and memory consumption, weigh it thinking about the frequency of the activity

10:15 shanmu: LauJensen: thanks for the suggestion - I had missed future... (i am still a n00b :))

10:28 Bahman: Hi all!

10:53 FUser: ,(range 1000)

10:53 clojurebot: (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 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133

10:53 FUser: :)

11:16 ,(counted? (seq [2 33]))

11:16 clojurebot: false

11:16 FUser: ,(counted? (seq '(2 33)))

11:16 clojurebot: true

11:17 FUser: wat?

11:17 makes no sense

11:17 jarpiain: ,(doc counted?)

11:17 clojurebot: "([coll]); Returns true if coll implements count in constant time"

11:17 Chousuke: FUser: they're different types

11:18 FUser: they are both sequences

11:18 Chousuke: ,(let [x '(2 3)] (identical? x (seq x)))

11:18 clojurebot: true

11:18 Chousuke: that's the reason

11:18 FUser: look

11:18 ,(counted? [2 32])

11:18 clojurebot: true

11:18 FUser: ,(counted? '(23 2))

11:18 clojurebot: true

11:19 MayDaniel_: ,[(type (seq [1 2])) (type (seq '(1 2))]

11:19 clojurebot: Unmatched delimiter: ]

11:19 FUser: ,(counted? (seq [2 23]))

11:19 clojurebot: false

11:19 raek: seqs are not guaranteed to be counted

11:19 FUser: these are all expected

11:19 yeah

11:19 raek: but PersistentLists are their own seqs

11:19 FUser: but why are seqences made out lists counted

11:19 raek: so (seq a-list) happens to be counted

11:19 FUser: also maps

11:19 tensorpudding: where's a good place to get a tutorial to clojure?

11:19 Chousuke: FUser: because lists don't need to be made into sequences.

11:20 FUser: they are sequences already

11:20 raek: (let [l (list 1 2 3)] (identical? l (seq l)))

11:20 ,(let [l (list 1 2 3)] (identical? l (seq l)))

11:20 clojurebot: true

11:20 FUser: ,(counted? (seq {3 22}))

11:20 clojurebot: true

11:20 Chousuke: I suppose it might be an oversight, though.

11:21 FUser: whats the diff between seq function and sequence function?

11:22 ,(seq nil)

11:22 clojurebot: nil

11:22 FUser: ,(sequence nil)

11:22 clojurebot: ()

11:22 FUser: oh

11:23 raek: tensorpudding: this covers the basics http://en.wikibooks.org/wiki/Learning_Clojure

11:24 FUser: sequence is also faster it seems

11:25 (time (do (sequence (range 1000000000)) nil))

11:25 raek: I have seen 'sequence' before...

11:25 FUser: ,(time (do (sequence (range 100000000)) nil))

11:25 clojurebot: "Elapsed time: 0.135 msecs"

11:26 FUser: ,(time (do (seq (range 100000000)) nil))

11:26 clojurebot: "Elapsed time: 0.212 msecs"

11:26 raek: seq is the one that is usually used to turn a collection into a sequence

11:27 _ulises: ,(doc sequence)

11:27 clojurebot: "([coll]); Coerces coll to a (possibly empty) sequence, if it is not already one. Will not force a lazy seq. (sequence nil) yields ()"

11:28 tensorpudding: what does clojure call lambda?

11:28 Kruppe: fn

11:28 (fn [] (print "hi"))

11:28 tensorpudding: okay

11:29 clojure looks pretty good for being built on java, i suppose

11:30 Kruppe: tensorpudding: It's pretty nice, id say its more built on the jvm than built on java though.

11:32 raek: there are plans to reimplement the compiler (which is now written in Java) in Clojure

11:32 FUser: :D

11:33 the only problem is that clojure uses a shitton of reflection and allocated billions of objects per second

11:34 raek: reflection is only used of java methods calls

11:35 and can be avoided completely, if the type is known (e.g. through type hints)

11:35 Raynes: tensorpudding: Ooh, you're the second prominent #haskell user in here in the last week.

11:35 tensorpudding: heh

11:35 Raynes: kmc is here too. <3

11:36 FUser: raek: so if I am using clojure Fns, I am not using reflection?

11:36 raek: FUser: exactly.

11:37 clojure fns are always take Objects and return Objects

11:37 FUser: allocations are still a problem though

11:37 raek: yes

11:37 FUser: they did some testing

11:37 Raynes: raek: All your clojure fns are belong to us.

11:37 raek: but the HotSpot JVM is pretty good at it

11:38 FUser: compared ArrayList and LinkedList in java, inserting in the middle of the list, which is O(n) for array list and O(1) for linked list

11:38 raek: but having immutable data structures kinda requires much allocation

11:38 FUser: array list still faster unless the list size is over a million

11:39 simply the allocations for the linked list objects

11:39 are too much

11:39 raek: I guess that the mutable data structures are simpler and faster, but they still have the problems Clojure is trying to solve

11:39 FUser: and that's java mutable linked list, I can only imagine how badly the clojures quasiconstant time inserts must be

11:40 Chousuke: Don't imagine, measure :)

11:40 FUser: I'm just sayin'...O(n) notation doesn't say shit :P

11:40 raek: neither PersistentVector nor PersistentList is the correct data structure for doing fast inserts to the middle

11:40 I have heard that chouser is working on some data structure that has good performance for that

11:41 Chousuke: Finger trees

11:41 wakeupsticky: best clojure tutorial for the non-java programmer (i'm familiar with lisp and haskell)?

11:42 FUser: transient vectors are probably fast

11:43 Chousuke: They'll still be slow for inserts in the middle

11:43 FUser: if they are actually java ArrayList then they are fast

11:43 raek: wakeupsticky: these were what I got started with. YMMV. http://clojure.blip.tv/posts?view=archive&nsfw=dc

11:43 Chousuke: they aren't.

11:43 they can't be. :/

11:44 because transient->non-transient and vice versa must be a constant time operation

11:44 FUser: ok then I'll just use (.java.util.ArrayList) :P

11:45 Chousuke: if you're really doing lots of inserts, maybe :P

11:45 FUser: fastest access too

11:45 Chousuke: but realise that you're giving up safety and ease of use

11:45 FUser: I know

11:46 I can't cope with having 300 times slower apps

11:46 Chousuke: I'm not sure about that.

11:47 For a whole bunch of apps Clojure's vectors won't be a bottleneck

11:47 Don't give up on them until you encounter a real performance problem.

11:48 Fast programs are nice, but working ones are nicer :P

11:48 FUser: clojure has a bunch of weird performance issues

11:48 Chousuke: Like?

11:49 FUser: (if (> its 0)

11:49

11:49 compared to

11:49 Chousuke: I can't think of anything that's particularly weird. There is room for improvement though.

11:49 FUser: (if (> its (int 0)))

11:49 guess the speed difference

11:49 Chousuke: FUser: in the former case, there is boxing

11:49 FUser: not only that

11:49 Chousuke: so of course it's slower

11:50 FUser: but there's also lookup in > function

11:50 for type

11:50 Chousuke: yeah, because it's polymorphic :p

11:50 FUser: second version runs 9 times faster

11:50 Chousuke: (numerical performance is kind of the focus of 1.3 btw)

11:51 So expect things to improve

11:51 FUser: that kind of performance differences for such a simple change in code is unacceptable

11:51 Chousuke: No they are not

11:51 it's not a simple change,

11:51 it does a lot.

11:51 FUser: I'll spend time saved in development doing profiling afterwards

11:51 well technically yes

11:52 but I can't see why I'd have to cast a constant 0, why can't compiler do that for me

11:52 Chousuke: Because the compiler is not very good yet.

11:52 Kruppe: FUser: its a new language, 1.3 will improve that particular problem

11:52 FUser: :)

11:52 Chousuke: It doesn't try to be, either; there are bigger things to do first.

11:52 Kruppe: FUser: for now its not perfect, thats for sure.

11:54 FUser: sorry I'm mad, but after doing SQL optimizations, where there's a bunch of hidden rules how things get evaluated and slightly changed but semantically same sentences produce vastly different performance I'm really disgusted by these kinds of things

11:55 it all becomes just a whole bunch of arcana

11:55 and code gets ugly fast

11:56 Kruppe: FUser: I sympathize, I wrote a fairly complicated simulation in clojure and it was a real pain to work out all the performance kinks.

11:56 FUser: the simulation was easy to write though.

11:59 FUser: yeah but you see what I mean....you write a simple sql query, optimizer screws it up in ways you know nothing of, then you scour the forums for ages to find some kind of hack (adding dumb shit like "or false" to queries, that makes the optimizer do things differently)

12:00 and that simple query becomes ugly unreadable and ununderstandeable to any other programmer, unless they are in the know of these hacks

12:01 Kruppe: FUser: Its performance definitely isn't a non issue, if its not good enough right now you could always use something else.

12:02 FUser: Or write the bottlenecks in java since you're already on the jvm.

12:02 FUser: well, I am not using it professionally so it's not much of an issue

12:02 Kruppe: FUser: oh, well in that case. Readability isn't such a huuuuuuuge hit.

12:02 Chousuke: Or you could go and improve the compiler, and be everyone's hero :)

12:02 FUser: :D

12:02 Kruppe: FUser: if you don't need concurrency semantics you could always use common lisp.

12:03 FUser: I find it easier to write fast code in CL atm, but i suspect that will change soon enough.

12:03 FUser: CL?

12:03 Kruppe: FUser: common lisp

12:03 FUser: oh

12:03 never used lisp

12:03 mostly java

12:03 Chousuke: In Clojure's case the compiler is destined to be rewritten in Clojure someday though.

12:04 FUser: my main java issues are already solved by C#

12:04 so that would be my perfect language

12:04 Kruppe: Chousuke: yeah I have confidence that rich is very concerned with performance.

12:04 FUser: but I have job requirement to use java so I'm stuck with it

12:04 Chousuke: Yeah.

12:04 FUser: I'm taking up clojure purely for the learning experience

12:05 since it's my first dynamically typed functional language

12:06 I'm fresh out of ideas what to make in it

12:06 Kruppe: FUser: It's a general purpose language, could make anything you want in it.

12:06 FUser: that's my main problem, I was learning Android, J2Me, Clojure, but I have no inspiration about what to make in them so I end up not practicing enough

12:06 Kruppe: FUser: performance issues aside I suppose.

12:07 FUser: I know :)

12:07 Kruppe: FUser: could just pick an open source project and contribute

12:07 FUser: hm....

12:07 not a bad idea

12:07 Kruppe: FUser: dunno if there are any clojure open source projects you would want to contribute to. But you could look.

12:09 FUser: it's funny how I'm the only guy at the office who programs and reads about programming in his spare time

12:09 people call me an academic

12:11 Kruppe: FUser: those people are probably just lazy and are surprised at your initiative

12:11 FUser: probably burnt out on coding java

12:12 FUser: I'm amazed. They have no drive to better themselves at their chosen profession

12:12 even though they are terrible at java

12:12 I don't need to improve my java, I'm one of the best in the firm

12:13 Kruppe: FUser: working at large companies can ruin you desire for self improvement

12:13 FUser: I see shit daily that would bring tears to your eyes

12:13 40 employees

12:13 Kruppe: FUser: oh

12:13 FUser: every non-member function in the project is in a class named Utils

12:14 every constant in the project is in a class named Constants

12:14 shit like that

12:14 Kruppe: FUser: that sounds pretty tame, but this is also a little offtopic now

12:14 FUser: class structure is 1 level deep at most, there are no interfaces defined

12:14 ok

12:15 basically cobol programmers trying to do OO

12:15 OOP

12:15 Kruppe: FUser: it sounds like that structure was just decided by a manager

12:15 FUser: nope, by actual programmers with 10 year more experience than me

12:16 Kruppe: FUser: I guess their minds have been somewhat tainted by working in cobol all the time.

12:16 FUser: no kidding :D

12:16 Kruppe: FUser: teach em how it's done then, you then will really be the academic.

12:16 FUser: that's why I'm learning clojure, not to get completely trapped in Java mindset

12:17 Kruppe: FUser: if learning is your goal i recommend haskell as well. Lots of interesting programming language concepts are available in it to play around with.

12:17 FUser: don't get your heart set on writing haskell for money or anything though.

12:18 FUser: true

12:18 Kruppe: FUser: clojure is a nice intermediate step though, you get to play around with macros and FP.

12:18 FUser: yeah

12:18 Kruppe: FUser: not to mention really slick concurrency.

12:18 FUser: hell I'm hoping for C# someday

12:18 at least it has function pointers

12:19 Kruppe: FUser: not a huge fan, but I don't enjoy programming for windows so.

12:19 raek: there is Clojure CLR...

12:19 FUser: implementing interfaces for a simple filter function in java is maddening

12:19 C# delegates neatly cover a lot of this

12:20 raek I'm not pining for CLR

12:20 just having delegates (function pointers actually) and proper templates (C# ones not java ones) would solve a lot of my day to day work problems with java

12:21 Kruppe: FUser: I don't doubt it.

12:21 FUser: clojure has all of it also, of course

12:21 but it's less commercially popular, so I'm not gonna get a job with it

12:21 Kruppe: FUser: Hey boss, can I use this java library called clojure?

12:22 FUser: hehe, you know

12:22 I thought about it :D

12:22 Kruppe: FUser: actually that would never fly.

12:22 FUser: and it would be pretty irrisponsible of you to decieve your boss like that.

12:22 FUser: I know I know :D

12:22 Kruppe: FUser: and your code would be unmaintainable by anyone else there sadly

12:22 FUser: if only it were that easy

12:22 FUser: yes that is the main problem

12:23 I leave company now they can't fix anything in that code,because nobody else knows clojure

12:23 Kruppe: FUser: I tried convincing my boss to use svn or git for our software projects

12:23 FUser: svn ? version control system?

12:23 Kruppe: FUser: even that was difficult

12:23 FUser: yeah, we weren't using any version control for the longest time

12:23 FUser: it was pretty depressing

12:23 FUser: wow

12:24 that's pretty bad

12:24 Kruppe: FUser: I don't work there anymore.

12:24 FUser: I'm trying to tell the boss that we need design documentation

12:25 Kruppe: FUser: really? That I find really unusual.

12:25 FUser: we are making none since the customers only pay for requirements documentation

12:25 Kruppe: FUser: i need to practically document my bathroom schedule

12:25 FUser: so bascially each programmer is free to design his parts of the program however he wants

12:25 you only have architectural restrictions

12:26 you have to use this DB, that XML Serializer library, that web service etc

12:26 so project parts vary wildly in quality depending on who from our firm is working on them

12:27 Kruppe: FUser: that's unfortunate.

12:27 FUser: only for our customers :DDDDDD

12:27 see this is how it kills you...I stopped giving a fuc

12:29 Kruppe: FUser: Yeah, that will happen if you're not careful.

12:29 FUser: I told my boss multiple times that better programmers should be doing class design for whole project and worse programmers should be implementing closely specified indivdual methods

12:29 can't be arsed to do it again

12:30 Kruppe: FUser: that sucks.

12:31 kryft: C# templates? Are those anything like C++ templates?

12:32 FUser: not sure

12:32 I just know that Java Generics are much like C# templates

12:32 Chousuke: Nothing like C++ templates then :/

12:32 FUser: but C# templates are proper and Java Generics are just stupid compiler hack with limited functionality due to havign to be backwards compatible

12:33 Kruppe: FUser: they work alright though. It could be worse.

12:33 FUser: I've run into their limitations several times before

12:33 Kruppe: FUser: language warts like that happen over time.

12:34 FUser: yeahhhh. Sometimes java just makes things difficult.

12:34 FUser: It could be better if Sun wasn't being so stubborn with their compatiblity

12:34 raek: I find it interesting that the C++ template system is Turing complete...

12:35 FUser: you can't run java 5 classes on java 1.4 anyway so why bother

12:35 Kruppe: FUser: its not stubbornness necessarily.

12:35 FUser: They don't want to scare anyone away.

12:35 FUser: in general they have done a real good job keeping java THE language for business.

12:36 FUser: here an example: public void <E> someMethod(E param) {

12:36 Kruppe: FUser: as a result it may not be the nicest language to work with but its still extremely popular.

12:36 FUser: E.class doesn't work, E.getClass() doesn't work

12:36 Kruppe: FUser: yeah thats one of those warts right there.

12:36 SergeyD: Hi, is there a way to get colorful Clojure cheat sheet? It was in the zip a year ago, but now that link is broken. (In the bottom of http://clojure.org/cheatsheet)

12:37 FUser: http://clojuredocs.org/quickref/Clojure%20Core

12:40 raek: SergeyD: I have the .tex file. Can you compile that?

12:40 SergeyD: FUser: thanks for another source

12:41 raek: yes, I'll figure out

12:41 FUser: what's a monad

12:42 raek: SergeyD: http://raek.se/cheat-sheet/

12:42 kryft: FUser: http://intensivesystems.net/tutorials/monads_101.html

12:42 FUser: (I don't really know myself, but I plan to read that at some point and find out. ;)

12:43 SergeyD: raek: thanks!

12:43 Kruppe: kryft: I've used haskell for a few personal projects, and I still can't really describe what monads are in words.

12:52 raek: compiled PDFs are now up too http://raek.se/cheat-sheet/

12:53 SergeyD: raek: thanks :)

13:03 _ulises: can anybody recommend a good library for performing 2d vector operations?

13:03 I've sort of handcrafted my own but I'm sure that there are better options out there (google wasn't my friend :(

13:04 esj: _ulises: I think Incanter wraps Colt

13:04 _ulises: oh, right

13:04 esj: unsure how far they went

13:04 _ulises: I am looking for something a bit more lightweight though :)

13:05 ,(doc max)

13:05 clojurebot: "([x] [x y] [x y & more]); Returns the greatest of the nums."

13:05 Kruppe: Anyone else having trouble getting incanter and cake to work together?

13:05 esj: _ulises: oh, in that case the seq functions are your friend

13:06 _ulises: seq? how? kind of like (apply map + points) where points is ([x y] [x y]...) ?

13:06 raek: ,(merge-with + {:x 1, :y 2} {:x 0, :y -3})

13:06 clojurebot: {:x 1, :y -1}

13:06 _ulises: ooh

13:06 nice!

13:06 raek: not a seq function, but...

13:06 _ulises: no no, that is awesome

13:07 dnolen: _ulises: cantor is pretty good if you have simple needs, http://github.com/ztellman/cantor

13:07 _ulises: now I have to figure out how to use the same style for euclidean distance and the other fns...

13:08 esj: dnolen: thanks for the pointer - that looks pretty useful

13:08 _ulises: dnolen: that looks good! thanks

13:08 Kruppe: (require '(incanter core stats charts)) gives me a java.lang.ExceptionInInitializerError using cake

13:08

13:08 raek: ,(map + [1 2] [0 -3])

13:08 clojurebot: (1 -1)

13:08 dnolen: _ulises: using maps or vectors is ridiculously slow if you're doing interactive grahis and the like

13:08 _ulises: dnolen: indeed!

13:08 dnolen: s/grahis/graphics

13:09 _ulises: cantor has good perf, identical to using javax.vecmath in an immutable manner.

13:09 _ulises: awesome, will give it a whirl

13:10 I can see how this is somewhat targeted to a physics engine

13:10 dnolen: _ulises: yeah it's integrated into penumbra, the clojure opengl library

13:10 _ulises: cool

14:10 kmc: wow a bunch of haskellers showed up :D

14:10 rlb: Is the best way to access a static nested java class to just import Foo$Bar?

14:13 kmc: Chousuke, finger trees in Clojure? sweet

14:14 raek: #clojure - #haskell cross-pollination?

14:14 kmc: seems so

14:14 FUser, Kruppe, i can try to explain monads if you like, or at least give some relevant meta-advice

14:14 tensorpudding: i had been meaning to try clojure for a little while

14:15 _ulises: kmc: I wouldn't mind that :)

14:15 tensorpudding: it's not a lot like haskell so far as i can tell though

14:15 kmc: me too

14:15 tensorpudding, i think it's philosophically close to Haskell, and technologically quite different

14:16 the barrier to me getting started was setting up all the java classpath apache maven 80 mb of code to do nothing jvm that tries to take down your whole system bs

14:17 tensorpudding: i had tried setting it up before

14:17 kmc: so i had a couple false starts due to that

14:17 but eventually i got lein set up ok

14:17 tensorpudding: i was inspired to try again while cleaning up the mess that was my .emacs

14:17 kmc: and the actual clojure part of clojure is nice

14:18 tensorpudding: clojure seems to have improved a lot on the packaging front

14:19 for that matter, ELPA too

14:19 raek: Clojure and Haskell seems to have the preference for immutability in common.. (well, maybe preference is a bit of an understatement in the case of Haskell :) )

14:20 I remember the time before lein...

14:20 tensorpudding: haskell likes immutability, but also code segregation through typing, which clojure doesn't appear to have

14:20 raek: yes, Clojure tries to do as much as possible without types

14:21 Kruppe: kmc: I wouldn't mind a nice description of monads. Thanks for the offer.

14:21 raek: data representation, dynamic dispatch and hierarchies doesn't have to do anything with types

14:22 _ulises: +1 on the monads explanation :)

14:22 kmc: raek, well Haskell has mutable data structures too

14:22 raek: inc

14:22 kmc: and in fact there's some very popular haskell libs that use mutation behind the scenes, but present a pure interface

14:22 _ulises: s/+1/inc/

14:22 kmc: writing such a thing is tricky

14:22 raek: reminds me of transients

14:22 kmc: yes

14:23 Haskell's ST monad is a lot like transients -- you get to use mutation locally, and expose the result as pure value

14:23 in Haskell the type system proves that your mutation doesn't leak out

14:23 and so there's no runtime overhead, compared to less safe approaches

14:23 raek: Haskell is very high on my to-learn list

14:24 probably #1

14:24 tensorpudding: the only way to get performance on some things is mutation behind the scenes

14:24 Kruppe: raek: real world haskell did a good job for me. Pretty awesome book.

14:25 FUser: how's performance of Haskell

14:25 raek: ah, yes. I have borrowed that book from a friend. have barely started with it.

14:25 Kruppe: FUser: very good.

14:26 FUser: immutable data structures cause similar performance problems but you can use mutable data structures if necessary.

14:26 raek: ever since I was introduced to SML in the Programming Theory course I'm attending, I have been incresingly interested in learning Haskell

14:26 kmc: GHC is one of the smartest native-code compilers i know of

14:26 for any language

14:27 Chousuke: kmc: I don't know the status of Chouser's finger tree implementation though. It seemed sort of half-ready the last time I checked.

14:27 Kruppe: kmc: I miss macros when im in haskell though, template haskell feels clunky :(

14:27 kmc: yes

14:27 Template Haskell is incredibly clunky

14:27 that's one of my main complaints with Haskell these days, and it's one of my main reasons for learning Clojure

14:27 FUser: I miss types in clojure or even plain old C style structs

14:27 tensorpudding: TH is an dark, dingy failed attempt masquerading as a code extension.

14:27 kmc: metaprogramming is so powerful and so underappreciated, and Lisp is absolutely king there

14:28 Kruppe: FUser: clojure has structs

14:28 kmc: i wouldn't say TH is "failed" -- it is used in an essential role by a wide variety of useful projects. it's just a lot more pain than necessary

14:28 Chousuke: records :P

14:28 kmc: anyway, monads!

14:28 FUser: if they are implemented as maps then they aren't stucts even if they are named as such

14:28 Kruppe: kmc: rock on

14:28 kmc: my advice on learning about monads

14:29 Chousuke: FUser: records are the closest you get to C-style structs

14:29 Kruppe: FUser: they are quite fast as well

14:29 kmc: one thing to keep in mind is that "monad" is just the name of a generic API

14:29 public class List<T> implements Monad ...

14:29 and it's implemented by a lot of different unrelated things

14:29 Chousuke: They provide a maplike interface for convenience and are immutable.

14:30 kmc: people often look for a deep intuitive connection between all the monad instances

14:30 when they wouldn't expect this of just any generic API

14:30 Chousuke: (deftype is there if you need custom behaviour, but that's not recommended)

14:31 kmc: It helped me a lot to think of a monad as an "execution strategy" kind of thing :P

14:31 kmc: also, before you read (or write!) a monad tutorial, you should read: http://byorgey.wordpress.com/2009/01/12/abstraction-intuition-and-the-monad-tutorial-fallacy/

14:31 FUser: (Kruppe if they are maps then they aren't fast TBH

14:31 kmc: the Haskell community has moved pretty strongly against all these analogy-based tutorials

14:31 Kruppe: FUser: i don't think they are maps under the hood.

14:31 kmc: the common wisdom now is to get comfortable with a few concrete monad types

14:31 raek: FUser: (btw, transients in clojure, a way to temporarily use a data structure as a mutable one: http://clojure.org/transients)

14:31 kmc: you don't have to care as much about what the generic API means, if you focus on one type at a time

14:32 and also, to learn some of the less powerful (meaning more general) APIs first

14:32 functor and applicative functor

14:32 Kruppe: kmc: the one that really confuses me is ST, and the type errors i get when using it.

14:32 kmc: yeah, ST is pretty special

14:32 its specialness comes not from being a monad, but from the primitives that are provided for ST specifically

14:33 same for IO, STM, etc.

14:33 it's a common fallacy to learn IO first and then generalize it to all monads

14:33 when really IO is a strange atypical monad

14:33 kryft: kmc: Right, familiarize yourself with a few concrete examples and then let your brain do the generalization from there.

14:33 kmc: Kruppe, over in #haskell we'd be happy to help you with ST type errors

14:33 Kruppe: kmc: yeah that seems to always be the first monad to be described, maybe because its used all the time

14:34 kryft: kmc: I have a tendency to want to understand everything as generally as possible from the get-go, and that usually doesn't turn out so well. :)

14:34 Kruppe: kmc: thanks hehe, but its been a while since my last use of the ST monad. My projects right now are tied with C libs and python.

14:34 kmc: i like the approach of some materials (LYAH?) where they present IO early on, but give you the concrete explanation and avoid the m-word until much later

14:34 some of the people who "don't get monads" are actually not getting the idea of building IO-descriptions for later execution

14:35 which is an orthogonal idea

14:36 kryft: kmc: I take it you use both clojure and haskell?

14:36 kmc: yup

14:36 * djahandarie giggles

14:36 kmc: i've been using Haskell for about 5 years

14:36 just learning Clojure

14:37 awkorama: what do you guys use closure for?

14:37 Kruppe: awkorama: closures? or clojure?

14:38 awkorama: sorry, i meant clojure

14:38 the language for jvm

14:38 Kruppe: awkorama: just making sure. I've used it for simulations mostly. Dunno about everyone else.

14:38 tensorpudding: hmm, i have the clojure-contrib installed, but it seems (use 'clojure.contrib.monads) doesn't work

14:38 Kruppe: awkorama: its a general purpose language though

14:39 awkorama: Kruppe: sure, but what about traditional 3 layer enterprise web app?

14:39 can it handle these?

14:39 tensorpudding: and now i've got it talking about classpaths

14:39 awkorama: what about annotations and stuff? i found no info on these in clojure

14:39 Kruppe: awkorama: I don't see why not, but I haven't tried it myself.

14:40 awkorama: you have access to all of javas libs and can basically write java in clojure if you want.

14:40 zakwilson: Clojure has the ability to talk to databases and render templates or generate HTML.

14:40 raek: tensorpudding: how are you starting clojure? lein?

14:40 awkorama: zakwilson: including transaction management?

14:41 tensorpudding: I installed clojure from the Ubuntu repositories

14:41 /usr/bin/clojure -r

14:41 rlb: FUser: I belive records aren't "maps" at all, i.e. they're compiled classes where the members are fields.

14:41 tensorpudding: it's a script

14:41 rlb: (and can have optional type annotations)

14:41 FUser: that's cool

14:41 tensorpudding: does some environment mashing

14:41 FUser: I'll use precompiled version then

14:41 raek: tensorpudding: I wouldn't recommend starting clojure that way. it makes classpath management very hard.

14:42 tensorpudding: for just "give me a repl" use http://github.com/liebke/cljr

14:42 FUser: I use clojurebox

14:42 tensorpudding: eeeenh

14:42 zakwilson: awkorama: ClojureQL appears to handle transactions. I have not used it though.

14:42 tensorpudding: i really was wanting to not have to use much in the way of hand-compiled stuff

14:42 raek: tensorpudding: for projects (i.e. code in more than one source file) use http://github.com/technomancy/leiningen

14:44 the thee major clojure tools (lein, cake, irclj) have all been released since ~november 2009..

14:44 tensorpudding: hmm

14:45 kmc: i'm using leiningen even for tiny 1-file projects

14:45 it's pretty easy

14:45 tensorpudding: leiningen is like cabal?

14:45 kmc: tensorpudding, don't be that guy ;)

14:45 tensorpudding: what do you mean?

14:45 kmc: "hi #haskell, please tell me which Haskell function is like GetXW3byF97() from PHP thanks"

14:45 tensorpudding: i was asking you

14:46 kmc: thait said, leiningen is like cabal ;)

14:46 djahandarie: GetXW3byF97 only works in PHP kmc, Haskell isn't powerful enough to support it

14:46 kmc: but it can also do stuff like launch a repl

14:46 raek: it manages dependencies and the class path, among other things

14:46 SergeyD: tensorpudding: ubuntu's clojure is quite old - version 1.0.*

14:46 kmc: and it can build a jar with all your clojure libs baked in, so you can distribute it to Java zombies

14:47 tensorpudding: i've got 1.1.0 here

14:47 raek: basic workflow for a new project: lein new foo; cd foo; <editor> project.clj; lein deps; lein repl

14:47 tensorpudding: on maverick

14:47 it sounds like cabal but even better

14:47 hmm

14:47 raek: you declare dependencies in project.clj, and leiningen takes care of downloading it and putting it on the classpath

14:48 cljr is like lein, but with one global project

14:48 tensorpudding: how is the classpath handled? env mangling?

14:48 raek: it constructs it from what's in project.clj

14:49 tensorpudding: okay

14:49 does lein work with clojure 1.1.0?

14:49 raek: every project has its own lib/ directory with its versions of its dependencies

14:49 tensorpudding: oh hey, it's named after that story about the ants

14:49 raek: yes, just change [clojure "1.2.0"] to [clojure "1.1.0"] in project.clj

14:49 tensorpudding: i read that in middle school

14:49 kmc: tensorpudding, when i set up lein i did it in a way that downloaded the newest clojure automatically

14:49 rlb: I'm still not happy with what appears to be the java (and apparently inherited in clojure) practice of "just run this cmd and don't worry about where all the code comes from, who wrote it, or whether or not it's been vetted". I hope eventually that changes (i.e. wrt maven, clojars, etc.).

14:50 tensorpudding: kmc: downloaded it where?

14:50 kmc: tensorpudding, http://github.com/technomancy/leiningen

14:50 raek: into ~/.m2

14:50 kmc: yeah

14:50 tensorpudding: one of the things i strongly dislike about cabal is how it defaults to putting things in the home directory

14:50 kmc: i had to apt-get install maven first

14:50 raek: it uses maven for the dependency stuff

14:50 Once: If anyone is familiar with fnparse please take a peek at http://paste.lisp.org/+2H88 Very simple example, and I'm not sure what the best solution is. Problem is exampled in the paste.

14:50 tensorpudding: so i don't know where things are

14:50 kmc: which in turn downloaded about 80 MB of Apache Very Serious Enterprise Java libraries

14:51 Once: problem is explained*

14:51 tensorpudding: though i guess clojure basically is just a couple jarfiles isn't it?

14:51 raek: it is.

14:51 kmc: tensorpudding, yep, there's a jar for clojure and another for clojure-contrib

14:51 and another for each 3rd-party lib you install

14:51 tensorpudding: why ~/.m2?

14:51 raek: that's why you basically have to start it with some tool

14:52 maven 2, I think

14:52 tensorpudding: what's maven?

14:52 is that java's build tool?

14:52 raek: a java build tool

14:52 yes.

14:52 tensorpudding: okay

14:52 raek: leiningen uses the dependency parts of it

14:52 tensorpudding: where are the scripts installed?

14:52 raek: which scripts?

14:53 tensorpudding: do i have to edit my $PATH?

14:53 the lein script

14:53 raek: yes

14:53 the lein script is the only script

14:56 ihodes: hey all! it's been a while. anyone here familiar with Compojure?

14:59 zakwilson: ihodes: I am a little bit.

14:59 amalloy: zakwilson: if booleans said that they would be adorable

15:00 ihodes: zakwilson: well i'm using it and Enlive to serve up some static pages on my local machine. problem is, the CSS will not load. I've tried relative and absolute paths, and opening the page myself (with the relative path) as a static file in safari displays the CSS just fine. any ideas?

15:00 zakwilson: Instead of loading the CSS, what does it do?

15:01 ihodes: the raw HTML displays, as if unstyled

15:03 LauJensen: ihodes: paste your app ?

15:03 raek: ihodes: what happens if you enter the stylesheet url in the browser?

15:04 tensorpudding: okay, so i have lein setup

15:04 how do i get emacs to use it?

15:04 raek: tensorpudding: install ELPA in emacs first

15:04 if you don't already have it

15:04 tensorpudding: i already did

15:05 to install clojure-mode

15:05 raek: ok, then install packages slime, slime-repl and clojure-mode

15:05 ihodes: (html/deftemplate index "main.html" [] )

15:05 (defroutes example

15:05 (GET "/" [] (render (index)))

15:05 raek: slime is for interacting with the clojure process

15:05 ihodes: (route/not-found "Page not found"))

15:05 LauJensen: ihodes: You also need to tell your app to serve sttic files

15:05 static

15:06 ihodes: LauJensen: what do you mean?

15:06 LauJeson: it's serving the static HTML just fine; just without the CSS

15:06 main.html is in resources/

15:06 tensorpudding: i've used slime before

15:06 LauJensen: ihodes: Nothing in what you pasted is telling Compojure to serve CSS files right? So when you template looks for /css/main.css, it wont find anything

15:06 tensorpudding: with CL

15:06 raek: ihodes: you need to tell your app that GETting /foo.css means serving the file resources/foo.clj

15:06 LauJensen: ihodes: What it does, is read main.html from disk, and serve it via a template

15:07 raek: tensorpudding: then add [swank-clojure "1.2.1"] to your project as a :dev-dependency

15:07 LauJensen: ihodes: if all your static files are in resources/, try adding the middleware (wrap-file "resources")

15:07 zakwilson: ihodes: paste the whole thing to a pastebin?

15:07 raek: do lein deps, and then lein swank

15:07 ihodes: LauJeson: do i need to include that middleware somewhere? that sounds like what I want to do

15:07 LauJenson

15:08 raek: you need both slime and slime-repl

15:08 tensorpudding: example project.clj http://gist.github.com/555485

15:09 amalloy: ihodes: try LauJensen :)

15:09 raek: lein swank should start a swank server on port 4005, which you can connect to with emacs with M-x slime-connect

15:09 LauJensen: ihodes: Yea you do. I havent used Compojure in a long time, but I think its (defroutes ex (wrap-file "resources") (GET "/" ....

15:10 Also make sure you import it in your namespace declaration ring.middleware file

15:10 (thanks amalloy)

15:10 tensorpudding: oh lame

15:11 got an exception

15:11 zakwilson: Is there a currently accepted "best" set of tools to use for web stuff in Clojure?

15:12 tensorpudding: oh wait, right, need to change versions

15:12 LauJensen: zakwilson: Depends on who you ask. There's primarily Moustache and Compojure. I like Moustache a lot and its very similar to Enlive (by the same author).

15:12 tensorpudding: no, that didn't fix it

15:12 LauJensen: I also like Compojure. But not enough to use it

15:13 ihodes: LauJensen: what are the main differences? i'm just starting a project using Enlive; should I give Moustache a look first?

15:13 raek: tensorpudding: swank-clojure 1.2.1 requires clojure 1.2 I think

15:13 LauJensen: ihodes: I think you should yea. Its a very elegantly designed micro-webframework. Check out the readme on its github page.

15:13 zakwilson: I have been using Compojure, though I haven't touched the web part of the app that uses it in a while.

15:13 raek: I'm currently very happy with the Ring + Moustache + Enlive combo

15:14 tensorpudding: raek: i thought leiningen grabbed the right version of clojure for you?

15:14 ihodes: i'll give Moustache a go, then. do you know if Chris will be updating Enlive or Moustache anytime soon?

15:14 tensorpudding: the exception is related to ant, it seems

15:15 raek: leiningen picks the clojure version you tell it to

15:15 tensorpudding: it's grabbing 1.2.0, supposedly

15:15 LauJensen: ihodes: AFAIK I know there are no plans in the immediate future

15:15 raek: tensorpudding: could you paste the stack trace?

15:16 zakwilson: Moustache looks like it might be good. I hate the name though.

15:16 raek: if you mix [clojure "1.2.0"] with [clojure-contrib "1.1.0"] for example, it will not work

15:17 since clojure-contrib is ahead-of-time compiled for 1.1

15:17 and clojure doesn't guarantee binary compatibility between verisons

15:17 freakazoid: I implemented base62 in Clojure - does anyone care if you have to convert, say, a sha1 hash to a BigInteger first?

15:18 the semantics are slightly different than base64.

15:18 tensorpudding: http://hpaste.org/40648/lein_dep_fails

15:18 freakazoid: I could make it the same as base64 by treating a byte stream as a base 256 number *after* the decimal point.

15:18 tensorpudding: my project.clj is the same as the one you gisted

15:18 raek: tensorpudding: have you executed "lein self-install"?

15:19 tensorpudding: yes

15:20 raek: which version of lein? the one linked on the project page?

15:20 tensorpudding: from git

15:20 1.4.0-SNAPSHOT, apparently

15:20 raek: ah

15:20 you have to build the bleeding edge version with leiningen...

15:21 tensorpudding: bleeding edge version of which?

15:21 raek: of leiningen itself

15:21 http://github.com/technomancy/leiningen/raw/stable/bin/lein

15:22 that one is 1.3.1

15:22 tensorpudding: is there a stable branch?

15:22 raek: yes

15:23 the installation instructions likns to that one

15:25 tensorpudding: dammit, i hate git

15:26 kryft: tensorpudding: Why?

15:26 tensorpudding: because it's like mercurial, but more confusing

15:26 but everyone uses it, and no one uses mercurial

15:28 trying to remember how to manage remote branches is one thing which i don't fully get

15:29 raek: git has a steep learning curve

15:29 tensorpudding: okay, there, i've checked out stable

15:30 raek: you only need the file I linked

15:31 everything else is .jars that it downloads automatically when you do lein self-install

15:31 tensorpudding: i know

15:32 but since i bothered checking out the lein source, and made a /usr/local/bin symlink from it for the lein script, i didn't want to hardcode my lein script

15:33 it's working now

15:34 ugh, it even created a .gitignore

15:34 i suppose clojure is a heavy git community

15:35 raek: yes, I suppose so...

15:35 tensorpudding: i'll have to edit the lein scripts to make an .hgignore instead

15:35 raek: source on github and jars on clojars seems to be *very* common

15:37 ihodes: LauJensen: i'm having trouble rending my template using Moustache now; http://pastebin.org/263049

15:37 make that rendering

15:37 rplevy: what is a reasonable test of pmap vs map that would demonstrate speedup on a 4 core machine?

15:39 rlb: I'm working with maildirs from clojure -- does anyone know if it's possible to get the filename from a javax maildir message?

15:40 raek: ,(time (dorun (map (fn [_] (java.lang.Thread/sleep 20)) (range 100))))

15:40 clojurebot: "Elapsed time: 2127.817 msecs"

15:40 raek: ,(time (dorun (pmap (fn [_] (java.lang.Thread/sleep 20)) (range 100))))

15:40 clojurebot: "Elapsed time: 90.17 msecs"

15:41 raek: pmap is useful when the computation to do for each element takes long time

15:41 for very small computations, it is not recommended

15:42 rplevy: raek: thanks!

15:43 raek: np :)

15:44 SergeyD: rake: Nice clean example. But I can't figure out why the difference is 20x times on a 2-core processor :)

15:44 ihodes: anyone here know mucha botu Moustache?

15:45 raek: ihodes: you might need to use wrap-file-info too

15:46 SergeyD: raek: oh, I got it.

15:46 ihodes: raek: i'm not even there yet haha — i'm having trouble getting moustache to render my template

15:46 raek: oh, please share!

15:47 ihodes: http://pastebin.org/263049

15:47 raek: thought the thread pool was 2 x no-of-processors

15:47 ihodes: you don't need to do the apply str step

15:48 LauJensen: [""] (response (templatename args))

15:48 ihodes: ^^

15:48 raek: Ring accepts sequences of strings (those that the templates return)

15:48 ah, yes. that makes sense.

15:48 ihodes: raek: just getting rid of "render" didnt work.

15:48 LauJensen: response is in which ns?

15:50 raek: ihodes: (defn ok [body] {:status 200, :headers {"Content-Type" "text/html; charset=UTF-8"}, :body body})

15:50 ^ this is what I use

15:50 [""] (fn [_] (ok (index)))

15:50 or, you could move that (fn ..) into ok

15:51 ihodes: raek: perfect!

15:51 raek: that's awesome. thanks so much!

15:51 raek: the rigth hand side of the route rule should eval to a ring handler

15:51 :)

15:51 ihodes: raek: didn't realize i needed to be passing a map back

15:51 raek: i'll read more about ring. i just started using this about 20 mins ago :\ time for some real reading now. thanks so much

15:52 raek: ihodes: this is what you need to know: http://github.com/mmcgrana/ring/blob/master/SPEC

15:52 SergeyD: raek: Seems like the thread pool is about 30 on my computer

15:52 raek: basically, what keys are in the request and response

15:53 ihodes: raek: awesome! anything i should know about Moustache beyond what's in the little doc cgrand has?

15:53 raek: well, everything about moustache follows from syntax.html... if you know how to interpret it

15:54 SergeyD: raek: 32 actually, 16 for each core

15:54 raek: just remember that things (app [..] <here>) are threaded differently fomr things (app <here>)

15:54 Raynes: Moustache is so dead simple, the docs he provides is amazingly sufficient.

15:54 raek: *treated

15:54 Raynes: It's compojure that needs more documentation.

15:54 raek: even though thosw two cases overlap somewhat

15:55 wrapping the first case in [ ] always yields the second case

15:55 ihodes: raek: i don't know how; what should i read in order to interpret that haha—i'm familiar with grammars etc, so maybe a guide eists somewhere to introduce this to me? would be useful for my continuing to work with enlive as well

15:55 raek: ihodes: by looking at the example he provides, I think most of should be pretty clear

15:56 the grammar is nice if you want to be certain about the details

15:56 ihodes: raek: ah nevermind, this grammar makes perfect sense. and the docs look nice. i think i can handle this :)

15:56 raek: if you are familiar with grammars, then it should be pretty straight forward, I think

15:56 ihodes: raek: thanks again!

15:57 raek: yeah it's not as bad as i was expecting; pretty much a cfg haha

15:57 Raynes: $seen cemerick

15:57 sexpbot: cemerick was last seen quitting 1019 minutes ago.

15:59 Raynes: -> (/ 1019.0 60)

15:59 sexpbot: ⟹ 16.983333333333334

16:01 amalloy: Raynes: sexpbot is yours, right? if the minutes aren't helpful, why not get him to tell you hours as well?

16:01 Raynes: If one more person asks me that, I'm going to make sexpbot timestamp intelligently.

16:02 That's at least 6 people in the last two months. :p

16:02 amalloy: heh. well, i don't mind the minutes myself, but since the *author* seems to find minutes inconvenient...

16:02 raek: ,((juxt #(/ % 60) #(rem % 60)) 1019)

16:02 clojurebot: [1019/60 59]

16:02 Raynes: It's been in my invisible TODO list forever. I just haven't gotten around to it. I haven't been getting around to much lately.

16:04 amalloy: ,((juxt quot rem) 1019 60) ; raek?

16:04 clojurebot: [16 59]

16:05 amalloy: sexpbot: source?

16:05 KirinDave: Wait what?

16:05 Ah

16:05 Raynes: $whatis sexpbot

16:05 sexpbot: sexpbot = http://github.com/Raynes/sexpbot

16:06 raek: /facedesk

16:07 amalloy: raek: it's a good thing you're a founding member of the juxt fan club or we'd have to kick you out

16:07 raek: :-)

16:08 ihodes: Raynes: you should make sexpbot timestamp intelligently!

16:08 ;)

16:09 Raynes: He's right, you know.

16:09 Just as soon as I get a good night's sleep rather than the 4 hour increments I've been getting over the last two days.

16:09 amalloy: Raynes: i'll fork and do it myself if you want. looks pretty easy in seen.clj

16:10 Raynes: I'd love you forever.

16:10 LauJensen: Such an affectionate young man

16:12 Derander: I'm trying to implement a file watcher daemon in clojure. Currently, I have a function like this: http://gist.github.com/63122 . In ruby, C, or other languages that I know, I'd slap that logic in a while loop and put a sleep of some reasonable amount of time in

16:13 I have no idea how to do this idiomatically in clojure

16:13 Most clojure programs that I read are more of the "compute this thing" or "listen for this event", not the "do this thing indefinitely" variety

16:13 Raynes: Derander: Sure that's the right gist?

16:13 amalloy: (loop [] (do-stuff) (Thread/sleep 1000)) ; would work, dunno if it's idiomatic

16:14 er. and put a (recur) at the end, sorry

16:14 Derander: Raynes: that is definitely not, weird

16:14 Raynes: (while true ..)

16:14 Derander: http://gist.github.com/631226 is

16:14 LauJensen: amalloy: busywaiting... I think there is a FileWatcher class actually, or maybe Im thinking of C#

16:14 Raynes: (defn x [] (while true body (recur))) = (defn x [] (recur ...))

16:14 Derander: LauJensen: When I was googling, I found some sort of FileWatcher mechanism in java 7

16:15 Raynes: LauJensen: I didn't tell him to recur in (while true ..)

16:15 Derander: alright, I'll explore recur. Thanks for the info

16:15 Raynes: amalloy told him to recur at the end of the loop.

16:15 :p

16:15 LauJensen: Raynes: Oh right, sorry for not being able to tell you two Americans apart

16:16 Derander: LauJensen: I imagined that in a snotty british accent.

16:16 Raynes: :>

16:16 Not quite.

16:16 LauJensen: Haha!

16:16 KirinDave: Derander: Write (forever fn)

16:17 Derander: Use the trampoline to recur, and make sure that it returns a future so the repl doesn't block.

16:17 I'm not sure how you'd enable killing, but it's not like that's the intent, anyways. :)

16:17 You could probably put in a kill switch.

16:17 Derander: KirinDave: I've never heard of a trampoline, I've read about futures but have no idea how to use them. I'll do some reading.

16:17 KirinDave: Then you can write (forever #'alone)

16:17 Derander: haha.

16:19 Raynes: You can use futures in places where you'd do (.start (Thread. (fn [] ..))) a lot of the time.

16:19 LauJensen: haha

16:19 Derander: Raynes: I must confess that I've never done threaded programming in clojure either. I've written a total of 62 lines in the language. This is my first project

16:20 but I'll read read read and figure it out

16:20 Raynes: Gotta start somewhere.

16:20 Derander: mmhmm. it's more approachable than haskell at least

16:20 LauJensen: Derander: 62 lines is a very good start, it corresponds to 824 lines of Scala of 1400 lines of PHP

16:20 roughly...

16:20 Raynes: LauJensen: What about Ruby

16:20 raek: (def running? (atom true)) (future (loop [] (if @running? do-stuff clean-up)))

16:20 KirinDave: LauJensen: That is math I want to see

16:20 LauJensen: Raynes: 74 ? :)

16:20 Derander: Raynes: approximately equivalent

16:20 KirinDave: Raynes: 62 lines as well, but only if you use eigenclasses.

16:21 Derander: I've been writing ruby for 3 years and never really used eigenclasses

16:21 LauJensen: KirinDave: 62 lines, but behavior will be unpredictable

16:21 Raynes: Derander: With all due respect to Haskell (I adore the language), a brick wall is more approachable at high speeds.

16:21 Derander: Raynes: yes

16:21 LauJensen: Haskell is fantastic.

16:21 KirinDave: LauJensen: 62 lines, but it each line will take 1 year to execute, and won't run if you've required ActiveRecord.

16:21 Raynes: Yes it is.

16:21 LauJensen: hehe

16:21 Derander: better: 62 lines, and 120 lines of unit testing.

16:21 KirinDave: Haskell is beautiful. There is a difference. ;)

16:21 Haha, all written in advance

16:22 LauJensen: Derander: In Ruby, even unit tests wont save you

16:22 KirinDave: With a mock framework more complex and powerful than almost any other project in the language.

16:22 Derander: LauJensen: I usually write integration tests for my ruby projects anyway

16:22 but that's because I am filled with hubris

16:23 LauJensen: I guess if you build commercial software in Ruby, you do deserve a bit of punishment

16:23 KirinDave: LauJensen: If you need unit tests to successfully complete a project, ruby is a rough road.

16:23 Some languages require champions to ride them.

16:23 You can quote me on that.

16:23 Derander: the biggest project that I've worked on in ruby is 15k lines of code

16:23 LauJensen: Ouch!

16:23 Derander: it's actually pretty nice

16:24 if the templating was in haml life would be perfect

16:24 LauJensen: Derander: nice as in, you got rich from bugfixing it ?

16:24 KirinDave: LauJensen: It's not a condemnation.

16:24 LauJensen: KirinDave: What is it then ?

16:24 KirinDave: LauJensen: It's a compliment, actually. Ruby is a superbike.

16:24 Derander: LauJensen: nah, nice as in it works pretty well and is easy to grok and work with

16:24 KirinDave: LauJensen: The problem is you rev the throttle too fast and suddenly you're SuperDave.

16:24 LauJensen: Derander: impressive, I thought that was impossible with Ruby

16:24 Derander: when I finish pushing it to 1.9.2 it'll be damn fast too

16:24 KirinDave: Hanging from your bike's handlebars, body horizontal with the acceleration.

16:25 I have more metaphors, if you need them.

16:25 Derander: ruby was my first language after php. we've had a long and tender relationship

16:25 tensorpudding: if you have a function which takes [& args], how can you mangle (arg arg) to make it work as input to the function?

16:27 wait, apply seems to be it

16:27 aav: tensorpudding: (applu myfunc args) - if i got your question right

16:27 apply

16:28 shanmu: Hi, I am trying to represent db records as clojure records - I am trying to do defrecord dynamically

16:28 tensorpudding: except doh, it's a macro, not a function

16:28 KirinDave: Derander: Same.

16:28 Except the PHP part.

16:28 Ruby was my first dynamic language that I loved.

16:28 :)

16:29 shanmu: I am using metadata to get column names as a map of string, and when I try to defrecord using them, hitting a classcastexception unable to cast String to IObj

16:30 KirinDave: So... I've been wondering.

16:30 What's the right way to make something that responds to @deref correctly?

16:30 tensorpudding: i'm really getting annoyed by how restrictive macros seem to be

16:31 KirinDave: tensorpudding: What in particular is bothering you?

16:31 tensorpudding: well, you can't apply them

16:32 or use them as functions

16:32 Chousuke: if you need to apply a macro you probably have a weird macro :/

16:32 KirinDave: tensorpudding: You have to understand, when you say (defmacro ...) what you're saying is (open up my compiler and add....)

16:32 tensorpudding: The very act of applying things is generally a runtime process.

16:32 And as such the compiler has no place

16:32 tensorpudding: i didn't decide to make or and and macros

16:32 KirinDave: Ah.

16:32 The Classic Complaint™

16:33 and and or aren't actually macros.

16:34 They're special forms.

16:34 Chousuke: well, except that they are macros :P

16:34 tensorpudding: hmm

16:34 KirinDave: Chousuke: Implementation detail ;)

16:34 Chousuke: and no they're not really special forms

16:34 tensorpudding: ,(reduce or true [true false true])

16:34 clojurebot: java.lang.Exception: Can't take value of a macro: #'clojure.core/or

16:34 Raynes: KirinDave: No, they seriously aren't special forms.

16:35 Chousuke: if is a special form, or and and are just macros

16:35 Raynes: -> (doc and)

16:35 sexpbot: ⟹ "Macro ([] [x] [x & next]); Evaluates exprs one at a time, from left to right. If a form returns logical false (nil or false), and returns that value and doesn't evaluate any of the other expressions, otherwise it returns the value of the last expr. (and) returns true."

16:35 KirinDave: Raynes: Ah, i'm thinking CL.

16:35 Raynes: Not a special form.

16:35 tensorpudding: ,(reduce (fn [x y] (or x y)) true [true false true])

16:35 KirinDave: Sorry.

16:35 clojurebot: true

16:35 KirinDave: tensorpudding: Yes

16:35 Chousuke: but the thing is that macros work with code

16:35 tensorpudding: if you wrap it in a lambda, it works

16:35 KirinDave: tensorpudding: Right, because a function is generated.

16:35 Chousuke: apply works with runtime data.

16:35 tensorpudding: i'm trying to translate something from haskell into clojure

16:35 to learn the former better

16:35 Raynes: -> (some false? [true false true])

16:35 sexpbot: ⟹ true

16:36 KirinDave: Raynes beat me to it.

16:36 Raynes: That essentially accomplishes the same thing without any macros.

16:36 amalloy: Raynes: sent a pull request for sexpbot

16:36 Raynes: amalloy: Thank you, kind sir. Your work is appreciated.

16:37 KirinDave: It must be Haskellers Try Clojure week. I've seen a ton of guys from #haskell in here lately. :D

16:38 Chousuke: heh.

16:38 KirinDave: Raynes: Reaching for something. :)

16:38 amalloy: hmmm. does github have a "merge with upstream" function or do i have to figure out how to do it from git?

16:38 Chousuke: amalloy: pull from upstream, push into your fork? :/

16:39 KirinDave: Hum

16:40 I'm working on asciidoc-ing my clojure & the web chapter for my book

16:40 This is the final code for a URL shortener. I know it works, but any failures to emulate idiomatic code would be appreciated.

16:40 (err, pointing them out, that is)

16:40 https://gist.github.com/f3509ac3fe7859fe527d

16:41 And before you ask, the silly storage stubs are there so that couchdb can be hooked in later.

16:55 shanmu: Hi, Can I dynamically declare a record?

16:57 I get an error when trying (def name-list ["id" "name"]) (defrecord org name-list)

16:58 ,(do (def name-list ["id" "name"]) (defrecord org name-list))

16:58 clojurebot: DENIED

16:58 chouser: you'll need to use eval or something

17:01 amalloy: or a macro. i think i gisted something like this a while back, let me find it

17:04 well, i guess it's not that close. but the general idea is (defmacro record-from-strings [fields] `(defrecord ~@(map symbol fields))) (record-from-strings ["org" "id" "name"])

17:04 kjeldahl: http://stackoverflow.com/questions/678867/how-to-defn-a-function-from-string-in-clojure

17:10 shanmu: amalloy, kjeldahl: thanks!

17:23 Raynes: $seen cemerick

17:23 sexpbot: cemerick was last seen quitting 18 hours and 24 minutes ago.

17:23 Raynes: amalloy_: My love. <3

17:40 amalloy_: Raynes: woo!

17:40 amalloy: ~seen cemerick

17:40 clojurebot: no, I have not seen cemerick

17:40 amalloy: heh. win for sexpbot

17:41 Raynes: Maybe he stores the info in memory. If so, a restart would wipe it (which is a possibility).

17:42 KirinDave: Oh I hope he doesn't have a data store for seen

17:42 Raynes: A seen database can get really huge.

17:43 sexpbot using mongodb for seen (among a lot of other things).

17:44 amalloy: clojurebot uses (ref {}) to store the seen list

17:44 Raynes: Yeah, in memory. It probably just restarted since cemerick left.

17:44 amalloy: yeah

17:59 shanmu: I had to use (defmacro record-from-strings [fields] `(defrecord ~@(map symbol fields))) (record-from-strings ["org" "id" "name"]), does that look alright?

18:00 oops! wrong paste

18:00 I had to use (defmacro record-from-strings [rec-name fields] `(defrecord ~(symbol rec-name ) ~(map symbol fields))) (record-from-strings "org" ["id" "name"])

18:01 does that look alright?

18:01 amalloy: yeah, looks reasonable. i forgot it doesn't want the @ there

18:02 shanmu: amalloy: thanks a lot! this solves my problem nicely

18:03 amalloy: shanmu: just keep in mind it will only work with literals - you can't do like (def x ["foo"]) (record-from-strings "org" x)

18:04 shanmu: oh.. ok... I was planning to do defrecords for table columns in a db (obtained via c.c.sql)

18:05 amalloy: macros can't have access to runtime data. they happen before runtime

18:05 but there is a way to do it if your db info will be known at compile time

18:05 shanmu: amalloy: thanks! is there any way to do it? the db info would be available during compile time...

18:06 amalloy: shanmu: see http://clojure-log.n01se.net/date/2010-10-17.html, especially the link to http://gist.github.com/630662

18:06 shanmu: amalloy: thanks! looking thorugh

18:17 clojurebot: The Tao, considered as the Rabbit, began.

18:40 amalloy: shanmu: that help solve your problem?

18:42 shanmu: amalloy: no, not exactly... the problem is I donot know my macros... reading up on them now

18:42 I tried (defmacro record-from-strings [fields] `(defrecord ~@(map symbol fields))) (record-from-strings ["org" "id" "name"])

18:42 oops!

18:42 I tried (defn create-record [rec-name fields] `(defrecord ~(symbol rec-name) ~(map symbol fields)))

18:42 then (defmacro make-record [rec-name fields] `(~(create-record rec-name fields)))

18:43 but (let [n "recName" f ["f1" "f2"]] (make-record n f))

18:43 errors with Don't know how to create ISeq from: clojure.lang.Symbol

18:44 amalloy: shanmu: (let [blah] (stuff)): if stuff is a macro, it can't access the contents of blah because that's happening at runtime

18:45 the way i would solve a problem like yours is to define (define-sql-records) as a macro, which calls (lookup-sql-tables), a function

18:46 define-sql-records takes no arguments, or maybe one that's the name of the db to use or something; lookup-sql-tables queries the database and returns some code, which define-sql-records splices into its return value so that it's available at compile time

18:49 shanmu: amalloy|gone: thanks for the advice! will try something

18:51 raek: making some Active Record-like system?

19:07 FUser: what's the difference between :while and :when in macro "for"?

19:07 ,(for [x (range 15) :when (> x 5)] x)

19:07 clojurebot: (6 7 8 9 10 11 12 13 14)

19:08 FUser: ,(for [x (range 15) :while (> x 5)] x)

19:08 clojurebot: ()

19:09 FUser: ,(for [x (range 10) :when (> x 5) :while (> x 5)] x )

19:09 clojurebot: (6 7 8 9)

19:10 FUser: ,(for [x (range 15) :when (even? x) :while (> x 5)] x)

19:10 clojurebot: ()

19:10 shanmu: raek: not a full fledged activerecord like system

19:10 FUser: im confused

19:13 Lajla: FUser, obviously looking at this, while stops after the first false, and when continues.

19:13 But just doesn't put it into the list if it's false.

19:14 FUser: but check this out

19:15 ,(for [x (range 15) y (range 10) :when (even? x) :while (> x 5)] x)

19:15 clojurebot: (6 6 6 6 6 6 6 6 6 6 8 8 8 8 8 8 8 8 8 8 10 10 10 10 10 10 10 10 10 10 12 12 12 12 12 12 12 12 12 12 14 14 14 14 14 14 14 14 14 14)

19:15 FUser: identical case as when it returns empty list

19:15 except it has an additional variable that isn't used

19:15 and it suddenly behaves totally differently

19:16 Lajla: I have no idea how that works no.

19:16 Could even be a bug.

19:16 Ask raek, he is omnipotent.

19:17 FUser: :D

19:17 you mean omniscient surely

19:19 Lajla: Well, if you can do all things, that includes knowing all things, or at least answering all quaestions.

19:27 FUser: :)

19:37 chouser: :when and :while control the previously specified loop

19:59 shanmu: amalloy: its working now!!

19:59 (defmacro record-from-table [table-name]

19:59 `(defrecord ~(symbol table-name) ~(map symbol (get-columns-map table-name))))

19:59 (defn get-columns-map [table-name]

19:59 (sql/with-connection db

19:59 (map #(:column_name %1)

19:59 (resultset-seq (-> (sql/connection)

19:59 (.getMetaData)

19:59 (.getColumns nil nil table-name nil))))))

19:59 sorry, pasting it

20:00 amalloy: shanmu: great! yeah, i was about to say paste

20:01 shanmu: http://pastebin.com/4ihxfMED

20:01 amalloy: thanks for the guidance! just like you said, a macro which calls a function to get column list

20:05 KirinDave: shanmu: #(:sym %1)

20:05 shanmu: Or

20:05 ,(map :col [{:col 1}])

20:05 clojurebot: (1)

20:05 zakwilson: If I want clojure-contrib 1.3 from Leiningen, where do I find appropriate version strings? I see that it has been split in to core and [other stuff] but [org.clojure/clojure/contrib/core "1.3.0-alpha1"] seems like it should work (and doesn't)

20:05 KirinDave: shanmu: Understand?

20:06 duck1123: I have a bunch of files I'm reading for my tests (lazytest) and

20:06 previously I had them in the root of my application, but I want to

20:06 move them to src/test/resources (using maven) is slurp the best way to

20:06 contiue reading them, and if so, should I specify the path in the src

20:06 directory, or is there a better way?

20:06 ahh, sory about the multi-line

20:08 dysinger: duck you could find the files in your classpath if you put them in maven's src/test/resources dir

20:09 shanmu: KirinDave: sorry, didnot understand that...

20:10 KirinDave: shanmu: You don't need the #().

20:11 shanmu: :keywords are invokable.

20:11 shanmu: KirinDave: got it! sorry, bad habit of adding an anon func as soon as I type map!

20:11 KirinDave: shanmu: Same. :)

20:12 ninjudd: zakwilson: [org.clojure.contrib/complete "1.3.0-SNAPSHOT"] should work

20:12 shanmu: KirinDave: thanks! will remember that keywords are invokable... :)

20:13 zakwilson: ninjudd: looks good so far. Thanks.

20:13 duck1123: dysinger: right, my question was what is the best way to now read those files from the classpath. (slurp "entry.xml") is no longer working.

20:13 clojurebot: Alice felt a violent blow underneath her chin - it had struck her foot! She was walking with nameless simplicity.

20:14 duck1123: I know there's an easy way to do it, but I can't remember it, and google is failing me

20:14 ninjudd: zakwilson: no problem. or you can just add the specific libs from contrib you want. e.g. [org.clojure.contrib/find-namespaces "1.3.0-SNAPSHOT"]

20:16 zakwilson: ninjudd: I'll start with everything, and get specific if I decide by uberjar is too uber.

20:19 ninjudd: zakwilson: that works. though if you are writing a library that you're going to put on clojars, it is probably best to have specific deps. looks like complete pulls in 61 jars!

20:20 zakwilson: I am not writing a library, and I am not putting what I'm writing on clojars.

20:20 Sorry. Super proprietary. Going to make me a zillionare. Etc.

20:21 ninjudd: zakwilson: i see. well then you'll be able to afford all 61 jars ;)

20:21 duck1123: I need to go through my projects and go down to the specific contribs I need

20:23 zakwilson: I'll even be able to afford sixty-TWO jars!

20:26 shanmu: thanks a lot people! #clojure rocks, as always....

20:26 dysinger: duck1123: (-> (Thread/currentThread) (.getContextClassLoader) (.getResourceAsStream "x/y/z.txt") (slurp))

20:27 (slurps file from classpath)

20:29 duck1123: dysinger: ok, so maybe it wasn't as easy as I thought. Thanks a lot

20:30 amalloy: dysinger: the parens aren't necessary for one-arg functions in ->, eg

20:30 ,(-> 1 inc inc inc)

20:30 clojurebot: 4

20:30 duck1123: you wouldn't by any chance to know how to get lazytest failures to fail the build?

20:31 amalloy: (whether that makes things more readable is down to taste, of course)

20:34 dysinger: duck1123: it'd be pretty easy to make a fn to slurp-from-cp

20:34 and just use that instead of plain slurp

20:35 duck1123: just did. looking for instances of slurp atm. :)

20:35 dysinger: easy peasy

20:39 duck1123: dysinger: what are you using for code coverage with maven atm?

20:58 dysinger: duck1123: I'm using lein mostly

21:25 cemerick: duck1123: code coverage is orthogonal to build tooling

21:25 I presume something like Clover would get the job done, though it'd be a bit of a mess insofar as it's not clojure-aware.

21:26 Presumably there's some code coverage tools that have plugin architectures amenable to informing them about non-Java languages.

21:43 jstirrell`: hi

21:44 what's the easiest way to get a new collection of, say, every third item from an old collection?

21:45 cemerick: ,(take-nth 3 (range 20))

21:45 clojurebot: (0 3 6 9 12 15 18)

21:45 cemerick: jstirrell`: ^^

21:45 jstirrell`: sweet thanks!

22:04 Raynes: cemerick: Evening.

22:05 cemerick: Raynes: howdy

22:05 Raynes: How was your weekend?

22:05 cemerick: Very busy. Working on the book at the moment.

22:05 Raynes: Ooh, goody.

22:06 cemerick: Rewriting stuff this early on is surely a bad sign. :-/

22:06 Raynes: Only means you're a perfectionist. When kept in check, that can be a very valuable asset.

22:06 cemerick: heh, indeed

22:06 Otherwise, it was a perfect autumn day.

22:07 Raynes: Indeed. It's been a beautiful week here. Nice and cool.

22:07 moogatronic: +1 for perfect autumn day.

22:07 cemerick: Warmish but breezy, mostly sunny, tons of fantastic treescapes.

22:07 Breakfast out, then a small hike, then a visit to Old Deerfield.

22:08 * cemerick is New England-y.

22:08 Raynes: Well, I'm off to bed. I'll talk to you in the morning. I should be up, so just ping me whenever you get around to calling expedia (DOT COOOOOOOOM).

22:08 moogatronic: we're a little moisture starved in mid-southern indiana , burn ban in effect for most counties, going to impact my up-coming backpacking trip

22:08 cemerick: Raynes: Figure after 8:30 anyway

22:08 Raynes: Right, I should be up or nearly up.

22:09 Goodnight, fair #clojure.

22:09 moogatronic: goodnight. =)

22:13 clojurebot: "You're nothing but a pack of cards, after all? Can you play croquet with the bitterest grief; and soldiers under sentence of execution?"

22:14 cemerick: wow, that was random

22:14 maravillas: clojurebot must be reading lewis carroll lately

22:16 curious...both that quote and the one at 8:12 are from http://twitter.com/#!/WonderTao

22:17 "Text built by mashing up Alice's Adventures in Wonderland with the Tao Te Ching. Created with Python & Markov chains."

22:17 cemerick: very random

22:36 Lajla: So how are things going in noTCOland now?

22:38 cemerick: same as they always have; see recur

22:38 or trampoline

22:38 Lajla: I know them.

22:39 I'm just feeling like that remark.

22:39 I am actually the second best clojure programmer in the world, second only to the microsoft Chief Software Architect.

22:40 chouser: cemerick: hi

22:41 cemerick: chouser: bonsoir

22:41 Lajla: Terve

22:41 chouser: I feel like I've been gone

22:42 cemerick: There was certainly a disturbance in the Force.

22:43 chouser: heh

22:48 wow, vars are suddenly in flux?

22:48 cemerick: indeed

22:51 chouser: someone asked me at strangeloop, "what's next"

22:51 cemerick: "how much time do you have?"

22:52 chouser: which of course is a common question. and I'm always tempted to guess

22:53 I said "I don't know" and "maybe pods" ...not realizing dynamic binding and future/send had *already* *changed*

22:54 cemerick: mmm, the future/send change is pretty friggin' huge

22:54 That "fixes" vars and binding quite a lot.

22:59 coldhead: thanks clojurebot

23:02 chouser: yep

23:45 cemerick: This seems like an unfortunate asymmetry:

23:45 ,(-> ::foo str keyword)

23:45 clojurebot: ::sandbox/foo

23:45 cemerick: vs.

23:45 ,(-> 'foo str symbol)

23:45 clojurebot: foo

23:47 cemerick: Meaning, namespaced keywords aren't trivially string round-trippable.

23:56 chouser: ,(-> :foo str keyword)

23:56 clojurebot: ::foo

23:56 chouser: ,(-> `foo str symbol)

23:56 clojurebot: sandbox/foo

23:57 chouser: ,(-> :foo name keyword)

23:57 clojurebot: :foo

23:57 chouser: cemerick: I think I'm missing your point

23:57 cemerick: I'm tired; perhaps my point is foolish.

23:58 I think one should be able to do (-> ::foo str keyword) and get the proper keyword out.

23:58 As things stand, you have to munge the string before keywordizing it.

23:58 hiredman: ,(pr-str ::foo)

23:58 clojurebot: ":sandbox/foo"

23:59 cemerick: sure

23:59 my point was about asymmetry, not about not being able to do the thing

23:59 chouser: ah, I see what you're saying

23:59 pr-str is the inverse of eval, though

Logging service provided by n01se.net