2011-03-31
| 00:07 | amalloy | mec_: (defn mapmap [f & colls] (for [c colls] (map f c)))? |
| 00:08 | amalloy | i guess that's different |
| 00:21 | mec_ | here we go https://gist.github.com/895803 |
| 00:27 | mec_ | tho not sure how you would adapt that to pre or post |
| 00:29 | brehaut | (defn lift-map [f n col] (((apply comp (repeat n (partial partial map))) f) col)) |
| 00:29 | brehaut | &(let [lift-map (fn [f n col] (((apply comp (repeat n (partial partial map))) f) col)] (lift-map inc 3 [[[1 2] [3] [4 5 6]]])) |
| 00:29 | sexpbot | java.lang.IllegalArgumentException: let requires an even number of forms in binding vector |
| 00:30 | brehaut | &(let [lift-map (fn [f n col] (((apply comp (repeat n (partial partial map))) f) col))] (lift-map inc 3 [[[1 2] [3] [4 5 6]]])) |
| 00:30 | sexpbot | ⟹ (((2 3) (4) (5 6 7))) |
| 00:30 | brehaut | im pretty sure theres a special circle of hell for that |
| 00:31 | mec_ | lol |
| 00:32 | mec_ | my gist lets you apply a different f at each depth |
| 00:35 | brehaut | mec_: yeah mine is specifically a narrow application of a lifted functor over sequences |
| 00:36 | brehaut | it could probably be made into a more general functor by using clojure.contrib.generic.functor/fmap |
| 00:38 | amalloy | brehaut: nice, ((( |
| 00:38 | amalloy | a 100% reliably indicator of good code |
| 00:39 | brehaut | amalloy: haha yes. i thought (partial partial … was also a pretty strong indicator |
| 00:39 | amalloy | (partial partial apply) is better |
| 00:39 | brehaut | thats true |
| 00:40 | brehaut | (use 'clojure.contrib.generic.functor) |
| 00:40 | brehaut | &(use 'clojure.contrib.generic.functor) |
| 00:40 | sexpbot | java.io.FileNotFoundException: Could not locate clojure/contrib/generic/functor__init.class or clojure/contrib/generic/functor.clj on classpath: |
| 00:40 | brehaut | ,(use 'clojure.contrib.generic.functor) |
| 00:40 | clojurebot | java.io.FileNotFoundException: Could not locate clojure/contrib/generic/functor__init.class or clojure/contrib/generic/functor.clj on classpath: |
| 00:40 | brehaut | oh well |
| 00:52 | jacortinas | ,(= 2 2.0) |
| 00:52 | clojurebot | true |
| 00:54 | amalloy | &(.equals 2 2.0) |
| 00:54 | sexpbot | ⟹ false |
| 00:55 | jacortinas | hmm |
| 00:55 | jacortinas | clojure-koans have a problem written as (= __ (= 2 2.0)) |
| 00:56 | jacortinas | with the answer for __ being false |
| 00:56 | jacortinas | feels wrong though, can someone explain this to me? |
| 00:56 | jacortinas | &(= 2 2.0) |
| 00:56 | sexpbot | ⟹ true |
| 00:56 | trptcolin_ | yeah, that's the case in 1.3 |
| 00:57 | jacortinas | I though as much |
| 00:57 | trptcolin_ | clojure-koans is currently on 1.3-alpha4 |
| 00:57 | raek | ,*clojure-version* |
| 00:57 | clojurebot | {:major 1, :minor 2, :incremental 0, :qualifier ""} |
| 00:57 | jacortinas | so I cloned the clojure-koans repo, then ran lein deps |
| 00:57 | jacortinas | and then was only doing "script/run" |
| 00:57 | raek | I think clojure has always had numeric equality defined that way |
| 00:58 | jacortinas | and it's apparently running it using 1.2 |
| 00:58 | trptcolin_ | jacortinas: wacky - 2 clojure jars in the lib dir or something? |
| 00:59 | trptcolin_ | raek: in 1.2, (= 2 2.0), but not in 1.3 |
| 01:00 | jacortinas | trptcolin_: no, this is the contents of the lib (clojure-1.3.0-alpha4.jar deps.clj jline-0.9.94.jar junit-3.8.1.jar) |
| 01:00 | trptcolin_ | it was one of the very few changes i needed to make to the koans after updating to 1.3-alpha1 |
| 01:00 | trptcolin_ | and yet you do ./script/run and *clojure-version* is 1.2? |
| 01:00 | raek | ah, hrm. |
| 01:02 | trptcolin_ | err, i mean ./script/repl :) |
| 01:03 | jacortinas | hmm |
| 01:03 | jacortinas | seems to be just fine now |
| 01:04 | jacortinas | maybe just me being stupid... let's just pretend this never happened |
| 01:04 | trptcolin_ | what never happened? ;) |
| 01:04 | jacortinas | lol |
| 01:04 | jacortinas | what? |
| 01:04 | clojurebot | what is seq |
| 01:05 | jacortinas | test? |
| 01:05 | clojurebot | forget latest is 1382 |
| 01:05 | jacortinas | eh? |
| 01:18 | sritchie | hey all -- does anyone have any insight into why I'm getting this sequence after fn*, in this macro? https://gist.github.com/895855 |
| 01:19 | sritchie | if I take away the fn (even though that renders this useless), that surrounding set of parens after fn* goes away |
| 01:22 | mec_ | is there a switch statement? i swear i remember seeing one |
| 01:23 | scottj | there's cond and condp and case |
| 01:23 | mec_ | ah case, thanks |
| 01:27 | raek | ,((fn ([x] (* x x))) 5) |
| 01:27 | clojurebot | 25 |
| 01:28 | raek | sritchie: if you have lists in that position, you can have multiple arities of the function |
| 01:28 | sritchie | got it |
| 01:29 | sritchie | I see that (fn [x] (* x x)) macroexpands to the same thing, so turns out my problem lies elsewhere |
| 01:29 | raek | sritchie: I often use macroexpand-1 when checking my macros, since it only expands the thing I'm working on |
| 01:29 | raek | (well, one step of it) |
| 01:30 | sritchie | raek: that's proven really helpful |
| 01:30 | raek | the (-> ...) will expand to (phase-fn session_... [x] (+ 1 2)) |
| 01:31 | raek | i.e. the session will appear before the argument vector |
| 01:32 | raek | you can work around it by either letting the anonymous fn to a local, or by adding an extra pair of parens around it |
| 01:32 | raek | ,(-> 5 ((fn [x] (* x x))) inc) |
| 01:32 | clojurebot | 26 |
| 01:32 | sritchie | oh |
| 01:33 | sritchie | oh! I see |
| 01:34 | sritchie | raek: you're the man, the second pair of parens was just what I needed |
| 01:42 | amalloy | hey raek, glad you like |
| 01:42 | amalloy | (assuming you like, anyway, or you wouldn't mention it) |
| 01:44 | scottj | nice I don't have to edit my clojure-mode.el anymore |
| 01:45 | amalloy | scottj: i just edited .emacs, before putting together that code. seems weird to add to clojure-mode.el |
| 01:46 | scottj | oh I didn't read the commit closely, yeah I have those changes in .emacs, what I have in clojure-mode.el is things I want to be highlighted like defuns |
| 01:48 | amalloy | scottj: if you want to send me your clojure-mode.el i can see about adding a customization for that |
| 01:48 | sritchie | raek: one more quick macro question -- is there a way, here, to have that last statement write something if (seq (rest forms)) is true, and simply not exist if not? https://gist.github.com/895876 |
| 01:48 | sritchie | I don't want nil, if the conditional evaluates to false |
| 01:48 | scottj | amalloy: https://github.com/scottjad/clojure-mode/commit/a7cbdfabb23a17feddc983c5c98e48d9fdd84396 |
| 01:49 | amalloy | sritchie: return either a vector or nil, and splice it in |
| 01:49 | amalloy | eg `(whatever whatever ~@(when foo [`(actual code)])) |
| 01:50 | amalloy | &(let [foo true] `(whatever whatever ~@(when foo [`(actual code)]))) |
| 01:50 | sexpbot | ⟹ (clojure.core/whatever clojure.core/whatever (clojure.core/actual clojure.core/code)) |
| 01:50 | amalloy | &(let [foo false] `(whatever whatever ~@(when foo [`(actual code)]))) |
| 01:50 | sexpbot | ⟹ (clojure.core/whatever clojure.core/whatever) |
| 01:50 | raek | amalloy: yes, certainly! I've been doing this: (eval-after-load 'clojure-mode '(define-clojure-indent (foo 'defun) (bar 'defun))) |
| 01:50 | sritchie | amalloy: fantastic, thanks a lot |
| 01:50 | amalloy | raek: so had i till last night |
| 01:50 | amalloy | did it one too many times :P |
| 01:51 | scottj | https://github.com/technomancy/clojure-mode/pull/15 this feature is nice |
| 01:51 | raek | sritchie: you mean something like (do (when (some-pred? x) ...) x)? |
| 01:52 | raek | I think it's hard to squeeze something like that into -> |
| 01:52 | sritchie | what amalloy referenced was right on -- here's what I did, see the last one -- https://gist.github.com/895876 |
| 01:53 | sritchie | whoops, without that println |
| 01:55 | amalloy | scottj: i don't know enough about elisp compile-vs-load semantics to know whether i could implement that |
| 01:56 | amalloy | the indentations i was pleased to discover i could cause to take effect instantly |
| 01:58 | amalloy | sritchie: it seems kinda weird to be unquoting almost every form in your syntax-quote. have you considered building it with just (list)? |
| 02:00 | sritchie | I'm still very, very young where macros are concerned, so I'm up for any advice -- |
| 02:00 | amalloy | well, this particular advice is questionable, so... :P |
| 02:01 | sritchie | so, you're saying, use list, then backquote anything that needs to be -- or, flip back-quotes and unquotes? |
| 02:01 | amalloy | yeah, something like that |
| 02:02 | amalloy | i'm not sure it comes out looking better in this case |
| 02:02 | sritchie | it does look crowded now, for sure |
| 02:03 | amalloy | i mostly just advocate people realizing macros don't have to be one gargantuan backtick-form |
| 02:13 | amalloy | whoa sritchie: you're using symbols like foo# outside of a backtick. they don't have any special meaning there |
| 02:13 | sritchie | amalloy: okay, so for those let-bound variables, just use subphase and left? |
| 02:13 | amalloy | yeah |
| 02:16 | sritchie | amalloy: thanks for the macro help |
| 02:17 | sritchie | point taken, about the backtick, too |
| 02:18 | amalloy | sritchie: some proposed edits at https://gist.github.com/895897 |
| 02:19 | amalloy | i guess [argvec & [subphase & left]] is silly. should be equivalent to [argvec subphase & left] |
| 02:20 | amalloy | but i guess if you don't always have a subphase, the double-& is needed |
| 02:21 | hiredman | multifn! |
| 02:21 | hiredman | (fn [argvec |
| 02:21 | sritchie | when left is fine, here? |
| 02:21 | sritchie | I guess "left" is going to be nil |
| 02:21 | hiredman | (fn ([argvec] ...) ([argvec subphase] ...) ([argvec subphase left] ...)) |
| 02:21 | sritchie | okay, got that |
| 02:22 | hiredman | & for optional arguments is used a lot, but multifns almost always end up better |
| 02:22 | sexpbot | java.lang.Exception: Can't take value of a macro: #'clojure.core/for |
| 02:22 | sritchie | amalloy: yeah, there's actually one more line -- (check-session (str "The session passed out of" '~subphase)) |
| 02:23 | sritchie | so, I was thinking that the version that only gets an arg vector, like (phase-fn []), should return an identity phase that checks the incoming session |
| 02:23 | sritchie | rather than just identity |
| 02:23 | amalloy | hiredman: he already has a 1-arity version and a 2+ arity version. i proposed, callously, converting it to a 1-arity and 3+ arity |
| 02:24 | hiredman | amalloy: and? |
| 02:25 | amalloy | hiredman: in theory that introduces a distinction because he gets an exception for calling with just two args. arguably this is better than generating a bogus expansion, but i didn't make the change intentionally |
| 02:27 | amalloy | ugh. and my previous statement is totally false. never mind. they are identical |
| 02:28 | amalloy | gist updated to reflect that added prettiness |
| 03:24 | thorwil | good morning! |
| 03:26 | mec_ | wow it is morning, time for bed |
| 03:26 | thorwil | so, using appengine-magic, i submit a form with a "body" of text and want to store that in the datastore |
| 03:27 | thorwil | with a long text, it complains that a String property only takes up to 500 characters |
| 03:28 | thorwil | I have to make it use a Text property instead |
| 03:28 | thorwil | in the source of ackbar, i found (:import (com.google.appengine.api.datastore EntityNotFoundException Text))) |
| 03:29 | thorwil | (ds/save! (Post. url title (Text. body) ts in-feed? category)) |
| 03:29 | thorwil | but if i do the same, i get: "java.lang.RuntimeException: java.lang.IllegalArgumentException: Don't know how to create ISeq from: com.google.appengine.api.datastore.Text" |
| 08:16 | Licenser | aloa |
| 08:18 | mec | Can paredit swap a form with the one above it? (a b |(c d) -> (c (a b d)) |
| 10:20 | simard | is there a way to have "lein swank" start faster ? or "lein" anything, for that matter ? |
| 10:21 | TimMc | You could use cake instead. :-P |
| 10:23 | cemerick | simard: try `lein interactive` |
| 10:23 | cemerick | described in the FAQ here: https://github.com/technomancy/leiningen ;-) |
| 10:26 | simard | hum so it's java's fault |
| 10:27 | simard | well, that's hardly surprising anyway, where else would have lein lost its time :) |
| 10:27 | dnolen | hmm 2K lines of pure Clojure is powerful stuff. |
| 10:28 | simard | dnolen: I wrote a little app for making grocery lists out of scalable recipes... in a few hours and 125 lines of clojure, and I'm quite sure an experienced clojure programmer could reduce it much.. then I realized how hard to debug that would have been if written in C |
| 10:28 | simard | I'm in love with the language now :D |
| 10:29 | simard | I just need to find a new project |
| 10:29 | simard | dnolen: what's these 2K lines do btw ? |
| 10:30 | dnolen | simard: my logic programming library i been hacking on for 6 months or so. |
| 10:31 | simard | logic programming eh.. is it out somewhere ? |
| 10:31 | clgv | simard: now I am curious. why would have been harder to debug in C than in Clojure? |
| 10:31 | dnolen | simard: https://github.com/swannodette/logos |
| 10:31 | dnolen | about to add a fast constraint feature a la XSB, getting close. |
| 10:31 | kephale00 | clgv: if only because he probably wouldn't have been using a c interpreter |
| 10:32 | simard | clgv: clgv well, somehow bugs seem easier to find or avoid |
| 10:32 | simard | clgv: I don't have hard science to back this up.. it's just how it feels |
| 10:32 | clgv | simard: hm ok that's a blurry fuzzy answer ;) |
| 10:32 | simard | yeah :) |
| 10:33 | simard | maybe it's because you can do so much more with less code... assuming the number of bugs is proportionnal to the length of code |
| 10:33 | clgv | I for myself found that there is a lack of debugging tools for clojure. the jvm ones dont help much in a lot of cases since you see only the compile java bytecode there |
| 10:34 | dnolen | clgv: have you looked at cdt ? |
| 10:34 | powr-toc | dnolen, woah... you're faster than SWI? |
| 10:34 | clgv | dnolen: what is cdt? |
| 10:35 | dnolen | powr-toc: :D only for Zebra really, SWI does some wacky optimizations for certain kinds of logic programs. |
| 10:35 | simard | clgv: oh yeah I would suppose that's a problem in itself.. but I found you can "debug" by examining subexpressions on the fly with the interpreter. I expect someday I will need a more sophisticated debugger though |
| 10:35 | simard | or I might not |
| 10:36 | dnolen | powr-toc: but in general the goal is to have a reasonable fast Prolog from Clojure. Constraints on variables, Tabling. |
| 10:36 | dnolen | clgv: http://georgejahad.com/clojure/cdt.html |
| 10:36 | powr-toc | dnolen: cooool! how does mini kanren differ from prolog? |
| 10:37 | dnolen | powr-toc: some programs can be run in reverse that can't run in reverse in Prolog. fairer search strategy. easier to make parallel. |
| 10:38 | dnolen | I'm brainstorming having optional support for fork/join, you can mark your logic program in such a way as to say run this bit in parallel if possible. |
| 10:39 | powr-toc | sounds like it might be quite neat |
| 10:40 | dnolen | powr-toc: being faster than SWI on some things is kind of interesting, SWI is 200K of C last I checked, I'm at 1.6K of Clojure. Perhaps persistent data structures are a win here. |
| 10:40 | powr-toc | dnolen, how so? |
| 10:41 | simard | 200K vs 1.6K ? and it does "the same thing" ? |
| 10:41 | dnolen | powr-toc: miniKanren is a purely functional design, a map of bindings is passed through the logic program, so easy to map to Clojure's persistent data structures. |
| 10:42 | dnolen | simard: no, doesn't do the same thing. Prolog's are usually based on Warren's Abstract Machine or some variant of it. |
| 10:42 | dnolen | simard: but it's why I'm interested in miniKanren, 200 lines of Scheme get you a lot of Prolog's characteristic. |
| 10:44 | powr-toc | haha yeah, every lisp contains a half implemented poorly specified version, slow version of prolog ... so the saying goes anyway :-) It'd be nice to have something serious :-) |
| 10:45 | simard | I should take a more involved look into these logic languages some day.. if I could find an application for them in my research. apart from solving the Zebra puzzle, what kind of "real-world" problem can it solve (and be useful in doing so) ? |
| 10:46 | dnolen | powr-toc: yeah I've trying hard to make it fast, been slow going. |
| 10:46 | powr-toc | sounds like you're getting somewhere |
| 10:46 | dnolen | powr-toc: one could say it's a crazy performance experiment for me. |
| 10:46 | dnolen | simard: you'll need to look at the *large* body of existing literature. |
| 10:47 | clgv | simard: what research are you doing? |
| 10:47 | dnolen | simard: constraint solvers are getting big. declarative networking, static analysis, semantic web, theorem proving... |
| 10:48 | simard | clgv: basically, wireless microelectronics, for biomedical implants. I'm not going in vivo, but I design the chip considering constraints of low-power, small form factor, wide bandwidth. |
| 10:48 | simard | a bit far from CS anyway. |
| 10:48 | clgv | indeed ;) |
| 10:49 | simard | but I want to converge to neuroscience eventually.. I'm hopeful I will find a way to mix all that together (microelectronics, neuroscience, CS). :) |
| 10:51 | powr-toc | ewww semantic web :-) |
| 10:52 | pyr | hi guys |
| 10:52 | clgv | I wonder if I will ever see the day when semantic web is put to some real use ;) |
| 10:53 | powr-toc | clgv: for humanities sake, I hope not! |
| 10:53 | clgv | lol :D |
| 10:53 | gtrak | skynet? |
| 10:53 | pyr | seeing conversation diverge from the normal course, i'll just put out there that $job is hiring clojure people (not 100% clojure) in Paris, if anyone's interested, pyr@milestonelab.com |
| 10:53 | powr-toc | its only use right now seems to be in keeping academics on the funding gravy train |
| 10:55 | clgv | hmm maybe I should claim that I do semantic web as well to get some funding next year ;) |
| 10:55 | powr-toc | gtrak: haha not a chance ... I'm more concerned about the environmental costs of rdf processing... and if it ever finds a real use, the dread that one day I might have to use semantic web technologies again :-\ |
| 10:56 | powr-toc | clgv: lol |
| 10:58 | gtrak | powr-toc, but the environmental cost comes with a gain of being able to do more stuff, I think. That's an argument to use against any new technology. Plus, how many cpus are sitting idle as we speak? |
| 11:00 | clgv | gtrak: that an argument for SETI@home or *@home ... lol ;) |
| 11:00 | gtrak | sure, or cloud-computing |
| 11:01 | gtrak | I guess that was two arguments in one, the one I'd want to argue about is if the processing is worth the gain |
| 11:01 | clgv | uuuh, then you have to know whether there is anything to gain |
| 11:02 | gtrak | indeed |
| 11:06 | powr-toc | gtrak: Personally I always though the semantic web came more from the "do less with more" school of design, rather than the "more with less" one |
| 11:10 | no_mind | dnolen, so why not document you knowledge ? |
| 11:10 | clgv | dnolen: write down for others to learn ;) |
| 11:11 | dnolen | heh not enough time in the day dammit. |
| 11:11 | kephale00 | dnolen: voice record then later run voice-to-text |
| 11:43 | kephale00 | Is there a way (other than a custom macro) of defining key/val pairs in order such that keys which are defined later can reference previously defined key/vals? |
| 11:43 | kephale00 | similar to the way let works |
| 12:07 | scottj | kephale00: maybe not a good idea, (reduce (fn [m [k v]] (assoc m k (if (keyword? v) (m v) v))) {} {:a 1 :b :a :c :b}) |
| 12:12 | kephale00 | scottj: well using that technique would need a little more substitution than the keyword? check, as I'd like to be able to use previously defined values within full expressions such as {:a 3 :b 8 :c (+ (m :a) (m :b))} |
| 12:36 | mec | How might I generalize post- and pre- walk, and what might be better names? https://gist.github.com/895803 |
| 13:07 | amalloy | mec: try paredit-convolute-sexp |
| 13:07 | amalloy | with point right before c, as i recall |
| 13:10 | amalloy | ah, point right before d, i guess |
| 13:11 | amalloy | (a b (c |d)) M-x paredit-convolute-sexp => |(c (a b d)) |
| 13:12 | amalloy | i have it bound to M-LEFT, and i use it for turning (if something (f a b) (f a c)) into (f a (if something b c)) |
| 13:15 | duncanm | la la la |
| 13:17 | mec | le sigh, 2 days until JoC arrives |
| 13:25 | technomancy | who's in charge of planet clojure? |
| 13:26 | dakrone | I believe that would be Alex Ott |
| 13:26 | dakrone | oh perhaps not, I believe he was just a contributor |
| 13:31 | mec | amalloy: lol i was just reading your blog and didnt even realize it until I saw your def for unfold |
| 13:32 | amalloy | heh |
| 13:32 | amalloy | that must be...my most recent entry, i guess |
| 13:48 | mec | amalloy: how come you make unfold* instead of just recurring on unfold: (cons value (unfold next done? new-seed)) |
| 13:48 | amalloy | mec: didn't want to pass next and done over and over |
| 13:49 | amalloy | it's worth optimizing HOFs like that that i expect to use in lots of places |
| 13:49 | amalloy | (imo. opinions may vary. consult your lawyer before use, etc etc) |
| 13:50 | mec | makes sense |
| 13:58 | dnolen | any Clojurians who are also Schemers? |
| 13:59 | technomancy | I implemented it once. never used it though. |
| 14:00 | cemerick | ha. :-) |
| 14:00 | dnolen | technomancy: giving a preso in NYC for people getting familiar w/ Scheme but not Clojure. Curious to know what a Schemer would like to hear covered. |
| 14:01 | technomancy | dnolen: talk to KirinDave next time he's around. |
| 14:02 | dnolen | technomancy: ah good idea. |
| 14:08 | duncanm | dnolen: hey, mr. swannodette! |
| 14:08 | duncanm | dnolen: i was a Schemer before learning Clojure |
| 14:10 | duncanm | dnolen: for me, having generic operations for seqs was a big deal, no more length/string-length/vector-length |
| 14:11 | dnolen | duncanm: hey! yeah, I'm definitely going to talk about the benefit of having the core data structures built on interfaces. other things? |
| 14:12 | duncanm | dnolen: the STM stuff (refs, atoms, agents) is another obvious thing |
| 14:12 | duncanm | dnolen: i haven't looked into clojure macros much, maybe that's something also? |
| 14:12 | technomancy | dnolen: the cultural differences of not having to worry about whether libraries you bring in carry mutability concerns is worth mentioning |
| 14:12 | technomancy | dnolen: it seems like schemers appreciate immutability but can't enforce it. |
| 14:12 | duncanm | dnolen: also, depending on which scheme, they might be interested in module/namespace stuff |
| 14:12 | dnolen | duncanm: yeah, probably won't have enough time to get into all the concurrency stuff. |
| 14:13 | technomancy | dnolen: http://clojure.org/state is important for anyone to hear regardless of concurrency though. |
| 14:13 | dnolen | duncanm: oh yeah good point. technomancy: true, for that reason it seems like the study group focuses on Racket. |
| 14:13 | technomancy | dnolen: does racket let you disable setcar/setcdr? |
| 14:13 | duncanm | technomancy: yes |
| 14:13 | technomancy | excellent |
| 14:14 | duncanm | oh |
| 14:14 | duncanm | dnolen: little things, but the literal syntaxes in Clojure are fun |
| 14:15 | duncanm | dnolen: the Racketeers decided to make []s synonymous with ()s, which other Schemers didn't like |
| 14:15 | duncanm | dnolen: and Clojure has shown that by keep them distinct, it can result in a pretty nice syntax |
| 14:15 | amalloy | duncanm: i remember that from before i even knew the difference between common lisp and scheme |
| 14:15 | technomancy | dnolen: here's what was interesting to me right off the bat coming from elisp: http://technomancy.us/121 |
| 14:16 | technomancy | clojurebot: clojure |can| make the Kessel Run in under twelve parsecs. |
| 14:16 | clojurebot | Roger. |
| 14:16 | dnolen | duncanm: yeah I noticed that, [] in Racket. |
| 14:16 | amalloy | clojurebot: clojure? |
| 14:17 | amalloy | hm |
| 14:17 | duncanm | dnolen: the #() lambda syntax is a particularly nice touch, for me |
| 14:17 | dnolen | technomancy: old sckool! pre lein right? |
| 14:17 | amalloy | technomancy: what did that do? |
| 14:17 | technomancy | dnolen: absolutely |
| 14:17 | technomancy | clojurebot: botsmack |
| 14:17 | technomancy | I killed it. =( |
| 14:17 | amalloy | ~o/ |
| 14:17 | amalloy | :( |
| 14:17 | duncanm | dnolen: oh, btw, nice call pointing out that prolog quote from a few weeks ago |
| 14:17 | technomancy | amalloy: |foo| is for arbitrary verbs in definitions |
| 14:17 | amalloy | technomancy: i thought so too, though i'd only seen |reply| or something similar. but then he didn't answer |
| 14:18 | dnolen | duncanm: thanks, I kinda stumbled on that by accident. I just recalled that Alan Kay had a soft spot for Prolog. |
| 14:18 | duncanm | dnolen: oh, he still does |
| 14:18 | duncanm | dnolen: i'm friends with someone who's at his research outfit |
| 14:19 | duncanm | dnolen: are you on their 'fonc' mailing list? it's kinda low-volume, but occasionally, interesting tidbits bubble up |
| 14:19 | hiredman | clojurebot: ping? |
| 14:19 | clojurebot | PONG! |
| 14:19 | dnolen | duncanm: cool. I have a couple of their papers I need to sort through. |
| 14:19 | hiredman | clojure? |
| 14:19 | clojurebot | clojure is cheating |
| 14:19 | duncanm | dnolen: i started reading Ch 4.4 of SICP after that exchange about prolog with you on twitter |
| 14:19 | dnolen | duncanm: no but I've run into it in my google searches time to time. |
| 14:19 | duncanm | dnolen: it's low volume, so it's not a hassle to subscribe |
| 14:20 | duncanm | dnolen: and Alan himself replies from time to time |
| 14:20 | dnolen | duncanm: nice! Ch 4.4 is good stuff. I remember dismissing it 7 years ago and 'not worth it' |
| 14:20 | duncanm | heh |
| 14:21 | duncanm | dnolen: i have a copy of Norvig's PAIP too, i think he too has a chapter on implementing Prolog in Lisp |
| 14:21 | duncanm | and of course, norvig's book covers a lot of grounds on different types of search |
| 14:22 | dnolen | duncanm: Yeah I look at PAIP from time to time. The main issue with PAIP is that it does lean on imperative programming a bit, so it's not always natural/obvious to convert to Clojure. |
| 14:22 | duncanm | ahh, yeah |
| 14:23 | duncanm | dnolen: i started with Scheme first, and like you, thought CL and Scheme were similar |
| 14:23 | duncanm | dnolen: i ported some CL to Scheme a few summers ago, and was initially shocked to see all the SET!s |
| 14:24 | dnolen | duncanm: I often find myself spending a crazy amount just trying to sort out how to do things efficiently in Clojure. It's challenging and rewarding. |
| 14:24 | duncanm | dnolen: i know that feeling, sometimes i wonder if it's worthwhile (to do everything functionally) |
| 14:25 | duncanm | when the data size is small, there's no real need to parallelize, the priority is to make it work ASAP, |
| 14:25 | dnolen | duncanm: heh agreed. Can't wait for Pods. |
| 14:25 | duncanm | spending time trying to rewrite something functionally seems like a real distraction |
| 14:26 | dnolen | duncanm: yeah Clojure has a hammock development feel. But I do notice if you solve it the hard way up front, a lot of things are easy later. |
| 14:26 | nickik | dnolen, are pods more of a speed inprovment or something else? |
| 14:27 | nickik | too |
| 14:27 | nickik | I never used transiants for example because I just don't have code that requires it. |
| 14:27 | dnolen | nickik: another reference type, not really related to speed, but it would be safe place to but mutable stuff. |
| 14:29 | duncanm | dnolen: oh, you might want to talk about destructuring |
| 14:30 | duncanm | dnolen: CLers know about them, but it's not common in Scheme |
| 14:30 | dnolen | duncanm: yeah I have a bunch of slides like "Where is car?!" |
| 14:30 | duncanm | ahh, but Racket has fancy syntax nowadays |
| 14:30 | duncanm | keywords and stuff like that |
| 14:31 | nickik | My other car is a cdr. |
| 14:31 | dnolen | Racket is just plain fancy. in a good way. |
| 14:31 | duncanm | heh |
| 14:31 | duncanm | dnolen: i went to Northeastern as an undergrad, so my profs were the PLT folks |
| 14:32 | dnolen | duncanm: crazy folk. |
| 14:32 | duncanm | dnolen: Typed Scheme is the fanciest iteration of it all! |
| 14:32 | amalloy | dnolen: not really a schemer here, but i imagine it's important to cover the fact that seqs *really aren't* car/cdr pairs under the hood (i also imagine you already knew this) |
| 14:32 | dnolen | duncanm: totally. want for Clojure. |
| 14:32 | joly | dnolen: You're probably already covering it, but I'd expect no TCO and the lesser reliance on explicit recursion to be of interest |
| 14:33 | dnolen | amalloy: yeah will talk about that. joly: that's the later half of the talk - life w/o TCO. |
| 14:33 | duncanm | the name changes are somewhat "annoying" |
| 14:34 | dnolen | duncanm: any particular that you confuse a lot? |
| 14:34 | duncanm | even now, i think i'll feel happy if s/def/define/, s/defn/define-function/, s/do/begin/ |
| 14:34 | nickik | I think your the expert on the life w/o TCO |
| 14:34 | duncanm | dnolen: do and begin still bothers me a bit ;-P |
| 14:34 | dnolen | duncanm: noted. |
| 14:34 | duncanm | dnolen: but i like clojure's assoc a lot |
| 14:35 | duncanm | scheme's assoc is now get in clojure, i think |
| 14:35 | dnolen | duncanm: I noticed when I go back and forth between Racket/Clojure I mixup my define/defn a lot. |
| 14:35 | duncanm | dnolen: oh! = vs. all the variants of equal? eq? eqv? is another point |
| 14:36 | technomancy | yeah, point them at Baker's Equal Rights for Functional Objects |
| 14:36 | duncanm | i don't think i ever got them quite right in my head |
| 14:36 | duncanm | assoc assv and something else |
| 14:36 | technomancy | very compelling to non-FP-users |
| 14:37 | joly | I loved switching to built-in maps from Scheme's hash tables, not having to find the right SRFI to load, etc |
| 14:38 | duncanm | actually, i haven't thought of this before: instead of doing fancy destructuring in the arg list, is it faster to just use the java overload feature? |
| 14:38 | dnolen | duncanm: yeah = awesome is on my slides. |
| 14:38 | duncanm | (for handling simple optional arguments) |
| 14:38 | amalloy | duncanm: yes |
| 14:38 | duncanm | (defn foo ([a] ...) ([a b] ...)) is kinda unexpected, coming from Scheme |
| 14:39 | dnolen | duncanm: yup will address that too. |
| 14:39 | duncanm | and occasionally results in rather nice code |
| 14:40 | dnolen | duncanm: do the PLTers have any opinions of the Indiana Scheme crew? |
| 14:40 | duncanm | oh |
| 14:41 | duncanm | haha |
| 14:41 | duncanm | Chez Scheme? |
| 14:41 | duncanm | people get very attached to their preferred scheme systems.... |
| 14:42 | dnolen | duncanm: heh yeah. |
| 14:42 | duncanm | dnolen: i think PLTers are particularly proud of their syntax and module system, and consider other systems 'inferior' simply because they don't have them |
| 14:42 | amalloy | duncanm: reminds me of lispers in general |
| 14:42 | duncanm | dnolen: so Chez Scheme i think is a straight up impl of syntax-case, where as PLT's syntax is a superset of syntax-case |
| 14:43 | dnolen | another thing that frustrated me was the difference between the various Schemes. In fact it's probably my only complaint about Racket, that sometimes figuring out how to write R5RS is a pain the butt. |
| 14:43 | duncanm | and i dunno what module system the Chez people use, maybe nothing at all before, and now moving towards the R6RS one? |
| 14:43 | duncanm | i know of a couple of famous Schemers who are happy with the Javascript-style of modules (ha!) |
| 14:44 | dnolen | ugh |
| 14:44 | duncanm | define a bunch of null top levels |
| 14:44 | duncanm | write everything inside a let |
| 14:44 | dnolen | double ugh |
| 14:44 | duncanm | set! the internal defines to the top levels |
| 14:44 | duncanm | presto! |
| 14:45 | duncanm | actually, i dunno about "a couple" |
| 14:45 | duncanm | anyhow, i've seen that done before |
| 14:45 | duncanm | dnolen: there's a PLT alum at mozilla now, working on getting proper modules |
| 14:45 | dnolen | David Herman right? |
| 14:46 | duncanm | right |
| 14:49 | duncanm | i understand the philosophy at all that, but i wish there were a defclass in Clojure, just for writing JComponents ;P |
| 14:57 | hiredman | b/win 14 |
| 15:04 | duncanm | technomancy: i'm reading a blog lamenting the lack of namespaces in tcl now, but whenever i see arguments like that, i think emacs lisp |
| 15:05 | duncanm | technomancy: i'm not saying it's a bad thing to have namespaces, but emacs lisp has shown that it's definitely possible to build a robust and long-lasting software system without it |
| 15:05 | duncanm | all of this has been said in the beautiful code chapter before... |
| 15:05 | technomancy | duncanm: I don't know; everyone I talk to who writes much elisp code wishes it had a module system. |
| 15:06 | duncanm | technomancy: oh of course |
| 15:06 | technomancy | just results in lots of extra typing =\ |
| 15:06 | duncanm | all i'm saying, emacs is ane existance proof that namespaces are a necessity |
| 15:06 | duncanm | are not a necessity |
| 15:06 | technomancy | yeah, that's true |
| 15:07 | duncanm | i wonder if a similar argument can be made for hygienic macros |
| 15:07 | duncanm | ;-P |
| 15:17 | Havvy | What is the idiomatic way to dynamically create functions? |
| 15:19 | TimMc | Havvy: Composition, closures, etc. |
| 15:19 | TimMc | That's probably not what you're asking, though. |
| 15:19 | duncanm | wave your hands! |
| 15:20 | Havvy | Closures, no. Not sure what you mean by composition. Trying to create a function that defines two other functions that may be used later in the program. |
| 15:22 | TimMc | Havvy: Defines functions that have names that can be used from elsewhere in the program, or just functions that will be passed around as values and later called? |
| 15:22 | Havvy | Former |
| 15:23 | joly | I don't think it's encouraged, but you can (defn a[] (defn b[] 6)), and b isn't defined until you call a |
| 15:24 | TimMc | Unless you hear otherwise from the more experienced people in the channel, I'd say what you're doing is not idiomatic in the first place. |
| 15:24 | raek | Havvy: have you considered macros? |
| 15:24 | brehaut | rule of thumb: defs should only changed by a developer |
| 15:25 | Havvy | raek: I have, but was hoping not to have to use them. |
| 15:25 | brehaut | changing them programattically is not idiomatic |
| 15:25 | TimMc | Havvy: Note that in joly's suggestion, the inner defn creates a global var that is immediately available, but not set until a is run. |
| 15:26 | brehaut | Havvy: perhaps if you explained the problem you are trying to solve (ie, take a step back) we might be able to provide more specific ideas |
| 15:26 | Havvy | TimMc: I understand that. But it runs into the issue of if you don't know what the name of the function is... |
| 15:26 | TimMc | Oh, the name would be b. |
| 15:27 | TimMc | But brehaut is right. |
| 15:27 | raek | Havvy: there is probably some other way of solving the problem. currently, we know nothing about the problem you are trying to solve. you question was regarding a proposed solution, and not about the problem itself |
| 15:27 | Havvy | brehaut: Given the name of two measurements a and b, and a ratio, create two functions for converting between a and b "a=>b" and "b=>a". |
| 15:29 | Havvy | I already have a function that can create the names. |
| 15:29 | brehaut | Havvy: ok, next thing: what is the context for this behaviour |
| 15:29 | joly | I'd be inclined to go the macro route |
| 15:30 | Havvy | An end unto itself, or otherwise trying to learn more about the language. |
| 15:30 | nickik | mybe put the functions into a hashmap and look them up by name |
| 15:30 | TimMc | Havvy: Wouldn't you have to call these by name from elsewhere in your code anyway? |
| 15:31 | Havvy | TimMc: Yes. |
| 15:31 | TimMc | Then I suspect I don't understand what the pain point is. |
| 15:32 | brehaut | Havvy: from what you have said it sounds like a simple macro should do the job for you |
| 15:32 | duncanm | a macro could work, but is it what you really want? |
| 15:33 | duncanm | hmm |
| 15:33 | duncanm | i've been writing snippets of clojure at work for 2 yrs, and i have yet to write a single macro |
| 15:33 | duncanm | maybe i'm just not that smart ;P |
| 15:33 | Havvy | duncanm: The entire task is a task upon itself. brehaut: So this can only be done using macros? |
| 15:34 | brehaut | duncanm: it sounds like he wants to create named pairs of functions from a template; that sounds like a suitable application to me :) |
| 15:35 | joly | Might be possible in other ways, but a macro seems more straightforward |
| 15:35 | brehaut | Havvy: im not super up on the details of vars and namespaces, but anything else requires def shenanigans |
| 15:36 | TimMc | Contrived problems (and I mean that in a neutral sense) often have different solutions than very similar real-world problems. A macro might be suitable for this experiment, but not for a real app. |
| 15:36 | raek | Havvy: the thing is, if you call def in a function, you will unconditionnally mutate a global variable. (this might be safe in some specific cases, but not in general) unconditional mutation is what clojure was designed to get away from. |
| 15:36 | duncanm | hah! |
| 15:37 | duncanm | 15:24 Given the name of two measurements a and b, and a ratio, create two functions for converting between a and b "a=>b" and "b=>a". |
| 15:37 | raek | it is possible, just unideomatic |
| 15:37 | duncanm | i mean |
| 15:37 | TimMc | raek: Nothing wrong with a macro (called from the top level) to def stuff though, yeah? |
| 15:38 | duncanm | (defn make-convertors [a b ratio] (letfn a->b ... b->a ...)) and then return a seq of the two funcs |
| 15:38 | raek | well, if any time is the time for defs, it would be compile-time |
| 15:38 | Havvy | raek: I understand that. They are technically impure, but the side effect is what I care for. Though duncanm's line avoids that a bit. |
| 15:40 | duncanm | do you really need (compare-foo->bar a-foo a-bar) instead of ((make-comparator foo bar) a-foo a-bar) |
| 15:40 | nickik | if you ned them to be only computet once you could make a atom that holds the functions |
| 15:40 | duncanm | you can memoize make-comparator! |
| 15:40 | Havvy | Though I think there would still be the issue that letfn is a macro and won't execute the code necessary to make it read a->b at run-time. |
| 15:41 | TimMc | Havvy: It sounds like you want a top-level form of (defconv a b 4.5) that turns into (def a->b [a] (* a 4.5)) (def b->a [b] (/ b 4.5)) |
| 15:41 | Havvy | duncanm: It's a contrived example, so I don't need anything. The latter does seem more idiomatic though. |
| 15:41 | TimMc | Is that correct? |
| 15:42 | Havvy | TimMc: Yes. |
| 15:42 | duncanm | i saw some Ruby code where the guy went all out generating functions like that |
| 15:42 | duncanm | it seems silly to me |
| 15:42 | Havvy | It is silly. |
| 15:42 | duncanm | i think it was some translation API |
| 15:43 | duncanm | so he generated all variations of from_english_to_russian (text) and from_russian_to_english (text) |
| 15:43 | duncanm | so on |
| 15:43 | duncanm | oh |
| 15:43 | duncanm | it's ruby too, so it's test.from_english_to_russian |
| 15:43 | duncanm | woohoo! |
| 15:44 | brehaut | i'm curious if F#'s units of measure stuff could be ported to idiomatic clojure |
| 15:44 | duncanm | brehaut: the surface syntax part is probably not the difficulty |
| 15:45 | brehaut | indeed; it relys on a lot of type system stuff to track units which is already heading down a different path to idiomatic clojure |
| 15:46 | TimMc | Havvy: Should be an easy macro to write. |
| 15:46 | Havvy | TimMc: Yes, it should. :) |
| 15:48 | Havvy | Can a macro contain multiple definitions like functions can? I.e. is (defmacro ... [a b n] exprs [a b] exprs) allowed? |
| 15:48 | amalloy | yes, but you have to write it properly (just as you would a function) |
| 15:48 | amalloy | (defmacro ([a b n] exprs) ([a b] exprs)) |
| 15:49 | duncanm | it'd be nice if syntax-rules were available |
| 15:49 | duncanm | i dunno what the difficulties are for implementing that |
| 15:49 | TimMc | syntax-rules won't help here |
| 15:49 | Havvy | Ah, I knew I was missing parens somewhere. It looked too ambiguous. |
| 15:49 | amalloy | duncanm: someone implemented (most of?) that already. i don't know scheme so i can't speak to how good an impl it is |
| 15:50 | dnolen | https://github.com/qbg/syntax-rules |
| 15:50 | Havvy | IMO, those parenthesis are easier to read than a bunch of lines of other languages. |
| 15:50 | duncanm | dnolen: i saw that too, browsing thru the tests didn't reveal anything interesting to me |
| 15:53 | dnolen | duncanm: yeah I'm not sure what state it's in. |
| 15:54 | duncanm | yeah, i don't even know what the interface to defmacro is |
| 15:55 | duncanm | i used a Scheme with explicit-renaming macros, so define-syntax took in a lambda with environment/renamer/comparer |
| 15:55 | TimMc | $findfn 'user/a 'a |
| 15:55 | sexpbot | [] |
| 15:55 | TimMc | $findfn 'user/a "a" |
| 15:55 | sexpbot | [clojure.core/name clojure.contrib.string/as-str] |
| 15:57 | TimMc | Havvy: I think I have a macro for this now. |
| 15:58 | TimMc | It's kind of hacked together, but if you want to see it: https://gist.github.com/897116 |
| 15:59 | TimMc | And if you want to work through it yourself first, that |
| 15:59 | TimMc | works too. |
| 16:01 | Havvy | What's the point of letting num-sym to a gynsym'd name? |
| 16:01 | technomancy | http://github.com/technomancy/lein-retest <= would love to see feedback on that |
| 16:01 | TimMc | Havvy: Making sure it is only eval'd once. |
| 16:01 | mec | Havvy: If you mean num-expr it's so that doesnt potentially evaluate twice |
| 16:01 | TimMc | It might be an intensive computation. |
| 16:02 | technomancy | gotta love it when the readme has more lines than the implementation |
| 16:02 | Havvy | TimMc: Ah, useful. |
| 16:03 | TimMc | Havvy: Or worse, it might have side-effects. :-) |
| 16:03 | amalloy | yeah. usually unless your macro is used explictly to evaluate things more than once, you should usually use let to make sure args aren't evaluated more than once |
| 16:04 | TimMc | Havvy: Ideally, the macro would also have some error-checking code to make sure that you don't do (defconv (a) :b 5) or something. |
| 16:04 | TimMc | You should add that as an exercise. :-) |
| 16:05 | amalloy | TimMc: throwing an exception at expansion time sounds like fine error-checking |
| 16:05 | amalloy | which i think is what you end up doing? |
| 16:05 | TimMc | I honestly don't know. |
| 16:05 | TimMc | It might just do weird shit. |
| 16:05 | amalloy | &(symbol '()) |
| 16:05 | sexpbot | java.lang.ClassCastException: clojure.lang.PersistentList$EmptyList cannot be cast to java.lang.String |
| 16:05 | amalloy | tada |
| 16:06 | TimMc | &(symbol (str '())) |
| 16:06 | sexpbot | ⟹ clojure.lang.PersistentList$EmptyList@1 |
| 16:06 | amalloy | &(name ()) |
| 16:06 | sexpbot | java.lang.ClassCastException: clojure.lang.PersistentList$EmptyList cannot be cast to clojure.lang.Named |
| 16:06 | TimMc | Yup. |
| 16:06 | TimMc | But that's an implementation detail and there really should be an explicit check. |
| 16:07 | amalloy | not unreasonable |
| 16:07 | TimMc | If the user makes a mistake like (defconv 'a 'b 5) they get java.lang.ClassCastException: clojure.lang.Cons cannot be cast to clojure.lang.Named (NO_SOURCE_FILE:0) |
| 16:07 | TimMc | and who the hell know what that means without a decent error message. :-) |
| 16:07 | Havvy | I've a function that does this. Catches keywords and empty lists already. (str-join "=>" [a b] |
| 16:08 | amalloy | Havvy: eh? does what? join already exists |
| 16:08 | Havvy | And handles the case when you send it 'a and 'b by actually working. |
| 16:08 | Havvy | str-join is in clojure.contrib.str-utils |
| 16:08 | amalloy | Havvy: gross. just use clojure.string/join |
| 16:08 | amalloy | contrib is for things that aren't already in core, ideally |
| 16:09 | Havvy | (doc clojure.string/join) |
| 16:09 | clojurebot | Huh? |
| 16:09 | amalloy | &(require '[clojure.string :as str]) |
| 16:09 | sexpbot | ⟹ nil |
| 16:09 | amalloy | &(doc str/join) |
| 16:09 | sexpbot | ⟹ "([coll] [separator [x & more]]); Returns a string of all elements in coll, separated by an optional separator. Like Perl's join." |
| 16:11 | Havvy | (str/join ['a 'b] "=>") |
| 16:11 | amalloy | Havvy: wrong order |
| 16:11 | amalloy | &(str/join "," '[a b]) |
| 16:11 | sexpbot | ⟹ "a,b" |
| 16:13 | hiredman | anyone know if redefing causes the watchers on a var to be notified? |
| 16:14 | Havvy | Now I want to write in a book I don't own. X.X |
| 16:15 | TimMc | hiredman: It does. |
| 16:16 | TimMc | (based on a test I just did) |
| 16:17 | TimMc | hiredman: "Var watchers |
| 16:17 | TimMc | are triggered only by root binding changes, not thread-local |
| 16:17 | TimMc | set!s. |
| 16:17 | TimMc | bah |
| 16:19 | sritchie | hey all -- is there some way to return an anonymous macro in clojure? |
| 16:19 | amalloy | sritchie: to *return* an anonymous macro? no; what is it you want to do? |
| 16:19 | sritchie | let me post a gist |
| 16:20 | TimMc | sritchie: Whatever you're doing, stop it! |
| 16:20 | sritchie | haha, okay |
| 16:20 | TimMc | I want to see, though. :-) |
| 16:20 | sritchie | https://gist.github.com/897167 |
| 16:21 | sritchie | so! originally, this was a single macro called phase-fn, that stuck a line that "checked" the threaded argument between ever y form |
| 16:21 | sritchie | s/ever y/every |
| 16:21 | sexpbot | <sritchie> so! originally, this was a single macro called phase-fn, that stuck a line that "checked" the threaded argument between every form |
| 16:21 | sritchie | I wanted to generalize it, by allowing it to accept different checkers, and give me back a macro with that checker implemented |
| 16:22 | sritchie | -> can be substituted for ->, it doesn't matter for this example |
| 16:23 | sritchie | so, (checked-thread-fn identity) would give me back a macro that was equivalent to -> |
| 16:24 | sritchie | the only requirement is that the checker function take two arguments -- the threaded argument, and a string explaining the form that caused the break |
| 16:25 | sritchie | AND, of course, I made up macro-fn right now. |
| 16:25 | amalloy | sritchie: (a) can you kill sritchie_, he's ruining my tab-completion; (b) you could either make it def a top-level macro and use that, or make it take all the args at once and expand immediately, instead of returning a macro that will expand |
| 16:26 | amalloy | eg instead of ((checked-fn identity) [args] whatever more stuff), call (checked-fn identity [args] whatever more stuff) |
| 16:26 | TimMc | technomancy: Exception in thread "main" java.lang.Exception: retest requires robert/hooke dep. |
| 16:27 | TimMc | Ah, I suppose I need that for hooks. |
| 16:30 | TimMc | Can't lein-retest pull that in? |
| 16:31 | sritchie | amalloy: for the first option, like this? https://gist.github.com/897167 |
| 16:31 | amalloy | sritchie: no; you want the second defmacro to be part of the expansion, so it needs to be in backticks |
| 16:32 | amalloy | $google amalloy macro writing macros |
| 16:32 | sexpbot | First out of 30 results is: Clojure: macro-writing macros |
| 16:32 | sexpbot | http://hubpages.com/hub/Clojure-macro-writing-macros |
| 16:36 | sritchie | amalloy: okay, I'll play with this. the issue with a macro-writing macro is that, to get the identity expander, I need to have the line (checked-thread-fn identity-threader (fn [arg & rest] arg)) |
| 16:37 | technomancy | TimMc: it can't pull it in because it's a dev-dep, and hooke needs to be a regular dep. needs to be clarified in the readme. |
| 16:37 | Havvy | Heh: #'user/:b=>:a |
| 16:37 | technomancy | good catch though |
| 16:37 | sritchie | Ideally, I could include (def identity-threader (checked-thread-fn (fn [arg & rest] arg))) |
| 16:37 | amalloy | sritchie: that's kinda-sorta possible but not the easiest way |
| 16:38 | sritchie | I guess the outer macro could be called with (def-checked-threader identity-threader (fn [arg & rest] arg)) |
| 16:38 | sritchie | with better names |
| 16:38 | amalloy | right |
| 16:39 | amalloy | see also https://github.com/amalloy/amalloy-utils/blob/master/src/amalloy/utils/macro.clj#L26, which would let you define all your threaders in one go |
| 16:39 | sritchie | hey, great |
| 16:39 | sritchie | there's anon-macro |
| 16:40 | amalloy | sritchie: that's mine too |
| 16:40 | amalloy | but it uses macrolet |
| 16:40 | sritchie | yup |
| 16:40 | amalloy | you can't actually return that macro - it only exists inside the macrolet scope |
| 16:42 | sritchie | thanks, I'm on the right track, now! I'm a bit confused about how to add a backtick around my other backticked stuff -- this will be good practice |
| 16:42 | TimMc | They just nest, right? |
| 16:42 | amalloy | sritchie: as my article above says, doing that is usually a recipe for unnecessary pain |
| 16:42 | sritchie | actually, I can have a backtick inside a backtick, whtat am I talking about |
| 16:42 | amalloy | TimMc: yes, but try getting the unquoting right |
| 16:43 | TimMc | eep |
| 16:43 | amalloy | &`(let [foo# 10] `(inc ~foo#)) |
| 16:43 | sexpbot | ⟹ (clojure.core/let [foo__11114__auto__ 10] (clojure.core/seq (clojure.core/concat (clojure.core/list (quote clojure.core/inc)) (clojure.core/list foo__11114__auto__)))) |
| 16:43 | sritchie | haha, sorry, I can tell I'm skidding around in the dark, thanks for bearing with me |
| 16:52 | mec | I seem to do (condp #(%1 %2) ..) alot, it feels like there should be a better way |
| 16:53 | dnolen | mec: (condp #(%1 %2) x ...) whre x is %1? |
| 16:54 | mec | oh sorry #(%2 %1) |
| 16:55 | amalloy | mec: two of my utils let you write #(%2 %1) as (reorder invoke). more wordy for sure and maybe not something to brag about, but you might prefer it |
| 16:59 | sritchie | https://gist.github.com/897167 -- the 1-argument version expands properly, but the 2+ is having some issues |
| 16:59 | sritchie | am I allowed to nest a syntax-quote like that? |
| 17:00 | sritchie | amalloy: same issue you pointed out in your sexpbot call |
| 17:01 | amalloy | sritchie: i didn't point out an issue; i gave an example of how gross the correct way looks |
| 17:01 | sritchie | oh, yeah, the call to seq does make things look quite gross |
| 17:01 | amalloy | sritchie: looks like you're missing a ~ on (when ~left) |
| 17:02 | amalloy | oh |
| 17:02 | amalloy | nm |
| 17:02 | sritchie | yeah, I think that one's okay -- |
| 17:02 | sritchie | this is the error -- Can't use qualified name as parameter: pallet.crate.hadoop/session__9445__auto__ |
| 17:03 | amalloy | ah |
| 17:03 | amalloy | `(fn [~'session#]), i think |
| 17:04 | amalloy | or to avoid figuring out how to combine all those unquotes, you can let a gensym at the toplevel for session, and use it everywhere |
| 17:04 | amalloy | &`(let [x# 1] `(let [y# 2])) is your problem |
| 17:04 | sexpbot | ⟹ (clojure.core/let [x__11123__auto__ 1] (clojure.core/seq (clojure.core/concat (clojure.core/list (quote clojure.core/let)) (clojure.core/list (clojure.core/apply clojure.core/vector (clojure.core/seq (clojure.core/concat (clojure.core/list (quote clojure.core/y__1112... http://gist.github.com/897242 |
| 17:05 | amalloy | observe that y is being turned into clojure.core/y__1112. instead ##``(let [~'y# 2]) should fix it |
| 17:05 | sexpbot | ⟹ (clojure.core/seq (clojure.core/concat (clojure.core/list (quote clojure.core/let)) (clojure.core/list (clojure.core/apply clojure.core/vector (clojure.core/seq (clojure.core/concat (clojure.core/list (quote y__11131__auto__)) (clojure.core/list 2))))))) |
| 17:06 | sritchie | okay, that makes sense |
| 17:06 | amalloy | haha then you're one step ahead of me :) |
| 17:06 | sritchie | I'm checking out the expansion of the identity threader now, I think I'm almost there |
| 17:06 | sritchie | hell of a way to go to get something equivalent to -> :) |
| 17:06 | amalloy | indeed |
| 17:10 | sritchie | working -- https://gist.github.com/897167 |
| 17:12 | amalloy | sritchie: oh man, that ~'macro-name just screams error - is it actually right? |
| 17:12 | amalloy | i guess it is. jeez i hate these things |
| 17:12 | sritchie | amalloy: yeah, this might end up staying a thought experiment |
| 17:13 | amalloy | good plan |
| 17:13 | amalloy | (no offense) |
| 17:14 | amalloy | if you want to see something really monstrous you should check out clojail's safe-eval construct (used by sexpbot): https://github.com/cognitivedissonance/clojail/blob/master/src/clojail/core.clj#L109 |
| 17:14 | sritchie | none taken |
| 17:14 | sritchie | I actually like the idea of the monster that's getting created, here -- |
| 17:15 | sritchie | but it's very convoluted, getting there |
| 17:15 | amalloy | *chuckle* |
| 17:20 | sritchie | amalloy: last question, before I let this die -- |
| 17:20 | sritchie | https://gist.github.com/897167 -- is this the proper way to do a top-level session gensym? |
| 17:20 | amalloy | yep |
| 17:20 | sritchie | I'm getting Unable to resolve symbol: G__10075 in this context |
| 17:21 | amalloy | hm |
| 17:22 | sritchie | not that important, just curious |
| 17:22 | amalloy | &(let [x (gensym)] `[(inc ~x) `(inc ~~x)]) |
| 17:22 | sexpbot | ⟹ [(clojure.core/inc G__11146) (clojure.core/seq (clojure.core/concat (clojure.core/list (quote clojure.core/inc)) (clojure.core/list G__11146)))] |
| 17:23 | Havvy | When I return multiple values, what is the best type to return them as? A list? |
| 17:23 | amalloy | Havvy: vector |
| 17:23 | Havvy | Kk. |
| 17:23 | amalloy | the literal syntax is much more convenient for those |
| 17:24 | mec | All of these ways to search a map for keys look hackish, there has to be a better way https://gist.github.com/897285 |
| 17:24 | Havvy | [] instead of (list ...) yeah... :P |
| 17:25 | TimMc | mec: Use the map as the predicate? |
| 17:25 | dnolen | hmm what would you call a map like thing in which keys point to multiple values and the values point back to multiple keys? multi-multi-map ? |
| 17:27 | mec | TimMc: I like it, would I just use nil for the expr? |
| 17:27 | TimMc | Not familiar with condp yet, so I can't judge hackishness. |
| 17:27 | mec | your solution is perfect, cant believe it never occured to me |
| 17:28 | TimMc | What does my solution look like? :-P |
| 17:28 | mec | i updated the gist |
| 17:28 | amalloy | sritchie: i think it needs another quote |
| 17:29 | amalloy | ~'~session |
| 17:29 | clojurebot | Cool story bro. |
| 17:29 | dnolen | mec: what about select-keys ? |
| 17:30 | amalloy | (condp contains? m :key1 key1 :key2 key2) |
| 17:30 | mec | oo i like it even more |
| 17:31 | amalloy | &(condp contains? {:x 1} :y 1 :x 0) |
| 17:31 | sexpbot | java.lang.IllegalArgumentException: No matching clause: {:x 1} |
| 17:31 | TimMc | mec: Are the values expressions that do things or just simple literals? |
| 17:31 | mec | ya thats no good, the order is wrong |
| 17:31 | mec | TimMc: both |
| 17:31 | amalloy | errrr i guess that's true |
| 17:31 | TimMc | OK, so you need delayed eval, got it. |
| 17:32 | amalloy | i always have to look up argument order for condp |
| 17:32 | TimMc | $findfn {:x 1} :x true |
| 17:32 | sexpbot | [clojure.core/not= clojure.core/distinct? clojure.core/contains?] |
| 17:33 | TimMc | $findfn :x {:x 1} true |
| 17:33 | sexpbot | [clojure.core/not= clojure.core/distinct? clojure.core/not-any? clojure.core/not-every?] |
| 17:33 | hiredman | ~botsnack |
| 17:33 | clojurebot | thanks; that was delicious. (nom nom nom) |
| 17:33 | mec | how is not-any? there true |
| 17:34 | amalloy | mec: ##(:x (first {:x 1})) |
| 17:34 | sexpbot | ⟹ nil |
| 17:34 | mec | ah hah |
| 17:35 | Havvy | Is there a built-in function that tells me if a string is a substring of another string, and if so, at what location it starts at? |
| 17:35 | TimMc | $findfn :b '#{a b c} true |
| 17:35 | sexpbot | [clojure.core/not= clojure.core/distinct? clojure.core/not-any? clojure.core/not-every?] |
| 17:35 | TimMc | $findfn 'b '#{a b c} true |
| 17:35 | sexpbot | [clojure.core/not= clojure.core/distinct? clojure.core/not-any? clojure.core/not-every?] |
| 17:35 | TimMc | Havvy: .indexOf ? :-) |
| 17:36 | Havvy | Thanks. |
| 17:36 | Havvy | (New to both Clojure and Java I am.) |
| 17:37 | TimMc | ,(.indexOf "slaughter" "laugh") |
| 17:37 | clojurebot | 1 |
| 17:37 | TimMc | (Sorry, the only word-in-word I could come up with on the spot was kind of creepy.) |
| 17:37 | Havvy | Heh, what an interesting substring for that word. :P |
| 17:38 | amalloy | TimMc: you won't find anything useful for those findfns because ##('#{a b c} 'b) |
| 17:38 | sexpbot | ⟹ b |
| 17:38 | amalloy | doesn't return true |
| 17:38 | TimMc | Ah, right... logical true. |
| 17:38 | amalloy | insane clowns: putting the laugh back in slaughter |
| 17:40 | amalloy | Havvy: btw .indexOf returns -1 if it doesn't match. that's logical true, so you have to check for it |
| 17:40 | Havvy | amalloy: REPL testing has told me as such. |
| 17:40 | amalloy | hurrah for the repl |
| 17:40 | TimMc | indeed |
| 17:41 | Havvy | Also my memory of Javascript told me something similar. ;) |
| 17:45 | sritchie | amalloy: better identity phase-fn -- (defmacro unchecked-phase-fn [argvec & forms] `(fn [session# ~@argvec] (-> session# ~@forms))) |
| 17:46 | Havvy | Creating a function that returns the left-hand and right-hand side of a string "a=>b". Throws an error if there is no arrow in it. What would be the line for that? (throw "StringMissingArrow")? |
| 17:47 | TimMc | You need to throw a Throwable of some sort, just like in Java. |
| 17:47 | Havvy | I have no knowledge of Java. |
| 17:47 | TimMc | So, you could do (throw (IllegalInputException. "Missing arrow yada yada")) |
| 17:47 | amalloy | TimMc: that class doesn't exist :P |
| 17:47 | amalloy | try IllegalArgumentException |
| 17:47 | TimMc | yeah, that one! |
| 17:48 | Havvy | (throw (IllegalArgumentException. "Test error!")) |
| 17:48 | amalloy | &(throw (IllegalArgumentException. "Test error!")) |
| 17:48 | sexpbot | java.lang.IllegalArgumentException: Test error! |
| 17:49 | Havvy | For s-exp-bot, what do the & and , reader functions do? |
| 17:50 | TimMc | They're not reader functions, just triggers. |
| 17:51 | TimMc | , is clojurebot's trigger |
| 17:51 | clojurebot | java.lang.Exception: Unable to resolve symbol: is in this context |
| 17:51 | TimMc | See? :-) |
| 17:51 | Havvy | & is for sexpbot then? |
| 17:51 | sexpbot | java.lang.Exception: Unable to resolve symbol: is in this context |
| 17:51 | TimMc | clojurebot: Do you not know what the meaning of "is" is? |
| 17:51 | clojurebot | meaning of life is to become one with Lisp |
| 17:51 | Havvy | clojurebot++ |
| 17:52 | amalloy | (inc clojurebot) |
| 17:52 | sexpbot | ⟹ 1 |
| 17:52 | amalloy | Havvy: ^ |
| 17:52 | TimMc | ~botsnack works too :-P |
| 17:52 | clojurebot | thanks; that was delicious. (nom nom nom) |
| 17:52 | amalloy | heh |
| 17:52 | Havvy | &(clojurebot) |
| 17:52 | sexpbot | java.lang.Exception: Unable to resolve symbol: clojurebot in this context |
| 17:52 | amalloy | they are greedy buggers |
| 17:53 | amalloy | Havvy: he doesn't know about clojurebot when he's actually eval-ing code with &. only when you activate the karma plugin by saying (inc someone) |
| 17:53 | Havvy | (inc amalloy) |
| 17:53 | sexpbot | ⟹ 6 |
| 17:53 | Havvy | (inc TimMc) |
| 17:53 | sexpbot | ⟹ 1 |
| 17:54 | TimMc | &(inc TimMc) <-- the *real* inc |
| 17:54 | sexpbot | java.lang.Exception: Unable to resolve symbol: TimMc in this context |
| 17:54 | amalloy | he also recognizes inline eval requests like ##'clojurebot and ##(dec 10) |
| 17:54 | sexpbot | (quote clojurebot) ⟹ clojurebot |
| 17:54 | sexpbot | (dec 10) ⟹ 9 |
| 17:55 | Havvy | So that explains why the double hash is used. |
| 17:55 | TimMc | Yeah, you need something unlikely to trigger the bot by accident. |
| 17:56 | TimMc | You can also private-message the bots. |
| 17:56 | TimMc | clojurebot: |
| 17:56 | clojurebot | #<ClassCastException java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.String;> |
| 17:56 | TimMc | bah |
| 17:56 | amalloy | lol nice work TimMc |
| 17:56 | Havvy | Lawl. |
| 17:56 | TimMc | Wait, what was that? |
| 17:56 | Havvy | sexpbot: |
| 17:57 | Havvy | sexpbot: (+ 2 2) |
| 17:57 | Havvy | clojurebot: (+ 2 2) |
| 17:57 | clojurebot | 5 (for large values of 2) |
| 17:57 | TimMc | ahaha |
| 17:57 | Havvy | clojurebot: (* 2 2) |
| 17:57 | clojurebot | * is just for when you are lazy and sloppy |
| 17:57 | amalloy | TimMc: looks to me like he does (into-array args) on the assumption that args will be strings. if you give it no args it winds up being an object array, which causes problems later |
| 17:57 | TimMc | Now it's just grabbing quotes. |
| 17:57 | Havvy | (+ 1 2) |
| 17:57 | clojurebot | 3 |
| 17:57 | amalloy | ~#24 |
| 17:57 | clojurebot | 24. Perhaps if we wrote programs from childhood on, as adults we'd be able to read them. |
| 17:57 | Havvy | clojurebot: (+ 1 2) |
| 17:57 | clojurebot | ,(let [testar (fn [x y] (if (= (reduce + (filter odd? (range 0 x))) y) (str y " is an")) )] (testar 10 25)) |
| 17:58 | Havvy | clojurebot: (+ 2 1) |
| 17:58 | clojurebot | ,(let [testar (fn [x y] (cond (= (reduce + (filter odd? (range 0 x))) y) (str y " is a")) )] (testar 11 25)) |
| 17:58 | Havvy | ... |
| 17:58 | TimMc | Havvy: You're not using the eval trigger, so it is free-associating. |
| 17:58 | amalloy | Havvy: if you address him with a message he doesn't understand, he just does his best, i think |
| 17:58 | amalloy | clojurebot: ,(+ 2 1) |
| 17:58 | clojurebot | 5 (for large values of 2) |
| 17:59 | TimMc | heh |
| 17:59 | amalloy | hmph |
| 17:59 | amalloy | well, you can pm him ,(+ 2 1) |
| 17:59 | TimMc | clojurebot: (+ 2 14) |
| 17:59 | clojurebot | ,(let [testar (fn [x y] (cond (= (reduce + (filter odd? (range 0 x))) y) (str y " is a")) )] (testar 11 25)) |
| 18:00 | Havvy | clojurebot: ,(+ 5 10) |
| 18:00 | clojurebot | Excuse me? |
| 18:00 | TimMc | Havvy: /msg clojurebot ,(+ 5 10) |
| 18:00 | TimMc | Oh, and it will also occasionally respond to things that weren't addressed to it, just for fun. |
| 18:00 | Havvy | TimMc: I know how to use IRC. I'm an IRC OP on the server of an IRC client that Freenode blocks. |
| 18:01 | TimMc | Hah, OK. :-) |
| 18:01 | Havvy | clojurebot: .Math.PI |
| 18:01 | clojurebot | excusez-moi |
| 18:01 | TimMc | ,Math/PI |
| 18:01 | clojurebot | 3.141592653589793 |
| 18:01 | TimMc | for statics |
| 18:01 | TimMc | / for statics |
| 18:02 | Havvy | Oklahoma I think... |
| 18:02 | Havvy | Nope, Indiana. |
| 18:02 | TimMc | Arkansas, as the urban legend I know tells it. |
| 18:02 | amalloy | indiana, i thin |
| 18:02 | Havvy | http://en.wikipedia.org/wiki/Indiana_Pi_Bill |
| 18:05 | TimMc | Oh hah, I didn't know about that one. |
| 18:06 | TimMc | All the ones I had heard of involved a Southern state. :-P |
| 18:06 | TimMc | Good to know the real story. |
| 18:07 | no_mind | is there a list of clojure based applications somewhere ? |
| 18:07 | amalloy | clojurebot: pi is about three, in Indiana |
| 18:07 | clojurebot | Alles klar |
| 18:07 | amalloy | pi? |
| 18:07 | clojurebot | pi is about three, in Indiana |
| 18:08 | TimMc | amalloy: Pi *is* about three, though. |
| 18:08 | amalloy | TimMc: it's not *defined* as "about three" |
| 18:08 | Havvy | clojurebot: no, pi is about three point two in Indiana. |
| 18:08 | clojurebot | In Ordnung |
| 18:08 | Havvy | pi? |
| 18:08 | clojurebot | pi is about three, in Indiana |
| 18:08 | amalloy | Havvy: i doubt he'll soak that up |
| 18:08 | Havvy | no, pi? |
| 18:09 | Havvy | no? |
| 18:09 | Havvy | amalloy: Not as smart as firebot then. :( |
| 18:35 | Havvy | https://gist.github.com/897401 << Will this do the error handling? |
| 18:37 | TimMc | Havvy: What happens when you (macroexpand-1 `(defratios (a) :b 3)) ? |
| 18:38 | Havvy | false |
| 18:39 | TimMc | and is returning false, so that's what the form will expand to |
| 18:39 | TimMc | What you actually need to do is throw an error. |
| 18:40 | TimMc | when or when-not would be appropriate here. |
| 18:41 | Havvy | If I use a when, how can it throw an error? |
| 18:42 | TimMc | (when condition stuff ...) rest of macro ... |
| 18:42 | TimMc | And stuff should involve a throw |
| 18:42 | TimMc | I updated my gist with my solution. |
| 18:42 | TimMc | https://gist.github.com/897116 |
| 18:44 | Havvy | Ah. Useful to know. |
| 18:47 | Havvy | All this time, and only 42 lines of code. I sure hope my productivity will increase. |
| 18:48 | Havvy | 9 of which are practically done by you Tim. |
| 18:54 | amalloy | Havvy: you could have written 300 lines of java with less functionality than 42 lines of clojure. don't judge productivity by LOC |
| 18:55 | kephale00 | Havvy: or if LOC really make you feel better write a clojure script to generate code for you and run it overnight |
| 18:55 | amalloy | btw TimMc it seems silly to use a# and b# for symbols that will (a) be exposed in the :arglist meta, and (b) can't be accessed by user's code |
| 18:55 | goodside | Or, if you do judge productivity by LOC, consider them a negative. |
| 18:56 | amalloy | i like (defn ~ab-sym [~'a] (* ~'a num#)) |
| 18:57 | TimMc | amalloy: Ah, that's what I was looking for. |
| 18:59 | Havvy | amalloy: I'm pretty sure that I'd be writing the same in Java, if I was writing in it... |
| 18:59 | amalloy | arguably better still, you can remove the repetitive structure of the defns: `(let [num# ~expr] ~@(for [[op arg name] [['* 'a ab-sym] ['/ 'b ba-sym]]] `(defn ~name [~arg] (~op ~arg ~num#)))) |
| 18:59 | TimMc | I've heard of a programmer boasting that at his last job he was responsible for -100,000 LoC or something. |
| 18:59 | TimMc | Deleting is good. |
| 19:00 | Havvy | Only when you start refactoring... |
| 19:00 | brehaut | http://www.folklore.org/StoryView.py?story=Negative_2000_Lines_Of_Code.txt |
| 19:00 | amalloy | Havvy: huh? |
| 19:00 | kephale00 | Havvy: with Clojure you are almost always refactoring as soon as you start writing your code |
| 19:01 | kephale00 | it is a different development process than procedural languages |
| 19:01 | TimMc | brehaut: Similar story, yeah. Maybe the original. |
| 19:01 | kephale00 | unless you were using a java interpreter |
| 19:01 | amalloy | i guess my proposed change probably doesn't work because num# is being used in two contexts and gets a different symbol. something similar though |
| 19:09 | amalloy | https://gist.github.com/897441 makes a couple changes to yours, Havvy |
| 19:09 | TimMc | No syntax highlighting? |
| 19:10 | amalloy | TimMc: i forked his and his didn't have any. sec |
| 19:10 | amalloy | there |
| 19:10 | TimMc | thanks |
| 19:11 | amalloy | could probably do better by using a-symb instead of 'a |
| 19:11 | TimMc | amalloy: I'm not sure what you were trying to say about the gensym. |
| 19:12 | TimMc | ,`(a# a#) |
| 19:12 | clojurebot | (a__4781__auto__ a__4781__auto__) |
| 19:12 | amalloy | &`(let [a# 1] ~@[`(let [a# 1])]) |
| 19:12 | sexpbot | ⟹ (clojure.core/let [a__11632__auto__ 1] (clojure.core/let [a__11631__auto__ 1])) |
| 19:12 | amalloy | is what i had written |
| 19:13 | TimMc | Ah, so they weren't in the same syntax-quote. |
| 19:13 | amalloy | right |
| 19:13 | amalloy | so in my gist i get a gensym explicitly |
| 19:25 | amalloy | i've noticed CL code often uses a gensym when it needs a sentinel: (let ((end (gensym))) (return a bunch of items, stopping when one of them is eq to end)). in clojure i usually do (let [end (Object.)] (take-while (complement #{end}) (iterate #(or more-stuff end)))) |
| 19:25 | amalloy | should i be using gensyms as well, or is (Object.) more idiomatic? |
| 19:26 | TimMc | You should probably request a UUID from a web service at macro expand time. |
| 19:26 | TimMc | Clearly. |
| 19:26 | brehaut | TimMc: i didnt realise you work for an Enterprise |
| 19:26 | TimMc | :-) |
| 19:26 | TimMc | new Object() is idiomatic for Java, that I know. |
| 19:27 | amalloy | TimMc: which is weird, because i don't remember ever seeing new Object() in my years writing java |
| 19:28 | TimMc | I saw it used as a sentinel and also as a thing to synchronize on. |
| 19:28 | brehaut | amalloy: it probablly looked like Private Class MySentinel Implements ISentinel {} … new MySentinel(); |
| 19:28 | amalloy | TimMc: synchronization i've seen |
| 19:28 | amalloy | even as *shudder* a recommended best practice |
| 19:29 | amalloy | so here's something weird: ##(let [a1 (gensym "a") a2 (symbol (str "a" "11687"))] [a1 a2 (= a1 a2)]) |
| 19:29 | sexpbot | ⟹ [a11687 a11687 true] |
| 19:30 | amalloy | are gensyms not guaranteed perpetually-unique like in CL? |
| 19:31 | TimMc | Try again with eq. |
| 19:31 | amalloy | TimMc: you mean identical? |
| 19:32 | TimMc | yeah |
| 19:33 | amalloy | sure, they're not the same object (verified this). but i thought CL did something that prevented them even evaluating the same |
| 19:33 | TimMc | Oh, huh... ##(identical? 'a 'a) has different behavior in Clojure than in PLT Scheme. |
| 19:33 | sexpbot | ⟹ false |
| 19:34 | TimMc | I think. |
| 19:38 | ssideris | hello, I tried to do (apply proxy-super a [b c d]) |
| 19:38 | ssideris | And I got: Can't take value of a macro: #'clojure.core/proxy-super |
| 19:38 | amalloy | i notice that in sbcl (eq 'a 'a) is true |
| 19:39 | amalloy | TimMc: yeah |
| 19:39 | ssideris | I understand why |
| 19:39 | ssideris | but I'm not sure how I would go about writing differently |
| 19:39 | amalloy | ssideris: you want a macro that expands into a call to proxy-super, probably |
| 19:39 | TimMc | ssideris: Macros are infectious. |
| 19:40 | ssideris | amalloy: oh you mean something like apply-proxy-super ? |
| 19:41 | ssideris | (which does not exist yet) |
| 19:41 | amalloy | uhhh, probably. keep in mind the args will have to all be known at compile time anyway or you're just moving the problem |
| 19:42 | ssideris | hm, they're not |
| 19:42 | amalloy | then you ain't calling a macro that needs to know something about them |
| 19:43 | ssideris | I'll look into the macroexpand-1 of proxy-super and mimic that |
| 20:03 | gertalot | anyone else having trouble accessing clojure.org? I'm getting an SSL domain name mismatch for wikispaces.com |
| 20:35 | htierno | Hi there, i'm new to clojure. I was checking out the ants simulation code |
| 20:35 | gertalot | sigh :( I guess I'm the only one who can't access the clojure website eh. |
| 20:36 | htierno | I was having a hard time understanding the def world ... expression |
| 20:36 | TimMc | gertalot: works for me |
| 20:36 | gertalot | hm. |
| 20:36 | brehaut | htierno: can you provide al ink to the ants code you are looking at? |
| 20:36 | htierno | yeah |
| 20:36 | htierno | http://clojure.googlegroups.com/web/ants.clj?gda=g2CpRjoAAACo4x-COryhtXrsT4ddJVE-X_nZkB4F4_E0DdHzerfpau9OU0NQiFWgQuhmPR7veGf97daDQaep90o7AOpSKHW0 |
| 20:36 | brehaut | (htierno its very old (for clojure) and there are few versions in the wild) |
| 20:37 | gertalot | it's accessing session.wikispaces.com and they're using a content distribution network through edgecast, but the ssl certificate isn't valid :( |
| 20:37 | htierno | this is the function |
| 20:37 | htierno | ;world is a 2d vector of refs to cells |
| 20:37 | htierno | (def world |
| 20:37 | htierno | (apply vector |
| 20:37 | htierno | (map (fn [_] |
| 20:37 | htierno | (apply vector (map (fn [_] (ref (struct cell 0 0))) |
| 20:37 | htierno | (range dim)))) |
| 20:37 | htierno | (range dim)))) |
| 20:37 | brehaut | htierno: have you dont any functional programming before? |
| 20:38 | htierno | brehaut: yes, but only in school 10 years ago |
| 20:38 | htierno | I've read a lot about clojure |
| 20:38 | htierno | a couple of books |
| 20:38 | brehaut | htierno: ok cool. so a good way to start unpacking this is from the inside of the expression out |
| 20:39 | brehaut | and to jump ahead, the result of the expression is a vector of vectors |
| 20:39 | brehaut | ie a 2d struction |
| 20:39 | htierno | how did you figure that out |
| 20:39 | htierno | ? |
| 20:39 | gary_poster | wallyworld, would you still like that pypi permission? |
| 20:39 | brehaut | how did i figure what out? that its a 2d structure? |
| 20:39 | htierno | brehaut: yes |
| 20:40 | gary_poster | meh sorry, wrong channel :-P |
| 20:40 | brehaut | a) i read the program a few years ago, but importantly b) there is two "(apply vector (map …" nested |
| 20:41 | htierno | brehaut: ok, that's and interesting hint |
| 20:41 | brehaut | htierno: so the first bit of could you should look at is |
| 20:41 | hiredman | apply vector is very old, vec is preferable |
| 20:41 | brehaut | htierno: (map (fn [_] (…)) (range dim) |
| 20:42 | htierno | brehaut" |
| 20:42 | brehaut | hiredman: there are lots of old things in this example; it also has (dorun (for…) for example |
| 20:42 | htierno | brehaut: his applying fn with the world function arguments to the ref ? |
| 20:42 | brehaut | htierno: sorry, the first bit of code. ive abbrevated it down to the core for you. |
| 20:43 | htierno | what's dim ? |
| 20:43 | brehaut | dim is defined to be 80 |
| 20:43 | htierno | oh, sorry |
| 20:43 | htierno | yes, it's defined up there |
| 20:44 | brehaut | htierno: so range generates a sequence from 0 to dim-1 |
| 20:44 | htierno | so, the "inner" vector it's 80 in lenght |
| 20:44 | brehaut | yup |
| 20:44 | brehaut | the body of the fn in map (ref (struct cell 0 0)) tells you what each item i nthe vector contains |
| 20:45 | htierno | I can't see that |
| 20:45 | htierno | the indentation mess me up a bit |
| 20:46 | brehaut | you'll also notice that the argument to fn is _ (an underscore) this is idiomatic for that the argument is ignored |
| 20:46 | brehaut | htierno: its the body of the (fn … ) passed to the inner map |
| 20:47 | htierno | so, the first (range dim) makes a sequence of 80 in length |
| 20:47 | brehaut | someone can probably confirm this, but i think defstruct and struct are deprecated as of 1.2 |
| 20:47 | brehaut | ,(map (fn [_] :c) (range 10)) |
| 20:47 | clojurebot | (:c :c :c :c :c :c :c :c :c :c) |
| 20:47 | gertalot | could someone please point me to the clojure api docs? Normally I access that through clojure.org but that's inaccessible for me atm. |
| 20:47 | brehaut | gertalot: you could try clojuredocs.org/ |
| 20:48 | gertalot | excellent brehaut! ty |
| 20:48 | htierno | clojurebot: ok, i got that |
| 20:48 | clojurebot | bartj: it's not broken. Unless you know the performance hit there is actually a problem, I'd recommend leaving it alone. |
| 20:49 | Havvy | ##*out* |
| 20:49 | brehaut | htierno: so the 'ref' function returns a new STM reference that wraps its argument |
| 20:49 | brehaut | htierno: in this case a 'struct' which you canthink of as a map (the data structure, not the function) |
| 20:50 | htierno | ok, so then we have 80 ref cells |
| 20:50 | brehaut | yup |
| 20:50 | htierno | actually a vector of ref cells |
| 20:50 | brehaut | correct |
| 20:50 | brehaut | so we had previously (apply vector (map (fn [_] …) (range dim))) |
| 20:51 | brehaut | where the … made ref cells |
| 20:51 | htierno | yes, that make the vector of vectors of ref cells |
| 20:51 | brehaut | you can see that code repeated except that … is now the expresion that generates a vector of refs |
| 20:52 | brehaut | htierno: so that all makes sense now? |
| 20:52 | htierno | not yet |
| 20:52 | htierno | I don't get the indentation |
| 20:52 | brehaut | may i suggest experimenting in your repl? |
| 20:53 | brehaut | htierno: if you have a list form such as (fun arg arg arg) |
| 20:53 | htierno | everything else is clear now, thanks for the patience brehaut |
| 20:53 | brehaut | and you add line breaks, the first character of the second argument should line up with the first character of the first argument |
| 20:54 | htierno | ok then |
| 20:54 | htierno | so map takes a fn and a sequence |
| 20:54 | brehaut | yup |
| 20:54 | htierno | thanks |
| 20:54 | brehaut | htierno: do you have a repl running? |
| 20:54 | htierno | thanks again for your patience |
| 20:54 | htierno | yes |
| 20:54 | htierno | but I was trying to read some code |
| 20:54 | brehaut | htierno: try (doc map) for instance |
| 20:54 | brehaut | (doc map) |
| 20:54 | clojurebot | "([f coll] [f c1 c2] [f c1 c2 c3] [f c1 c2 c3 & colls]); Returns a lazy sequence consisting of the result of applying f to the set of first items of each coll, followed by applying f to the set of second items in each coll, until any one of the colls is exhausted. Any remaining items in other colls are ignored. Function f should accept number-of-colls arguments." |
| 20:55 | brehaut | htierno: it will tell you what the possible arguments it can take are |
| 20:55 | brehaut | and no problem |
| 20:55 | htierno | thanks brehaut |
| 20:56 | brehaut | htierno: while the ants demo is cool and you can learn a lot from it, its 3 stable versions of clojure out of date in terms of idioms, so it might differ from more recent code you find |
| 20:56 | brehaut | so just keep that in mind |
| 20:57 | htierno | about the things deprecated in that example |
| 20:57 | htierno | apply vector is replaced by vec ? |
| 20:57 | brehaut | yup |
| 20:58 | brehaut | htierno: rule of thumb for #clojure, if hiredman tells you something, its right |
| 20:59 | htierno | what about struct ? |
| 20:59 | htierno | that seems ok |
| 20:59 | htierno | cell is a struct defined earlier |
| 20:59 | brehaut | htierno: its been deprecated i believe. defrecord replaces it |
| 20:59 | brehaut | but learning about defrecords is probably overkill for you ATM |
| 21:00 | htierno | ok, I will look up that |
| 21:00 | brehaut | htierno: a struct is just a fancy map with keyword keys anyway |
| 21:00 | brehaut | so you can just treat it as a map |
| 21:00 | htierno | ok |
| 21:00 | htierno | I'm looking at the API |
| 21:01 | htierno | and it doesn't say that this macro is deprecated |
| 21:01 | htierno | so, how do you now for sure ? |
| 21:01 | htierno | or is it that defrecord is actually "more" correct ? |
| 21:02 | htierno | by "more" correct I mean better |
| 21:02 | brehaut | so the idea of structs is that they are maps with faster access; defrecord is the same idea with a radically different implementation that compiles down to host classes |
| 21:02 | brehaut | so its capable of being _much_ faster |
| 21:02 | htierno | great, so it's actually not deprecated |
| 21:03 | htierno | but there is a better way of doing the same thing |
| 21:03 | brehaut | if it is not officially deprecated, it is nolonger idiomatic |
| 21:03 | htierno | ok |
| 21:04 | brehaut | htierno: http://clojure.org/data_structures#Data%20Structures-StructMaps theres a note immediate below 'StructMaps' that doesnt use the word deprecated but states the same thing |
| 21:04 | htierno | is there another group about clojure for us newbies ? |
| 21:05 | htierno | I don't like to ask stupid questions that may offend some users on this channel |
| 21:05 | brehaut | htierno: you wont offend anyone |
| 21:05 | brehaut | not by asking a question anyway |
| 21:06 | htierno | ok, thanks again |
| 21:32 | amalloy | structs are officially deprecated. someone was insisting that "deprecated" means "it will be removed at some point", and that it must not be deprecated because that's not a guaranteed outcome by any of the docs. but "deprecated" means "you shouldn't do this [anymore]", and structs are that |
| 21:34 | amalloy | i'm not sure that vec is a replacement for apply vector, though of course in most cases it is. it doesn't seem unreasonable, to me, to prefer (apply vector 1 2 some-var) to (vec (list* 1 2 some-var)) |
| 21:50 | htierno | amalloy: thanks for the explanation |
| 21:50 | htierno | amalloy: why don't you put the "deprecated" tag on struct ? |
| 21:51 | amalloy | umm. (a) i don't have anything like commit access to clojure.core, (b) clojure functions don't have javadoc? |
| 21:51 | Havvy | amalloy: They do have metadata though. ;) |
| 21:52 | Havvy | #^{:deprecated-to 'defrecord} |
| 21:52 | Havvy | Hmm, can metadata have metadata? :P |
| 21:52 | cemerick | yup, they're all maps :-) |
| 21:53 | Havvy | Has anybody made use of that feature? |
| 21:53 | cemerick | There's always someone crazy enough. |
| 21:54 | cemerick | Metadata is "real" data somewhere, so it might need metadata in that context. |
| 21:54 | cemerick | Who's to say that you don't need metadata on your metadata? |
| 21:55 | tomoj | hardly barely |
| 21:55 | amalloy | heh |
| 21:56 | cemerick | I can't get enough of somewhat-out-of-date memes. |
| 21:57 | tomoj | seems like in the limit the best memes would be those that only you have |
| 21:58 | Havvy | tomoj: You mean inside jokes? |
| 21:58 | tomoj | with oneself? I guess |
| 21:58 | tomoj | the "best" memes in some sense are those that spread best, but then they're not cool anymore |
| 21:59 | Havvy | A meme is just an idea that spreads...which really just sounds like a fancy word for 'idea'. |
| 22:00 | Havvy | Oh wait, it is a unit of cultural idea, value, or pattern... |
| 22:01 | tomoj | I guess "meme" is a good meme |
| 22:01 | Havvy | I wonder if a meme could be spread: "Every time you say something is a meme, you prove evolution." :P |
| 22:02 | brehaut | tomoj: careful, cemerick only barely suppressed the yo dawg the first time round |
| 22:02 | tomoj | don't you have to suppress something to barely suppress it? |
| 22:02 | tomoj | use/mention I guess? |
| 22:02 | amalloy | tomoj: he suppressed one of them. the other snuck out |
| 22:02 | tomoj | :) |
| 22:03 | cemerick | brehaut: don't worry, I've composed myself again. |
| 22:03 | brehaut | (comp cemerick cemerick) ? |
| 22:04 | cemerick | MPD is right around the corner. |
| 22:06 | tomoj | I feel like if I'm a function I should be one if its parameters too |
| 22:06 | tomoj | s/parameters/arguments/ |
| 22:06 | Havvy | tomoj: So you can update yourself? |
| 22:07 | Havvy | Hmm, if a ref contains a function that contains code to modify that function, would it work? |
| 22:07 | tomoj | I guess you can get a reference to a ref inside a function in the ref, but callers will only see the new function if they go through the ref |
| 22:08 | Havvy | :confused |
| 22:10 | Havvy | java.lang.Exception: Unable to resolve symbol: do-sync in this context |
| 22:10 | Havvy | :( |
| 22:10 | brehaut | Havvy: what about dosync ? |
| 22:11 | Havvy | Oh. Yes, that works. |
| 22:11 | Havvy | Yes, a ref that is a function can modify itself. >_> |
| 22:12 | brehaut | of course |
| 22:15 | tomoj | a ref that is a function? |
| 22:15 | brehaut | tomoj: i presume he means a ref that contains a function |
| 22:15 | tomoj | a function in a ref can modify the ref |
| 22:16 | tomoj | functions are surely immutable? |
| 22:30 | Havvy | le sigh: (def test-ref (ref (fn [] (dosync (ref-set test-ref 10))))) |
| 22:31 | Havvy | ,(def test-ref (ref (fn [] (dosync (ref-set test-ref 10))))) |
| 22:31 | clojurebot | DENIED |
| 22:31 | Havvy | &(def test-ref (ref (fn [] (dosync (ref-set test-ref 10))))) |
| 22:31 | sexpbot | java.lang.SecurityException: You tripped the alarm! def is bad! |
| 22:32 | amalloy | Havvy: what's the point? a ref/atom can be set to anything by anyone; not sure what you're trying to demonstrate |
| 22:33 | Havvy | I would think it would run into a race condition with itself...but it seems not. |
| 22:36 | amalloy | there is nobody to race with. it's *not* modifying the function's code in any way |
| 22:36 | tomoj | functions that get removed from refs run just as fine as those that don't |
| 22:37 | amalloy | it just has three objects of interest: a ref-to-anything, a function, and the integer 10. the ref begins pointing at the function. the ref is deref'd, the resultant function is called (nobody is even looking at the ref anymore at this point), and the function sets the ref to point to 10 |
| 22:39 | amalloy | &(let [a (atom nil)] (reset! a (fn [] (reset! a 10))), (@a), @a) |
| 22:39 | sexpbot | ⟹ 10 |
| 22:40 | Havvy | If you can call the number 10 interesting. It's merely a 'what can this be replaced with?' value. But yeah, nifty that it can do that. |
| 22:42 | pdk | 10 is badass man |
| 22:42 | pdk | no hati |
| 22:42 | pdk | hatin |
| 23:32 | gertalot | ugh. It's Friday afternoon... what is the practical difference between atoms and refs? |
| 23:32 | gertalot | wondering what the use cases are for both. |
| 23:34 | amalloy | atoms: changing something that can be grouped under a single object. refs: coordinating changes across multiple things |
| 23:34 | gertalot | thanks amalloy! |
| 23:34 | gertalot | that helps. |
| 23:35 | amalloy | i rarely use refs: i find it interesting and challenging to work out how to fit the stuff i need to work with under a single atom |
| 23:36 | gertalot | so, suppose I have Jobs that represent long-running computations, I could use (def jobs (atom {})) to store jobs |
| 23:36 | amalloy | indeed |
| 23:36 | gertalot | and each job could be a ref, because the long running computations need to update Job state every now and then |
| 23:36 | gertalot | or is that wrong? :) |
| 23:37 | amalloy | it's on the crazy side |
| 23:37 | gertalot | haha :) |
| 23:37 | gertalot | ok |
| 23:37 | gertalot | the thing is, I don't want to couple job storage to the computations. |
| 23:38 | amalloy | i'd do like (swap! jobs update-in [job-id] assoc :done true) |
| 23:38 | amalloy | or whatever |
| 23:38 | gertalot | ah that gives me hope. That's close to what I currently have, but I thought there could be a better way |
| 23:38 | gertalot | thanks again amalloy! |
| 23:39 | amalloy | rata had an interesting case convincing me that (atom {id (agent nil), id2 (agent nil)}) was a good idea, but in general nesting reference types seems dangerous |
| 23:41 | gertalot | I think I'll stay away from it unless I really really need it, in which case I'd probably have a good argument for it too. |
| 23:41 | tomoj | I heard you like reference types |
| 23:42 | amalloy | groan |
| 23:44 | tomoj | &(let [a (ref nil) b (ref a)] (dosync (ref-set a b))) |
| 23:44 | sexpbot | java.lang.StackOverflowError |
| 23:44 | tomoj | why? |
| 23:44 | clojurebot | why not? |
| 23:44 | tomoj | why? |
| 23:44 | clojurebot | why not? |
| 23:44 | tomoj | every time? |
| 23:46 | amalloy | weird |
| 23:47 | tomoj | oh |
| 23:47 | tomoj | &(let [a (ref nil) b (ref a)] (dosync (ref-set a b) nil)) |
| 23:47 | sexpbot | ⟹ nil |
| 23:47 | tomoj | it's just the printing, which is exactly the stack overflow I was expecting |
| 23:47 | amalloy | hah |
| 23:57 | scottj | clojure scripting just got better, jark supports super simple #! and is really fast, launching the persistent JVM if not already running |
| 23:58 | scottj | it's official, leiningen is being deprecated in favor of cake |