#clojure log - Sep 11 2010

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

0:24 sproust: tomoj/ihodes: another way to define simple zip: (partition 2 (interleave coll1 coll2))

0:25 tomoj: looks more than 3 times slower

0:25 sproust: This one _does_ use Clojure's slightly odd form of cons (interleave defined recursively via lazy-seqs)

0:25 tomoj: does it?

0:25 tomoj: ,(time (dorun (partition 2 (interleave (range 10000000) (range 1000000)))))

0:25 sproust: Ouf...

0:25 clojurebot: "Elapsed time: 6054.071 msecs"

0:25 tomoj: ,(time (dorun (map vector (range 10000000) (range 1000000))))

0:25 clojurebot: "Elapsed time: 2309.176 msecs"

0:25 sproust: Yup.

0:28 chouser: ,(time (dorun (map-indexed vector (range 10000000))))

0:28 clojurebot: Execution Timed Out

0:28 chouser: :-(

0:28 sproust: This clojurebot friend is pretty resilient :-)

0:48 Hmmm ... I have a function that is implemented as two nested for loops, which produces side effects (writes out files).

0:49 An enclosing (dorun/doall is not enough to force execution of the inner for loop.

0:49 What's the idiomatic solution to this?

0:50 (I've patched it up with a (doall) around the inner loop, but my sense of aesthetics thinks it stinks. Curious to know what's the word from the pros.)

0:52 tomoj: use doseq instead?

0:52 for?

0:52 clojurebot: for is not a loop

0:55 sproust: tomoj: interesting; the similarity btw for and doseq never came to mind. Thanks.

0:57 I guess what I want really is doseq.

0:57 Works like a charm!

1:09 quotemstr_: What would be the canonical way, in Clojure, to wait for a counter to descend below a certain value, then accept() a connection?

1:09 I'd normally use a condition variable for that sort of thing.

1:10 tomoj: is the counter in a ref/atom?

1:10 (what would it mean to wait for it to descend otherwise?)

1:13 quotemstr_: Let's say it's a ref.

1:16 tomoj: d'oh

1:21 quotemstr_: Would an atom be better here?

1:21 It's the waiting-until-decremented part that's the issue.

1:22 Should I just create an agent and fire off something every time I'd decrement a counter?

1:27 tomoj: what are you counting?

1:28 quotemstr_: Connections.

1:28 There are 1024 connection slots (protocol-bound), and it's not good to accept() a connection if there are no slots available.

1:28 I just thought I'd ask about the canonical Clojure approach. More traditionally, you could use a condition variable, or a semaphore.

1:28 (The counting semaphore is the classic solution to this problem.)

1:30 tomoj: ideally you wouldn't have any state :)

1:32 quotemstr_: And ideally, I wouldn't have to work, and I'd have a Cessna, and a beautiful wife, and be on the cover of Newsweek every month.

1:32 :)

1:32 But IO is a fact of life, alas.

1:34 tomoj: that you're doing IO doesn't mean you need an atom

1:34 but I don't understand what you're doing

1:35 (nor is it likely that I will if you try to explain it, sorry)

1:36 quotemstr_: Fair enough.

1:37 But global knowledge isn't necessary. :)

1:37 _mst: I'd be tempted to have a main thread calling accept() on the socket and then push the accepted socket onto a blocking queue for the workers to take off (fairly traditional again...)

1:37 that feels fine to me in terms of being idiomatic :)

1:38 quotemstr_: _mst: That's cleaner, but the problem is that the consequences are externally visible.

1:38 _mst: A client can call connect() then hang. It's better not to complete the accept() at all until resources to back that connection are available.

1:39 _mst: ahh I see

1:44 so ideally you'd like the worker processes to be calling accept() when they're actually ready?

1:44 quotemstr_: Yeah.

1:45 ... should I just create 1024 workers?

1:47 _mst: I guess it makes life easier just to statically create them all at startup

1:49 quotemstr_: That might solve this particular problem, but it doesn't tell me how to create the equivalent of a counting semaphore.

1:53 _mst: off the top of my head I can't think of how I'd implement one using clojure's concurrency abstractions, but in reality I'd probably go straight to java.util.concurrent.Semaphore if I was sure that's what I wanted

1:53 not very helpful, sorry :)

1:55 quotemstr_: Thanks anyway. :)

2:31 amalloy: i'm not sure i get the github philosophy. i've made a fix to the documentation for clojure.core; how do i submit it for approval?

2:54 sproust: When I eval a (ns) directive, are the files referred to loaded every time? Is there not a cache of Clojure modules? How does that work?

3:09 amalloy: sproust: i'm not sure, but i think this depends what you mean. (ns foo) itself doesn't load anything, of course; (ns foo (:use (bar baz))) loads bar.baz exactly once over the lifetime of your program no matter how many times you write that form

3:10 KirinDave: I think I need a clojure t-shirt.

3:11 I think that's the best way I could get better at clojure.

3:11 amalloy: I went to clojure-conj and all I got was this (promise 'shirt)

3:13 KirinDave: amalloy: We need something really good.

3:13 none of this erlangfactory shit.

3:13 We need something that ugmonk could sell.

4:48 n2n3: ,(|)

4:48 clojurebot: java.lang.Exception: Unable to resolve symbol: | in this context

6:19 kjeldahl: Any pointers for doing simple unbuffered text file output in Clojure? Do I have to dive into the java libs?

6:20 mrBliss: maybe spit is what you need

6:21 never mind

6:21 kjeldahl: Yeah, it closes the file as well...

6:23 But the source of it shows it's pretty simple, even if using the java libs, so I might become inspired by it. Thanks for the pointer.

6:25 raek: the java classes are still used

6:25 however, there are some functions in clojure.java.io that makes it simpler

6:33 with, c.j.io only the .write call has to be in java... (or if you use spit, none)

6:36 (use '[clojure.java.io :only [writer]]) (with-open [f (writer "file/path")] (doseq [x some-coll] (.write f (make-some-string x))))

6:45 this is buffered though... if you need unbuffered output, you have to use the java classes directly (and pass output as java arrays)

6:53 kjeldahl: raek: Thanks. It's for a logging type class though where each clojure program runs as a separate process and communicates with a java host through stdout. The java host filters _all_ io, which is why the clojure programs has to log to a file.

6:53 raek: Which means that with-open might not be ideal for this use case.

6:57 raek: yes, with-open would not be very useful in that case

6:57 might be better to just define the writer as a global var

6:57 kjeldahl: Yeah, I'll use the with-open source for "inspiration".

6:59 raek: the only io-related calls it makes is to .close the file when done (or when a exception is thrown)

7:02 (def log-writer (writer "file/path")) (defn log [s] (doto log-writer (.write s) .newLine .flush)) ; simple example I just made up

7:03 and then (.close log-writer) should be called when the application exits

7:06 Chousuke: You might want to use an agent to serialise access to te log-writer if you have any parallelism.

7:19 kjeldahl: Thanks for the help. Raek's code looks fine (haven't tested yet, but will do so shortly).

7:31 raek: Code works fine. Thanks.

7:43 raek: (def logger (agent (writer "log.txt"))) (defn log-line [log-writer s] (doto log-writer (.write s) .newLine .flush)) (send logger log-line "test")

7:53 Raynes: Morning.

9:16 edbond: how to use non-maven jars with leiningen?

9:25 I did mvn install:install-file

9:27 Raynes: edbond: Note that doing that sort of thing kinds of kills the point of dependency management in the first place. If you have open source jars that aren't already on a maven repository somewhere, you can also upload them to clojars.

10:04 insomniaSalt: hi all

10:07 c, java, emacs-lisp, starting clojure as of today

10:07 xD

13:04 Anniepoo_: why doesn't (def (symbol "foo") 7) work? I'm expecting it to be (def foo 7)

13:05 wtetzner_: because you're trying to set the form '(symbol "foo") to 7

13:06 def doesn't evaluate it's first argument

13:06 Anniepoo_: ah, light bulb goes on

13:07 (it's a surface mount LED)

13:11 depressingly, I'm doing just enough clojure that each new project I'm a noob again

13:11 KirinDave: Anniepoo_: Relish that feeling

13:12 Utopiah: Anniepoo_: tried taking notes?

13:13 Anniepoo_: @Utopiah not sure how I'd structure 'notes' - it's more that I lose the 'clojure mindset'

13:14 Utopiah: I dont know how you'd structure them either but I know that it helps me in most tricky situation, precisely because I have to structure my thoughts and can re-access recurrent problems anytime efficiently

13:17 insomniaSalt: for me, this is facilitated in emacs' org-mode

13:18 Utopiah: insomniaSalt: yes, there a plenty of good tools, the only bad answer IMHO is "well right! Im going to do one right away in Clojure (or whatever problem Im trying to solve)!" ;)

13:19 Anniepoo_: I have a freemind mind map with all my emacs knowledge in it

13:21 Utopiah: but nothing on Clojure?

13:22 Anniepoo_: I have a directory full of snippets of clojure goodness

13:23 including 'chouser explains state' and 'jesusthisisawkward'

13:32 Blackfoot: is there a way to define a struct or record such that trying to use undeclared keys will result in an exception? or even better, a compile time check if they key is known?

13:33 Anniepoo_: Blackfoot - you could iterate thru the keys and check that each is present in some list of allowed keys, but

13:33 I suspect you're trying to write java in clojure.

13:34 ah, I misread your question

13:34 Blackfoot: main motivation is to simply avoid making typos in key names, since they are not checked

13:35 Anniepoo_: the think of undefined keys just returning nil has it's plusses and minuses

13:35 Blackfoot: right, i don't mind it while iterating/developing

13:37 Raynes: Blackfoot: http://gist.github.com/575379 might be helpful.

13:40 Anniepoo_: It'd be nice to have a tool in the editor that had a list of symbols. Whenever you typed one that wasn't on the list it'd underline in red or something

13:40 same tool could do autocomplete

13:40 Blackfoot: yes, that'd be a start for the editor

13:40 Anniepoo_: it'd have some 'add this to symbols' key

13:41 Blackfoot: well vim, and i'm sure emacs, can autocomplete from any token it has previously seen

13:42 Anniepoo_: it can? I didn't know that! how do I activate that?

13:42 Blackfoot: Raynes: I think the core issue is enforcing a protocol... so maybe i should just be using a protocol

13:42 ^N or ^P in vim

13:43 herdrick: question regarding compojure:

13:43 i tried to run the hello world on the compojure site

13:43 didn't work

13:43 Anniepoo_: M-/

13:43 herdrick: do i need to install jetty / does the project.clj deps not include jetty itself?

13:44 Blackfoot: Raynes: imagine i am reasonably sure that every Circle record has a diameter, I don't want a NullPointer exception way down the line when I type (:diameer circle)

13:45 Anniepoo_: I think they unit testing folks would say that should get caught by unit testing

13:47 herdrick: sorry, i'm back now - bad connection

13:47 the error i got was "Exception in thread "main" java.lang.ClassNotFoundException: clojure.main"

13:50 Blackfoot: herdrick: i have not done the tutorial, but i would make sure a) project.clj has a :main key, b) the namespace in which your main function exists has a :gen-class key, and c) the main function in the namespace is named correctly (usually -main)

13:52 herdrick: hi Blackfoot: no, there's no :main anything in my project.clj

13:52 nor 'main' anywhere else

13:52 i think compojure doesn't need it

13:53 in any case, it looks like i do need to download jetty separately no mention of that in the 'getting started' hello world docs....

13:55 Blackfoot: ah ok

14:03 herdrick: oops, no it did include jetty already

14:03 crud

14:03 well, it appears the hello-world example is broken

14:03 or something

14:04 or i am incorrectly pasting the code or config stuff in...

14:05 sigh

14:07 chouser: herdrick: I'm sorry -- I know it can be frustrating. Unfortunately I've never used compojure at all so I'm in no position to help.

14:07 herdrick: chouser: no worries - thanks anyway!

14:07 chouser: class not found "clojure.main" suggests clojure.jar itself is not in your classpath

14:07 but I don't know lein well enough to tell you where to look to fix that

14:10 tomoj: the repl task doesn't take any arguments

14:10 and it should be src/hello_www/core.clj, not src/hello-www/core.clj

14:11 raek: better to do just do "lein repl" followed by "(require 'hello-www.core)" in the repl

14:12 the lein repl command has never officially been taking two args

14:12 that just happened to work due to its implementation for some versions

14:12 so yes, the example is broken.

14:13 *one arg

14:28 herdrick: tomoj: ok - thanks

14:28 lein repl by itself breaks for me in the same way

14:28 so it can't even find the clojure jar?

14:28 odd

14:29 Raynes: chouser: Also, it wasn't the multimethods causing that weird memory leak in sexpy.

14:29 tomoj: herdrick: did you run `lein deps` ?

14:29 Raynes: Just letting you know. I figured it might have been something weird going on there.

14:29 herdrick: yes

14:30 tomoj: `lein -v`?

14:30 herdrick: Leiningen 1.1.0 on Java 1.6.0_20 Java HotSpot(TM) 64-Bit Server VM

14:31 tomoj: well, that's pretty old

14:31 herdrick: ah ok!

14:31 thanks

14:31 tomoj: `lein upgrade`

14:31 herdrick: yeah, doing that now, thanks!

14:32 this is probably the problem

14:32 tomoj: dunno.. the repl task shouldn't have done that in 1.1.0 either

14:33 raek: I have sent a PM on github to James Reeves (the author of compojure) about the lein usage (which was erroneous anyway)

14:39 herdrick: hot dog - that worked

14:39 thanks tomoj:

14:40 and raek: thanks, the (require 'hello-www.core) was necessary starting lein with 2 args still doesn't work

14:40 tomoj: herdrick: are you an emacs dude by chance?

14:40 herdrick: yep

14:40 well, i use it i like it ok ;)

14:41 tomoj: I usually replace the (run-jetty example {:port 8080}) with something like (defonce server (run-jetty #'example {:port 8080 :join? false}))

14:41 then you can C-c C-k the file and the server will stay running and pick up the changes

14:41 raek: interactive development with slime is really handy for web programming

14:42 no need to restart the server

14:42 as long as you remember to var quote the handler function (as tomoj's example does)

14:42 herdrick: ok, that is exactly the kind of thing i love

14:43 tomoj: what's that run-jetty function?

14:43 raek: lein swank in the terminal and M-x slime-connect in emacs

14:43 tomoj: it's from ring.adapter.jetty, it just starts jetty with a ring handler

14:43 raek: after adding :dev-dependencies [[swank-clojure "1.2.1"]] to project.clj

14:44 Raynes: chouser: Ping me when you get a moment.

14:44 raek: it starts the http server

14:44 herdrick: raek: ok, thanks and then (require 'hello-www.core) to start the server?

14:44 or run-jetty ?

14:45 raek: that depends on whether your hello_www/core.clj contains the run-jetty call :)

14:45 the require line loads and evaluates everything in the file

14:46 so, I would recommend adding tomoj's line to the core.clj file (replacing the old one)

14:47 and starting it with (require 'hello-www.core)

14:47 running require again will not re-evaluate the file

14:47 (unless you pass the :reload option)

14:49 in emacs, when connected with slime, you can evaluate code (and redefine functions) with C-x C-e or C-M-x

14:50 the C-c C-k tomoj mentioned basically does a (require '... :reload) for the current buffer

16:33 chouser: Raynes: pong

16:35 Raynes: chouser: Apparently, there wasn't a 'memory leak' at all. I was able to reproduce it on a small scale just by reloading clojure.java.io around 300 times and watching the memory usage rise. However, I decided to try to make sexpbot run out of memory by reloading, but eventually it appears to stabilize and even lower quite a bit at some point.

16:36 I'm not sure why, but it doesn't appear to be a real problem.

16:36 chouser: hm, so perhaps it was just GC behavior

16:36 though that doesn't explain the live object counts going up

16:36 Raynes: Calling the GC manually doesn't do anything.

16:36 If that means anything.

16:38 <raek> the java process increases its memory usage when I run (dotimes [_ 1e7] (fn [] 1))

16:39 raek: I think it stopped to increase after a while

16:39 Raynes: Just like in sexpy.

16:40 raek: yupp, it stops at 227 MB

16:40 Raynes: I don't give sexpbot much breathing room as far as memory goes.

16:40 chouser: watching the jvm

16:40 Raynes: Probably why it didn't take long for it to stop rising.

16:40 chouser: watching the jvm's use of memory from the OS perspective doesn't tell you much about what's going on inside

16:40 but I thought using yourkit to watch the live object counts *did* mean something.

16:41 Raynes: It tells me that sexpbot is unlikely to explode if a user reloads two hundred times in a session. :>

17:02 arohner: does clojure-1.3 with pst break swank-clojure?

17:02 I'm using C-c C-l to load files, and when I get a compile error, I don't get a stacktrace anymore

17:02 this worked before changing from 1.2 to 1.3

17:02 Chousuke: I suppose it might've broken swank

17:02 since the stacktrace format changed

17:03 though hm. I suppose that depends on what swank does to get the stacktrace.

17:04 arohner: compile errors in the swank repl also don't work

17:04 this is really easy to check, one sec

17:09 yeah, clojure-1.3 snapshots with pst break slime

17:09 I can reproduce the error solely by switching clojure jars

17:17 kjeldahl_: In the following line: (defmacro dbg[x] `(let [x# ~x] (println '~x "=" x#) x#))

17:17 What does x# mean?

17:17 Chousuke: it's an autogensym

17:18 meaning it gets replaced with something unique whenever the macro is expanded

17:18 raek: it becomes a symbol with a unique suffix

17:18 ,`foo#

17:18 clojurebot: foo__5254__auto__

17:18 kjeldahl_: Ah, ok, thanks.

17:18 Chousuke: it's there to avoid clashes with names that might already exist.

17:19 kjeldahl_: Got it, thanks.

17:19 raek: all instances of x# will become the same autogensymed symbol, since they're in the same syntax-quoted expression

17:19 kjeldahl_: Just the keyword autogensym lets me google it. :-)

17:19 technomancy: arohner: could you open an issue?

17:19 arohner: technomancy: sure

17:19 technomancy: I was a little reluctant without a patch :-)

17:20 raek: [(list `foo# `foo#) `(foo# foo#)]

17:20 ,[(list `foo# `foo#) `(foo# foo#)]

17:20 clojurebot: [(foo__5257__auto__ foo__5258__auto__) (foo__5259__auto__ foo__5259__auto__)]

17:20 technomancy: arohner: oh, don't be shy about that

17:20 we're not jumping straight to 1.3 at work, so I'm not sure when I'll be able to take a look at it, but it's good to have it tracked somewhere

17:20 mark mcg. doesn't do IRC, does he?

17:33 jjido: (hello "everyone!")

17:33 I am looking at the examples in the Clojure distribution. Are [] the same as ()?

17:35 Raynes: Those are two different data structures.

17:35 [] is a vector and () is a list.

17:35 bozhidar: jjido: [] denotes a vector

17:35 () - a list

17:35 vectors are optimized for random access

17:36 Raynes: -> (conj [2] 3)

17:36 sexpbot: => [2 3]

17:36 Raynes: -> (conj '(2) 3)

17:36 sexpbot: => (3 2)

17:37 Raynes: -> [(cons 3 '(2)) (cons 3 [2])]

17:37 sexpbot: => [(3 2) (3 2)]

17:38 bozhidar: I don't think that cons-ing was a particularly illustrative example :-)

17:38 one has to be aware of the fundamentals of data structures

17:38 not clojure itself to understand the difference between vectors and lists

17:39 Raynes: bozhidar: The example was for me. :p

17:40 bozhidar: Raynes: hehe, yep it's a bit tricky that cons returns a seq

17:40 some people are surprised at the beginning

17:43 jjido: and when the vector has just one element eg. loop [match (re-find m)]

17:43 mmh bad example

17:44 (defn minutes-to-millis [mins] (* mins 1000 60))

17:46 raek: in macros/special syntax (like let and defn) vectors are often used when the first element does not represent an operation (as in ordinary function application)

17:47 much like some scheme interpreters allow [] as ()

17:48 however, in clojure they're not just syntactic sugar, but actually different data structures

17:49 jjido: ok so in the above [match (re-find m)] is not a function application

17:50 code/examples/sequences.clj

17:53 raek: exactly

17:53 just like in (defn square [x] (* x x)), [x] is not a function application

17:54 jjido: have you programmed in any Lisp before?

17:54 jjido: I feel that makes sense

17:54 raek: very little in my uni years

17:54 raek: loop is a special form

17:55 jjido: does it mean it is like quote?

17:55 raek: normal evaluation rules do not apply to macros and special forms

17:55 yes, in the sense that you don't need to quote the symbol in defn

17:56 jjido: ok

17:56 I may be interested in learning more about loop. I came to Clojure because

17:56 raek: variable lookup is never done on the symbol "match" in that case

17:57 jjido: I am looking to write a compiler for my functional-oriented language

17:58 ok I understand

18:00 raek: much (if not most) of clojure is described at http://clojure.org/Reference (same as the links in the left sidebar)

18:00 the special forms (loop and friends) are described here: http://clojure.org/special_forms

18:02 when I learned clojure, I mostly studied the clojure.org page and these videos: http://clojure.blip.tv/posts?view=archive&nsfw=dc

18:02 I would also recommend the book "Programming Clojure" by Stuart Halloway

18:04 the example you are looking at are from that book :)

18:10 jjido: raek: correct, forgot it came from there

18:11 I already tried using Java. People I showed the code were: "oh, my eyes!" ;) The main function is some initialisation then: while (true) next = next.eval();

18:12 that was a program I tried converting from my language to Java. I think Clojure will be a better match

18:15 mmh metadata

18:15 that's nice

18:51 "Defines a function (fn). Fns are first-class objects that implement the IFn interface. The IFn interface defines an invoke() function that is overloaded with arity ranging from 0-20."

18:52 is that 20-args limitation a problem for anyone?

18:53 chouser: I've never come close

18:55 jjido: is there a way to extend that number. I think that may cause me trouble

18:55 I want to program using CPS

18:56 _ato: ,(fn [a b c d e f g h i j k l m n o p q r s t & [u v w x y z]] 1)

18:56 clojurebot: #<sandbox$eval5264$fn__5266 sandbox$eval5264$fn__5266@1500b26>

18:57 jjido: _ato: yes thanks

19:05 Chousuke: jjido: the limit might drop to ten at some point so keep that in mind

19:09 jjido: Chousuke: which point?

19:09 Chousuke: with primitive support I think? so in 1.3

19:10 jjido: Chousuke: why not keep it to 20 for non-primitive types?

19:11 Chousuke: I don't know the reasoning

19:11 only that rhickey was planning to do it to limit the number of methods a bit. But now I'm not even sure if he did it or if he found another solution.

19:11 jjido: it could be even enlarged. I think when there is a primitive type arg you get a combinatorial explosion

19:12 but all non-primitive is fine

19:12 Chousuke: in any case you can always use a rest arg

19:13 Raynes: How can one kill a jetty server started with run-jetty?

19:13 Chousuke: which allows an infinite number of arguments

19:13 (literally, you can apply a function to an infinite sequence :P)

19:13 jjido: lol

19:13 "Note that recur is the only non-stack-consuming looping construct in Clojure. There is no tail-call optimization and the use of self-calls for looping of unknown bounds is discouraged." that is important!!

19:16 MayDaniel: Raynes: (.stop server), assuming that's what you meant by kill.

19:17 Raynes: MayDaniel: Does that actually kill it, or just stop it so it can be started again later?

19:17 * Raynes checks the jetty docs.

19:17 MayDaniel: It's just stops it.

19:17 Raynes: I've got to kill that sucker!

19:21 raek: jjido: it is possible to do CPS by using trampoline

19:22 jjido: raek: what is trampoline? something that preserves stack?

19:32 raek: ,(doc trampoline)

19:32 clojurebot: "([f] [f & args]); trampoline can be used to convert algorithms requiring mutual recursion without stack consumption. Calls f with supplied args, if any. If f returns a fn, calls that fn with no arguments, and continues to repeat, until the return value is not a fn, then returns that non-fn value. Note that if you want to return a fn as a final value, you must wrap it in some data structure and unpack it after trampoline r

19:37 jjido: raek: looks like my while (true) next = next.eval();

19:37 I was going to write it: (loop [next] (recur (next)))

19:46 kiras: so i'm trying to make a text editor, which i've never done before, using clojure, which i've never written a real program in before... i have some questions regarding with-open and also file io/buffers/etc. in clojure/java...

19:46 first, i'm thinking it probably makes sense to keep a file open until the user closes it, right? i mean, you wouldn't typically open it and close it again every time you wanted to read something from it or write to it... so from there i was thinking it would make sense to do something kind of like this: http://gist.github.com/575669 instead of using with-open, at least for the files that are going to be edited by the user.

19:47 am i totally off in my approach to this?

19:49 Chousuke: kiras: don't use map for side-effects

19:49 kiras: map is lazy so your side-effects might never happen

19:49 kiras: use doseq

19:49 kiras: chousuke: i considered using doseq, but got complaints about recursion in finally

19:49 Chousuke: hmmh

19:50 weird

19:50 kiras: chousuke: i could probably just force map or no?

19:50 Chousuke: oh well, then wrap the map call in dorun

19:50 kiras: ok, i'll do that

19:51 is my overall approach ok though?

19:51 i really couldn't see how to use with-open in this situation

19:52 Chousuke: I think it'll do for at least a simple editor

19:52 There's no real way to use with-open.

19:52 here

19:53 kiras: so keep going until any shortcomings become apparent?

19:53 Chousuke: I suppose.

19:53 keeping the files open all the time might not be optimal but it's probably good enough to start with

19:53 kiras: ah

19:54 in what way would it be less than optimal?

19:54 i figured i'd probably use lazy sequences with them, so they'd need to stay around?

19:55 Chousuke: lazy sequences and IO don't mix very well, so be careful.

19:55 kiras: either that or i'd have to open the file, read the entire contents (not sure what to do if the file is too large?)...

19:55 jjido: How do you do currying in Clojure?

19:55 Chousuke: partial application is done with partial

19:56 kiras: i may have to think more about that then

19:57 jjido: Chousuke: thanks!

19:58 Chousuke: Don't overuse pointfree style in Clojure though, it's not as idiomatic as in Haskell :)

19:59 kiras: would it make more sense to just read the file into a buffer, then close it and open it again for writing?

19:59 Chousuke: I've seen some pretty hairy code trying to avoid using named parameters :P

19:59 kiras: probably not, that wouldn't work well for large files

19:59 kiras: I suppose most OSes can handle a large amount of open files anyway

20:00 kiras: chousuke: at this point, probably

20:06 Chousuke: I wonder if this bit of trivia on Wikipedia is true:

20:06 The name "currying", coined by Christopher Strachey in 1967, is a reference to logician Haskell Curry. The alternative name "Schönfinkelisation", has been proposed as a reference to Moses Schönfinkel.[2]

20:07 jjido: thanks god the first was chosen!

20:07 :)

20:07 Chousuke: That might be a troll but it's an amusing one.

20:09 There is a reference though.

20:09 jjido: no native support for declaring classes in Clojure?

20:09 Chousuke: There's gen-class

20:10 but that's Java interop, not Clojure

20:11 the closest to a class you can get without resorting to java-land things is a record

20:11 jjido: I want something with a "field": message which can be "overriden"

20:11 is struct-map is a record?

20:11 Chousuke: so you should just have a map or a record with a message key

20:11 no, defrecord

20:11 struct-maps are pretty much deprecated

20:11 jjido: ok

20:12 Chousuke: note that records don't support inheritance either. you need to structure your logic differently :)

20:12 jjido: this is where I saw struct-map: http://clojure.org/data_structures

20:13 Chousuke: yeah. They've been in Clojure for a long time

20:13 but records do everything struct maps did, with better performance :P

20:13 jjido: the page should be revised

20:15 How do I change a value associated with a key in a record?

20:15 (without mutating of course)

20:15 Chousuke: assoc works, records work like maps

20:16 At least I think assoc works

20:16 but I'm getting too tired to think straight now

20:16 so good night :P

20:16 jjido: gn

20:17 kiras: night

20:17 ty for your help

20:27 zoldar: hello, how do I read session contents when using ring.middleware.session? I have routes defined using defroutes but I don't know how to pass the whole session map as a single argument to the handler function. Configuration of my routes: http://paste.lisp.org/display/114460

20:35 jjido: is there a shorthand for a function without parameter eg. (fn [] 33)

20:37 unquote?

20:41 java.lang.IllegalStateException: Var clojure.core/unquote is unbound. (NO_SOURCE_FILE:0)

20:44 I found the shorthand, #(33)

21:02 chouser: jjido: nope

21:02 ,#(33)

21:02 clojurebot: #<sandbox$eval5279$fn__5280 sandbox$eval5279$fn__5280@755d27>

21:03 chouser: ,(let [f #(33)] (f))

21:03 clojurebot: java.lang.ClassCastException: java.lang.Integer cannot be cast to clojure.lang.IFn

21:03 chouser: maybe constantly

21:04 jjido: weird.

21:04 ,(#(33))

21:04 clojurebot: java.lang.ClassCastException: java.lang.Integer cannot be cast to clojure.lang.IFn

21:04 jjido: ,(#(+ 3 33))

21:04 clojurebot: 36

21:07 tomoj: #(foo) is (fn [] (foo))

21:13 jjido: ok I see ((fn [] (33)))

21:14 is there the equivalent of (rest list) for a sequence [1 2 3]?

21:14 I want [2 3]

21:22 (subvec [1 2 3] 1)

21:24 tomoj: pop works, but backwards

21:26 sproust: Hmmmm... clojure.string.replace collides with clojure.core.replace

21:27 tomoj: that happens

21:28 sproust: I'm not enough of a local to say anything like that yet... but may I suggest unique names across all the core?

21:28 tomoj: "core" is probably a bad word

21:28 sproust: Then again, this saves me: (:refer-clojure :exclude [replace])

21:28 tomoj: oh, no it's not

21:28 (:require [clojure.string :as string])

21:29 sproust: Sure, I was "using" instead.

21:29 But :only.

21:29 I'm sure you know what I mean :-)

21:31 tomoj: there's also :rename

21:33 sproust: tomoj: I like your thinking. Do you always :require everything? Do you :use anything?

21:33 tomoj: I :use, but I feel bad about it afterwards :P

21:34 sproust: Hahahha :)

21:34 tomoj: :only is good

21:34 I don't know why I care anyway, I can just M-.

21:35 guess it's useful when you're looking at code without slime

21:35 sproust: M-. rules.

21:35 How _dare_ you suggest one should use a computer without an Emacs running on it.

21:36 tomoj: I wouldn't think of it

21:36 but sometimes you don't have a jvm handy to load the code into, or you have a jvm but for whatever reason it's not handy to load the code into it

22:02 tufflax: I followed http://riddell.us/ClojureOnUbuntu.html this guide to setting up clojure, but when I try to run the command "clj" I get back: clj-env-dir: command not found. What's wrong?

22:04 running ./clj-env-dir when im in the correct dir works btw

22:05 But I'm a linux noob so I don't know what I should do to get the clj alias working

22:15 mefesto: tufflax: you can copy or symlink it to a dir in your path

22:16 tufflax: for me, I have $HOME/bin in my path so I just copied it there as 'clj'

22:17 jjido: How do I exit a program without exception? (.exit System 0) does not work

22:17 mefesto: jjido: (System/exit 0)

22:19 jjido: mefesto: that's it! Thank you.

22:33 I got my program to run. http://pastebin.ca/1938589

22:33 But it displays 8 messages instead of 7!

22:34 tomoj: jjido: has someone already complained about your parenthesis style?

22:34 jjido: lol sorry :-(

22:35 tomoj: I don't want to bug you about it if you've already heard and decided to stick with it

22:35 if not, http://mumble.net/~campbell/scheme/style.txt is a good read

22:35 jjido: thanks.

22:36 tomoj: putting closing parens on their own line will get you people like me telling you not to do that

22:36 but if you really want to, I won't stop you :)

22:38 did you use '_return and '_throw to avoid clobbering^?

22:39 jjido: yes

22:39 they are my return and throw continuations

22:42 tomoj: what is the (loop [a (vals 0) ...] ...) thing?

22:42 oh, I see

22:43 I thought it was #'vals from clojure.core

22:43 jjido: don't know that one

22:43 tomoj: ,(vals {1 2 3 4})

22:43 clojurebot: (2 4)

22:43 jjido: it was values first but my editor made it keyword color

22:44 I will change to numbers?

22:44 tomoj: 'vals works just fine, I just wasn't reading closely enough

22:45 I think clobbering things in core is actually acceptable style

22:46 why did you go for (subvec vals 1) instead of (rest vals) ?

22:47 I think I remember you wanted a vector back? but why?

22:47 jjido: the interpreter gave me out a list with (rest vals)

22:47 tomoj: why isn't a list OK, though?

22:48 (it's not actually a list)

22:48 jjido: I suppose I have that old-fashioned idea that the type of a variable should not change (not used to Lisp really)

22:48 tomoj: ,(class (rest [1 2 3]))

22:48 clojurebot: clojure.lang.PersistentVector$ChunkedSeq

22:48 tomoj: well, one of clojure's big focuses is the seq abstraction

22:49 if you're doing the kind of sequence processing where it doesn't matter whether you have a vector or a list or whatever, you just use the seq abstraction

22:49 jjido: ok

22:50 how about (next vals)?

22:50 tomoj: next is good

22:51 hmm, what should (strictly-ascending [1 2 3] :yes :no) return?

22:51 jjido: :yes

22:51 tomoj: for me, it returns :no

22:54 ,(letfn [(strictly-ascending [vals _yes _no] (if (every? (fn [[a b]] (< a b)) (partition 2 1 vals)) _yes _no))] (strictly-ascending [1 2 3] :yes :no))

22:54 clojurebot: :yes

22:54 jjido: I made a mistake

22:55 I had (tail 1) and changed it to (first tail)

22:55 should be: (recur b (tail 1) (next tail))

22:56 tomoj: another idiom is to avoid explicit loop/recur and use the seq functions when possible

22:57 jjido: the algorithm should compare the first two elements in the list and shift the list 1 element

22:59 tomoj: ,(let [vals [1 2 3 3 5 4]] (map #(< %1 %2) vals (rest vals)))

22:59 clojurebot: (true true false true false)

22:59 tomoj: ,(let [vals [1 2 3 4 5]] (every? true? (map #(< %1 %2) vals (rest vals))))

22:59 clojurebot: true

23:00 rhudson: There's actually a much simpler way to do it. All the Clojure comparison operators are n-ary, not binary.

23:00 jjido: coool

23:00 rhudson: (apply < [1 2 3 4 5])

23:00 ,(apply < [1 2 3 4 5])

23:00 clojurebot: true

23:00 rhudson: ,(apply < [1 2 2])

23:00 clojurebot: false

23:00 tomoj: nice

23:01 jjido: ah it is already built-in. I did not try it with a vector

23:03 tomoj: that's 10x as fast, too https://gist.github.com/01bb734fc4aa8d87acb0

23:03 jjido: I still have the "bug"

23:04 _loop is called one too many time

23:05 tomoj: why do (strictly-ascending [n 7] foo bar) instead of (if (< n 7) foo bar) ?

23:06 jjido: because the latter is not CPS

23:06 rhudson: Why is CPS important to you?

23:07 defn: Does anyone know if clojure-conj holds the promise of putting presentations online through a service like confreaks?

23:07 jjido: rhudson: I want to compile a CPS-based language for the JVM

23:07 defn: I am always hearing about rhickey giving talks on Clojure but am almost always disappointed to find out they're not online anywhere for the public.

23:08 jjido: replacing with if (< n 7) takes care of the bug

23:14 tomoj: that's strange

23:14 I thought they'd be equivalent

23:14 jjido: got it!

23:15 tomoj: jjido: how is (if (< n 7) yes no) not CPS if (strictly-ascending [n 7] yes no) is?

23:16 jjido: tomoj: in fact I should return #(strictly-ascending [n 7] yes no)

23:17 the problem was that the 1st arg (yes branch) was evaluated

23:19 tomoj: so #(if (< n 7) yes no) counts as CPS?

23:21 jjido: well, what I do is that the main loop takes a continuation and runs it waiting for the next continuation

23:22 usually with CPS you just directly call the next continuation

23:22 but that grows the stack

23:22 rhudson: ,(doc trampoline)

23:22 clojurebot: "([f] [f & args]); trampoline can be used to convert algorithms requiring mutual recursion without stack consumption. Calls f with supplied args, if any. If f returns a fn, calls that fn with no arguments, and continues to repeat, until the return value is not a fn, then returns that non-fn value. Note that if you want to return a fn as a final value, you must wrap it in some data structure and unpack it after trampoline r

Logging service provided by n01se.net