2010-09-11
| 00:24 | sproust | tomoj/ihodes: another way to define simple zip: (partition 2 (interleave coll1 coll2)) |
| 00:25 | tomoj | looks more than 3 times slower |
| 00:25 | sproust | This one _does_ use Clojure's slightly odd form of cons (interleave defined recursively via lazy-seqs) |
| 00:25 | sproust | tomoj: does it? |
| 00:25 | tomoj | ,(time (dorun (partition 2 (interleave (range 10000000) (range 1000000))))) |
| 00:25 | sproust | Ouf... |
| 00:25 | clojurebot | "Elapsed time: 6054.071 msecs" |
| 00:25 | tomoj | ,(time (dorun (map vector (range 10000000) (range 1000000)))) |
| 00:25 | clojurebot | "Elapsed time: 2309.176 msecs" |
| 00:25 | sproust | Yup. |
| 00:28 | chouser | ,(time (dorun (map-indexed vector (range 10000000)))) |
| 00:28 | clojurebot | Execution Timed Out |
| 00:28 | chouser | :-( |
| 00:28 | sproust | This clojurebot friend is pretty resilient :-) |
| 00:48 | sproust | Hmmm ... I have a function that is implemented as two nested for loops, which produces side effects (writes out files). |
| 00:49 | sproust | An enclosing (dorun/doall is not enough to force execution of the inner for loop. |
| 00:49 | sproust | What's the idiomatic solution to this? |
| 00:50 | sproust | (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.) |
| 00:52 | tomoj | use doseq instead? |
| 00:52 | tomoj | for? |
| 00:52 | clojurebot | for is not a loop |
| 00:55 | sproust | tomoj: interesting; the similarity btw for and doseq never came to mind. Thanks. |
| 00:57 | sproust | I guess what I want really is doseq. |
| 00:57 | sproust | Works like a charm! |
| 01: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? |
| 01:09 | quotemstr_ | I'd normally use a condition variable for that sort of thing. |
| 01:10 | tomoj | is the counter in a ref/atom? |
| 01:10 | tomoj | (what would it mean to wait for it to descend otherwise?) |
| 01:13 | quotemstr_ | Let's say it's a ref. |
| 01:16 | tomoj | d'oh |
| 01:21 | quotemstr_ | Would an atom be better here? |
| 01:21 | quotemstr_ | It's the waiting-until-decremented part that's the issue. |
| 01:22 | quotemstr_ | Should I just create an agent and fire off something every time I'd decrement a counter? |
| 01:27 | tomoj | what are you counting? |
| 01:28 | quotemstr_ | Connections. |
| 01:28 | quotemstr_ | There are 1024 connection slots (protocol-bound), and it's not good to accept() a connection if there are no slots available. |
| 01:28 | quotemstr_ | I just thought I'd ask about the canonical Clojure approach. More traditionally, you could use a condition variable, or a semaphore. |
| 01:28 | quotemstr_ | (The counting semaphore is the classic solution to this problem.) |
| 01:30 | tomoj | ideally you wouldn't have any state :) |
| 01: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. |
| 01:32 | quotemstr_ | :) |
| 01:32 | quotemstr_ | But IO is a fact of life, alas. |
| 01:34 | tomoj | that you're doing IO doesn't mean you need an atom |
| 01:34 | tomoj | but I don't understand what you're doing |
| 01:35 | tomoj | (nor is it likely that I will if you try to explain it, sorry) |
| 01:36 | quotemstr_ | Fair enough. |
| 01:37 | quotemstr_ | But global knowledge isn't necessary. :) |
| 01: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...) |
| 01:37 | _mst | that feels fine to me in terms of being idiomatic :) |
| 01:38 | quotemstr_ | _mst: That's cleaner, but the problem is that the consequences are externally visible. |
| 01:38 | quotemstr_ | _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. |
| 01:39 | _mst | ahh I see |
| 01:44 | _mst | so ideally you'd like the worker processes to be calling accept() when they're actually ready? |
| 01:44 | quotemstr_ | Yeah. |
| 01:45 | quotemstr_ | ... should I just create 1024 workers? |
| 01:47 | _mst | I guess it makes life easier just to statically create them all at startup |
| 01:49 | quotemstr_ | That might solve this particular problem, but it doesn't tell me how to create the equivalent of a counting semaphore. |
| 01: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 |
| 01:53 | _mst | not very helpful, sorry :) |
| 01:55 | quotemstr_ | Thanks anyway. :) |
| 02: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? |
| 02: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? |
| 03: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 |
| 03:10 | KirinDave | I think I need a clojure t-shirt. |
| 03:11 | KirinDave | I think that's the best way I could get better at clojure. |
| 03:11 | amalloy | I went to clojure-conj and all I got was this (promise 'shirt) |
| 03:13 | KirinDave | amalloy: We need something really good. |
| 03:13 | KirinDave | none of this erlangfactory shit. |
| 03:13 | KirinDave | We need something that ugmonk could sell. |
| 04:48 | n2n3 | ,(|) |
| 04:48 | clojurebot | java.lang.Exception: Unable to resolve symbol: | in this context |
| 06:19 | kjeldahl | Any pointers for doing simple unbuffered text file output in Clojure? Do I have to dive into the java libs? |
| 06:20 | mrBliss | maybe spit is what you need |
| 06:21 | mrBliss | never mind |
| 06:21 | kjeldahl | Yeah, it closes the file as well... |
| 06:23 | kjeldahl | 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. |
| 06:25 | raek | the java classes are still used |
| 06:25 | raek | however, there are some functions in clojure.java.io that makes it simpler |
| 06:33 | raek | with, c.j.io only the .write call has to be in java... (or if you use spit, none) |
| 06:36 | raek | (use '[clojure.java.io :only [writer]]) (with-open [f (writer "file/path")] (doseq [x some-coll] (.write f (make-some-string x)))) |
| 06:45 | raek | this is buffered though... if you need unbuffered output, you have to use the java classes directly (and pass output as java arrays) |
| 06: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. |
| 06:53 | kjeldahl | raek: Which means that with-open might not be ideal for this use case. |
| 06:57 | raek | yes, with-open would not be very useful in that case |
| 06:57 | raek | might be better to just define the writer as a global var |
| 06:57 | kjeldahl | Yeah, I'll use the with-open source for "inspiration". |
| 06:59 | raek | the only io-related calls it makes is to .close the file when done (or when a exception is thrown) |
| 07:02 | raek | (def log-writer (writer "file/path")) (defn log [s] (doto log-writer (.write s) .newLine .flush)) ; simple example I just made up |
| 07:03 | raek | and then (.close log-writer) should be called when the application exits |
| 07:06 | Chousuke | You might want to use an agent to serialise access to te log-writer if you have any parallelism. |
| 07:19 | kjeldahl | Thanks for the help. Raek's code looks fine (haven't tested yet, but will do so shortly). |
| 07:31 | kjeldahl | raek: Code works fine. Thanks. |
| 07: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") |
| 07:53 | Raynes | Morning. |
| 09:16 | edbond | how to use non-maven jars with leiningen? |
| 09:25 | edbond | I did mvn install:install-file |
| 09: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 | insomniaSalt | c, java, emacs-lisp, starting clojure as of today |
| 10:07 | insomniaSalt | 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 | wtetzner_ | def doesn't evaluate it's first argument |
| 13:06 | Anniepoo_ | ah, light bulb goes on |
| 13:07 | Anniepoo_ | (it's a surface mount LED) |
| 13:11 | Anniepoo_ | 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 | Anniepoo_ | 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 | Anniepoo_ | I suspect you're trying to write java in clojure. |
| 13:34 | Anniepoo_ | 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 | Anniepoo_ | 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 | Blackfoot | ^N or ^P in vim |
| 13:43 | herdrick | question regarding compojure: |
| 13:43 | herdrick | i tried to run the hello world on the compojure site |
| 13:43 | herdrick | 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 | herdrick | 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 | herdrick | nor 'main' anywhere else |
| 13:52 | herdrick | i think compojure doesn't need it |
| 13:53 | herdrick | 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 | herdrick | crud |
| 14:03 | herdrick | well, it appears the hello-world example is broken |
| 14:03 | herdrick | or something |
| 14:04 | herdrick | or i am incorrectly pasting the code or config stuff in... |
| 14:05 | herdrick | 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 | chouser | 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 | tomoj | 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 | raek | the lein repl command has never officially been taking two args |
| 14:12 | raek | that just happened to work due to its implementation for some versions |
| 14:12 | raek | so yes, the example is broken. |
| 14:13 | raek | *one arg |
| 14:28 | herdrick | tomoj: ok - thanks |
| 14:28 | herdrick | lein repl by itself breaks for me in the same way |
| 14:28 | herdrick | so it can't even find the clojure jar? |
| 14:28 | herdrick | 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 | herdrick | thanks |
| 14:31 | tomoj | `lein upgrade` |
| 14:31 | herdrick | yeah, doing that now, thanks! |
| 14:32 | herdrick | 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 | herdrick | thanks tomoj: |
| 14:40 | herdrick | 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 | herdrick | 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 | tomoj | 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 | raek | no need to restart the server |
| 14:42 | raek | 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 | herdrick | 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 | herdrick | or run-jetty ? |
| 14:45 | raek | that depends on whether your hello_www/core.clj contains the run-jetty call :) |
| 14:45 | raek | the require line loads and evaluates everything in the file |
| 14:46 | raek | so, I would recommend adding tomoj's line to the core.clj file (replacing the old one) |
| 14:47 | raek | and starting it with (require 'hello-www.core) |
| 14:47 | raek | running require again will not re-evaluate the file |
| 14:47 | raek | (unless you pass the :reload option) |
| 14:49 | raek | in emacs, when connected with slime, you can evaluate code (and redefine functions) with C-x C-e or C-M-x |
| 14:50 | raek | 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 | Raynes | 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 | chouser | though that doesn't explain the live object counts going up |
| 16:36 | Raynes | Calling the GC manually doesn't do anything. |
| 16:36 | Raynes | If that means anything. |
| 16:38 | Raynes | <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 | chouser | 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 | arohner | 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 | arohner | this worked before changing from 1.2 to 1.3 |
| 17:02 | Chousuke | I suppose it might've broken swank |
| 17:02 | Chousuke | since the stacktrace format changed |
| 17:03 | Chousuke | 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 | arohner | this is really easy to check, one sec |
| 17:09 | arohner | yeah, clojure-1.3 snapshots with pst break slime |
| 17:09 | arohner | 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 | kjeldahl_ | What does x# mean? |
| 17:17 | Chousuke | it's an autogensym |
| 17:18 | Chousuke | 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 | raek | ,`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 | arohner | technomancy: I was a little reluctant without a patch :-) |
| 17:20 | raek | [(list `foo# `foo#) `(foo# foo#)] |
| 17:20 | raek | ,[(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 | technomancy | 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 | technomancy | mark mcg. doesn't do IRC, does he? |
| 17:33 | jjido | (hello "everyone!") |
| 17:33 | jjido | 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 | Raynes | [] is a vector and () is a list. |
| 17:35 | bozhidar | jjido: [] denotes a vector |
| 17:35 | bozhidar | () - a list |
| 17:35 | bozhidar | 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 | bozhidar | one has to be aware of the fundamentals of data structures |
| 17:38 | bozhidar | 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 | bozhidar | 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 | jjido | mmh bad example |
| 17:44 | jjido | (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 | raek | much like some scheme interpreters allow [] as () |
| 17:48 | raek | 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 | jjido | code/examples/sequences.clj |
| 17:53 | raek | exactly |
| 17:53 | raek | just like in (defn square [x] (* x x)), [x] is not a function application |
| 17:54 | raek | jjido: have you programmed in any Lisp before? |
| 17:54 | jjido | I feel that makes sense |
| 17:54 | jjido | 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 | raek | yes, in the sense that you don't need to quote the symbol in defn |
| 17:56 | jjido | ok |
| 17:56 | jjido | 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 | jjido | 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 | raek | the special forms (loop and friends) are described here: http://clojure.org/special_forms |
| 18:02 | raek | 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 | raek | I would also recommend the book "Programming Clojure" by Stuart Halloway |
| 18:04 | raek | the example you are looking at are from that book :) |
| 18:10 | jjido | raek: correct, forgot it came from there |
| 18:11 | jjido | 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 | jjido | that was a program I tried converting from my language to Java. I think Clojure will be a better match |
| 18:15 | jjido | mmh metadata |
| 18:15 | jjido | that's nice |
| 18:51 | jjido | "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 | jjido | 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 | jjido | 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 | Chousuke | 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 | jjido | 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 | Chousuke | (literally, you can apply a function to an infinite sequence :P) |
| 19:13 | jjido | lol |
| 19:13 | jjido | "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 | 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 | jjido | 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 | kiras | 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 | kiras | am i totally off in my approach to this? |
| 19:49 | Chousuke | kiras: don't use map for side-effects |
| 19:49 | Chousuke | kiras: map is lazy so your side-effects might never happen |
| 19:49 | Chousuke | kiras: use doseq |
| 19:49 | kiras | chousuke: i considered using doseq, but got complaints about recursion in finally |
| 19:49 | Chousuke | hmmh |
| 19:50 | Chousuke | 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 | kiras | is my overall approach ok though? |
| 19:51 | kiras | 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 | Chousuke | There's no real way to use with-open. |
| 19:52 | Chousuke | here |
| 19:53 | kiras | so keep going until any shortcomings become apparent? |
| 19:53 | Chousuke | I suppose. |
| 19:53 | Chousuke | 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 | kiras | in what way would it be less than optimal? |
| 19:54 | kiras | 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 | Chousuke | kiras: probably not, that wouldn't work well for large files |
| 19:59 | Chousuke | 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 | Chousuke | 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 | jjido | :) |
| 20:07 | Chousuke | That might be a troll but it's an amusing one. |
| 20:09 | Chousuke | 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 | Chousuke | but that's Java interop, not Clojure |
| 20:11 | Chousuke | 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 | jjido | 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 | Chousuke | no, defrecord |
| 20:11 | Chousuke | 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 | Chousuke | but records do everything struct maps did, with better performance :P |
| 20:13 | jjido | the page should be revised |
| 20:15 | jjido | How do I change a value associated with a key in a record? |
| 20:15 | jjido | (without mutating of course) |
| 20:15 | Chousuke | assoc works, records work like maps |
| 20:16 | Chousuke | At least I think assoc works |
| 20:16 | Chousuke | but I'm getting too tired to think straight now |
| 20:16 | Chousuke | so good night :P |
| 20:16 | jjido | gn |
| 20:17 | kiras | night |
| 20:17 | kiras | 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 | jjido | unquote? |
| 20:41 | jjido | java.lang.IllegalStateException: Var clojure.core/unquote is unbound. (NO_SOURCE_FILE:0) |
| 20:44 | jjido | I found the shorthand, #(33) |
| 21:02 | chouser | jjido: nope |
| 21:02 | chouser | ,#(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 | jjido | ,(#(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 | jjido | is there the equivalent of (rest list) for a sequence [1 2 3]? |
| 21:14 | jjido | I want [2 3] |
| 21:22 | jjido | (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 | tomoj | (:require [clojure.string :as string]) |
| 21:29 | sproust | Sure, I was "using" instead. |
| 21:29 | sproust | But :only. |
| 21:29 | sproust | 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 | tomoj | I don't know why I care anyway, I can just M-. |
| 21:35 | tomoj | guess it's useful when you're looking at code without slime |
| 21:35 | sproust | M-. rules. |
| 21:35 | sproust | 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 | tomoj | 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 | tufflax | running ./clj-env-dir when im in the correct dir works btw |
| 22:05 | tufflax | 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 | mefesto | 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 | jjido | I got my program to run. http://pastebin.ca/1938589 |
| 22:33 | jjido | 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 | tomoj | 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 | tomoj | but if you really want to, I won't stop you :) |
| 22:38 | tomoj | did you use '_return and '_throw to avoid clobbering^? |
| 22:39 | jjido | yes |
| 22:39 | jjido | they are my return and throw continuations |
| 22:42 | tomoj | what is the (loop [a (vals 0) ...] ...) thing? |
| 22:42 | tomoj | oh, I see |
| 22:43 | tomoj | 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 | jjido | I will change to numbers? |
| 22:44 | tomoj | 'vals works just fine, I just wasn't reading closely enough |
| 22:45 | tomoj | I think clobbering things in core is actually acceptable style |
| 22:46 | tomoj | why did you go for (subvec vals 1) instead of (rest vals) ? |
| 22:47 | tomoj | 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 | tomoj | (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 | tomoj | 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 | jjido | how about (next vals)? |
| 22:50 | tomoj | next is good |
| 22:51 | tomoj | 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 | tomoj | ,(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 | jjido | I had (tail 1) and changed it to (first tail) |
| 22:55 | jjido | 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 | rhudson | ,(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 | jjido | _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 | tomoj | 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 | jjido | 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 | jjido | usually with CPS you just directly call the next continuation |
| 23:22 | jjido | 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 |