2009-06-05
| 03:57 | alinp | hi |
| 03:57 | alinp | is it possible in clojure to do something like that: (def x (eval "(+ 1 2)")) |
| 03:57 | alinp | ? |
| 03:58 | alinp | I'm sure this is not the function that needs to be used |
| 03:58 | alinp | but is there a function to be used for this purpose ? |
| 03:58 | opqdonut | you're not fine with (def x (eval '(+ 1 2))) ? |
| 03:58 | opqdonut | you could always invoke the reader |
| 03:58 | opqdonut | i dunno if it's exposed |
| 03:59 | opqdonut | ah, read |
| 04:00 | slashus2 | ,(eval (read-string "(+ 1 2)")) |
| 04:00 | clojurebot | DENIED |
| 04:00 | slashus2 | That is how you would do it alinp |
| 04:00 | opqdonut | ,(read-string "(+ 1 2)") |
| 04:00 | clojurebot | (+ 1 2) |
| 04:00 | opqdonut | yeah |
| 04:01 | alinp | read-string, thanks slashus2 & opqdonut |
| 04:37 | jdz | did anydoby mention that eval is evil? |
| 04:38 | opqdonut | of course it isn't :) |
| 04:39 | slashus2 | It would be bad if it was. |
| 04:39 | jdz | how so? |
| 04:39 | jdz | eval is the most evil function |
| 04:39 | jdz | i'm yet to come across a case when i need it... |
| 04:40 | opqdonut | not all metaprogramming can be done just with macros |
| 04:42 | jdz | i'd like to see an example |
| 04:44 | slashus2 | A really bad example would be if you wanted to use a macro in a function, and you want to expand the & more arguments. (eval `(amacro ~@more)) I don't know.. |
| 04:44 | opqdonut | well i have a macro that interprets a series of sexps into a complex data structure describing a computation |
| 04:45 | opqdonut | a "dsl" if you will |
| 04:45 | opqdonut | but i still want to invoke lisp deep within this sub-language |
| 04:45 | opqdonut | so the macro evals some parts |
| 04:47 | slashus2 | jdz: I think hiredman used it in clojurebot to evaluate form in cond-eval |
| 04:48 | jdz | slashus2: if you want to evaluate Clojure code, eval is what you use... |
| 04:49 | jdz | opqdonut: i'm still not convinced. |
| 04:49 | slashus2 | yep |
| 05:55 | yason | Hmmm, what's the idiomatic way to turn a sequence into a new sequence that contain N-sized chunks of the original sequence? |
| 06:00 | lenst | (doc partition) |
| 06:00 | clojurebot | "([n coll] [n step coll]); Returns a lazy sequence of lists of n items each, at offsets step apart. If step is not supplied, defaults to n, i.e. the partitions do not overlap." |
| 06:10 | opqdonut | gah, just realised why the eval command is , in clojurebot |
| 06:11 | yason | ah |
| 06:11 | yason | I've seen it before |
| 06:11 | yason | thanks |
| 09:06 | bstephenson | can anyone online answer a weird clojure.contrib.sql problem we are seeing? Otherwise, I will post the question to the newsgroup. |
| 09:15 | eevar2 | hard to tell if you don't ask your question.. |
| 09:32 | bstephenson | sorry, was hoping the SQL author was online....here is our problem: |
| 09:33 | bstephenson | we try to use the insert-values function to insert a record into a PostgreSQL database |
| 09:33 | bstephenson | turns out eh record was violating a foreign key constraint by referencing an account that was not in the accounts table |
| 09:33 | bstephenson | we got this error back from REPL: |
| 09:33 | bstephenson | <CompilerException java.lang.IllegalArgumentException: No matching |
| 09:33 | bstephenson | method found: println for class java.io.OutputStreamWriter |
| 09:33 | bstephenson | (NO_SOURCE_FILE:0)> |
| 09:34 | bstephenson | insterad of a JDBC error indicating that FK was violated (which we usually do) |
| 09:34 | bstephenson | both ID fields are UUID fields |
| 09:34 | bstephenson | once we put in the account intot he accounts table, the record we were trying to write went into the db without a hitch |
| 09:34 | bstephenson | wondering why we did not see a JDBC error when the problem was an FK violation? |
| 09:39 | bstephenson | ahh, sorry channel, we found the problem. Related to our editor, not clojure.contrib.sql |
| 10:23 | ezyang | Hey all; what's the difference between using (if (seq l)) and just directly checking if it's null? |
| 10:25 | Chouser | ezyang: an empty collection is logical true |
| 10:25 | Chouser | ,(let [c []] (if (seq c) "something" "nothing")) |
| 10:25 | clojurebot | "nothing" |
| 10:25 | Chouser | ,(let [c []] (if c "something" "nothing")) |
| 10:25 | clojurebot | "something" |
| 10:25 | ezyang | Oh. That's different from Scheme |
| 10:25 | ezyang | I thought an empty list was nil |
| 10:25 | Chouser | no |
| 10:26 | ozzilee | ,(seq []) |
| 10:26 | clojurebot | nil |
| 10:26 | Chouser | ,(let [c (list)] (if (seq c) "something" "nothing")) |
| 10:26 | jdz | ezyang: in scheme empty list is logical true, no? |
| 10:26 | clojurebot | "nothing" |
| 10:26 | Chouser | ,(let [c (list)] (if c "something" "nothing")) |
| 10:26 | clojurebot | "something" |
| 10:26 | ezyang | jdz: well, you do something like (null? list) |
| 10:27 | jdz | ezyang: same here, you do (seq lst) |
| 10:27 | ezyang | OK. |
| 10:28 | Chouser | in fact the idiomatic way to test for a non-empty collection is to use (seq x) in a boolean context. |
| 10:28 | Chouser | instead of (if (not (empty? coll)) ...), you say (if (seq coll) ...) |
| 10:28 | ezyang | Why is that the case? |
| 10:29 | jdz | because saying "something" sounds better than "not nothing"? |
| 10:30 | jdz | easier on the brain at least |
| 10:30 | ezyang | jdz: Oh, ok. |
| 10:30 | ezyang | I would normally use null? and then define the base case, and then do the regular stuff in the else |
| 10:32 | ezyang | Totally unrelated question: is there any way to dynamically update the REPL code |
| 10:32 | ezyang | without quitting the repl, recompiling, and then running again |
| 10:32 | ezyang | s/update the REPL code/update the code while you're in the repl/ |
| 10:32 | jdz | def? |
| 10:33 | jdz | well, how did you get the code in the repl in the first place? |
| 10:33 | ezyang | jdz: I changed my namespace |
| 10:33 | ezyang | And then the classpath found it |
| 10:33 | ezyang | The idea is I open the repl to debug some clj files, and then I edit those files |
| 10:34 | jdz | i have not tried, but maybe remove-ns + require will do |
| 10:34 | ezyang | I guess I'm being kind of unreasonable here |
| 10:34 | ozzilee | ezyang: (require 'my-ns :reload-all) |
| 10:34 | jdz | well, most people use some kind of a developement environment, like emacs + slime or netbeans or something |
| 10:35 | ezyang | I spent last afternoon trying to get VimClojure to work |
| 10:35 | ezyang | I think that I'm stuck on some special mvn behavior |
| 10:36 | jdz | serves you well for wanting to use vi[m] for lisp developmement *evil grin* |
| 10:37 | ezyang | I think it's kind of unreasonable to learn a new text editor (emacs) just to develop in it. |
| 10:37 | ezyang | s/in it/in clojure/ |
| 10:37 | jdz | well it's reasonable for a lisp developer to want to redefine stuff on the fly without reloading the world |
| 10:37 | jdz | like redefining functions, for instance |
| 10:37 | gnuvince | There's NetBeans, Eclipse, IntelliJ that are coming up with plugins for Clojure if you prefer. |
| 10:38 | gnuvince | Emacs is just so tightly knit with Lisp and its community that it's no wonder that the majority of Lispers prefer it. |
| 10:38 | Chouser | ezyang: I agree |
| 10:41 | ezyang | gnuvince: I totally understand why emacs is +1 for lisp development |
| 10:42 | ezyang | And it's also a text editor that is worth learning |
| 10:42 | Chouser | is it? is it really? |
| 10:42 | ezyang | I think you should be proficient in both vim and emacs :-) |
| 10:43 | gnuvince | ezyang: thankfully, I am :) |
| 10:43 | gnuvince | I use vim at work for Django work, and Emacs at home for Clojure and Haskell |
| 10:43 | gnuvince | And I'm pretty happy about my situation |
| 10:46 | piyo | ezyang: have you tried technomancy's clojure+emacs guide? http://technomancy.us/126 |
| 10:46 | ezyang | Not yet |
| 10:46 | piyo | It cleared up a number of problems for me |
| 11:18 | cemerick | we use netbeans + enclojure to very good effect, FWIW |
| 11:19 | cemerick | the debugger isn't there yet, but I'll bet it's not there for slime, either |
| 11:19 | Chouser | the size of all these tools scares me. :-/ |
| 11:20 | cemerick | If you can understand the whole thing top to bottom, chances are it doesn't do much for you. ;-) |
| 11:20 | Chouser | wow |
| 11:20 | cemerick | yeah, I always get that kind of reaction when talking to other programmers |
| 11:21 | cemerick | abstractions are good, they give you leverage. |
| 11:21 | Chouser | But I don't need to understand how it all works, I just need to understand how to use it. That's sufficiently scary for emacs, netbeans, eclipse... |
| 11:22 | cemerick | huh. I've always found NB very friendly. Somewhat more so than eclipse, and quite clearly more approachable than emacs. |
| 11:22 | aravind | Chouser: so.. what do you use for development? |
| 11:22 | Chouser | I'm always afraid to say. People (Rich included) mock me. |
| 11:22 | hiredman | notepad++ |
| 11:22 | Chouser | text editor. repl. |
| 11:23 | Chouser | ion3. |
| 11:23 | hiredman | Chouser: have you seen slime.vim? |
| 11:23 | aravind | I see, but don't you like the convenience of having a few key strokes compile/eval what you are working on? |
| 11:23 | hiredman | http://technotales.wordpress.com/2007/10/03/like-slime-for-vim/ |
| 11:24 | Chouser | vim with syntax coloring and indentation support. repl with rlwrap and vi-like bindings for tab completion and history. |
| 11:24 | hiredman | it lets you send code to a repl running in screen |
| 11:24 | Chouser | aravind: well, I have that. maybe more keystrokes than with slime, but not too bad. |
| 11:25 | Chouser | a couple keystrokes to select a portion of the code, an ion3 keystroke to focus on the repl, a keystroke to paste and execute. |
| 11:25 | ezyang | Gave up with vimclojure, am setting up emacs |
| 11:25 | aravind | Chouser: ion3 is supposed to be an awesome wm.. I used to use stumpwm for a while, but I finally gave up on tiling wms, switched to openbox (but was able to retain most of my keybindings). |
| 11:25 | Chouser | hiredman: I don't think I've tried that particular one. I did use whatever was before gorilla some, but it never really hooked me. |
| 11:26 | hiredman | Chouser: it is different from gorilla |
| 11:26 | Chouser | And I don't particularly *like* vim (vimscript in particular), but it's what I know, and the keybindings are undeniably powerful. |
| 11:26 | piyo | ezyang: what is your os |
| 11:27 | aravind | Chouser: how about auto navigating to your function definitions if you want to look some stuff up? You would have to hack it up with etags or something like that for equivalent functionality. |
| 11:27 | Chouser | I suppose I should try emacs, but the thought of having to learn elisp in order to customize it makes me gag a little. |
| 11:27 | hiredman | you start a repl inside a screen session and then you tell slime.vim the name of the screen session and the name of the window the repl is in, and it just sort of pastes the vode into the repl |
| 11:27 | hiredman | very loosely coupled |
| 11:27 | stuartsierra | Chouser: it's not that bad, 99% of the customization you'll ever want is in the *customize* GUI. |
| 11:28 | Chouser | hiredman: yeah, that sounds like pre-gorilla (sorry, can't remember the name). He had some vim/ruby code that sent forms to a screen session. |
| 11:28 | ezyang | piyo: Jaunty |
| 11:28 | Chouser | ...and I really must have vim bindings. the last couple times I tried switching to emacs I tried to do things the Emacs Way. I'm done with that. |
| 11:29 | aravind | Chouser: well.. it takes time. |
| 11:29 | Chouser | I know Chousuke uses vi bindings in emacs, but my recent attempts at that were unsatisfactory. |
| 11:29 | aravind | but then, if you are productive with your env, thats all that really matters. |
| 11:30 | Chouser | aravind: oh, I know. My last attempt at emacs went far enough that I was pretty comfortable with emacs bindings for navigating a file. Took time, but was somewhat rewarding. |
| 11:31 | Chouser | ...but then I needed features that were not built in, and spent some time trying to port a plugin from xemacs to emacs (or the other way around, I forget) ... largely failed, and then discovered the feature I needed was built in to vim. |
| 11:31 | piyo | ezyang: sudo aptitude install ant open-jdk-devel ... # etc... |
| 11:31 | piyo | ezyang: ? |
| 11:31 | aravind | I was a huge vim proponent, but its a nightmare trying to customize or hack the configs for anything other than the basic tabwidth, or syntax settings in it. So, I have been using emacs for some time now. |
| 11:32 | Chouser | now I'm just whining. I want emacs flexibility + vim keybindings + clojure core (for multithreading, customiaztion, etc.) |
| 11:32 | Chouser | when can I have that? :-) |
| 11:33 | ezyang | Oh, I already can run Clojure |
| 11:33 | ezyang | (re piyo) |
| 11:33 | ezyang | I was trying to "improve my productivity" with a non-crappy repl environment |
| 11:33 | aravind | Chouser: have you give emacs viper mode a chance, it may be just enough vi for you. |
| 11:33 | Chouser | I have. I should try again. |
| 11:34 | Chouser | I'm frequently startled by missing features, but I should try to get over it. |
| 11:35 | aravind | thats how I switched.. |
| 11:35 | Chouser | you don't use it anymore |
| 11:35 | Chouser | ? |
| 11:36 | aravind | vim, nope.. not unless I am in a remote system, when I need to use it for quick things. (I am a sysadmin). |
| 11:36 | Chouser | I mean, you don't use viper mode anymore? |
| 11:37 | aravind | oh viper mode.. nope, I used it to get started.. used it for a few months, then I tweaked the viper levels down to make it more and more emacsy, and finally turned it off for good. |
| 11:37 | Chouser | I just can't imagine living without command mode. |
| 11:38 | aravind | I did stick to pure viper (full vi) mode for a few months though. |
| 11:39 | aravind | command mode annoys me now, when I go to remote systems and start typing ALT-n and ALT-b in vim :) |
| 11:39 | Chouser | Holding down the ALT key seems like an inconvenient sort of command-mode. |
| 11:39 | Chouser | :-) |
| 11:41 | aravind | hehe, yeah.. like I said, it takes time :) |
| 11:42 | Chouser | see, and that would be fine if I were deeply convinced of the Rightness of emacs. But the language, the lack of concurrency, etc. weaken that conviction. |
| 11:42 | aravind | I still do like vi mode for other things though. my mutt is all vi mode and so is lynx (though I don't use that much these days). |
| 11:43 | aravind | Chouser: for me, it was more of a convenience thing and the fact that its immensely customizable should I need to. |
| 11:43 | Chousuke | I finally got visual block mode working properly with emacs/vimpulse. |
| 11:44 | Chousuke | turns out I had to disable CUA mode because it was screwing up the rendering for some reason |
| 11:44 | Chouser | Chousuke: really? works great here! in vim. :-) :-) |
| 11:44 | Chousuke | I still think emacs is fundamentally superior to vim |
| 11:44 | Chousuke | the interface is just not as good :) |
| 11:44 | Chouser | heh |
| 11:45 | Chousuke | elisp lacking concurrency support is a big wart though, but at least it's not vimscript :P |
| 11:46 | Chousuke | I wonder how they're going to go about adding threading to emacs. |
| 11:46 | aravind | although I will admit, gnus has defeated me, multiple times. I have tried and failed to adopt it as my mail client. Every time I give it a shot, I go running back to mutt :) |
| 11:47 | Chouser | I've never been a heavy email user, but I got gnus working nicely last time I tried. |
| 11:47 | piyo | ezyang: it's just that, when the installation asks you to "M-x clojure-install", it git-clones then does the ant build thing |
| 11:48 | ezyang | Oh yeah. No, the project I'm working on has its separate build environment, with hand-rolled jars and eveyrthing |
| 11:48 | aravind | Chouser: thats odd! you got gnus to play nice, but you have a hard time with emacs.. |
| 11:49 | cemerick | does anyone have recommendations for swing app frameworks, aside from the NB RCP? |
| 11:50 | Chouser | aravind: I really tried hard last time, getting emacs going. I wasn't even a lisper then... |
| 11:51 | aravind | Chouser: it took me a few attempts. |
| 11:53 | aravind | Chouser: if you want to switch (I am not saying you should), I'd start small. Don't try to get your entire env converted and working the way you think it should. |
| 11:53 | aravind | Chouser: I'd start with full blown viper mode.. etc.. |
| 11:55 | Chouser | :-) |
| 11:55 | Chousuke | viper doesn't have visual mode though. |
| 11:56 | aravind | I have used them both enough, that I don't really mind the taunting. |
| 11:56 | aravind | I take the zen approach and go "whatever works for you" :) |
| 11:56 | piyo | aravind: I like editting with root privs from emacs , /sudo::/etc/hosts , etc |
| 11:56 | Chousuke | I still use vim for some stuff |
| 11:57 | Chousuke | but for clojure editing I need emacs. |
| 11:57 | aravind | piyo: hehe |
| 11:58 | piyo | except emacs first needs to be installed into the os, while vi is sitting there |
| 11:58 | aravind | piyo: oh wait a minute.. you are serious? |
| 11:59 | piyo | aravind: M-x butterfly, baby |
| 11:59 | Chousuke | quite often emacs is too; but vi is pretty universal. |
| 11:59 | aravind | phew! |
| 11:59 | hiredman | piyo: well, the vi freebsd comes with is really vi, not vim |
| 11:59 | piyo | so I'm like sudo vi /etc/portage/package.mask # add cutting edge emacs |
| 12:00 | hiredman | which, uh, I'd rather not use for coding |
| 12:00 | piyo | aravind: you do use emacs TRAMP |
| 12:00 | piyo | aravind: ? |
| 12:00 | aravind | piyo: I do, if I have to do extended editing, and I can't replicate the env locally. |
| 12:01 | piyo | I was being serious with /sudo::/etc/hosts |
| 12:01 | aravind | no way! |
| 12:01 | aravind | you can't be! |
| 12:01 | piyo | I mean, it works |
| 12:02 | ezyang | Huh. Even with emacs+slime, it doesn't dynamically automatically update things. feh |
| 12:02 | piyo | I do set sudo so that I don't enter my password |
| 12:02 | aravind | piyo: sure does, but its like writing full blown swing application to cat/view a 10 line text file. |
| 12:03 | piyo | sometimes you want to M-x rectangle-yank inside a config file |
| 12:03 | piyo | :) |
| 12:03 | piyo | oh wait, you said 10 lines |
| 12:04 | piyo | I guess you could bang on "." for a while |
| 12:04 | aravind | piyo: vim + ex commands usually work fine for that kind of stuff for me. |
| 12:04 | piyo | aravind: as for me |
| 12:05 | piyo | hiredman: I only seem to use vi features, not vim |
| 12:06 | piyo | </offtopic> ? |
| 12:06 | aravind | I am out, have to get ready and head in to earn that paycheck. |
| 12:15 | piyo | let's talk about clojure |
| 12:15 | hiredman | ~clojure |
| 12:15 | clojurebot | clojure is like life: you make trade-offs |
| 12:16 | hiredman | ~clojure |
| 12:16 | clojurebot | clojure > scheme |
| 12:16 | gnuvince | ,(compare "clojure" "scheme") |
| 12:16 | clojurebot | -16 |
| 12:17 | gnuvince | ;-) |
| 12:17 | Chouser | ,(expression-info '(Integer. "5")) |
| 12:17 | clojurebot | {:class java.lang.Integer, :primitive? false} |
| 12:17 | Chouser | ,(expression-info '(int (Integer. "5"))) |
| 12:17 | clojurebot | {:class int, :primitive? true} |
| 12:17 | gnuvince | That's pretty neat |
| 12:18 | Chouser | I wish there were a way to use it on expression deep inside a nested context. |
| 12:24 | piyo | hey technomancy thanks for that emacs + clojure blog post, it was useful |
| 12:24 | technomancy | piyo: great, glad it was helpful |
| 12:24 | piyo | :) |
| 12:42 | ezyang | Hmm, I still can't get repl reloading to work |
| 12:45 | ezyang | What was the command to reload the namespace again? |
| 12:45 | ozzilee | (require 'my-ns :reload-all) ? |
| 12:46 | ezyang | Yeah, doesn't seem to do anything |
| 12:47 | ezyang | http://pastebin.com/mefa4d10 |
| 12:47 | stuartsierra | It won't delete old definitions. |
| 12:47 | ezyang | Oh. |
| 12:47 | ezyang | Ok, how should I do that? |
| 12:47 | stuartsierra | Try (remove-ns 'my-ns) first. |
| 12:48 | ezyang | Now I get Var plyzrdata.parser/parse-hoststat-line is unbound. |
| 12:50 | ezyang | (an IllegalStateException) |
| 12:50 | stuartsierra | Maybe your definitions are out of order? |
| 12:51 | ezyang | What do you mean by that? |
| 12:51 | ozzilee | ezyang: You have to define functions before you use them, unfortunately |
| 12:51 | ezyang | Oh, I know why |
| 12:52 | ezyang | Removing the namespace doesn't remove the function |
| 12:52 | ezyang | ozzilee: It loads fine the first time |
| 12:52 | ozzilee | ezyang: Ah, ok. |
| 12:52 | ezyang | So how would I remove all of the functions from a namespace... |
| 12:53 | hiredman | ns-unmap |
| 12:54 | hiredman | ,(ns-map *ns*) |
| 12:54 | clojurebot | {sorted-map #'clojure.core/sorted-map, read-line #'clojure.core/read-line, re-pattern #'clojure.core/re-pattern, pprint-map #'clojure.contrib.pprint/pprint-map, keyword? #'clojure.core/keyword?, val #'clojure.core/val, ProcessBuilder java.lang.ProcessBuilder, Enum java.lang.Enum, SuppressWarnings java.lang.SuppressWarnings, *compile-path* #'clojure.core/*compile-path*, max-key #'clojure.core/max-key, list* #'clojure.core/ |
| 12:55 | ezyang | Hm, so I would need to map ns-unmap on map |
| 12:56 | ezyang | ,(map (partial ns-unmap `plyzrdata.parser) (ns-map `plyzrdata.parser)) |
| 12:56 | clojurebot | java.lang.Exception: No namespace: plyzrdata.parser found |
| 12:56 | ezyang | Erm, I get the error rclojure.lang.PersistentHashMap$LeafNode cannot be cast to clojure.lang.Symbol |
| 12:56 | replaca | hiredman: autodoc json now has :namespace element for each entry in :vars |
| 12:56 | replaca | hiredman: that's what you were after, right? |
| 12:56 | ezyang | Given how difficult this seems to be, I'm probably going about this the wrong way |
| 12:59 | hiredman | replaca: yesssir |
| 12:59 | ezyang | Can I make clojure start the repl in a specific namespace? |
| 12:59 | replaca | hiredman: cool |
| 12:59 | replaca | hiredman: did you modify clojurebot to ignore autodoc updates? |
| 13:00 | hiredman | replaca: yes |
| 13:01 | replaca | hiredman: good idea, but I was getting used to the echo :-) |
| 13:02 | hiredman | displeasure was expressed in my direction |
| 13:02 | replaca | hiredman: yeah, makes sense. no real information there. |
| 13:03 | hiredman | (doc xml1->) |
| 13:03 | clojurebot | "clojure.contrib.zip-filter.xml/xml1->;[[loc & preds]]; Returns the first item from loc based on the query predicates given. See xml->" |
| 13:04 | replaca | nice |
| 13:05 | hiredman | so couchdb has no security features built in? |
| 13:07 | mrsolo | ah missing :gen-class i am such a dimwit |
| 13:17 | technomancy | hiredman: since it's all run over HTTP it's pretty easy to secure at the proxy level |
| 13:17 | technomancy | no need to build it into the DB |
| 13:53 | mrsolo | are there some online resource that help you to learn about writing macros? |
| 13:53 | dnolen | check the Clojure wiki |
| 13:53 | dnolen | also Practical Common Lisp and On Lisp are good general resources about macro writing and they are available for free |
| 13:53 | Chouser_1 | mrsolo: I learned by reading On Lisp, which is free online |
| 13:54 | mrsolo | ok |
| 13:55 | mrsolo | going through core.clj... ` seems to be in random places and i don't see the significants :-) |
| 13:55 | Chouser | On Lisp uses mostly Common Lisp and some Scheme, but the bulk of it is meaningful for Clojure, with a few syntactic adjustments |
| 13:55 | Chouser | heh, it's not random, I assure you. :-) |
| 13:55 | mrsolo | of course |
| 14:00 | ezyang | What are the performance properties of partial application in clojure? |
| 14:01 | ezyang | Does Clojure magically evaluate things it can evaluate when I do a partial application? |
| 14:01 | hiredman | partial just returns a new function |
| 14:01 | hiredman | uh |
| 14:01 | hiredman | it is function application, not magic |
| 14:01 | hiredman | ~def partial |
| 14:02 | ezyang | Ok :-( |
| 14:02 | hiredman | no magic whatsoever, not even a macro |
| 14:02 | hiredman | why the :-( ? |
| 14:02 | ezyang | (unrelated) I am currently editing files in Vim, popping over to emacs and using that to run them |
| 14:02 | ezyang | It's great. :-P |
| 14:03 | dnolen | ezyang: the cost is an additional function call, but those are cheap. |
| 14:03 | dnolen | er |
| 14:03 | dnolen | no |
| 14:03 | dnolen | rather the speed of apply |
| 14:07 | ezyang | So, the question here is there's a pre-computation to one of the parameters that should be done, and I was wondering if I could do it inside the function |
| 14:07 | ezyang | but that's not hte case |
| 14:08 | hiredman | ... |
| 14:08 | Chousuke | mrsolo: if the appearance of ` seems random to you, remember that it's just one way to write a list data structure that won't get evaluated. |
| 14:08 | ezyang | Btw, (load-file) is the magic I was looking for earlier on the channel |
| 14:08 | gnuvince | I got a general CS question for you guys: considering that getting the length and splitting a linked list are O(n) operations, is mergesort really a good candidate for sorting them? |
| 14:09 | Chousuke | mrsolo: macros must return clojure code, and clojure code is predominantly made of lists. thus, ` is very useful when making macros. |
| 14:09 | mrsolo | ah |
| 14:09 | Chousuke | mrsolo: you could write every macro without it too, though. |
| 14:09 | Chousuke | but that's a lot more complicated. |
| 14:11 | Chousuke | actually ` is not limited to quoting lists either, but that's where you see it most often. |
| 14:11 | Chousuke | ,(let [a 1] `[1 2 a ~a]) |
| 14:11 | clojurebot | [1 2 sandbox/a 1] |
| 14:11 | mrsolo | chousuke: i got this to work and i want to know why ..it tooks lot of trials and errors http://paste.lisp.org/display/81422 :-) |
| 14:12 | mrsolo | so ya reading some information on why and how of macros will be very helpful |
| 14:12 | Chousuke | mrsolo: did you try calling (macroexpand '(rp (+ 1 2)) |
| 14:13 | Chousuke | actually, that macro is a bit weird. |
| 14:13 | mrsolo | hmm i didn't.. but that gave (rp (+ 1 2)) back |
| 14:13 | Chouser | mrsolo: that macro is not what you want. |
| 14:14 | Chousuke | right |
| 14:14 | Chousuke | it doesn't return clojure code. |
| 14:14 | Chouser | the use of 'eval' is your first hint that something's wrong. |
| 14:14 | mrsolo | ok |
| 14:14 | Chouser | mrsolo: if you want less than a whole book, we can give you a few tips. |
| 14:15 | mrsolo | yet it works somehow |
| 14:15 | Chousuke | mrsolo: your macro runs the println and time at *compile time* |
| 14:15 | Chousuke | mrsolo: it doesn't actually expand to any code :) |
| 14:15 | Chousuke | unless (eval a) expands to code |
| 14:15 | mrsolo | (rp (map list-single-files '("/tmp", "/tmp"))) |
| 14:15 | mrsolo | gives back desired result.. though |
| 14:15 | Chouser | for example, first write out an example of calling your macro. Then write out the code you'd like your macro to produce for that example. |
| 14:15 | Chouser | Chousuke: yikes. good point. |
| 14:15 | Chousuke | mrsolo: but it doesn't happen at runtime |
| 14:16 | Chousuke | mrsolo: it happens at compile time. |
| 14:16 | mrsolo | ok |
| 14:16 | Chouser | so you've got an example of calling your macro there. that's a great start. |
| 14:16 | Chousuke | mrsolo: ask yourself: if rp were a function, what does it return? |
| 14:16 | Chouser | now, what code would you like your macro to produce in that case? |
| 14:16 | mrsolo | ok |
| 14:17 | Chouser | Maybe: (time (println "(map list-...)" (map list-...))) right? |
| 14:18 | mrsolo | right |
| 14:18 | Chouser | so, your macro should be a function that accepts the list '(map list-...) and returns the list '(time (println ...)) |
| 14:19 | Chouser | you can write regular code without ` or ~ do to that. |
| 14:19 | Chouser | if you want |
| 14:19 | Chousuke | actually. |
| 14:19 | mrsolo | well it was a function origional.. but i was tire dof quoting |
| 14:19 | mrsolo | all it does it print the sexp and time to run it |
| 14:20 | Chousuke | it might be good practice to actually write a function that does that. |
| 14:20 | mrsolo | oh? |
| 14:20 | Chouser | it would look something like (defmacro rp [a] (list `time (list `println (str a) a))) |
| 14:20 | mrsolo | (rp '(+ 2 3)) gets kinda tedous.. i though macro will let me do (rp (+ 2 3)) instead |
| 14:20 | Chouser | do you see why? |
| 14:21 | mrsolo | i see |
| 14:21 | ezyang | Hey all; what data-structure should I use if I will have a mapping like 0 => :tag1, 1 => :tag2, 2 => :tag3, etc |
| 14:21 | ezyang | There will a dozen-ish elements |
| 14:21 | ozzilee | ezyang: Hashmap? |
| 14:21 | ezyang | That seems like overkill... |
| 14:21 | ozzilee | Er. array I suppose. |
| 14:21 | ezyang | Is the array functional? |
| 14:21 | hiredman | ozzilee: vector |
| 14:21 | ozzilee | [:tag1 :tag2 :tag3 :tag4] |
| 14:22 | mrsolo | chouser: thanks! |
| 14:22 | ozzilee | Yeah, vector, sorry :-) |
| 14:22 | hiredman | ozzilee: that is a vector |
| 14:22 | stuhood | if the indexes will always be incrementing integers, then yea... a vector |
| 14:22 | ezyang | Does the vector give me O(1) access? |
| 14:22 | dnolen | yup |
| 14:22 | ezyang | Yup, always will be incrementing integers |
| 14:22 | ezyang | Awesome |
| 14:22 | hiredman | ,(keys [:a :b :c]) |
| 14:22 | clojurebot | clojure.lang.Keyword cannot be cast to java.util.Map$Entry |
| 14:22 | hiredman | :( |
| 14:23 | stuhood | aw... that should work |
| 14:23 | hiredman | ,(keys (map vector [:a :b :c] (range 20))) |
| 14:23 | clojurebot | clojure.lang.LazilyPersistentVector cannot be cast to java.util.Map$Entry |
| 14:23 | hiredman | Grrr |
| 14:23 | hiredman | ,(map (comp second vector) [:a :b :c] (range 20)) |
| 14:23 | clojurebot | (0 1 2) |
| 14:24 | ezyang | Hm. How do I convert a list to a vector... |
| 14:24 | hiredman | ,(vec '(1 2 3 4)) |
| 14:24 | clojurebot | [1 2 3 4] |
| 14:24 | ezyang | Sweet |
| 14:24 | hiredman | ezyang: clojure.org/api |
| 14:25 | ezyang | Yeah, sorry about that; should have looked that up first |
| 14:25 | Chousuke | (let [myfn (fn [lst] (concat lst '(2)))] (myfn '(+ 1))); mrsolo |
| 14:25 | Chousuke | ,(let [myfn (fn [lst] (concat lst '(2)))] (myfn '(+ 1))); damn |
| 14:25 | clojurebot | (+ 1 2) |
| 14:25 | ezyang | Here's anot so easy to lookup question: when does clojure approve of (comp)? |
| 14:25 | Chousuke | mrsolo: see how that function returns clojure code? |
| 14:25 | hiredman | ezyang: "approve" ? |
| 14:26 | hiredman | ~def comp |
| 14:26 | Chousuke | mrsolo: now, if you wanted to use myfn to write a macro that appends a 2 at the end of a clojure list form, you'd just do: (defmacro foo [form] (myfn form)) |
| 14:26 | ezyang | For example, I could do something like (comp vec map) but that seems a little poor... |
| 14:26 | hiredman | "poor"? |
| 14:27 | Chousuke | mrsolo: notice, no quotes; myfn already returns clojure code :) |
| 14:27 | ezyang | as in, poor form |
| 14:27 | hiredman | why would you say that? |
| 14:27 | Chousuke | mrsolo: if you can understand why this works, then you already are well on your way to understanding macros. |
| 14:28 | ezyang | hiredman: Sort of gut feeling. No good reason |
| 14:28 | hiredman | my feeling is partial and comp don't get used often enough |
| 14:28 | ezyang | New question: I'm looking at some code that is building maps using a reduce() |
| 14:28 | ezyang | I feel like there is a... better way of doing this |
| 14:28 | hiredman | people just use function literals everywhere |
| 14:29 | ezyang | maybe involving zipmap |
| 14:29 | hiredman | ezyang: better way of composing functions? |
| 14:29 | ezyang | Oh, sorry, I'm on another topic now :-P |
| 14:30 | mrsolo | chousuke: nice big difference between reading and writing though.. still lot a long way to go |
| 14:30 | Chouser | ezyang: did you look at 'into'? |
| 14:30 | stuhood | ezyang: reduce is a relatively good way, 'into' would be another |
| 14:30 | hiredman | ~def vec |
| 14:30 | Chousuke | mrsolo: yeah, but it's not that difficult once you really understand what macros do |
| 14:30 | hiredman | I imagine vec is faster then into |
| 14:30 | hiredman | than |
| 14:31 | digash | Does anybody know Scala here? I need to do a presentation on Clojure to Scala NY group. I've done Clojure to Java programmers before, but what Scala guys would want to here? |
| 14:32 | ezyang | stuhood: Why wouldn't zipmap work? |
| 14:32 | Chouser | digash: they want to talk about contravarient type signatures |
| 14:32 | ezyang | Say I have a vector [:a, :b, :c] and a list (1, 2, 3) and I want {:a 1, :b 2, :c 3} |
| 14:32 | hiredman | digash: my guess is smooth interop with java Collections |
| 14:32 | stuhood | ezyang: in that case, zipmap is the perfect fit |
| 14:32 | ezyang | ,(zipmap '[a b c] '(1 2 3)) |
| 14:32 | clojurebot | {c 3, b 2, a 1} |
| 14:32 | mattrepl | digash: macros over automated closures for designing DSLs |
| 14:32 | hiredman | scala is having a huge shakeup over their collections stuff right now |
| 14:32 | ezyang | Ok. |
| 14:33 | hiredman | ~scala |
| 14:33 | clojurebot | "you can usually accomplish a lot by laboriously enumerating type arguments everywhere." -- seen in #scala |
| 14:33 | Chousuke | mrsolo: they take clojure code as parameters: if you have a (foo [a]) macro and call it as (foo (+ 1 3)) then (= a '(+ 1 3)) is true. Then you operate on the parameters like any other function, and return new code (my earlier example would concat '(+ 1 3) and '(2), returning '(+ 1 3 2)) |
| 14:33 | Chousuke | mrsolo: this function is then run at compile time, and the macro invocation is replaced with its return value. |
| 14:34 | Chouser | digash: though I was never a committed Scalar, what brought me to Clojure was how much you could get done without ever declaring a type, and how easily a DSL can be made without needing scala's too-clever auto-casting (or whatever it's called that I've now forgotten) |
| 14:34 | Chousuke | Scalar :P |
| 14:34 | Chouser | :-) |
| 14:35 | hiredman | yeah, I think clojure's java interop is (surprisingly?) better then scalas except possibly for Annotations stuff |
| 14:35 | Chousuke | mrsolo: you can have side-effects like println in macros, but usually it's not what you want, since it's run at compile time. |
| 14:35 | digash | Chouser: thanks, I try DSL. Then the next questions what are the best DSL examples in Clojure? |
| 14:36 | Chousuke | mrsolo: however, what you DO often want is *return* code from a macro that has side-effects |
| 14:36 | hiredman | digash: you could ask in #scala to see what they want to hear about |
| 14:36 | Chouser | digash: enlive |
| 14:36 | digash | hiredman: thanks, i would go there but first wanted to swim in the friendlier waters. |
| 14:36 | hiredman | heh |
| 14:37 | hiredman | those darn scalars! |
| 14:37 | Chousuke | mrsolo: if returning code from a function makes sense to you, then you understand what "code as data" really means. |
| 14:37 | mrsolo | ya |
| 14:37 | mrsolo | i see why not |
| 14:37 | mrsolo | so |
| 14:38 | mrsolo | defmaco can be used to intentionally run some code during compile time? |
| 14:38 | mrsolo | for whatever the reason |
| 14:38 | Chouser | digash: http://github.com/Lau-of-DK/clojureql/tree/master |
| 14:38 | mattrepl | digash: someone in the crowd will probably ask about performance, so having some information on type annotations and unchecked arithmetic would be prudent |
| 14:38 | stuhood | digash: incanter seems pretty cool too http://github.com/liebke/incanter/tree/master |
| 14:39 | Chousuke | mrsolo: there are rules. |
| 14:39 | digash | mattrepl: is Scala performance on the par with Java native types? |
| 14:39 | Chousuke | mrsolo: it's not really compile time I guess, but "macro expansion time". usually macros are expanded first, and THEN stuff gets compiled. |
| 14:40 | mrsolo | what are the rules? |
| 14:40 | mattrepl | digash: I believe idiomatic Scala is more on par with Java than idiomatic Clojure |
| 14:40 | Chouser | mrsolo: sure, On Lisp shows some interesting performace tweaks by computing stuff at macro-expand time. |
| 14:40 | mrsolo | one can implement something similar to perl BEGIN i guess |
| 14:41 | Chousuke | mrsolo: a macro can't depend on runtime data, obviously :) |
| 14:42 | hiredman | mattrepl: scala still does a lot of intermediate object allocation |
| 14:42 | Chousuke | mrsolo: you can use whatever is available at macro expansion time, though. global vars etc. |
| 14:42 | hiredman | they also do what they call "de-scalafying" to get closer to java performance |
| 14:43 | Chousuke | scaling down? :) |
| 14:43 | Chousuke | (the mountain) |
| 14:44 | Chouser | toward the Java lowlands? |
| 14:44 | hiredman | yeah |
| 14:44 | Chousuke | clojure people can just take a paren and use it as a sled. |
| 14:45 | mattrepl | digash: destructing bind and keyword and rest params might be good material too |
| 14:45 | Chousuke | though the ride down might be fun but hitting the ground probably isn't. |
| 14:45 | Chousuke | hmm |
| 14:46 | hiredman | http://www.codecommit.com/blog/scala/scala-collections-for-the-easily-bored-part-1 |
| 14:46 | Chousuke | about destructuring bind, I was wondering if it is possible to improve the destructuring that it's always equivalent to a sequential let when the source form is known at macro expansion time to match the target. :/ |
| 14:47 | ezyang | Is there a list of clojure's string -> FOO conversion functions? |
| 14:47 | Chouser | ezyang: clojure doesn't have many of those. Mostly you use Java methods. |
| 14:47 | ezyang | ick |
| 14:48 | Chouser | ezyang: 'keyword' and 'symbol' take strings... |
| 14:48 | Chouser | ezyang: ick? |
| 14:48 | Chousuke | eg. expanding (let [[a b c] [1 2 3]]) to (let [a 1 b 2 c 3]) instead of the weird (let [a (get somegensym 0 nil) ...]) |
| 14:48 | Chouser | ,(Integer/parseInt "F00" 16) |
| 14:48 | clojurebot | 3840 |
| 14:48 | hiredman | ,(.toUpperCase "foo") |
| 14:48 | clojurebot | "FOO" |
| 14:49 | Chousuke | I have seen complaints about destructuring let being inexplainably slower than non-destructuring let, and I think it could be fixed :/ |
| 14:49 | hiredman | ,(-> "foo" .toUpperCase .toLowerCase ((partial map int)) ((parital reduce *))) |
| 14:49 | clojurebot | java.lang.Exception: Unable to resolve symbol: parital in this context |
| 14:50 | hiredman | ,(-> "foo" .toUpperCase .toLowerCase ((partial map int)) ((partial reduce *))) |
| 14:50 | clojurebot | 1256742 |
| 14:50 | ezyang | Why did... Integer/parseInt take two parameters? |
| 14:50 | clojurebot | why not? |
| 14:50 | Chousuke | ezyang: it's overloaded. |
| 14:50 | hiredman | ezyang: because you have to give it a base |
| 14:50 | ezyang | Ok... I need to curry the second parameter |
| 14:50 | hiredman | ,(Interger/parseInt "10" 2) |
| 14:50 | clojurebot | java.lang.Exception: No such namespace: Interger |
| 14:50 | ezyang | This is going to be complicated |
| 14:50 | hiredman | ,(Integer/parseInt "10" 2) |
| 14:50 | clojurebot | 2 |
| 14:51 | hiredman | ,(Integer/parseInt "10" 8) |
| 14:51 | clojurebot | 8 |
| 14:51 | Chousuke | ,(Integer/parseInt "10"); works too I think |
| 14:51 | clojurebot | 10 |
| 14:51 | ezyang | Oh, ok |
| 14:51 | cemerick | Chousuke: I can vouch for that. Got a 10% speedup on a key inner loop by eliminating [[v0 v1]] and using [v] with (v 0) and (v 1) |
| 14:51 | ezyang | ,Integer/parseInt |
| 14:51 | clojurebot | java.lang.Exception: Unable to find static field: parseInt in class java.lang.Integer |
| 14:52 | ezyang | Hmm... is it a first class function? |
| 14:52 | mrsolo | cemerick: ack! |
| 14:52 | Chouser | ,(let [from-hex #(Integer/parseInt % 16)] (from-hex "fa7")) |
| 14:52 | clojurebot | 4007 |
| 14:52 | ezyang | But you anonymized it... |
| 14:52 | cemerick | mrsolo: ack? |
| 14:52 | ezyang | I guess that works |
| 14:53 | mrsolo | cemerick: huge performance penality for such an innocent construct |
| 14:53 | Chouser | ezyang: no, it's a static method, not a Clojure function. |
| 14:53 | Chousuke | cemerick: the problem is that I don't think it's possible to help in the case where you do destructuring like [[v0 v1] v] |
| 14:53 | ezyang | :-* Well, I guess that's the price you pay for getting Java |
| 14:53 | Chousuke | cemerick: since the form of the source is not known |
| 14:53 | cemerick | mrsolo: yeah...well, it was a *very* hot spot, FWIW |
| 14:53 | Chouser | Chousuke: [v0 (v 0) v1 (v 1)] ? |
| 14:53 | Chouser | oh, if you want to allow for lists |
| 14:54 | cemerick | yeah, I don't think it's such a big deal. |
| 14:54 | cemerick | I got that particular hint from a post that gnuvince made recently, and I remember some commenters trashing on clojure due to the current state of affairs, so maybe CL doesn't have that issue. *shrug* |
| 14:55 | Chousuke | so why would (nth v 1) be slower than (v 1)? :/ |
| 14:55 | cemerick | one fewer method call? |
| 14:57 | Chousuke | ~source nth) |
| 14:57 | clojurebot | No entiendo |
| 14:57 | Chousuke | gah |
| 14:57 | Chousuke | ~source nth |
| 14:57 | ezyang | Does clojure have a built-in no-op? |
| 14:57 | Chouser | ,(do) |
| 14:57 | clojurebot | nil |
| 14:57 | Chousuke | identity? |
| 14:58 | cemerick | ezyang: identity |
| 14:58 | Chouser | nil |
| 14:58 | ezyang | Ok. |
| 14:58 | Chousuke | depends on the context I guess. |
| 14:58 | dnolen | ,(do nil (+ 4 5)) |
| 14:58 | clojurebot | 9 |
| 14:58 | cemerick | Chousuke: See, there's actually a number of levels indirection with nth |
| 14:58 | ezyang | ,(nil 1) |
| 14:58 | clojurebot | java.lang.IllegalArgumentException: Can't call nil |
| 14:58 | ezyang | ,(identity 1) |
| 14:58 | clojurebot | 1 |
| 14:58 | gnuvince | The doc says that nth is O(n) for sequences while Vectors can index in O(log_32 n) |
| 14:59 | Chousuke | cemerick: I think it should inline the not-found case too :/ |
| 14:59 | Chousuke | gnuvince: (v 1) is O(log_32 n) too, that's no different :) |
| 15:00 | cemerick | Chousuke: the function-call overhead could have been the difference in my case. |
| 15:00 | Chousuke | I think it's just that in destructuring, nth is used with the default value and it's not inlined. |
| 15:01 | Chouser | (v 1) compiles to (.invoke v 1), which calls v.nth((1).intValue()) |
| 15:01 | Chousuke | okay, so it's basically equivalent. |
| 15:02 | Chousuke | I wonder if the slowdown goes away if the 3-parameter case is added to inline arities as well |
| 15:02 | Chouser | I wonder if the Var lookup for 'nth' itself hurts much. |
| 15:04 | Chousuke | or perhaps c.lang.RT/nth does instanceof lookups that slow it down :/ |
| 15:07 | Chousuke | there's an enormous difference between doing (nth v 3) and (nth v 3 1) 10 million times. |
| 15:08 | Chouser | wild |
| 15:11 | Chouser | ,(let [v [1 2 3]] (time (dotimes [_ 10000] (v 1)))) |
| 15:11 | clojurebot | "Elapsed time: 6.454 msecs" |
| 15:11 | Chouser | what am I doing wrong here? |
| 15:11 | Chouser | ,(let [v [1 2 3]] (time (dotimes [_ 1000000] (v 1)))) |
| 15:11 | clojurebot | "Elapsed time: 101.76 msecs" |
| 15:12 | Chouser | hm, that looks vaguely sane. On my machine doing the lookup *100 more times only costs 0.5 more msecs. |
| 15:12 | Chouser | ,(let [v [1 2 3]] (time (dotimes [_ 10000000] (v 1)))) |
| 15:12 | clojurebot | "Elapsed time: 85.344 msecs" |
| 15:12 | hiredman | "Elapsed time: 390.49132 msecs" |
| 15:12 | hiredman | :( |
| 15:13 | Chouser | Chousuke: oh! |
| 15:13 | Chouser | destructuring uses (nth v x nil)! |
| 15:14 | Chouser | Chousuke: the notFound slowdown you spotted may be the main culprit for destructuring |
| 15:14 | Chousuke | inlining the 3-parameter case is still slower, but saves 200ms for 10 million lookups compared to not inlining |
| 15:15 | Chouser | what do you mean by inlining there? |
| 15:15 | Chousuke | nth has {:inline (fn [c i] `(. clojure.lang.RT (nth ~c ~i))) :inline-arities #{2}} |
| 15:15 | Chousuke | just adding the 3-parameter version there |
| 15:16 | Chouser | ah! |
| 15:17 | ezyang | Let's say I have a map of values and a map of functions and I'd like a map of (function value). What do I do? |
| 15:18 | ezyang | (the maps keys perfectly align) |
| 15:19 | Chousuke | hm |
| 15:19 | hiredman | (map #(%1 %2) (vals functions) (vals values)) would return a seq of (function value) |
| 15:19 | Chousuke | right... (map apply (vals fmap) (vals values)) |
| 15:19 | hiredman | or that |
| 15:20 | Chousuke | hmm |
| 15:20 | mrsolo | clojurebot runs on fast machine! |
| 15:20 | hiredman | uh |
| 15:21 | hiredman | Not Really |
| 15:21 | Chouser | I'd be nervous about using val seqs from two different maps |
| 15:21 | mrsolo | "Elapsed time: 222.746 msecs" |
| 15:21 | mrsolo | or mine is a very slow one |
| 15:23 | hiredman | (let [fmap {:a idenity :b identity} vmap {:a 1 :b 1}] (reduce #(assoc %1 %2 ((fmap %2) (vmap %2))) {} (vals fmap)) |
| 15:23 | hiredman | ,(let [fmap {:a idenity :b identity} vmap {:a 1 :b 1}] (reduce #(assoc %1 %2 ((fmap %2) (vmap %2))) {} (vals fmap)) |
| 15:23 | clojurebot | EOF while reading |
| 15:23 | hiredman | bah! |
| 15:24 | Chousuke | hmm |
| 15:24 | Chouser | ,(let [funcs {:a inc :b dec} values {:b 5 :a 10}] (into {} (for [[k f] funcs] [k (f (values k))]))) |
| 15:24 | clojurebot | {:b 4, :a 11} |
| 15:25 | tashafa | |
| 15:25 | Chousuke | ,(map (comp apply apply) (vals (merge-with vector {:foo + :bar -} {:foo 5 :bar 1}))) |
| 15:25 | clojurebot | java.lang.IllegalArgumentException: Wrong number of args passed to: LazilyPersistentVector |
| 15:25 | tashafa | how do you install clojure-mode.el thru ELPA? |
| 15:26 | Chousuke | (vals (merge-with vector {:foo + :bar -} {:foo 5 :bar 1}))) |
| 15:26 | Chousuke | gah |
| 15:26 | Chousuke | ,(vals (merge-with vector {:foo + :bar -} {:foo 5 :bar 1}))) |
| 15:26 | clojurebot | ([#<core$_PLUS___3949 clojure.core$_PLUS___3949@482bad> 5] [#<core$___3975 clojure.core$___3975@46a55e> 1]) |
| 15:26 | mrsolo | M-x package-install clojure-mode |
| 15:26 | tashafa | mrsolo thanks! |
| 15:27 | Chouser | Chousuke: ooh, I like where you're going. |
| 15:27 | Chousuke | safer than relying on the order anyway |
| 15:27 | tashafa | mrsolo: hmm, no match |
| 15:27 | Chousuke | (apply hash-map (merge-with vector {:foo '+ :bar '-} {:foo 5 :bar 1})))) |
| 15:27 | Chousuke | ,(apply hash-map (merge-with vector {:foo '+ :bar '-} {:foo 5 :bar 1})))) ;a hsfjslkfjg |
| 15:27 | clojurebot | {[:foo [+ 5]] [:bar [- 1]]} |
| 15:28 | Chouser | , (let [funcs {:a inc :b dec} values {:b 5 :a 10}] (merge-with #(%1 %2) funcs values)) |
| 15:28 | clojurebot | {:a 11, :b 4} |
| 15:28 | Chousuke | aha, even better. |
| 15:28 | mrsolo | tashafa: package-list-packages will list available packages |
| 15:28 | mrsolo | tash: it should be in there |
| 15:29 | mrsolo | tash: you can navirage then do package-menu-execute afterward 'I' to mark for install |
| 15:31 | tashafa | go it |
| 15:31 | tashafa | thanks man |
| 15:31 | tashafa | got it* |
| 15:31 | mrsolo | np |
| 15:32 | Chousuke | (let [fs {:foo + :bar - :zonk reduce} params {:foo [1 2] :bar [10 5] :zonk [conj #{} [1 2 3]]}] (merge-with apply fs params)); fun |
| 15:32 | Chousuke | ,(let [fs {:foo + :bar - :zonk reduce} params {:foo [1 2] :bar [10 5] :zonk [conj #{} [1 2 3]]}] (merge-with apply fs params)); ASDFSDJFK |
| 15:32 | clojurebot | {:foo 3, :bar 5, :zonk #{1 2 3}} |
| 15:33 | Chousuke | how is it that I ALWAYS forget the comma |
| 15:33 | ezyang | So, merge-with is the magic? |
| 15:33 | Chousuke | yeah |
| 15:34 | ezyang | I wonder if it'll 'splode if the keys don't match up |
| 15:34 | Chousuke | it probably will |
| 15:35 | Chousuke | or rather, this happens: |
| 15:35 | Chousuke | ,(let [fs {:foo + :bar - :zonk reduce} params {:foo [1 2] :bar [10 5] :zonk [conj #{} [1 2 3]] :nonexistent 5}] (merge-with apply fs params)); |
| 15:35 | clojurebot | {:nonexistent 5, :foo 3, :bar 5, :zonk #{1 2 3}} |
| 15:36 | ezyang | ,(merge-with apply {:foo +} {}) |
| 15:36 | clojurebot | {:foo #<core$_PLUS___3949 clojure.core$_PLUS___3949@482bad>} |
| 15:37 | ezyang | Ew |
| 15:37 | Chousuke | yeah, the function printing thing is ugly ;( |
| 15:37 | Chousuke | need metadata for functions so it can be made prettier! |
| 15:38 | Chousuke | should say something like #<Fn clojure.core/+> |
| 15:41 | hiredman | clojure.core/+ is a symbol |
| 15:42 | Chousuke | that's why it says Fn in there |
| 15:42 | hiredman | why would the function care about a symbol it might be bound to? |
| 15:42 | Chousuke | okay, well, it could be just #<Fn +> |
| 15:42 | hiredman | + is also a symbol |
| 15:42 | Chousuke | yes, but it's the function's name. |
| 15:42 | Chousuke | and if it has no name #<lambda 2398449> or something |
| 15:43 | Chousuke | point being, something that easily identifies the function's name and possibly origin |
| 15:44 | hiredman | the only thing a function really maps to is a java class, which is what the current .toString is |
| 15:44 | hiredman | ,(.toString (fn [])) |
| 15:44 | clojurebot | "sandbox$eval__1992$fn__1994@1be0369" |
| 15:44 | Chousuke | hiredman: that's why functions need metadata. |
| 15:46 | Chousuke | the .toString is useless and icky anyway so if there were metadata it could be used |
| 15:49 | Chousuke | I wonder if there's something that prevent IFn or AFn or something from just extending IMeta :/ |
| 15:52 | ezyang | Question: I want to dynamically define a function, like (def func (func-gen 0)) |
| 15:52 | ezyang | But it would be a defmethod |
| 15:52 | ezyang | So I'm a little confused how to do it (defmethod being a macro and such) |
| 15:53 | ezyang | Can I put the defmethod inside of another function? |
| 15:54 | Chouser | ezyang: usually best in these cases to do what the macro does, rather than try to call it. |
| 15:54 | Chouser | (.addMethod multifn :value (fn ...)) |
| 15:55 | stuartsierra | Chouser: where are the dispatch arguments? |
| 15:55 | stuartsierra | Oh, :value, I get it. |
| 15:56 | stuartsierra | Speaking of multimethods, did anyone ever figure out multiple-arg dispatch with inheritance? |
| 15:56 | stuartsierra | That is, (defmulti m (fn [x y] [(class x) (class y)])) |
| 15:59 | stuartsierra | Oh, never mind, isa? works on vectors of derived types. |
| 16:05 | ezyang | repl is giving me an exception, but not telling me where it came from... |
| 16:05 | Chouser | (.printStackTrace *e) |
| 16:06 | ezyang | Thanks! |
| 16:12 | ezyang | Hmm... apparently, #(%1 %2) is not equivalent to apply |
| 16:12 | Chouser | indeed not |
| 16:12 | Chouser | apply wants its final arg to be a collection, which it "unrolls" into the final args of the call. |
| 16:13 | Chouser | ,(apply + 1 2 [3 4 5]) |
| 16:13 | clojurebot | 15 |
| 16:13 | ezyang | savvy |
| 16:26 | ezyang | How do I introspect the contents of a multimethod? |
| 16:26 | Chouser | "contents"? |
| 16:29 | Chouser | ,(doc methods) ; perhaps |
| 16:29 | clojurebot | "([multifn]); Given a multimethod, returns a map of dispatch values -> dispatch fns" |
| 16:31 | cemerick | it's unfortunate that the names of the fns installed as multimethods don't consist of, say, a concatenation of the method name and the dispatch value. That'd be handy, though probably dicey to implement safely. |
| 16:33 | stuartsierra | especially since the dispatch value could be absolutely anything |
| 16:36 | ezyang | Hey, does (load) do any dicey caching based on filemtimes? |
| 16:38 | Chouser | it checks file mtimes to determine if it should load .class or .clj |
| 16:38 | ezyang | Ouch |
| 16:39 | mrsolo | what if it is in resource file? |
| 16:39 | ezyang | A behavior of this is that multimethods don't get reinitialized properly |
| 16:40 | mrsolo | i mean if a resource file has both .class or .clj, what gets loaded? |
| 16:40 | hiredman | mrsolo: if the clj is newer, it gets loaded |
| 16:42 | Chouser | http://code.google.com/p/clojure/source/browse/trunk/src/jvm/clojure/lang/RT.java#373 |
| 16:43 | ezyang | This is a likely bug, then |
| 16:48 | jkantz | in a single namespace make file_a, add a multimethod definition and (load "file_b") |
| 16:48 | jkantz | add a defmethod to file_b |
| 16:48 | jkantz | add another to file_c |
| 16:49 | jkantz | compile the namespace |
| 16:49 | jkantz | now change the file_b multi method |
| 16:49 | jkantz | and load-file on file_a |
| 16:49 | jkantz | the method in file_c will be gone |
| 16:50 | hiredman | a) you must be missing steps |
| 16:50 | hiredman | b) if by compile you mean AOT compile, you should not compile single segment namespaces |
| 16:51 | jkantz | "single segment namespaces"? |
| 16:51 | hiredman | ~namespaces |
| 16:51 | clojurebot | namespaces are (more or less, Chouser) java packages. they look like foo.bar; and corresponde to a directory foo/ containg a file bar.clj in your classpath. the namespace declaration in bar.clj would like like (ns foo.bar). Do not try to use single segment namespaces. a single segment namespace is a namespace without a period in it |
| 16:52 | hiredman | ~compile |
| 16:52 | clojurebot | the unit of compilation in clojure is the namespace. namespaces are compiled (not files). to compile a namspace the namespace needs to be on the classpath and so does ./classes/ (and the directory needs to exist) because clojure writes the class files to that directory. http://clojure.org/compilation |
| 16:53 | ezyang | The real code isn't single segment |
| 16:54 | jkantz | hiredman by b) do you rather mean you should not compile namespaces that have calls to load? |
| 16:55 | hiredman | no |
| 16:55 | hiredman | compiling namespaces that call load is fine |
| 16:56 | hiredman | it will cause the loaded code to be compiled |
| 16:56 | replaca | stuartsierra: it looks like the autodoc is right now. Can you confirm? http://code.google.com/p/clojure-contrib/wiki/StrUtils2ApiDoc |
| 16:56 | hiredman | jkantz: pastebin your test case |
| 16:56 | jkantz | right and then run into issues with defmulti and and defmethods in the loaded files when you try to reload the main file. |
| 16:57 | stuartsierra | replaca: closer, but not complete |
| 16:57 | replaca | what's missing? |
| 16:57 | jkantz | k, just a sec |
| 16:57 | hiredman | jkantz: I imagine you are running (defmulti ...) again which creates a new multimethod |
| 16:57 | stuartsierra | upper-case, lower-case, split, trim, contains?, get, split-lines, ltrim, rtrim... |
| 16:58 | hiredman | the new multimethod will not have any methods attached |
| 16:58 | replaca | k, I'll take a look |
| 16:58 | replaca | thanks |
| 16:58 | stuartsierra | sure, thanks for working on autodoc |
| 16:58 | ezyang | Right, but then when we (load) the sub files, the multimethod should then get repopulated |
| 16:58 | ezyang | What's happening is that (load) is not loading the subfiles |
| 16:58 | jkantz | hiredman, right, and due to the other files not being modified they aren't reloaded to re-add themethods |
| 16:59 | hiredman | so how is that a bug? |
| 16:59 | jkantz | not so much as a bug as a gotcha |
| 16:59 | ezyang | I would argue it's a bug |
| 17:00 | ezyang | There should be no functional difference between loading the clj and loading the class |
| 17:00 | hiredman | well, java cannot reload classes (unless you monkey with the classloader, I believe) |
| 17:00 | hiredman | so there must be |
| 17:01 | stuartsierra | Clojure monkeys with the classloader |
| 17:01 | jkantz | you'd have to pass on the dependency information to subsequent loads |
| 17:01 | replaca | stuartsierra: functions with no doc strings don't get put in the autodoc. Put an empty doc string if you believe they're that obvious |
| 17:02 | jkantz | ~load |
| 17:02 | clojurebot | download is http://code.google.com/p/clojure/downloads/list |
| 17:02 | stuartsierra | Ah, ok |
| 17:02 | jkantz | ,(doc load) |
| 17:02 | clojurebot | "([& paths]); Loads Clojure code from resources in classpath. A path is interpreted as classpath-relative if it begins with a slash or relative to the root directory for the current namespace otherwise." |
| 17:02 | replaca | stuartsierra: I think that explains all the funcs that were missed |
| 17:04 | hiredman | jkantz: is there a reason you are using load instead of require, use, etc |
| 17:05 | technomancy | I've played with defining methods in a different file from the defmulti. It's not a lot of fun when dealing w/ reloads. |
| 17:06 | hiredman | never had an issue with it with clojurebot |
| 17:06 | jkantz | hiredman, many individual methods organized each into their own file, don't want the extra namespaces |
| 17:07 | hiredman | ugh |
| 17:07 | technomancy | I think there's a way to force files to load even if they haven't changed. |
| 17:08 | technomancy | but yeah, if you step outside the one-file-per-namespace path, you're going to hit trouble |
| 17:08 | technomancy | no way around that |
| 17:08 | hiredman | is this a chrome thing? or is github's source code numbering brolen |
| 17:08 | hiredman | broken |
| 17:08 | jkantz | anyway touch * is the work around of the day |
| 17:08 | jkantz | hiredman why ugh? you find it gauche |
| 17:08 | clojurebot | why not? |
| 17:09 | hiredman | jkantz: sorry I was refering to loading up github and noticing the line numbers are off |
| 17:10 | jkantz | ah ok, I'm out of here, have a good weekend |
| 17:16 | replaca | stuartsierra: ok, I think the autodoc is right now |
| 17:19 | stuartsierra | replaca: yes, looks good. Thanks! |
| 17:19 | replaca | stuartsierra: thank you! |
| 17:25 | replaca | btw, for anyone who was here on Wednesday - turns out we broke the cable to the projector and that's why everything turned pink. A new cable fixed everything. |
| 17:28 | stuartsierra | Now you can copy files and streams in pure Clojure! |
| 17:28 | technomancy | oh, I was going to write that. |
| 17:28 | technomancy | nice. =) |
| 17:28 | technomancy | how about recursive copy now? =) |
| 17:29 | stuartsierra | You mean recursive copy of directories? |
| 17:29 | technomancy | yeah, so I don't have to shell out to "cp -r" |
| 17:30 | stuartsierra | Hmm. Worth having, although I was aiming to handle streams. |
| 17:30 | technomancy | stuartsierra: would you take that as a patch? |
| 17:30 | technomancy | yeah, it doesn't seem to belong in duck-streams |
| 17:30 | technomancy | there's probably enough stuff that could go into a file-utils namespace to justify its creation |
| 17:31 | stuartsierra | surely |
| 17:32 | technomancy | I've also got an extract-jar function that I thought should go in jar.clj |
| 17:33 | technomancy | but jar.clj could be subsumed into file-utils too |
| 17:33 | stuartsierra | Go for it. |
| 17:33 | technomancy | since there's only two functions in it |
| 17:33 | technomancy | stuartsierra: want me to make an issue+patch? |
| 17:34 | stuartsierra | Do you have a CA? Or commit access on contrib? |
| 17:35 | technomancy | just a CA |
| 17:36 | stuartsierra | Ok, you can make a patch or just email me the code. |
| 17:37 | technomancy | all righty |
| 17:37 | technomancy | just for extract-jar right? |
| 17:37 | technomancy | I haven't written recursive copy yet |
| 17:37 | stuartsierra | yeah, sure |
| 17:37 | stuartsierra | Well hop to it, then! :) |
| 17:38 | technomancy | hehe |
| 17:48 | replaca | stuartsierra: you're going crazy today! |
| 17:49 | stuartsierra | I'm shirking real work. :) |
| 17:50 | replaca | you and me both, man |
| 18:00 | replaca | stuartsierra: can I add fnmap.PersistentFnMap to compiled_classes in build.xml (that's where I'm putting anything that needs to be gen-classed to help support the autodoc) |
| 18:00 | replaca | I think that's fix the fnmap autodoc |
| 18:01 | stuartsierra | sure |
| 18:01 | replaca | k, thanks |
| 18:04 | stuhood | i have 1 hour and 30 minutes to write a mapreduce job in clojure for the first time |
| 18:04 | stuhood | let's see how this goes. |
| 18:05 | technomancy | stuhood: a hadoop mapreduce or just a pure-clojure one? |
| 18:05 | stuartsierra | stuhood: you've seen mine? |
| 18:05 | stuhood | technomancy: using the hadoop api from clojure... we already have some base classes in java |
| 18:05 | stuhood | stuartsierra: not yet... is it painful? |
| 18:06 | stuartsierra | The Clojure part is easy. The Hadoop API is... dense. |
| 18:06 | technomancy | stuartsierra: I read through yours. I think it would be super-helpful if you could make a blog post or something about how that works. |
| 18:06 | stuartsierra | I spent about a month learning Hadoop before I made serious use of it. |
| 18:07 | technomancy | reading the altlaw code was helpful, but trying to figure out which parts were specific to the task at hand vs which parts you need to copy was tricky. |
| 18:07 | stuartsierra | technomancy: yeah, it's on my agenda for... July? |
| 18:07 | technomancy | heh; ok cool. |
| 18:08 | technomancy | the job input and output formats are a lot to wrap your head around too |
| 18:08 | technomancy | I just got my example to the point where it would run; didn't actually get it to produce meaningful output. =) |
| 18:22 | stuartsierra | Good luck. I'm off. |
| 18:22 | triddell | technomancy: just created a blog and updated my tutorial: http://riddell.us/blog/2009/06/05/tutorials-available.html |
| 18:23 | triddell | now mentions you're approach |
| 18:23 | triddell | your that is |
| 18:24 | technomancy | cool |
| 18:24 | stuhood | if you don't add a ':state true' clause to gen class, do you still get a 'this' parameter added to your method calls? |
| 18:24 | hiredman | erm, I believe so |
| 18:25 | technomancy | triddell: I'm really _not_ trying to just drive hits to my blog, honest. It just comes off that way. =) |
| 18:25 | hiredman | wait |
| 18:25 | hiredman | stuhood: this is only in proxy |
| 18:25 | triddell | technomancy: just want the best info out there... that was my intent with the tutorial |
| 18:25 | hiredman | for gen-class the this parameter is explicit |
| 18:26 | triddell | technomancy: gotta run though... just wanted to give you and other an fyi |
| 18:26 | technomancy | cool; have fun w/ your new blog |
| 18:26 | triddell | technomancy: thx ;-) |
| 18:26 | hiredman | like, a function backing a two arg method needs to have arity 3 |
| 18:26 | stuhood | hiredman: explicit, in that i have to ask for it by saying :state true? |
| 18:26 | stuhood | gotcha |
| 18:26 | hiredman | no |
| 18:28 | rsynnott | technomancy: so that you can make a VAST FORTUNE on google ads? :) |
| 18:28 | technomancy | rsynnott: you've found me out! |
| 20:13 | mrsolo | hmm aquaemacs doesn't have locate-dominating-file .... |
| 20:59 | dbudworth | Just checking to see if my IRC client is functioning, no one is saying anything...right? |
| 20:59 | ctdean | right |
| 20:59 | dbudworth | ahh, good. thought i was crazy (or this mac irc client was)... (usually it's me) |
| 21:00 | ctdean | Just the time and day I think, not much going on |
| 21:06 | dbudworth | any idea how to get the classpath set when using emacs-starter-kit + slime + swank-clojure? the username.el in .emacs.d is loaded too late it seems to take effect |
| 21:06 | ctdean | nope, sorry. I always set the classpath by hand |
| 21:06 | dbudworth | trying to go through the "programming clojure" book, but when using slime I can't get the classpath to include the book root dir (which is needed for things like (use 'examples.foo) |
| 21:07 | dbudworth | you can set it inside clj? is there a way to dynamically add to the cp? |
| 21:07 | durka42 | yes and no, there is add-classpath but it's discouraged |
| 21:07 | ataggart | highly |
| 21:08 | dbudworth | normally, wouldn't even need it. but for this particular case (book examples) they make a big assumption about your working dir (or at least having the root be in the cp) |
| 21:09 | ataggart | skipping over and just using the book's repl.sh made life easier |
| 21:09 | ataggart | though I haven't gotten too far into the books code |
| 21:10 | dbudworth | yeah, that was the other choice. just use a regular shell. just thought slime was neat. IntelliJ's clojure plugin actually has a repl (and the standard Idea project classpath setup).. just wanted to use emacs' fanciness |
| 21:11 | ataggart | being neither an emacs user nor lisper, having to deal with emacs as well as learn the language was just too much to bear |
| 21:11 | ataggart | now I just need to figure out how to kill the IntelliJ REPL |
| 21:12 | dbudworth | there's a "delete repl" or something like that, that kills it... checking |
| 21:15 | dbudworth | tools -> add / remove reply (option-command-a/option-command-m on a mac) |
| 21:15 | dbudworth | s/reply/repl |
| 21:15 | ataggart | ah thx |
| 21:16 | ataggart | running doseq on an infinite fibonacci seq tends to bog things down |
| 22:53 | mattrepl | anyone been using c.c.error-kit? |