2011-02-10
| 00:03 | mec_ | is there a good way to map subvec across a vector for windowing? |
| 00:08 | tomoj | mec__: what are you going to do with the windows? |
| 00:08 | tomoj | I mean, do you really need vector windows? |
| 00:09 | tomoj | vs something like ##(partition 3 1 [1 2 3 4 5 6]) ? |
| 00:09 | sexpbot | ⟹ ((1 2 3) (2 3 4) (3 4 5) (4 5 6)) |
| 00:12 | mec__ | thats what i want, but i figured subvec would be a lot faster if I specifically had a vector |
| 00:15 | tomoj | well.. |
| 00:17 | tomoj | probably depends on window size and what you do with the windows |
| 00:17 | tomoj | for window size 3, it looks like partition is faster at generating the windows |
| 00:18 | tomoj | while for window size 10, subvec seems faster |
| 00:19 | tomoj | map is variadic, so you can (map #(subvec v %1 %2) x y) where x and y are seqs of the appropriate indices |
| 00:20 | mec__ | oh didnt think of that at all, thanks |
| 00:21 | tomoj | oh, wow |
| 00:22 | tomoj | (partition n 1 v) is O(n) for fixed v |
| 00:23 | mec__ | how is that possible? it creates a seq that touches the whole thing |
| 00:23 | tomoj | I mean, ignoring that factor |
| 00:24 | mec__ | its O(n) or O(count v) |
| 00:24 | tomoj | I think (partition w 1 v) is O(n*w) if v has n elements |
| 00:24 | mec__ | ah |
| 00:24 | tomoj | 'n' was a bad choice for window size |
| 00:24 | tomoj | subvec has a constant (or log32?) factor instead of w, I think, but for small w it's worse |
| 00:25 | tomoj | constant according to subvec's docs |
| 00:26 | tomoj | can you do better than O(n*w) on seqs in general for the step=1 case? |
| 00:28 | mec__ | i wouldnt think so, but subvec is deffinitly constant |
| 00:32 | tomoj | well, you can generate a seq of the windows in O(n) with something like (->> s (iterate next) (take-while identity) (drop-last (dec w)) (map #(take w %))), but that might be cheating compared to (partition w 1 s)? |
| 00:32 | amalloy | tomoj: constant according to the source too. it just creates an object storing the parent vector and the indices, and does the appropriate translated nth lookups in the parent when you access a subvec element |
| 00:35 | tomoj | I've been thinking lately about doing something like that for permutations |
| 00:36 | tomoj | sound feasible? |
| 00:37 | mec__ | Hard to say if it would be any faster, wouldnt you need a map for the old to new indices? |
| 00:37 | tomoj | yeah, but looking up the new index is practically constant while creating a new vector from scratch is O(n), yes? |
| 00:38 | mec__ | true but would creating the map be O(n) anyway? |
| 00:38 | tomoj | amalloy: thanks, I hadn't realized that's what subvec did, I'll look there for inspiration |
| 00:38 | tomoj | well, I only have one permutation |
| 00:38 | tomoj | and its inverse |
| 00:38 | tomoj | and need to apply them many times to many vectors with thousands of elements |
| 00:38 | tomoj | so I can have the maps already sitting around beforehand |
| 00:41 | tomoj | ooh, even with more permutations (say, hundreds), I can memoize all the combinations to avoid multiplying the log32 vector access |
| 00:54 | tomoj | oh, now I remember the problems I ran into.. it's really simple if you never change a permuted vector, not so simple if you do |
| 00:55 | tomoj | maybe I can get away with only implementing the read-only stuff for a while.. |
| 01:04 | no_mind | how do I produce html using compojure. When I call (html0 function, I get a compile time error |
| 01:04 | no_mind | (html) |
| 01:04 | no_mind | .(html) |
| 01:10 | puredanger | let's just hypothetically say that I have a deep aversion to every Java logger ever invented and that I want to do some logging from a Clojure app |
| 01:10 | technomancy | puredanger: it's simple, just use this logging abstraction framework |
| 01:10 | puredanger | is there a Clojure lib that does very basic logging? (not c.c.logging) |
| 01:11 | technomancy | you can plug in any logging implementation or even other logging abstraction frameworks! |
| 01:11 | puredanger | technomancy: <headdesk> |
| 01:11 | technomancy | (just ignore the fact that there are only two logging implementations in existence and at least three logging abstractions) |
| 01:12 | puredanger | technomancy: I see you share my love of Java logging f/ws |
| 01:13 | khaliG | anyone familiar with miglayout? i wish to use the do-layout function, but the compiler says java.lang.IllegalAccessError: do-layout does not exist |
| 01:14 | khaliG | oh i see it's an internal function |
| 01:34 | tomoj | would a feature that allowed you to delegate all unimplemented methods in a deftype to one of its fields be evil? not suggesting this feature, just want it now but suspect that it's evil |
| 01:39 | amalloy | tomoj: that sounds exactly like extending a class: implementation inheritance |
| 01:39 | amalloy | so i suspect the two are equally evil |
| 01:41 | tomoj | when you say it that way this sounds even more evil |
| 01:50 | no_mind | how can I install enlive using lein ? It gives me an error for dependency on org.apache.maven:super-pom:jar:2.0 |
| 01:52 | rata_ | can you search for something like *blah* in emacs history? |
| 01:54 | tomoj | no_mind: paste the entire output somewhere (not here) |
| 01:55 | amalloy | tomoj: it was not an accident :) |
| 02:17 | sritchie | hey all -- I've got a first draft of a function to walk a matrix with a window size and a step of 1, returning all window x window submatrices. would anyone be up for taking a look? |
| 02:17 | sritchie | https://gist.github.com/5b33bae6bb3e28b7f815 |
| 02:18 | sritchie | the output is correct, but i suspect there's a cleaner way of doing this |
| 02:22 | amalloy | sritchie: plus reduce and conj aren't lazy |
| 02:22 | raek | sritchie: check out the torus-window function: http://www.bestinclass.dk/index.clj/2009/10/brians-functional-brain.html |
| 02:23 | sritchie | this line: "Everytime we are applying rules to a cell we need to consider 9 cells in total: The target and his 8 neighbors." is exactly what I was going for |
| 02:23 | sritchie | awesome, thanks, raek |
| 02:24 | amalloy | except it sounds like you don't actually want a torus |
| 02:25 | raek | then using a window function like this might work: (defn window [coll] (partition 3 1 coll)) |
| 02:26 | raek | the number of windows will then be (- (count coll) 2) |
| 02:27 | sritchie | this is for a nearest neighbor analysis, so I do need to walk in both dimensions, with the window |
| 02:27 | sritchie | getting a lazy sequence of 2d vectors, ideally |
| 02:27 | sritchie | raek: that'll let me walk along 1d, right? |
| 02:28 | raek | yes, but the 'step' function uses it twice to get 2d |
| 02:29 | raek | hrm. also consider using 'for' instead of 'map' + anonymous function |
| 02:29 | raek | IMHO the code tends to be easer to read then |
| 02:30 | sritchie | raek: okay, good advice |
| 02:30 | amalloy | raek: agreed, i was gonna put something together with for |
| 02:31 | sritchie | raek: for looks a lot clearer, that's great |
| 02:32 | sritchie | is torus window lazy, here? |
| 02:32 | raek | yes |
| 02:32 | raek | partition is lazy |
| 02:33 | rata_ | sritchie: I haven't read the blog post yet, but this works for me: (mapcat (comp (partial apply map vector) (partial map (partial partition w 1))) (partition w 1 m)) |
| 02:34 | sritchie | rata_: ah, so that gets rid of my reduce conj step |
| 02:35 | rata_ | it does more than that I think |
| 02:35 | amalloy | brehaut: another one for the point-free brigade, it seems |
| 02:36 | sritchie | rat sorry, I meant mapcat got rid of that |
| 02:36 | rata_ | it's completely lazy and it doesn't use count |
| 02:36 | rata_ | yes |
| 02:37 | raek | the map vector step can't be lazy |
| 02:37 | rata_ | amalloy: what's the point-free brigade? those that don't like/use java interop? |
| 02:38 | rata_ | raek: but map is lazy |
| 02:38 | amalloy | rata_: heh, no. point-free is a style that is popular with haskell programmers. (partial (comp foo bar) 10) rather than #(foo (bar 10 %&)) |
| 02:39 | rata_ | ah hahaha ok =) |
| 02:39 | amalloy | ie, "talking" about functions and gluing them together without mentioning their actual params |
| 02:39 | rata_ | yes, I prefer that style... that % looks dirty |
| 02:39 | raek | you have something like (1 2 3 4) and turn it into [1 2 3 4]? |
| 02:40 | amalloy | i like point-free myself, and brehaut and Raynes are always teasing me that i should try haskell |
| 02:40 | rata_ | raek: no, that's vec |
| 02:40 | rata_ | for what I know about haskell, I like it... but I haven't done a project in haskell yet |
| 02:41 | amalloy | same |
| 02:42 | amalloy | $heval take 10 $ let fib = 1 : 1 : zipWith (+) fib (tail fib) in fib |
| 02:42 | sexpbot | ⟹ [1,1,2,3,5,8,13,21,34,55] |
| 02:42 | amalloy | rata_: brehaut tells me this is how all the cool kids generate fibonacci numbers |
| 02:42 | rata_ | amalloy: yes, that's pure beauty =) |
| 02:43 | rata_ | I loved it the first time I saw it |
| 02:43 | amalloy | *chuckle* well, i'm off to bed. i'll try to dream of parens instead of $ and . |
| 02:44 | rata_ | hahahaha |
| 02:44 | rata_ | good night amalloy |
| 02:44 | rata_ | do you guys know what's the best way to do ajax with clojure? |
| 02:45 | rata_ | best intended in a very subjective way of course |
| 02:46 | Scriptor | rata_: I prefer to just keep my server code strictly separated, jquery for the ajax calls, and maybe have a clojure handler return json |
| 02:49 | rata_ | Scriptor: so make the website in html+javascript and maybe call some clojure fns? |
| 02:49 | Scriptor | er, the front-end is in html+js, the backend would still use clojure |
| 02:50 | Scriptor | so yes, just send an ajax request to a url and have that url be tied to whatever callback you want |
| 02:51 | rata_ | have you any examples at which I could give a look? |
| 02:51 | Scriptor | not off the top of my head, and also not really with clojure |
| 02:52 | Scriptor | but you don't have to learn much, just how to send a request using javascript and how to return json in clojure |
| 02:53 | Scriptor | since otherwise a request is still just a request |
| 02:54 | rata_ | yes... do you know where I can learn those things? |
| 02:55 | raek | in ring, you can just respond with {:status 200, :headers {"Content-Type" "application/json"} (clojure.contrib.json/json-str some-data)} |
| 02:55 | raek | rata_: have you done server-side web programming in clojure? |
| 02:56 | rata_ | no... I know a bit of html and that's all |
| 02:56 | Scriptor | rata_: how much programming experience do you have in general? |
| 02:57 | rata_ | ~8 years |
| 02:57 | clojurebot | Pardon? |
| 02:57 | raek | ~test |
| 02:57 | clojurebot | lastest is 1135 |
| 02:57 | Fossi | :D |
| 02:58 | rata_ | I do "scientific" programming mainly (I don't know if that's a good name for what I do) |
| 02:59 | Scriptor | rata_: start off with some basic web apps using compojure or something like that, then start learning javascript and a little jquery |
| 03:00 | Scriptor | or whatever js framework you want |
| 03:00 | rata_ | ok... do you use compojure? |
| 03:00 | Scriptor | not personally |
| 03:00 | rata_ | what do you use? |
| 03:00 | Scriptor | don't really use clojure, really :p |
| 03:00 | raek | I usually use Ring + Moustache + Enlive |
| 03:00 | Fossi | yeah, any combination should do actually |
| 03:00 | rata_ | Scriptor: ah ok =) |
| 03:01 | raek | Ring + Compojure + Hiccup is another very common combo |
| 03:01 | rata_ | Scriptor: which language do you use? |
| 03:01 | raek | web programming in clojure is *very* modular |
| 03:01 | rata_ | raek: what's moustache and enlive for? |
| 03:01 | Scriptor | rata_: mainly php and python, but I've been learning lisp on the side |
| 03:01 | rata_ | ok |
| 03:01 | Scriptor | the principles of web dev are often the same |
| 03:01 | raek | moustache is for routing (mathcing URLs and HTTP methods), enlive is for html templating |
| 03:02 | raek | actually, enlive can do html scraping too |
| 03:02 | rata_ | raek: I thought ring was for routing |
| 03:02 | raek | it reads html from a file into a clojure datastructure, lets you transform it and turn it back into a html stream again |
| 03:03 | brehaut | rata_: ring is the HTTP to clj to HTTP translation layer |
| 03:03 | raek | ring is the standard for what a request and a response looks like |
| 03:03 | Fossi | it's so awesome that clojure has ring |
| 03:03 | raek | it comes with a web server that implements that contract |
| 03:03 | Fossi | java containers are a mess :> |
| 03:07 | rata_ | so, if I get it right, you put the html+js part in using enlive? |
| 03:08 | raek | if the html never changes, you don't pass it through enlive |
| 03:08 | brehaut | raek: enlive is a much more strongly seperated `templating system` than is typical |
| 03:08 | brehaut | you put your html and js into an html file |
| 03:09 | raek | (i.e. the web site uses ajax to transfer *all* data) |
| 03:09 | brehaut | and then you use ring to update that file for a particular resource |
| 03:11 | brehaut | that was at rata_ sorry |
| 03:12 | rata_ | mmm... then if I'm using ajax I'm not going to need enlive raek? |
| 03:13 | brehaut | rata_: ajax is a pretty vague term, but, as a term it usually refers to the client side program |
| 03:13 | brehaut | you dont 'need' anything on the server to do ajax |
| 03:14 | brehaut | rata_: you just have to write some route handlers that return data in a format your client side can handle (typically json these days, originally xml) |
| 03:14 | raek | rata_: that can be true. |
| 03:14 | raek | depends on how you do it. |
| 03:15 | rata_ | brehaut: but using ajax you can ask the server to compute something and then render it in the webpage without have to refresh it, right? |
| 03:15 | brehaut | rata_: correct |
| 03:15 | rata_ | and route handlers are clojure fns? |
| 03:16 | brehaut | yeah; you use either moustache or compojure to map a url to a fn |
| 03:16 | brehaut | that stage is route handling |
| 03:17 | rata_ | ok, so the client request the result of a computation asking for a url? |
| 03:17 | rata_ | and then renders it within the same page |
| 03:17 | brehaut | rata_: it doesnt as for the result of a computation; it asks for a resource - all urls map to resources in http. |
| 03:17 | brehaut | dont think of it as an RPC system |
| 03:18 | brehaut | theres two primary methods for accessing a resource: GET and POST (there is also PUT and DELETE, but for a variety of reasons they are not as common) |
| 03:18 | brehaut | GET purely gets; its an idempotent action |
| 03:18 | brehaut | POST is server specific |
| 03:19 | rata_ | resources sounds like there something in the server already... I need to compute something based on what the client put in the forms |
| 03:19 | brehaut | rata_: they dont have to be |
| 03:19 | rata_ | *there's |
| 03:19 | rata_ | ok |
| 03:19 | rata_ | so I do a GET or POST and get the result I need |
| 03:19 | brehaut | rata_: does the result of the calculation ever change? |
| 03:20 | rata_ | no, but there are infinite possible inputs |
| 03:20 | brehaut | sorry, i wasnt clear. |
| 03:20 | rata_ | (not sure if infinite, but huge anyway) |
| 03:20 | khaliG | the indenting behaviour of slime is really annoying |
| 03:21 | khaliG | it keeps trying to push my fns all the way across the screen |
| 03:21 | brehaut | rata_: if you pass the same inputs to the fun, will it always produce the same result |
| 03:21 | rata_ | yes |
| 03:21 | brehaut | then a GET on a resource with query parameters is completely fine |
| 03:21 | brehaut | which is nice because its super easy |
| 03:21 | rata_ | =) |
| 03:23 | rata_ | it's not a problem that the query parameters are long strings? |
| 03:23 | brehaut | how long? |
| 03:24 | brehaut | from memory you can safely assume 1024 characters for your url on any compliant HTTP server or proxy |
| 03:24 | rata_ | it can be longer than that I think |
| 03:25 | brehaut | sad; safer to go with a post then |
| 03:25 | brehaut | even though you'd proably never run into it in the real world |
| 03:26 | rata_ | there's no size limitation with post then |
| 03:26 | brehaut | rata_: have you got a non-ajax version of the web app going ? |
| 03:26 | rata_ | no... should I do that first? |
| 03:26 | brehaut | rata_: nope, post you send the arguments in the body of the request |
| 03:26 | brehaut | yeah i would recommend it |
| 03:27 | brehaut | ajax builds on all the basic ideas |
| 03:27 | brehaut | try http://mmcgrana.github.com/2010/07/develop-deploy-clojure-web-applications.html |
| 03:27 | brehaut | as a tutorial |
| 03:27 | rata_ | thanks =) |
| 03:27 | brehaut | heres the thing: the difference between an 'ajax' resource and a 'web page' resource is the content type it sends back |
| 03:28 | brehaut | you can legitimately have a page say, /hello/name |
| 03:28 | brehaut | that returns "<html><h1>Hello, name!</h1></html>" |
| 03:29 | brehaut | for a web browser (or default) |
| 03:29 | brehaut | and then returns "{"message":"Hello, name!"}" for 'ajax' requests |
| 03:30 | rata_ | so it's easy to ajaxify a non-ajax webpage? |
| 03:30 | brehaut | yes |
| 03:30 | brehaut | theres no reason your ajax version cant just consume the HTML version |
| 03:30 | rata_ | ok, thanks a lot =) |
| 03:31 | brehaut | and then just find the appropriate nodes in the DOM |
| 03:31 | brehaut | no problem |
| 03:31 | tomoj | wat |
| 03:31 | brehaut | tomoj: ? |
| 03:32 | tomoj | were you recommending generating html, then parsing that to generate json? |
| 03:32 | brehaut | tomoj: not recommending it per se |
| 03:33 | tomoj | ok |
| 03:33 | brehaut | i just didnt want rata_ to think that ajax was somehow magical or something special |
| 03:33 | Fossi | it's pretty easy and nice to have two output methods for your data though |
| 03:35 | rata_ | so then I'll have to make my fns to return json instead of html? |
| 03:35 | brehaut | yeah you can switch on the accepts header, or theres a header that libs like jquery add to ajax 'X-Request-With: ajax" i think? |
| 03:36 | brehaut | rata_ its really easy though; ring will provide you a request map which will have a key :headers which maps to a map |
| 03:37 | brehaut | that map will likely have an :accepts header, and maybe :x-requested-with |
| 03:38 | rata_ | but the main difference is you use enlive to return html, but not for json |
| 03:39 | Scriptor | rata_: right, json is pretty easy to generate, you can find json libs online |
| 03:40 | brehaut | c.c.json or clj-json will take standard clojure datastructures and generate json string for you |
| 03:40 | rata_ | ok, thanks again |
| 03:41 | brehaut | rata_: mmcgrana has another tutorial of interest http://mmcgrana.github.com/2010/08/clojure-rest-api.html |
| 03:41 | brehaut | shows you how to do json-responses |
| 03:42 | rata_ | I'll read it too |
| 03:42 | tomoj | huh. I think if I switch to clj-json from clojure-json I'll have to rename generate-string and parse-string to encode and decode |
| 03:43 | brehaut | win :) |
| 03:44 | tomoj | eh, I only considered it because it says "fast", but clojure-json isn't even close to a bottleneck anyway |
| 03:44 | brehaut | i wonder if i should change necessary-evil to use the same terms as clj-json before anyone actually starts depending on it |
| 03:45 | brehaut | parse and unparse are a bit clunky |
| 03:46 | tomoj | I like em better than those long things with their "-string"s sticking out |
| 03:48 | brehaut | i guess |
| 03:48 | brehaut | not particularly nice either way |
| 03:52 | meltingwax | hi |
| 03:52 | brehaut | night |
| 03:57 | meltingwax | is closure compatible with common lisp libraries? |
| 03:58 | opqdonut | no, it's a different language on a different platform |
| 04:00 | meltingwax | what if i really needed it |
| 04:01 | ejackson | you can try prayer... |
| 04:02 | meltingwax | thank you, i will try that |
| 04:03 | opqdonut | :D |
| 04:03 | ejackson | meltingwax: some claim it to be a pattern. |
| 04:04 | opqdonut | 541052.14 meltingwax$ thank you, i will try that |
| 04:04 | opqdonut | oops |
| 04:14 | rata_ | good night |
| 04:14 | rata_ | see you |
| 05:16 | fliebel | morning |
| 05:23 | no_mind | is there a working example of compojure and enlive ? |
| 05:30 | bobo | i think most examples with enlive are with moustache instead of compojure :-/ |
| 05:31 | Dranik | bobo, are there any? |
| 05:33 | bobo | examples of enlive + compojure? i have never seen any. but shouldnt be any problem reading about enlive with moustache and then change to compojure |
| 05:33 | no_mind | I think I have found the title for my next book... "Clojure for humans" |
| 05:34 | no_mind | bobo: they are not working with compojure... |
| 05:34 | no_mind | btw suggestion for any other templating engine to be used with compojure ? |
| 05:34 | no_mind | preferably something that can read files from hdd |
| 05:35 | bobo | no_mind: in what way are they not working? point me to some example you are reading and il see if i can compojurise it |
| 05:35 | no_mind | bobo: take any example |
| 05:35 | no_mind | I am getting Null pointer exception |
| 05:36 | bobo | is your template working without compojure? if you just call it? |
| 05:36 | bobo | null pointers with enlive usualy mean you point to a non existing .html |
| 05:37 | no_mind | the .html is accesible from the route |
| 05:38 | bobo | yes, but does enlive find it? thats not the same thing |
| 05:38 | bobo | enlive looks from your src folder |
| 05:38 | no_mind | k |
| 05:38 | clojurebot | package.el is part of Emacs now: http://repo.or.cz/w/emacs.git/blob_plain/HEAD:/lisp/emacs-lisp/package.el |
| 05:41 | Dranik | bobo, how about mustache + enlive? are there any examples or tutorials? |
| 05:42 | bobo | https://github.com/swannodette/enlive-tutorial/ |
| 05:42 | bobo | http://cleancode.se/2011/01/04/getting-started-with-moustache-and-enlive.html |
| 05:42 | bobo | the first is probably the better one, since i wrote the second :-p |
| 05:43 | raek | no_mind: it does not matter whether you use enlive with compojure or moustache. |
| 05:43 | Dranik | thanks |
| 05:44 | raek | I usually put my html templates in resources/ rather than src/, since they're not code |
| 05:45 | FkCek|a | http://www.bestinclass.dk/index.clj/2011/01/building-a-social-media-site.html |
| 05:45 | Dranik | bobo, the first is not available |
| 05:47 | bobo | Dranik: its not? im looking at it? |
| 05:48 | Dranik | wow! |
| 05:48 | Dranik | This webpage is not available |
| 05:48 | Dranik | that's what I've got |
| 05:48 | Dranik | oh its working now |
| 05:49 | bobo | no_mind: https://gist.github.com/820290 |
| 05:49 | bobo | index.html is in my src folder there, but as raek said they should be in resources in the end. |
| 05:50 | no_mind | k |
| 05:51 | bobo | raek: whats the best way to point the template to the resources folder? |
| 05:51 | bobo | just wrap-file ? |
| 05:52 | raek | deftemplate looks for files on the classpath and both src/ and resources/ are on it |
| 05:52 | bobo | ah |
| 05:52 | bobo | you learn every day! |
| 05:59 | raek | it would be nice if wrap-file could look for static files on a subdirectory of the classpath too... |
| 06:56 | cwb | startups |
| 07:16 | TobiasRaeder | morning |
| 07:19 | gfrlog | good morning |
| 07:20 | gfrlog | ,(let [good-+ (fn [& args] (apply + (shuffle args)))] (good+ 7 8 9)) |
| 07:20 | clojurebot | java.lang.Exception: Unable to resolve symbol: good+ in this context |
| 07:20 | gfrlog | ,(let [good+ (fn [& args] (apply + (shuffle args)))] (good+ 7 8 9)) |
| 07:20 | clojurebot | 24 |
| 07:22 | TobiasRaeder | is there some kind of idiomatic wrapper for dates in clojure? |
| 07:23 | fliebel | TobiasRaeder: I encountered Yoda-time a few times. It's used in sexpbot for example. |
| 07:23 | TobiasRaeder | then ill check that out how its done there, thanks |
| 07:24 | fliebel | TobiasRaeder: Oh, sorry, it's clj-time, which uses Yoda |
| 07:25 | TobiasRaeder | @fliebel clj-time looks nice :) |
| 07:26 | bobo | think its called joda-time with a j |
| 07:54 | no_mind | using enlive, how can I create a list element <li> dynamically from database? Given the template has a placeholder <ul. eleement. |
| 07:55 | fliebel | no_mind: I think you define one placeholder li, and repeat-for on a snippet of that li.. |
| 07:57 | bobo | no_mind: https://gist.github.com/820462 |
| 08:09 | no_mind | bobo: did you create a placeholder for <li> under <ul> in the template ? |
| 08:10 | bobo | no_mind: eh yes i belive so |
| 08:10 | no_mind | thnxs |
| 08:10 | bobo | https://gist.github.com/820477 |
| 08:10 | bobo | i stole it from my post about it |
| 08:13 | jkdufair | i'm looking for advice |
| 08:13 | jkdufair | i'm building a RESTful app on top of compojure |
| 08:14 | jkdufair | i need a way to represent data across this web app and also an iPhone app and an AJAXy web app |
| 08:14 | jkdufair | use JSON or some representation of s-expressions? |
| 08:16 | bobo | i would use json |
| 08:17 | jkdufair | bobo: are you aware of any clojure libs that serialize to JSON? |
| 08:17 | bobo | clojure.contrib/json |
| 08:18 | bobo | or something, there is one in contrib |
| 08:18 | bobo | json-str and read-sjon |
| 08:18 | jkdufair | super. thanks so much. |
| 08:28 | Cozey | is it possible to do something like (let [field 'staticField] (. SomeClass field)) ? |
| 08:28 | clgv | How can I make clojure inline a very often called function? I saw snippets somewhere - is there any documentation on that? |
| 08:29 | jkdufair | Cozey: I would think you'd need to write a macro for that |
| 08:30 | fliebel | clgv: Sounds interesting. What does inlining do? I know some functions use :inline in the meta, but I doubt it's the same thing. |
| 08:30 | clgv | fliebel: I think that's what I saw too. But I didn't find documentation on it |
| 08:31 | fliebel | clgv: I did, somewhere on the assemba space I think. |
| 08:31 | raek | Cozey: at runtime, you need reflection for that |
| 08:31 | clgv | I have function that is called around 4,000,000 times in 10 iterations. so it would be a good candidate ;) |
| 08:32 | Cozey | jkdufair: but when I make a macro and pass a variable to it, say: field, and then unquote it with ~foo, i still get (. Class field), and not the value of field |
| 08:32 | jkdufair | Cozey: oh boy. that's when i usually start drinking to truly understand macro expansion |
| 08:33 | Cozey | i know you're right |
| 08:33 | Cozey | but i feel like i'm missing some 'deref' or something similar |
| 08:33 | raek | macros are just functions that transform code in form of data structures |
| 08:34 | fliebel | clgv: http://www.assembla.com/spaces/clojure/search?q=inline |
| 08:34 | raek | Cozey: . is a special form and cannot be "applied" at runtime. the compiler needs to know the name of the field when the code is complied |
| 08:34 | raek | *compiled |
| 08:34 | jkdufair | yes and rockets are just tubes with propellants that go up in the sky :-) |
| 08:35 | fliebel | clgv: So, no direct documentation, but a few issues mentioning the feature. |
| 08:35 | Cozey | so is it possible to get a field by name known during runtime, without resolving to eval ? |
| 08:35 | raek | Cozey: use clojure.lang.Reflector/getInstanceField if you need to do it at runtime https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Reflector.java#L238 |
| 08:36 | clgv | fliebel: guess I have to check clojure source to see where it is used |
| 08:36 | Cozey | raek: ok thanks, this seems to be what i needed! |
| 08:36 | fliebel | clgv: https://github.com/clojure/clojure/blob/b578c69d7480f621841ebcafdfa98e33fcb765f6/src/clj/clojure/core.clj#L809 |
| 08:37 | clgv | fliebel: exactly the one I just clicked ;) |
| 08:37 | clgv | so well. it seems I have to repeat the definition in the inline statement |
| 08:37 | raek | Cozey: macros can be an alternative too (and would yield more performant code). it depends on how you are going to use it. |
| 08:38 | clgv | or define a macro for it ;) |
| 08:38 | fliebel | clgv: I think it's like definline for functions :) |
| 08:39 | Cozey | raek: yes but with macros i would need to know all the fields on compile time? |
| 08:39 | Cozey | without using Reflector |
| 08:39 | raek | (defmacro field-accessor [field-name] `(fn [instance#] (. instance# ~field-name))) |
| 08:40 | raek | Cozey: yes, but if the macro can figure out the field name at compile time (you have the whole clojure language at your disposal) then it would work |
| 08:40 | Cozey | agreed |
| 08:42 | clgv | fliebel: definline seems about right |
| 08:42 | AWizzArd | definline is the correct choice. |
| 08:52 | pdk | (doc definline) |
| 08:52 | clojurebot | "([name & decl]); Experimental - like defmacro, except defines a named function whose body is the expansion, calls to which may be expanded inline as if it were a macro. Cannot be used with variadic (&) args." |
| 08:53 | clgv | the syntax is a bit odd. seems you have to wrap the body into syntaxquotes |
| 08:54 | clgv | and use unquotes for the params everywhere |
| 08:55 | pdk | makes it just like macros already then! |
| 08:56 | clgv | I think it should be possible to do it without |
| 08:58 | fliebel | $source definline |
| 08:58 | sexpbot | definline is http://is.gd/bNmEu0 |
| 08:58 | fliebel | It actually adds the thing to the meta data. |
| 08:59 | fliebel | clgv: This just works: (definline blah [foo] (println foo)) |
| 09:00 | clgv | fliebel: my code with let-statement and more, does not ;) |
| 09:00 | fliebel | code? |
| 09:00 | clojurebot | peepcode is a commercial screencast series; see the Clojure one at http://peepcode.com/products/functional-programming-with-clojure by technomancy |
| 09:01 | clgv | I did wrap it into syntax quotes now. |
| 09:03 | clgv | I have to check both versions for a performance comparison now |
| 09:04 | chouser | definline essentially defines both a macro and a function with the same name |
| 09:05 | chouser | then Clojure chooses which to use at compile time based on how it's used. |
| 09:06 | fliebel | chouser: I guess that does not mean I can do macro tricks, and still use it as a function? |
| 09:06 | fliebel | And, in which cases is the macro used? |
| 09:07 | clgv | chouser: yes, that's what I saw. The question is: do I really need to use syntaxquotes? It didnt compile with out them |
| 09:07 | chouser | you *can* do (some) macro tricks, but they may only do what you mean in the macro version |
| 09:09 | clgv | I don't need macro tricks - inlining is sufficient^^ |
| 09:09 | fliebel | clgv: Can you paste an example of why you need syntax quotes? |
| 09:10 | fliebel | Ah, I see... |
| 09:11 | clgv | clgv: no minimal that you can run since there are a lot of dependencies. just try to use a let and an if-statement with several comparisons and additions. |
| 09:11 | fliebel | clojure.lang.Symbol cannot be cast to java.lang.Number |
| 09:12 | chouser | the macro version is used when the var is named literally at the head of a list |
| 09:12 | chouser | so (foo ...) uses the macro, (map foo ...) and ((identity foo) ...) use the fn |
| 09:12 | clgv | hmm performance benchmark show no significant improvement. seems the function call is no overhead for this case |
| 09:13 | chouser | clgv: the HotSpot JVM will inline function calls at runtime |
| 09:13 | clgv | I had about 230000 calls |
| 09:13 | clgv | chouser: it seems to do a pretty good job here. |
| 09:14 | fliebel | chouser: So what is a good use case for definline? |
| 09:14 | chouser | the reason definline exists is to allow for unboxed primitives. Of course there's new support for those in 1.3a4 |
| 09:15 | fliebel | So, definline is useless as of 1.3? |
| 09:15 | clojurebot | I don't understand. |
| 09:15 | chouser | I wouldn't be shocked if Rich removes :inline, but I would miss it. It's fun to exploit. |
| 09:15 | clgv | lol poor bot ;) |
| 09:16 | fliebel | chouser: Exploit? You mean makinf the fn do something unexpected when inlined? |
| 09:16 | chouser | yeah. |
| 09:18 | chouser | (definline add [a b] (if (and (number? a) (number? b)) (+ a b) `(+ ~a ~b))) |
| 09:19 | chouser | can you see what that does? |
| 09:20 | AWizzArd | This is evil! |
| 09:20 | clgv | good question. first case adds the numbers second case returns code that is an add statement |
| 09:21 | AWizzArd | First case is doing the addition at macro expansion time. |
| 09:21 | clgv | second-case is only used in macroexpansion time |
| 09:21 | chouser | everyone's right! |
| 09:21 | Chousuke | that's evil. |
| 09:21 | chouser | yes, evil. |
| 09:21 | AWizzArd | The second case calls a function + which is probably defined for a specific NS, where cores + is excluded. |
| 09:21 | chouser | well, useless at least |
| 09:22 | chouser | AWizzArd: nah, that's fine as clojure.core/+ |
| 09:22 | Chousuke | but hm |
| 09:23 | Chousuke | how does it work when you call it as a function? |
| 09:23 | AWizzArd | Chousuke: second case. |
| 09:23 | chouser | definline uses the macro with symbol arguments it provides itself in order to create the function version |
| 09:24 | AWizzArd | It is just a hack for something that the compiler potentially could do: replace literals. |
| 09:24 | chouser | It is the compiler! :-D |
| 09:24 | clgv | on repl it seems to have a "good" behavior |
| 09:24 | fliebel | chouser: I can't get it to work wrong. |
| 09:25 | chouser | yeah, it may not be evil. Closer to useless. |
| 09:25 | fliebel | makeing one of them * would be evil :) |
| 09:25 | chouser | so (add 1 2) does the addition at macroexpand time, putting 3 literally in the resulting code |
| 09:26 | chouser | (let [a 1] (add a 2)) still calls the macro version, but sees that a isn't a number and puts (+ a 2) in the code |
| 09:27 | chouser | with (map add [1 2] [3 4]), the compiler sees it can't call add as a macro and uses the function version, which of course is essentially (fn add [a b] (+ a b)) |
| 09:28 | AWizzArd | And Clojures + can not be optimized in such a way that (+ 1 2) is replaced by a literal 3. |
| 09:29 | chouser | I have used similar techniques to examine at compile time var values, do Java reflection, and generate substantially faster code, but fall back on perfectly acceptable runtime reflection when used as a function. |
| 09:29 | chouser | AWizzArd: why is that? |
| 09:30 | chouser | though I now think that's probably too much magic, despite how much fun it was. It's probably better to provide separate macro and function and let the user choose in such cases. |
| 09:31 | AWizzArd | Clojure can not know what + means until the program runs, because there is no defconstant. |
| 09:31 | AWizzArd | (def + -) |
| 09:31 | AWizzArd | (+ 10 2) |
| 09:31 | clojurebot | *suffusion of yellow* |
| 09:31 | AWizzArd | ,(let [+ -] (+ 10 2)) |
| 09:31 | clojurebot | 8 |
| 09:31 | AWizzArd | Dynamically typed. |
| 09:32 | chouser | the compiler can tell the difference there |
| 09:32 | chouser | and in fact does so. |
| 09:32 | AWizzArd | What about (in-ns 'clojure.core) (def + -) (in-ns 'my.ns) |
| 09:33 | AWizzArd | Functions can be changed at runtime in Clojure. |
| 09:33 | AWizzArd | This means that during compile time it is not known what a call will actually do. |
| 09:33 | chouser | Clojure assumes vars don't change from being macros to functions or vice-versa at runtime. |
| 09:34 | AWizzArd | Yes okay, macros will stay macros, fns will stay fns. However, the value of the var may change. |
| 09:35 | AWizzArd | I can do a (defn foo [] 1) and then after this (defn foo [] 2) |
| 09:35 | AWizzArd | I can eval things at runtime that changes the code. So during compile time we can not optimize such things away without using your definline trick, which is able to do it. |
| 09:37 | chouser | Clojure could inline such things if it also inlined a check to make sure the value of the var hasn't changed. |
| 09:38 | AWizzArd | (foo x) could mean anything at runtime. |
| 09:38 | AWizzArd | Its meaning could change constantly. |
| 09:38 | chouser | no, foo must be either a var or a local |
| 09:39 | AWizzArd | Vars can be def'ed. |
| 09:39 | chouser | if it's a var, it's known at compile time to be a specific var in a specific namespace |
| 09:39 | AWizzArd | Yes, but it's value is not known. |
| 09:40 | chouser | usually it's value *is* known at compile time, and usually it won't change. |
| 09:40 | chouser | so Clojure could inline the current value, preceeding that inlined code with a check to make sure the var's value hasn't changed. |
| 09:40 | chouser | if it has, it would have to call out to a slower path instead of using the inlined version. |
| 09:40 | AWizzArd | usually yes, in nearly all cases |
| 09:40 | fdaoud | its value |
| 09:41 | AWizzArd | But it is not known 100%. |
| 09:41 | AWizzArd | In a loop foo could change constantly (if (= user-input 10) (defn foo [] 1) (defn foo [] 2)) |
| 09:41 | chouser | in practice, Clojure doesn't have to do this because HotSpot already does. |
| 09:41 | AWizzArd | Yes, HotSpot can do it at runtime. |
| 09:42 | AWizzArd | With more (static) information during compiletime however it could be done by the compiler. |
| 09:42 | chouser | I just exaplained how it could be done at compile time by the compiler. |
| 09:42 | AWizzArd | For example I sometimes wished there was a defconstan. |
| 09:43 | AWizzArd | Yes, the compiler can add an if. |
| 09:43 | AWizzArd | If it were known at compile time that a function could never change then this if would not be required too. |
| 09:43 | chouser | this gives you the benefit of inline performance in the most common cases without giving up the features of dynamic redefinition when you really need it. |
| 09:44 | chouser | even if you didn't know you were going to need it when you wrote that code |
| 09:44 | AWizzArd | Yes. |
| 09:45 | chouser | Clojure 1.3 now reduces the overhead required in that 'if' even more, and is part of the general speed improvement people are seeing there. |
| 09:45 | AWizzArd | My point is that your definline can do an optimization during macro expansion time which can not be done as long we want a dynamic system. |
| 09:46 | AWizzArd | How does it reduce an overhead in 'if'? |
| 09:48 | mtopolnik | i'm having a hard time with lazy-xml |
| 09:49 | mtopolnik | as soon as i access an element, it eagerly parses its whole contents |
| 09:49 | chouser | the details grow fuzzy in my head. I think it has something to do with in 1.2 each var had it's own volatile while in 1.3 all non-dynamic vars share a single global "var version" counter |
| 09:50 | mtopolnik | e.g. <root><first/><second><a/><a/><a/>......</second></root> |
| 09:50 | mtopolnik | as soon as i reach second, it parses all the a's |
| 09:50 | mtopolnik | even if i just ask for the :tag of second |
| 09:51 | mtopolnik | i've tried with xml-zip as well, but same problems |
| 09:54 | mtopolnik | is this behavior expected? |
| 09:56 | AWizzArd | chouser: I see. |
| 10:45 | fliebel | $seen dnolen |
| 10:45 | sexpbot | dnolen was last seen quitting 18 hours ago. |
| 10:59 | mattmitchell | i'm attempting to build up a string, conditionally. this is harder than i thought due to immutable state. the only thing i can think of is to use nested "let"s. |
| 10:59 | mattmitchell | does that seem like an ok solution? |
| 11:01 | fliebel | mattmitchell: A let binding can refer to previous bindings. ##(let [a 1 b (+ 1 a)] b) |
| 11:01 | sexpbot | ⟹ 2 |
| 11:01 | cemerick | mattmitchell: probably, but others may be better. e.g. str ignores nil arguments, so… |
| 11:01 | cemerick | &(apply str ["foo" (when false "bar") "baz"]) |
| 11:01 | sexpbot | ⟹ "foobaz" |
| 11:02 | mattmitchell | interesting |
| 11:02 | pdk | if you're building it up iteratively see if you can translate that into some recursive form with each call adding another piece to the return value |
| 11:02 | fliebel | You should also look at -> ##(-> "foo" (str "bar") (str "baz")) |
| 11:02 | sexpbot | ⟹ "foobarbaz" |
| 11:02 | raek | I guess one way could be to let each part of the string to be constructed to, either to some string value if it's going to be included, or to the empty string if it's not, and then just concatenate all the parts |
| 11:02 | pdk | or if you really think it'll be best to just do it iteratively stick the string value inside an atom which you can handle mutably |
| 11:03 | mattmitchell | wow thanks. good stuff. |
| 11:03 | cemerick | pdk: I can't say I've ever seen a scenario where that would make sense. |
| 11:06 | raek | (let [h (if-not (zero? hours) (format "%02d:" hours) ""), m (if-not (or (zero? hours) (zero? minutes)) (format "%02d:" minutes) ""), s (format ":%02d" seconds)] (str h m s)) |
| 11:22 | mattmitchell | raek: thanks. nice example. |
| 11:25 | mattmitchell | ,(contains? [1 2] 1) |
| 11:25 | clojurebot | true |
| 11:25 | fliebel | Has anyone here worked with Logos? I mean, you know, did some actual stuff with it. |
| 11:25 | mattmitchell | ,(contains? [1] 1) |
| 11:25 | clojurebot | false |
| 11:25 | mattmitchell | ... what's up with (contains? [1] 1) being false? |
| 11:25 | fliebel | mattmitchell: Common pitfall, contains? checks for index. |
| 11:25 | mattmitchell | fliebel: ah :) |
| 11:26 | fliebel | Try ##(some #{1} [3 4 5 1]) |
| 11:26 | sexpbot | ⟹ 1 |
| 11:26 | mattmitchell | ,(some [1] [1]) |
| 11:26 | clojurebot | java.lang.IndexOutOfBoundsException |
| 11:27 | fliebel | with a set, not a vector. |
| 11:28 | mattmitchell | ,(set [12]) |
| 11:28 | clojurebot | #{12} |
| 11:28 | mattmitchell | ,(some (set [1]) 1) |
| 11:28 | clojurebot | java.lang.IllegalArgumentException: Don't know how to create ISeq from: java.lang.Integer |
| 11:28 | fdaoud | ,(contains? [4 5] 1) |
| 11:28 | clojurebot | true |
| 11:28 | fdaoud | goof |
| 11:28 | mattmitchell | ,(some (set [1]) [1]) |
| 11:28 | clojurebot | 1 |
| 11:29 | chouser | ,(#{4 5} 1) |
| 11:29 | clojurebot | nil |
| 11:29 | chouser | ,(#{4 5} 5) |
| 11:29 | clojurebot | 5 |
| 11:30 | sritchie | pandora |
| 11:30 | sritchie | whoops, sorry, quicksilver kind of abandoned me there |
| 11:30 | fliebel | Are there javadocs for clojure.core? I'd be interested in the "known subclasses", so I can tell everything in Clojure that implements IFn. |
| 11:48 | Vinzent | Is it correct that (symbol "") returns something? |
| 11:49 | Vinzent | and not throws exception |
| 11:50 | raek | &(some (fn [x] (if (even? x) [:found-it x] nil))) [1 3 5 6 7]) |
| 11:50 | sexpbot | java.lang.IllegalArgumentException: Wrong number of args (1) passed to: core$some |
| 11:50 | raek | &(some (fn [x] (if (even? x) [:found-it x] nil)) [1 3 5 6 7]) |
| 11:50 | sexpbot | ⟹ [:found-it 6] |
| 11:50 | raek | &(symbol "") |
| 11:50 | sexpbot | ⟹ |
| 11:51 | raek | &(class (symbol "")) |
| 11:51 | sexpbot | ⟹ clojure.lang.Symbol |
| 11:51 | raek | Vinzent: seems like it returns a symbol, whose name is the empty string... |
| 11:51 | Fossi | nifty |
| 11:51 | Fossi | &(symbol "a") |
| 11:51 | sexpbot | ⟹ a |
| 11:52 | fliebel | &@clojure.java.javadoc/*local-javadocs* |
| 11:52 | sexpbot | java.lang.ClassNotFoundException: clojure.java.javadoc |
| 11:53 | raek | &(require 'clojure.java.javadoc) |
| 11:53 | sexpbot | java.security.AccessControlException: access denied (java.util.PropertyPermission os.name read) |
| 12:03 | fliebel | All classes implementing IFn: AFn, AFunction, AMapEntry, APersistentMap, APersistentSet, APersistentVector, ATransientSet, Keyword, LispReader.CharacterReader, LispReader.CommentReader, LispReader.DeprecatedWrappingReader, LispReader.DiscardReader, LispReader.DispatchReader, LispReader.EvalReader, LispReader.FnReader, LispReader.ListReader, LispReader.MapReader, LispReader.MetaReader, LispReader.RegexReader, LispReader.SetReader, LispReader.Strin |
| 12:05 | fliebel | What does a MapEntry do when called? |
| 12:06 | dnolen | wow, Google 'thread-local binding' and the first thing that comes up is Clojure. Neat idea that also seems to have origin in Mozart/Oz, seems like you could easily build Computation Spaces as described in CTM as a result. |
| 12:07 | chouser | whoa, the readers are IFns? I had never noticed. |
| 12:07 | fliebel | Hey dnolen! The Reasoned Schemer arrived yesterday. Could you shine some light on the differences between that and Logos? |
| 12:08 | dnolen | fliebel: logos.minikanren is a faithful implementation of the original ideas with considerable changes to get better performance, as well a solution to the fact that Clojure does support pairs. |
| 12:08 | dnolen | Clojure doesn't support pairs I mean. |
| 12:09 | fliebel | dnolen: what pairs? |
| 12:09 | dnolen | fliebel: (a . b) where b is not a proper tail is allowed in Scheme/Common-Lisp, not allowed in Clojure |
| 12:09 | fliebel | I also noticed that fresh seems to be replaced by exist? |
| 12:14 | chouser | (1 . 2) is what is returned by (cons 1 2) |
| 12:14 | fliebel | ah |
| 12:14 | chouser | I've always found the syntax to be confusing |
| 12:15 | chouser | (1 2 3 4) is the same as (1 . (2 . (3 . (4 . nil)))) I believe |
| 12:15 | fliebel | dnolen: And what is this solution? |
| 12:15 | fliebel | chouser: In Scheme, or in Clojure as well? |
| 12:15 | chouser | Clojure doesn't support dotted pairs. the "rest" of a seq is always a seq or nil, never a number or anything else. |
| 12:16 | chouser | ,(cons 1 2) |
| 12:16 | clojurebot | java.lang.IllegalArgumentException: Don't know how to create ISeq from: java.lang.Integer |
| 12:16 | fliebel | &(cons 1 (cons 2 nil)) |
| 12:16 | sexpbot | ⟹ (1 2) |
| 12:17 | chouser | right. well-behaved lists, not dotted pairs of arbitrary values. |
| 12:17 | fliebel | I still don't understand the dots, then we could just as well start writing (1 + 1) |
| 12:17 | dnolen | fliebel: oh yeah, my version is based on the version in William Byrd's thesis (2009). The Reasoned Schemer is based on a earlier version (2005) |
| 12:18 | chouser | in general I think where you would use pairs in other lists, you use vectors in Clojure. |
| 12:18 | dnolen | fliebel: main differences, is fresh -> exist and they committed to interleaving search and abandoned Prolog depth-first option |
| 12:18 | chouser | fliebel: yes, the syntax is confusing. Maybe it helps to think of ( . ) as the whole thing. The parens there don't really mean the same as they do in a regular list. |
| 12:19 | chouser | would be less confusing if pairs were written as <1 2> or something. So <1 <2 <3 nil>>> is (1 2 3) |
| 12:20 | fliebel | dnolen: Is the later an implementation detail, or something I'm going to need to worry about? |
| 12:20 | dnolen | fliebel: the solution was to come up with with a new datastructure called LConSeq. This supports the tail being something other than a proper seq - in particular an un-ground logic variable. |
| 12:20 | fliebel | chouser: Yea. |
| 12:20 | dnolen | LConsSeq I mean. |
| 12:21 | chouser | dnolen: record or type? |
| 12:21 | pdk | i thought clojure forced all lists to be proper lists |
| 12:21 | dnolen | fliebel: Prolog depth-first has issues. interleaving search prevents certain forms of divergence that exist in Prolog. |
| 12:21 | chouser | pdk: it does. Sorry to confuse, I'm talking about other lisps here. |
| 12:21 | dnolen | chouser: type. record adds a bunch of Seq stuff I don't want. |
| 12:24 | fliebel | dnolen: Thanks :) I only just did the first chapter of The Reasoned Schemer, and I'm really enjoying it. I'm trying to use Logos to try things out. |
| 12:24 | fdaoud | ,(let [a + + 2] (a + 4)) |
| 12:24 | clojurebot | 6 |
| 12:24 | dnolen | fliebel: cool, careful there's one major bug I haven't had time to tackle not sure if it'll crop up w/ their examples. |
| 12:26 | fliebel | dnolen: What is it? Surely not the set/map unification mentioned in the issue on github. |
| 12:27 | dnolen | fliebel: no, set/map unification works now. sets are a bit slow tho. issue is a bit hard to explain, but it has to do with cond-e. |
| 12:29 | fliebel | dnolen: I think you said something about a blog post about connecting the ends, any news on that? (I see what you meant with the book layout now :) |
| 12:30 | dnolen | fliebel: TRS is particularly sweet in that you come to understand the fundamental idea behind Prolog in about ~200 LOC. The hardest 200 LOC I've ever read :) |
| 12:32 | dnolen | fliebel: I'll need to find some time, but the book glosses over half of the implementation. Unification/substitution is a tough topic, they cover that. Then they completely skip over how they produce the stream of solutions. William Byrd's thesis covers that, but their implementation is dense. |
| 12:34 | dnolen | fliebel: I think my version is easier to follow, since Clojure has real type dispatch. |
| 12:35 | dmiles_afk | my dream intepretor is LISP+PROLOG+CLOJURE on a JVM |
| 12:35 | dmiles_afk | or even .NET |
| 12:35 | dmiles_afk | oh but making it very efficient :) |
| 12:39 | fliebel | dnolen: Cool, awesome work :) gtg now. I think I'll have loads of questions for you later, when I catch you here the next time :) |
| 12:58 | fliebel | What are RestFn and PersistentTreeMap? |
| 12:58 | phenom_ | hey everyone, i was having a convo with a colleague and he points out that multimethods make explicit use of casting to dispatch and casting is wrong ... how do i respond ? |
| 12:59 | fliebel | phenom_: Casting? |
| 13:00 | amalloy | phenom_: i suggest telling him he is crazy |
| 13:01 | __name__ | good morning |
| 13:01 | Scriptor | morning __name__ |
| 13:01 | phenom_ | amalloy: I need more than that :P I try to explain that we separate the decision process from the code acting on the parameters, which he responds with "well, just because they're separate, doesn't mean it's not effectively a huge if/else check" |
| 13:02 | raek | phenom_: like in java? if (x instanceof Foo) { Foo y = (Foo) x; ... } |
| 13:02 | chouser | where is casting being done? what's wrong with casting? what's wrong with a huge if/else check? |
| 13:02 | chouser | I'm clearly confused. |
| 13:02 | __name__ | can you include a route as a subdirectory of a route in compojure? so, e. g., foo/* is matched as * in another route? |
| 13:02 | amalloy | phenom_: the difference is it's not centralized like an if/else |
| 13:03 | phenom_ | but it still is just a large if/else check for any types i want to handle right ? |
| 13:03 | amalloy | if apache released a clojure library with a multimethod in it, i could add my own types of objects and have them handled flawlessly by the existing multi |
| 13:03 | amalloy | try doing that with a "real" if/else |
| 13:03 | dmiles_afk | if (x instanceof Foo) ((Foo)x).bar(); benches way faster than just ((Foo)x).bar(); btw |
| 13:04 | phenom_ | so it's a sort of dynamic if/else |
| 13:04 | dmiles_afk | after JIT |
| 13:04 | phenom_ | i can add as I like |
| 13:04 | raek | phenom_: I think that two of the points with multimethods are that their implementations is an open set (can be extended by others) and they don't have to be defined inside a type in order for it to be able to participate |
| 13:05 | amalloy | dmiles_afk: really? that's surprising |
| 13:05 | raek | also, the hierarchy used for selecting the method does not have to be the java class hierarchy |
| 13:05 | amalloy | even if x is always a Foo? |
| 13:05 | dmiles_afk | amalloy: CHECKCAST is removed in the ifelse |
| 13:05 | phenom_ | but to participate, for most scenarios I'll need to do a cast |
| 13:05 | phenom_ | (eg. vector? seq? etc) |
| 13:06 | raek | clojure is dynamically typed, so you don't cast more than usual |
| 13:06 | hiredman | that is not a cast |
| 13:06 | dmiles_afk | but what saddens me is that ((Foo)x).bar(); is faster than x.bar(); |
| 13:06 | chouser | I'm so confused. |
| 13:06 | dmiles_afk | if "Foo" inherits the method |
| 13:07 | raek | phenom_: what do you mean by "cast"? |
| 13:07 | phenom_ | eek, isn't a call to vector? a class check ? |
| 13:07 | dnolen | multifns use a dispatch table and they cache lookups. I don't know where if/else or casting comes into the picture. |
| 13:07 | dnolen | phenom_: ^ |
| 13:08 | dmiles_afk | so hopfully in bytecode clojure if/else casts to the actual implmneting type |
| 13:09 | raek | for me, a (dynamic) cast is the operation of turning an Animal reference into a Cat reference when you know it is one |
| 13:09 | dmiles_afk | so hopfully in bytecode clojure if instanceofs and then casts to the actual implmneting type |
| 13:10 | raek | clojure does casts when doing java method invocations. clojure fns are Objects -> Object |
| 13:10 | dmiles_afk | thats good it does assume coercions |
| 13:11 | dmiles_afk | thats good it DoesNT assume coercions |
| 13:11 | phenom_ | dnolen: i mean deciding which function to call is done with a class check (instanceof) ... get (vector?) |
| 13:12 | amalloy | phenom_: no |
| 13:12 | raek | phenom_: a multimethod has a dispatch function that yields a dispatch value when passed the arguments of the invocation. this function can be 'type' |
| 13:12 | dmiles_afk | i'd kinda hope that (vector? ..) means it implements a IClojureVector or somesuch |
| 13:12 | amalloy | pseudocode: (let [dispatch-fns {Vector vector-fn, List list-fn}] ((dispatch-fns (class arg)) arg)) |
| 13:13 | chouser | phenom_: when a multimethod is called, your dispatch function is invoked first. It is not uncommon for the dispatch fn to get the class of the first arg, but it can do whatever you want. |
| 13:13 | dmiles_afk | as in instanecof IClojureVector |
| 13:13 | amalloy | but it doesn't have to be a class-based dispatch |
| 13:13 | raek | phenom_: then you define implementations for some dispatch values (e.g. String, Integer, Keyword, etc) |
| 13:13 | dmiles_afk | ah thats nice its not bound to java class structure |
| 13:14 | phenom_ | right, so I am checking the class ... i understand you can dispatch on anything and return any value also |
| 13:14 | chouser | if you ask for the class of the object, that's what you get. Note this is not instanceof. |
| 13:14 | amalloy | somewhere around here i have a multimethod that dispatches on the size of its argument with (defmulti blah count) |
| 13:15 | chouser | after your dispatch fn returns something (such as a class), clojure does a (memoized) heirarchy lookup to find the appropriate defmethod to call. |
| 13:15 | phenom_ | but even for functions like get .. internally it needs to check class type (PersistentVector or PersistentMap) to properly dispatch ? |
| 13:15 | amalloy | chouser: as a side note, i imagine it dumps out the whole memoization cache if you add a new dispatch fn |
| 13:16 | chouser | amalloy: I believe that's correct. or if you change the heirarchy. :-) |
| 13:16 | dmiles_afk | one day i am sure it could be surgicall dumped |
| 13:16 | phenom_ | is there a detailed book that goes into the internals? or is it just a learn by reading code kinda thing ? |
| 13:17 | amalloy | phenom_: the internals are not very interesting. you are ascribing properties to them that they do not have |
| 13:17 | raek | the comparison would be more like x.getClass == c rathern than x instanceof C |
| 13:17 | chouser | phenom_: clojure.core/get is not a multimethod. |
| 13:17 | amalloy | in pseudo-java: switch (foo.getClass()) {case List: foo.length(); case Map: foo.size();} |
| 13:18 | amalloy | and because you can add new case statements at any time, it's a million times less brittle than an if/else or actual switch |
| 13:18 | chouser | phenom_: clojure.core/get currently has an if/else inside to do the right thing. It may later be done with a protocol, which would amount to much the same thing. |
| 13:19 | amalloy | chouser: really? i would have expected that it casts to IAssociative and calls the interface method or something |
| 13:19 | phenom_ | chouser: RT.get does instance checks no ? |
| 13:19 | phenom_ | *class check |
| 13:20 | dnolen | phenom_: getting a class and an isa? check is like the fastest thing possible on the JVM. you can do that a billion times in less than a second. also you can us a class as a map key, if you don't find it, then you do the isa? check on all keys, once you find it, you cache it. |
| 13:20 | chouser | amalloy: it does, but besides supporting ILookup and IPersistentSet, get supports java.util.Map, strings and arrays. |
| 13:20 | dnolen | ,{(class []) :look-ma-a-class-as-a-key} |
| 13:20 | clojurebot | {clojure.lang.PersistentVector :look-ma-a-class-as-a-key} |
| 13:20 | amalloy | chouser: yeah, i'm reading it now |
| 13:21 | chouser | amalloy: note the splitting of the 'get' method into 'getFrom'? I think that's to support better inlining by hotspot and/or branch prediction in the CPU. |
| 13:23 | amalloy | chouser: hm, i wonder why IPersistentSet doesn't extend ILookup |
| 13:23 | chouser | It may just be historical. I think ILookup is newer. |
| 13:24 | chouser | I need to write a ticket to extract Sequential from ISeq |
| 13:32 | mattmitchell | (doc select-keys) |
| 13:32 | clojurebot | "([map keyseq]); Returns a map containing only those entries in map whose key is in keys" |
| 13:32 | mattmitchell | ,(select-keys {:one 1 :two 2 :three 3} [:two :one]) |
| 13:32 | clojurebot | {:one 1, :two 2} |
| 13:33 | mattmitchell | hmm, is there a way to specify the keys you want, in order? |
| 13:33 | mattmitchell | oh oops... what i mean is, is there a way to specify the values you want, in order? |
| 13:33 | chouser | ,(map {:one 1 :two 2 :three 3} [:two :one]) |
| 13:33 | clojurebot | (2 1) |
| 13:33 | mattmitchell | chouser: awesome thanks |
| 13:34 | amalloy | chouser, mattmitchell: also ##((juxt :two :one) {:one 1 :two 2 :three 3}) |
| 13:34 | sexpbot | ⟹ [2 1] |
| 13:34 | mattmitchell | ,(doc juxt) |
| 13:34 | clojurebot | "([f] [f g] [f g h] [f g h & fs]); Alpha - name subject to change. Takes a set of functions and returns a fn that is the juxtaposition of those fns. The returned fn takes a variable number of args, a... |
| 13:35 | mattmitchell | cool |
| 13:35 | amalloy | &(doc juxt) |
| 13:35 | sexpbot | ⟹ "([f] [f g] [f g h] [f g h & fs]); Alpha - name subject to change. Takes a set of functions and returns a fn that is the juxtaposition of those fns. The returned fn takes a variable number of args, and returns a vector containing the result of applying each fn to the... http://gist.github.com/821050 |
| 13:35 | mattmitchell | ,(prn "test") |
| 13:35 | clojurebot | "test" |
| 13:35 | mattmitchell | &(prn "test") |
| 13:35 | sexpbot | ⟹ "test" nil |
| 14:10 | markskilbeck | Hi, all. Say I have a vector of 10 elements, and I want to change 2 random elements of it. How would I go about writing a function to do that? |
| 14:10 | markskilbeck | dotimes? |
| 14:12 | amalloy | markskilbeck: do you actually want to change them in place, or return a modified copy? |
| 14:12 | amalloy | (if the former, reconsider because that is evil) |
| 14:12 | markskilbeck | A modified copy, I suppose. |
| 14:12 | rata_ | hi |
| 14:12 | markskilbeck | As is the way of clojure. |
| 14:12 | markskilbeck | Sup, rata_. |
| 14:12 | amalloy | in that case, you don't want anything that starts with "do" - those usually just perform side effects |
| 14:13 | markskilbeck | Noted. |
| 14:14 | amalloy | markskilbeck: you probably want to select two indices at random, then perform the swaps. you might be interested in the discussion fliebel and i had a week or two ago about shuffling |
| 14:14 | dnolen | ,(-> [1 2 3 4] (assoc (rand-int 4) 'foo) (assoc (rand-int 4) 'bar)) |
| 14:14 | clojurebot | [1 bar foo 4] |
| 14:14 | dnolen | no so thing as changing a vector in place anyway |
| 14:14 | dnolen | s/so/such |
| 14:14 | sexpbot | <dnolen> no such thing as changing a vector in place anyway |
| 14:14 | clojurebot | Gabh mo leithscéal? |
| 14:15 | markskilbeck | dnolen: That's fine, though if I then want to modify 3 indices, I've got to duplicate code. |
| 14:15 | amalloy | markskilbeck: iterate |
| 14:15 | markskilbeck | Ah! |
| 14:15 | markskilbeck | Bob's your mother's brother. |
| 14:16 | amalloy | &(nth (iterate #(assoc % (rand-int (count %)) 'foo) [1 2 3 4 5 6] 3) |
| 14:16 | sexpbot | java.lang.Exception: EOF while reading |
| 14:16 | amalloy | &(nth (iterate #(assoc % (rand-int (count %)) 'foo) [1 2 3 4 5 6]) 3) |
| 14:16 | sexpbot | ⟹ [foo 2 foo 4 5 foo] |
| 14:16 | amalloy | but this might result in hitting up the same index multiple times, resulting in fewer than N elements changing |
| 14:17 | markskilbeck | That's fine. |
| 14:21 | markskilbeck | So the (nth ... 3) takes the third? iteration? |
| 14:22 | amalloy | markskilbeck: it takes the fourth entry in the list, where the zeroth entry is the original vector |
| 14:23 | amalloy | https://gist.github.com/805747 is several different approaches to a very similar problem that you might be interested in |
| 14:23 | amalloy | and http://www.raynes.me/logs/irc.freenode.net/clojure/2011-02-01.txt contains a discussion of the above |
| 14:24 | markskilbeck | Brill. Thanks. |
| 14:25 | markskilbeck | Wait, why the 4th entry? I wanted to modify only 2 indices, but wouldn't that modify (possibly) 4? |
| 14:25 | amalloy | markskilbeck: it will modify up to three |
| 14:26 | amalloy | 0th entry modifies 0, 1st entry 1, 2nd entry up to 2... |
| 14:26 | amalloy | i think my original statement was poorly worded |
| 14:26 | markskilbeck | I see, I see. |
| 14:27 | amalloy | &(take 5 (iterate #(conj % 10) [])) |
| 14:27 | sexpbot | ⟹ ([] [10] [10 10] [10 10 10] [10 10 10 10]) |
| 14:27 | markskilbeck | amalloy: you're most helpful |
| 14:28 | amalloy | markskilbeck: you're welcome! |
| 14:31 | markskilbeck | And that is a _long_ discussion. |
| 14:32 | amalloy | markskilbeck: well it's an interesting topic :) |
| 15:13 | rata_ | LauJensen: I'm reading your post http://www.bestinclass.dk/index.clj/2009/10/brians-brain-echoes-from-the-web.html and don't understand why the 1d vector for the board representation is not accurate |
| 15:13 | LauJensen | rata_: Because there is no way to tell from a single index where exactly on the board you are, ie. left isn't simply -1 as it might move you up one row. It creates pretty patterns but its not Brians Brain anymore |
| 15:18 | rata_ | LauJensen: oh ok =) |
| 15:21 | rata_ | LauJensen: but the important thing was that using a 1d vector instead of a matrix made the performance improvement, so it's maybe worth fixing the neighbours fn |
| 15:21 | LauJensen | rata_: See Christophes follow-up posts for major performance boosts |
| 15:21 | LauJensen | He made it even faster than the CL version |
| 15:21 | rata_ | using clojure? |
| 15:23 | rata_ | LauJensen: where can I find Christophes follow-up posts? |
| 15:23 | rata_ | LauJensen: did he use clojure? |
| 15:24 | LauJensen | http://clj-me.cgrand.net/page/2/ |
| 15:26 | rata_ | thanks |
| 16:10 | rata_ | LauJensen: do you know if it's possible to make the rendering and the computation run at 25fps? I don't want to miss frames |
| 16:10 | rata_ | interesting optimizations has done cgrand to your code btw |
| 16:19 | amalloy | markskilbeck: out of curiosity what method did you end up using? |
| 16:40 | edoloughlin | Is there any hope of attaching clojure source to a referenced JAR file in Counterclockwise (e.g., clj-record)? |
| 16:54 | cinch | Moooooo |
| 17:00 | _2x2l | do the TheDeadline guys hang out around here? |
| 17:06 | cinch | (whois _2x2l) |
| 17:19 | TimMc | I've been using the *warn-on-reflection* flag, and was surprised to see that @dereferences do not carry their :tag metadata through. |
| 17:21 | amalloy | TimMc: @foo is sugar for (deref foo). how would you type-hint the deref function to make that work? |
| 17:21 | TimMc | Good question. |
| 17:22 | TimMc | I guess I'm still kind of fuzzy on how type hinting works. |
| 17:23 | amalloy | TimMc: it would require type-inference that clojure doesn't really have (yet?) |
| 17:25 | TimMc | So (. obj method arg) will not need reflection if arg is :tagged explicitly, and (. obj method (producer)) works similarly... but @arg is hiding a function call. |
| 17:26 | TimMc | I suppose you'd have to have some mechanism to say "my type is the same as parameter 3's type" or somesuch. :-/ |
| 17:28 | amalloy | TimMc: indeed, and java's generics do that |
| 17:29 | amalloy | public <T> T deref(IDeref<T> obj) {return obj.deref();} |
| 17:31 | TimMc | Oof, I really shouldn't be :tagging those (ref)s anyway -- it's their *contents* that I want to hint. |
| 17:33 | dnolen | TimMc: question is, what are you putting in refs that need type-hinting ? |
| 17:33 | TimMc | AffineTransform instances. |
| 17:34 | dnolen | TimMc: for what benefit? |
| 17:34 | TimMc | My graphics app needs to update those as the viewport changes. |
| 17:35 | TimMc | I don't want my coordinate transforms to get out of sync with the rotation, scaling, etc. |
| 17:35 | TimMc | I suppose that as long as they are only modified from the event loop I don't really need the transactions... |
| 18:01 | mattmitchell | how can i check if a string starts with a regexp? |
| 18:02 | amalloy | &(doc re-find) |
| 18:02 | sexpbot | ⟹ "([m] [re s]); Returns the next regex match, if any, of string to pattern, using java.util.regex.Matcher.find(). Uses re-groups to return the groups." |
| 18:02 | brehaut | use an start anchor in the regexp |
| 18:02 | amalloy | &(map #(re-find #"^blah" %) ["blahtwer" "wablah"]) |
| 18:02 | sexpbot | ⟹ ("blah" nil) |
| 18:10 | tomoj | xb |
| 18:58 | TimMc | I'm implementing an undo/redo buffer for my program. I think I should move my def'd userdat variables into a map, and then I can push the current map onto the undo buffer before I change data in response to the user. |
| 18:59 | TimMc | So, question: Is there a way to keep the :doc metadata? |
| 18:59 | TimMc | (on the individual wads of state that I keep for the user) |
| 19:00 | brehaut | ,(meta ^{:doc "foo"} {:a 1}) |
| 19:00 | clojurebot | {:doc "foo"} |
| 19:00 | tomoj | are you sure you want vars there? |
| 19:00 | TimMc | brehaut: I want doc on :a. :-/ |
| 19:01 | TimMc | Am I asking for something that doesn't exist? |
| 19:02 | tomoj | yes, keywords can't have metadata |
| 19:02 | brehaut | TimMc: if you want it on a keyword then yes |
| 19:02 | TimMc | That is, by consolidating a bunch of (def ^{:doc "stuff"} foo ()) into (def userdata {:foo ()}), I lose individual docstrings? |
| 19:03 | brehaut | ,^{:doc "foo"} :a |
| 19:03 | brehaut | for instance |
| 19:03 | clojurebot | Metadata can only be applied to IMetas |
| 19:03 | TimMc | Hmm, OK. |
| 19:03 | tomoj | are users of your program familiar with clojure? |
| 19:03 | brehaut | is clojurebot going to throw me the exception? |
| 19:03 | tomoj | that's the only way it makes sense to me for that stuff to be in vars |
| 19:03 | TimMc | tomoj: This is internal stuff. |
| 19:04 | tomoj | better question: does your program include a clojure repl? |
| 19:04 | TimMc | tomoj: What is the alternative? (This is an interactive graphics program using Swing, to give some context.) |
| 19:05 | tomoj | so how do you change the data in response to the user? |
| 19:05 | TimMc | I have components that have event listeners that call functions (to update state) that need to refer to the components. |
| 19:05 | tomoj | what I mean is, how do you update the state |
| 19:06 | tomoj | def, again? alter-var-root? what? |
| 19:06 | TimMc | def |
| 19:06 | TimMc | (again) |
| 19:06 | tomoj | ok, pretty sure what you're doing is evil then |
| 19:06 | TimMc | Hah, OK. |
| 19:06 | tomoj | maybe an atom would be better suited? |
| 19:07 | tomoj | hard to say since I still don't really get what you're doing. but vars aren't variables, and if you're treating them like the variables you're used to, it's probably bad |
| 19:08 | TimMc | I've done some functional programming in the past, but I've never had to deal with this much mutable state in that context before. |
| 19:08 | tomoj | the only reason you're even allowed to redef is for development |
| 19:08 | TimMc | OK, I will definitely keep that in mind! |
| 19:08 | brehaut | im also wondering if you are abusing the metadata stuff? |
| 19:09 | tomoj | the other state abstractions to look into are atoms, refs, and agents |
| 19:09 | brehaut | metadata is largely for tooling (or so i understand) |
| 19:10 | TimMc | brehaut: I doubt it. I just like using machine-discoverable doc syntax. |
| 19:10 | TimMc | If I ever use a smart IDE to work on my code, this *should* make it easier to work with. |
| 19:11 | TimMc | tomoj: I tried refs, but I think they're more high-powered than I need. Agents look scary and alien, but I will learn what to use them for at some point. |
| 19:12 | tomoj | with (def userdata (atom {:foo ()})) |
| 19:12 | brehaut | TimMc: refs are always a good safe bet |
| 19:13 | tomoj | you can do things like (swap! userdata update-in [:foo] conj 3) |
| 19:13 | tomoj | then (:foo @userdata) is (3) |
| 19:13 | brehaut | they have additonal coordination semantics so if you ever need to access two refs, they can be transactional |
| 19:14 | TimMc | STM, yeah |
| 19:14 | brehaut | however, if you just have a undo stack, current doc, redo stack structure (perfect case for a zipper) then all you'd need is an atom |
| 19:15 | TimMc | zipper... heard of, but never used one of those before! Exciting. |
| 19:15 | brehaut | TimMc: basically its a double linked singlely ended list |
| 19:16 | TimMc | Aren't they more like tree+cursor? |
| 19:16 | brehaut | descibed as a pair of singly linked list |
| 19:16 | brehaut | completely persistent |
| 19:16 | brehaut | i think there may be a couple of things with the same name |
| 19:17 | brehaut | or the tree version is a generalisation of the list version |
| 19:18 | TimMc | hmm |
| 19:18 | brehaut | i am trying to look it up to find some docs for you, but my internet is running slow as mollasas |
| 19:20 | TimMc | brehaut: Thanks, but I don't know if I need a dedicated data structure for this -- a couple of functions oughta take care of this. |
| 19:24 | brehaut | TimMc: im not sure i understand; an undo / redo stack and current state in a world with persistent data structures is exactly this thing |
| 19:25 | TimMc | Sure, but I can just use two lists and conj/rest. |
| 19:25 | TimMc | I'd effectively implement the same thing myself. |
| 19:26 | brehaut | yeah thats the bit i dont understand |
| 19:26 | TimMc | Well, I don't know the name of the thing I'd want to use instead, or if Clojure has it. |
| 19:29 | TimMc | If I find out, I'll happily switch to using it. :-) |
| 19:30 | TimMc | (Since I am very much still learning Clojure, I don't consider it a waste of time to try to reimplement things that I could just grab libraries for.) |
| 19:42 | amalloy | brehaut: i had a good non-tooling use of metadata. maybe it was evil, i dunno |
| 19:42 | brehaut | amalloy: im sure they exist, but im sure its the minority |
| 19:42 | amalloy | brehaut: agreed. i think it's the first time i've had a reason |
| 19:42 | amalloy | for meta of any kind |
| 19:48 | amalloy | if anyone's interested, i wanted to wrap up "get this from the database" in a function so i could pass it to non-db-aware code; i attached meta to the function about what kinds of things it was looking for so i could use it to write to the database if i needed to |
| 20:17 | rata_ | brehaut and amalloy: I use metadata for storing the connected components of a graph and not have to recompute them... don't know if that's considered evil |
| 20:17 | brehaut | rata_: my rule of thumb is 'is it actual data for my program' |
| 20:19 | brehaut | if its actual data, then i'd use a map or record |
| 20:20 | bytecolor | rata_: isn't that sort of how clojure.zip is implemented? |
| 20:20 | rata_ | it's not any additional data... it's computable from just the data it goes with |
| 20:21 | rata_ | bytecolor: I don't know... haven't looked at clojure.zip implementation |
| 20:27 | brehaut | bytecolor: zip attaches the functions used to create the zipper (eg branch? end? etc) but the actual path and context information is part of the zipper itself |
| 20:28 | bytecolor | ah, ok. I'd only peeked at the code a couple times. |
| 20:28 | amalloy | brehaut: "actual data" and "my program" seem almost too vague to be useful here |
| 20:29 | bytecolor | I think I've learned clojure mostly from reading the core and contrib source. |
| 20:30 | bytecolor | waiting on the dead tree version of the joy of clojure to come out |
| 20:30 | no_mind | Someone explain to me what exactly is this code snippet doing (map #(section-model % link-model) sections) |
| 20:31 | no_mind | wha tis % operator ? I cant find it even in cheatsheet |
| 20:32 | amalloy | no_mind: anonymous function shorthand |
| 20:32 | phenom_ | how do i add classes or dirs to the class path when i launch cake's swank ? |
| 20:32 | amalloy | #(foo % 10) === (fn [x] (foo x 10)) |
| 20:33 | no_mind | amalloy: is anonymous function shorthand #() ? |
| 20:34 | amalloy | er...yes, i guess? i don't understand the question |
| 20:38 | TimMc | no_mind: It's not an operator. |
| 20:38 | no_mind | k |
| 20:39 | TimMc | no_mind: #(... % ...) is equivalent to something like (fn [x] ... x ...) |
| 20:39 | no_mind | k |
| 20:39 | TimMc | It's the single argument to the anonymous function. |
| 20:39 | brehaut | no_mind: http://clojure.org/reader |
| 20:39 | brehaut | under macro characters, dispatch |
| 20:41 | TimMc | no_mind: Note that I forgot an important pair of parens in my expansion. |
| 20:45 | TimMc | brehaut: If you're at all curious, I finally pushed my in-progress graphics app to github: https://github.com/timmc/CS4300-HW3/blob/master/src/timmcHW3/core.clj |
| 20:48 | TimMc | (I should add a "n00b at work" warning in the readme.) |
| 20:49 | brehaut | TimMc: im not sure why you need a seperate ref for past and future |
| 20:50 | brehaut | (def history (ref [[], []])) would suffice |
| 20:50 | TimMc | True. What's the advantage? |
| 20:50 | brehaut | simplicity |
| 20:51 | TimMc | And I suppose some conceptual atomicity as well. |
| 20:51 | brehaut | yes |
| 20:51 | brehaut | i dont think you need 3 ref-sets; you should be able to get by with one |
| 20:52 | brehaut | ffirst on your history ref will give you the current state |
| 20:53 | TimMc | Yeah, I did debate on whether to have the current state as part of the undo history or not. |
| 20:53 | TimMc | I need to think about that some more. |
| 20:53 | brehaut | it makes the updating of the undo and redo stack trivial |
| 20:53 | brehaut | you dont have to sidestep through the current state |
| 20:56 | TimMc | I've also been considering whether I want a more complex undo/redo system. |
| 20:56 | brehaut | no, you want to get your program working first :P |
| 20:56 | TimMc | Notice how most word processors will undo chunks of typing at a time? |
| 20:58 | TimMc | True. |
| 20:58 | pdk | hey uh |
| 20:58 | pdk | which libraries are clojurebot/sexpbot using for irc interaction again |
| 20:58 | TimMc | I wasn't planning on doing fancy skiplist history quite yet. |
| 21:00 | TimMc | pdk: clojurebot appears to be using PircBot, a Java thingy. |
| 21:01 | TimMc | I bet both are open source on github. |
| 21:02 | TimMc | pdk: https://github.com/Raynes/sexpbot |
| 21:09 | pppaul | anyone home? |
| 21:09 | pppaul | i'm feeling really stupid with a simple clojure problem i have regarding maping over a dictionary |
| 21:10 | brehaut | pppaul: oh? |
| 21:10 | pppaul | (map identity (vals v)) |
| 21:10 | pppaul | ({:id 6822400, :name "Adam Tran"} {:id 43535, :name "Sdfsfsd"}) |
| 21:10 | pppaul | solve360.name-fixer> (map #({:id (:id %), :name (:name %)}) (vals v)) |
| 21:10 | pppaul | the last line gives an error |
| 21:10 | brehaut | pppaul: maps return MapEntries for seqs |
| 21:10 | brehaut | they look like pairs |
| 21:11 | pppaul | um |
| 21:11 | pppaul | how can i get a visual on that? |
| 21:11 | pppaul | or is there a better way to do what i want? |
| 21:11 | brehaut | ,(map identity {:a 1 :b 2 :c 3}) |
| 21:11 | clojurebot | ([:a 1] [:b 2] [:c 3]) |
| 21:11 | pppaul | which is transforming a map |
| 21:12 | mattdw | pppaul: also, #({..}) is going to try to call the map, I believe, not return it |
| 21:12 | pppaul | oh |
| 21:12 | brehaut | mattdw: correct |
| 21:12 | pppaul | ok |
| 21:13 | mattdw | turn it into an (fn [v] ...) if you just want the map returned |
| 21:14 | pppaul | thanks |
| 21:14 | gfrlog | ,(seq {:a 1 :b 2 :c 3}) |
| 21:14 | clojurebot | ([:a 1] [:b 2] [:c 3]) |
| 21:14 | pppaul | i want to transform the map into a new map |
| 21:14 | pppaul | what would be the best way to do this? |
| 21:14 | gfrlog | you want to map the map? |
| 21:14 | Kowboy | don't confuse the map the function and map the datatype |
| 21:14 | brehaut | (into {} (map f m)) |
| 21:14 | pppaul | datamap to datamap |
| 21:15 | gfrlog | you want to change the keys, the values, or both? |
| 21:15 | pppaul | like XSLT |
| 21:15 | brehaut | f needs to take a pair and return a pair |
| 21:15 | pppaul | cool |
| 21:15 | Kowboy | the function map will return a sequence, not a data map |
| 21:15 | pppaul | a seq of datamaps is ok |
| 21:16 | brehaut | eg ##(into {} (map (fn [[k v] [(dec k) (inc v)]) {1 2 3 4 5 6})) |
| 21:16 | pppaul | that's what i'm starting with |
| 21:16 | gfrlog | ,(into {} (map (fn [[k v] [(dec k) (inc v)]) {1 2 3 4 5 6})) |
| 21:16 | clojurebot | Unmatched delimiter: ) |
| 21:16 | gfrlog | ,(into {} (map (fn [[k v] [(dec k) (inc v)]) {1 2 3 4 5 6}) |
| 21:16 | clojurebot | Unmatched delimiter: ) |
| 21:16 | Kowboy | can you give us an example of a 1 entry map and what you want it transformed into? |
| 21:16 | gfrlog | ,(into {} (map (fn [[k v] [(dec k) (inc v)]] {1 2 3 4 5 6})) |
| 21:16 | clojurebot | EOF while reading |
| 21:16 | pppaul | ({:id :name :etc....},{}) -> ({:id :name},{}) |
| 21:16 | gfrlog | ,(into {} (map (fn [[k v] [(dec k) (inc v)]] {1 2 3 4 5 6}))) |
| 21:16 | clojurebot | java.lang.RuntimeException: java.lang.Exception: Unsupported binding form: (dec k) |
| 21:17 | gfrlog | ,(into {} (map (fn [[k v]] [(dec k) (inc v)]) {1 2 3 4 5 6}))) |
| 21:17 | clojurebot | {0 3, 2 5, 4 7} |
| 21:17 | gfrlog | ah finally |
| 21:17 | pppaul | interesting |
| 21:18 | Kowboy | can the bot tell me the doc string of (into)? |
| 21:18 | gfrlog | ,(doc into) |
| 21:18 | clojurebot | "([to from]); Returns a new coll consisting of to-coll with all of the items of from-coll conjoined." |
| 21:18 | gfrlog | clojurebot: thanks |
| 21:18 | clojurebot | thanks for your suggestion, but as usual it is irrelevant |
| 21:19 | gfrlog | I think (into) is kind of an ugly function for these purposes. But I don't think there's anything better at the moment |
| 21:19 | gfrlog | ,(into #{1 2 3} [2 3 4]) |
| 21:19 | clojurebot | #{1 2 3 4} |
| 21:20 | brehaut | gfrlog: you could use hash-map or array-map |
| 21:20 | gfrlog | (doc hash-map) |
| 21:20 | clojurebot | "([] [& keyvals]); keyval => key val Returns a new hash map with supplied mappings." |
| 21:20 | Kowboy | curious, what is the purpose of splitting a multi-entry map into a bunch of single-entry maps? |
| 21:20 | gfrlog | Kowboy: I have no idea, who suggested that? |
| 21:20 | Kowboy | why wouldn't you just use a sequence of tuples (2 element sequences)? |
| 21:20 | gfrlog | ,(doc array-map) |
| 21:20 | clojurebot | "([] [& keyvals]); Constructs an array-map." |
| 21:21 | Kowboy | pppaul is trying to do that |
| 21:21 | pppaul | ({:id :name :etc....},{}) -> ({:id :name},{}) |
| 21:21 | pppaul | that is what i want |
| 21:21 | gfrlog | brehaut: we were talking about mapping a map -- is that what you were suggesting hash-map for? |
| 21:21 | pppaul | i'm braindead now, though |
| 21:21 | Kowboy | what's the difference between {:a 1} and [:a 1] if you aren't going to have multiple keys? |
| 21:21 | pppaul | i haven't worked with maps much |
| 21:21 | brehaut | gfrlog: as a replacement for into {} |
| 21:22 | gfrlog | Kowboy: I agree |
| 21:22 | pdk | (doc into) |
| 21:22 | clojurebot | "([to from]); Returns a new coll consisting of to-coll with all of the items of from-coll conjoined." |
| 21:22 | gfrlog | brehaut: so if I want {"jack" 12, "jill" 15} to be mapped to {:jack, 13, :jill, 16} |
| 21:22 | amalloy | &(map hash-map {1 2 3 4}) |
| 21:22 | sexpbot | java.lang.IllegalArgumentException: No value supplied for key: [1 2] |
| 21:22 | amalloy | &(map (partial apply hash-map) {1 2 3 4}) |
| 21:22 | sexpbot | ⟹ ({1 2} {3 4}) |
| 21:22 | gfrlog | how would hash-map make that easier? |
| 21:23 | amalloy | but i agree with the others, it's sorta silly to want this |
| 21:24 | gfrlog | ,(into {} (fn [[k v]] [(keyword k) (inc v)]) {"jack" 12, "jill" 15}) |
| 21:24 | brehaut | gfrlog: you said "I think (into) is kind of an ugly function for these purposes. But I don't think there's anything better at the moment"; i was suggesting the alternatives |
| 21:24 | clojurebot | java.lang.IllegalArgumentException: Wrong number of args (3) passed to: core$into |
| 21:24 | gfrlog | ,(into {} (map (fn [[k v]] [(keyword k) (inc v)]) {"jack" 12, "jill" 15})) |
| 21:24 | clojurebot | {:jack 13, :jill 16} |
| 21:24 | pppaul | (map (fn [v] {:id (:id v) :name (:name v)} ) (vals v)) : my solution |
| 21:24 | gfrlog | brehaut: I guess I'm thinking that using hash-map would be more cumbersome |
| 21:24 | amalloy | gfrlog: (for) will be a lot cleaner than (map (fn)) |
| 21:24 | pppaul | i don't know what it didn't work with #(%) format |
| 21:24 | brehaut | i think so to, hence my original use of into { } |
| 21:24 | gfrlog | ,(doc for) |
| 21:24 | clojurebot | "([seq-exprs body-expr]); List comprehension. Takes a vector of one or more binding-form/collection-expr pairs, each followed by zero or more modifiers, and yields a lazy sequence of evaluations of e... |
| 21:25 | gfrlog | brehaut: oh, okay -- I thought you were suggesting hash-map as better than into {} |
| 21:25 | pppaul | how would i use for? |
| 21:25 | gfrlog | amalloy: I'm getting that feeling that I've been missing out on a whole function for a long time |
| 21:25 | zakwilson | I'm still not used to the pervasive destructuring in Clojure. I see people post examples like the above and I want to go refactor all my ugly code. |
| 21:25 | amalloy | &(into {} (for [[k v] {"jack" 11 "jill" 15}] {(keyword k) (inc v)})) |
| 21:25 | sexpbot | ⟹ {:jack 12, :jill 16} |
| 21:26 | pppaul | wow, that is over my head |
| 21:26 | pppaul | "jack" -> :jack ??? |
| 21:26 | gfrlog | pppaul: for isn't that bad |
| 21:27 | pppaul | i would really like a tutorial on for |
| 21:27 | brehaut | pppaul: ##(keyword "foo") |
| 21:27 | sexpbot | ⟹ :foo |
| 21:27 | gfrlog | pppaul: are you wondering what the :jack syntax means? |
| 21:27 | pppaul | i'm wondering how "jack" is transformed into :jack |
| 21:27 | gfrlog | ,(for [x (range 5)] [x (inc x)]) |
| 21:27 | clojurebot | ([0 1] [1 2] [2 3] [3 4] [4 5]) |
| 21:28 | brehaut | pppaul: the keyword function |
| 21:28 | gfrlog | ,(keyword "jack") |
| 21:28 | clojurebot | java.lang.StackOverflowError |
| 21:28 | pppaul | oooooooooh |
| 21:28 | gfrlog | ,(keyword "jack") |
| 21:28 | clojurebot | :jack |
| 21:28 | pppaul | damn i'm tired |
| 21:28 | amalloy | &(map (juxt identity inc) (range 5)) |
| 21:28 | sexpbot | ⟹ ([0 1] [1 2] [2 3] [3 4] [4 5]) |
| 21:28 | pppaul | :P |
| 21:28 | gfrlog | amalloy: I agree, I was trying to do a trivial use of (for) |
| 21:28 | amalloy | kk |
| 21:29 | gfrlog | It's juxt what I was trying to use for for |
| 21:30 | Kowboy | ,(for [[k v] {:id 12 :name "Bob"}] {k v} ) |
| 21:30 | clojurebot | ({:id 12} {:name "Bob"}) |
| 21:30 | Kowboy | still, I'd use a vector instead |
| 21:30 | gfrlog | I'd use a java.util.HashMap<String, String> |
| 21:30 | brehaut | pppaul: http://clojuredocs.org/clojure_core/clojure.core/for go read that |
| 21:31 | amalloy | gfrlog: barf |
| 21:31 | Kowboy | ,(for [x {:id 12 :name "Bob"} ] x) |
| 21:31 | clojurebot | ([:id 12] [:name "Bob"]) |
| 21:32 | pppaul | reading |
| 21:34 | Kowboy | now I'm confusing myself on how map and for are different |
| 21:35 | amalloy | Kowboy: they treat multiple sequences differently |
| 21:36 | brehaut | pppaul: there are a couple of major uses: if you are doing multiple maps and/or filters for really tidys things up, and if you want the cross product of two or more collections |
| 21:36 | Kowboy | and for takes an expression/form while map takes a function? |
| 21:36 | brehaut | pppaul: the first example on that page shows a map and filter occuring in the same comprehension |
| 21:36 | amalloy | Kowboy: sure, that's mostly syntax sugar |
| 21:36 | brehaut | the second and third examples are crossproduces |
| 21:37 | brehaut | Kowboy: for has more in common with mapcat than with map |
| 21:37 | brehaut | Kowboy: it happens that when there is only a single sequence, it looks like map |
| 21:38 | arohner | has anyone used cron4j? Is it any good? |
| 21:39 | Kowboy | ok, found my equivalent expressions: |
| 21:39 | Kowboy | ,(map (fn [x] x) {:id 12 :name "Bob"}) |
| 21:39 | clojurebot | ([:id 12] [:name "Bob"]) |
| 21:39 | Kowboy | ,(for [x {:id 12 :name "Bob"} ] x) |
| 21:39 | clojurebot | ([:id 12] [:name "Bob"]) |
| 21:39 | Kowboy | not sure if my map version can be done more simply |
| 21:40 | brehaut | Kowboy: use identity instead of (fn [x] x) |
| 21:41 | amalloy | brehaut: or vec |
| 21:43 | Kowboy | ,(== (map identity {:id 12 :name "Bob"}) (for [x {:id 12 :name "Bob"} ] x)) |
| 21:43 | clojurebot | java.lang.ClassCastException: clojure.lang.LazySeq cannot be cast to java.lang.Number |
| 21:44 | Kowboy | darn |
| 21:44 | amalloy | Kowboy: =, not == |
| 21:45 | Kowboy | ,(= (map identity {:id 12 :name "Bob"}) (for [x {:id 12 :name "Bob"} ] x)) |
| 21:45 | clojurebot | true |
| 21:45 | Kowboy | wait, isn't = the assignment operator? |
| 21:46 | Kowboy | :-) |
| 21:52 | amalloy | at least clojure doesn't have === |
| 21:56 | Kowboy | === is for when you REALLY mean it |
| 21:57 | Kowboy | that's it, I'm going to define === and add it to the clojure.core ns |
| 21:57 | shachaf | Kowboy: And redefine == to randomly return the wrong answer 10% of the time. |
| 21:59 | Kowboy | brilliant! |
| 21:59 | TimMc | It's not random! :-( |
| 21:59 | TimMc | I can't speak for PHP, though. |
| 21:59 | Kowboy | how about !!= |
| 22:00 | Kowboy | the not-not-equal operator |
| 22:00 | amalloy | TimMc: php's implicit type conversions are even worse than javascript's, which are abominable |
| 22:00 | TimMc | amalloy: I think JS's == is not even transitive, which is awesome. |
| 22:03 | amalloy | really? e.g.? |
| 22:04 | TimMc | Ugh, can't find it now... |
| 22:04 | TimMc | I'll get back to you if I can reproduce it. |
| 22:05 | TimMc | amalloy: OK, here we go: '00' == 0 == '0' |
| 22:05 | TimMc | but '00' != '0' |
| 22:05 | amalloy | nice |
| 22:06 | TimMc | I had forgotten that JS did string parsing for integer equality. Yuck. |
| 22:07 | amalloy | TimMc: in php: '00' == 0 == 'ojhgfklh' |
| 22:08 | TimMc | (defn == [a b] true) |
| 22:10 | rata_ | hahaahaha |
| 22:10 | rata_ | how do you change the size of the slime history? |
| 22:12 | gfrlog | barfbag2273 |
| 22:21 | pdk | (doc read-line) |
| 22:21 | clojurebot | "([]); Reads the next line from stream that is the current value of *in* ." |
| 22:30 | Kowboy | ok, I have a tough one |
| 22:30 | Kowboy | I want a macro that can generate multiple functions |
| 22:31 | Kowboy | (make-call {:char-list "/chars" :foo "/foo" :bar "/bar" }) |
| 22:31 | Kowboy | to result in definitions like: (defn foo [] (println "/foo")) |
| 22:31 | tomoj | if there are no more arguments, may I suggest dropping the {}? |
| 22:31 | Kowboy | but for each pair in the map |
| 22:31 | Kowboy | ok |
| 22:32 | tomoj | not that it matters much.. |
| 22:32 | Kowboy | and bind them using let? |
| 22:32 | Kowboy | or for, rather |
| 22:33 | Kowboy | I actually am close |
| 22:33 | tomoj | no, just (defmacro make-call [& {:as foo}]) or whatever |
| 22:33 | Kowboy | right now, I get my defn's wrapped in a list |
| 22:33 | tomoj | just stick a 'do at the head |
| 22:34 | Kowboy | hmm...i tried that, maybe I did something wrong there |
| 22:34 | Kowboy | I know what I did |
| 22:34 | Kowboy | I should have done (list 'do .... |
| 22:34 | Kowboy | I just did ('do |
| 22:35 | tomoj | list* is often useful in situations like that |
| 22:35 | Kowboy | ,(doc list*) |
| 22:35 | clojurebot | "([args] [a args] [a b args] [a b c args] [a b c d & more]); Creates a new list containing the items prepended to the rest, the last of which will be treated as a sequence." |
| 22:36 | tomoj | ,(list* 'do (for [[k v] {:foo 3 :bar 4}] `(def ~k ~v))) |
| 22:36 | clojurebot | DENIED |
| 22:36 | tomoj | huh |
| 22:36 | tomoj | oh, of course |
| 22:37 | tomoj | ,(list* 'do (for [[k v] {:foo 3 :bar 4}] `(poop ~k ~v))) |
| 22:37 | clojurebot | (do (sandbox/poop :foo 3) (sandbox/poop :bar 4)) |
| 22:38 | Kowboy | hah, it works! |
| 22:38 | Kowboy | thanks |
| 22:41 | Kowboy | tomoj: trying to strip the {} |
| 22:41 | amalloy | `(do ~@body) is a common idiom |
| 22:41 | Kowboy | so [& args] |
| 22:41 | Kowboy | how to I bind that to pairs? |
| 22:42 | amalloy | Kowboy: with the {} :P |
| 22:42 | tomoj | pff |
| 22:42 | amalloy | or if you really prefer it, you can (partition 2 args) |
| 22:43 | tomoj | I guess you probably don't want {:as crap} in your arglist |
| 22:43 | amalloy | &(partition 2 [1 2 3 4 5 6]) |
| 22:43 | sexpbot | ⟹ ((1 2) (3 4) (5 6)) |
| 22:43 | Kowboy | (make-call :foo "/foo" :bar "/bar") |
| 22:44 | Kowboy | so I need to iterate over the args in pairs |
| 22:44 | Kowboy | not seeing it |
| 22:44 | tomoj | well destructuring can do it for you |
| 22:45 | tomoj | ..better not though |
| 22:46 | amalloy | &(let [args [:foo "/foo" :bar "/bar"]] `(do ~(map str (partition 2 args)))) |
| 22:46 | sexpbot | ⟹ (do ("clojure.lang.LazySeq@5d847e33" "clojure.lang.LazySeq@5d2b26fe")) |
| 22:46 | amalloy | &(let [args [:foo "/foo" :bar "/bar"]] `(do ~(map (partial apply str) (partition 2 args)))) |
| 22:46 | sexpbot | ⟹ (do (":foo/foo" ":bar/bar")) |
| 22:47 | amalloy | whoops, forgot the @ in ~@ |
| 22:48 | tomoj | you prefer `(do ~@x) to (list* 'do x)? |
| 22:48 | Kowboy | ok, I get the :as option now |
| 22:48 | Kowboy | [& {:as calls}] |
| 22:49 | amalloy | tomoj: not especially. but (cons 'do x) is better |
| 22:49 | amalloy | if you're going to do without ` |
| 22:50 | tomoj | core.clj confirms this spectacularly |
| 22:50 | tomoj | (if name (list* 'fn* name new-sigs) (cons 'fn* new-sigs)) |
| 22:50 | amalloy | heh |
| 22:52 | tomoj | has bit-seq left anyone else seriously confused? |
| 22:52 | amalloy | &(doc bit-seq) |
| 22:52 | sexpbot | java.lang.Exception: Unable to resolve var: bit-seq in this context |
| 22:52 | tomoj | from gloss, I should say |
| 22:52 | Kowboy | so, basically I am deciding whether to use a macro, or currying for my needs |
| 22:52 | Kowboy | they accomplish the same thing, with the macro approach being more DRY and the currying approach being a little clearer |
| 22:53 | Kowboy | I am defining groups of functions which have similar arg lists, but each function is specifying one of the args |
| 22:56 | amalloy | Kowboy: i don't follow |
| 22:57 | Kowboy | instead of this: (geturl "/foo" 1 2 3) (geturl "/blah" 1 2 3), etc.... |
| 22:57 | Kowboy | I'm turning that into (foo 1 2 3) and (blah 1 2 3) |
| 22:57 | Kowboy | so, using currying |
| 22:58 | Kowboy | (def foo (partial geturl "/foo")) |
| 22:58 | brehaut | Kowboy: thats not currying |
| 22:58 | brehaut | thats partial application |
| 22:58 | Kowboy | I thought it was the same thing |
| 22:58 | brehaut | no |
| 22:58 | Kowboy | close? |
| 22:58 | amalloy | they're related, anyway |
| 22:59 | brehaut | implict partial application is a property of curried functions |
| 22:59 | TimMc | I don't think you can have currying and variadic functions in the same language. |
| 22:59 | brehaut | TimMc: should i point you to the printf implemention in haskell? |
| 23:00 | brehaut | canonical example: (fn [a b c] (…)) curried would be |
| 23:00 | TimMc | brehaut: How does it know when to stop? |
| 23:00 | brehaut | (fn [a] (fn [b] (fn [c] (…))) |
| 23:00 | amalloy | TimMc: someone posted automatic currying of non-variadic defns on the clojure ng a month or two ago |
| 23:00 | brehaut | TimMc: the magic of type classes |
| 23:00 | TimMc | brehaut: Hrmf. GO figure, it's more Haskell magic. :-P |
| 23:00 | Kowboy | still not sure I see the difference |
| 23:01 | brehaut | Kowboy: the former would be called as (f 1 2 3) |
| 23:01 | brehaut | the latter as (((f 1) 2) 3) |
| 23:01 | Kowboy | ok, so currying is a chain of functions with a single argument |
| 23:01 | brehaut | yes |
| 23:02 | brehaut | well |
| 23:02 | brehaut | a curried function is |
| 23:02 | Kowboy | subtle difference |
| 23:02 | brehaut | yes |
| 23:02 | brehaut | but its important |
| 23:03 | brehaut | you can have partial application without currying, but in a language with proper curried functions there are a lot of optimisations that can be made |
| 23:03 | brehaut | [end of curry/partial rant] |
| 23:04 | amalloy | brehaut: don't proclaim that so soon |
| 23:04 | Kowboy | ok, so back to my decision, macros vs. partially applied functions |
| 23:04 | Kowboy | (def foo (partial geturl "/foo")) |
| 23:04 | Kowboy | vs |
| 23:04 | Kowboy | (make-call :foo "/foo" :bar "/bar") |
| 23:05 | Kowboy | any thoughts? |
| 23:05 | amalloy | Kowboy: they both sound kinda crazy to me tbh |
| 23:05 | TimMc | I have heard "avoid using macros when functions will do" as good Clojure style. |
| 23:05 | brehaut | haskell printf btw http://hackage.haskell.org/packages/archive/base/latest/doc/html/Text-Printf.html#v:printf |
| 23:05 | TimMc | Not sure if that's just for debugging difficulty, readability, or what. |
| 23:05 | Kowboy | well, I would be doing a lot of code duplication otherwise |
| 23:06 | amalloy | TimMc: and reusability/composability |
| 23:07 | TimMc | ooh, composability, right |
| 23:07 | Kowboy | the only reason to use partially applied functions is to avoid having to state the parameter list over and over again |
| 23:07 | TimMc | brehaut: Ohhh, does it know when to stop by reading the format string? |
| 23:07 | brehaut | TimMc: in this case yes but also magic ;) |
| 23:07 | TimMc | haha |
| 23:07 | TimMc | Of course magic. |
| 23:08 | Kowboy | magic - it's a feature of the language |
| 23:11 | brehaut | the primary piece of magic is actually 'pretty simple'; type classes can be polymorphic on the return type of functions |
| 23:12 | Kowboy | haven't learned Haskell yet |
| 23:12 | Kowboy | will someday, though |
| 23:12 | Kowboy | it's on my list |
| 23:14 | amalloy | Kowboy: i just don't think you need to do any top-level defs to get the partial/curried versions of your functions |
| 23:14 | amalloy | the eventual result you want is like (partial (partial (partial (partial get-url "/foo") 1) 10) 12), right? |
| 23:15 | amalloy | that looks like a job for reduce |
| 23:16 | Kowboy | sorry, the args after the url are parameters to a web service |
| 23:16 | amalloy | (reduce partial get-url ["/foo" 1 10 12]) |
| 23:16 | Kowboy | I just used integers for readability |
| 23:17 | Kowboy | ie, (get-url "/foo" username password account-num) |
| 23:18 | amalloy | Kowboy: uh-huh...the type of the args doesn't really matter |
| 23:18 | Kowboy | so I'm making methods like (foo username password account-num) |
| 23:18 | Kowboy | and (bar username password account-num) |
| 23:19 | Kowboy | well, hell, why don't I just link the code ;-) |
| 23:22 | Kowboy | https://bitbucket.org/craigmcdaniel/clojureve/src/039d3260328f/src/clojureve/api.clj |
| 23:22 | Kowboy | this is my first attempt at useful clojure code |
| 23:23 | Kowboy | so be gentle ;-) |
| 23:23 | technomancy | clojurebot: arrows is http://ro-che.info/ccc/12.html |
| 23:23 | clojurebot | Ok. |
| 23:25 | amalloy | Kowboy: my point is why are you def-ing these to vars in the first place? |
| 23:26 | Kowboy | as opposed to? |
| 23:28 | amalloy | (def account-calls (into {} (for [[name url] {"character-list" "CharacterList" ...}] {name (partial account-call (str "/account/" url ".xml.aspx"))}))) |
| 23:29 | amalloy | i mean, your service is going to be going through a list of account-based calls anyway, and looking through vars won't do it any good - it will want a map or a multimethod anyway |
| 23:30 | Raynes | I was going to be clever and say "Your first mistake is using Mercurial." but decided against it, because I'm a nice guy. |
| 23:31 | Kowboy | I guess there's not much of an Emacs vs Vim flame here, so you have to go for the git vs Mercurial ;-) |
| 23:31 | brehaut | Raynes: you are only allowed to use that joke with people still using svn |
| 23:31 | Raynes | Kowboy: Don't tell me you're using Vim as well? God, I wont be able to contain myself. |
| 23:32 | Kowboy | no, I'm using emacs |
| 23:32 | Raynes | Highest of fives. |
| 23:32 | brehaut | Raynes: yeah he uses vi, hg, win, and lein |
| 23:32 | amalloy | hahaha |
| 23:32 | Kowboy | is there a lein debate? |
| 23:32 | amalloy | Kowboy: lein/cake |
| 23:32 | TimMc | It is the only sexp-aware editor I could find that uses C-s for save. :-P |
| 23:32 | brehaut | Kowboy: raynes is young and polarised :P |
| 23:33 | Kowboy | I know the type |
| 23:33 | brehaut | Kowboy: yeah, any nerd under the age of 55 |
| 23:33 | brehaut | the ones over 55 arent polarised, just stuck in their ways |
| 23:33 | Kowboy | hey! |
| 23:33 | Kowboy | I must be between the 2 then ;-) |
| 23:34 | Kowboy | I see your point amalloy |
| 23:34 | Kowboy | but I'm writing an api others may use, and I think they may only care about a subset of the functions |
| 23:35 | Kowboy | in which case they will probably want to call the functions by name |
| 23:35 | amalloy | Kowboy: i don't see why. they can write ((account-call "character-list") more-args) |
| 23:36 | amalloy | and if you want, you can wrap that up in some defns with a macro |
| 23:36 | Kowboy | hmmm |
| 23:36 | amalloy | but the underlying functionality should be a map or a multi or something |
| 23:37 | Kowboy | a multi doesn't fit here does it? |
| 23:37 | Kowboy | unless you are talking about the different types of calls |
| 23:37 | amalloy | meh, i guess not |
| 23:37 | Kowboy | account, anonymous, character, etc |
| 23:38 | amalloy | yeah multi doesn't make a lot of sense here |
| 23:38 | Kowboy | I could wrap all those into one api call with multis |
| 23:38 | amalloy | but a map! |
| 23:43 | Kowboy | (derive ::character-list ::account-call) |
| 23:43 | Kowboy | I could use something like that for the dispatching |
| 23:43 | amalloy | Kowboy: maybe so |
| 23:44 | defn | http://clojuredocs.org/clojure_core/clojure.java.io/file |
| 23:44 | defn | what's up with the http:/asdf.com ? |
| 23:45 | defn | (the single slash) |
| 23:45 | Kowboy | I just recently learned about multis, so I may explore that |
| 23:46 | Kowboy | is there a shortcut version (macro) for derive that associates multiple child tags with a parent? |
| 23:46 | amalloy | Kowboy: just use doseq. you don't need a specific macro |
| 23:46 | Kowboy | wouldn't be much to write one |
| 23:47 | Kowboy | k |
| 23:47 | amalloy | it definitely shouldn't be a macro. a function is more than enough |
| 23:47 | Kowboy | yeah, not much to it really |
| 23:48 | Kowboy | just seems like something that would be pretty common |
| 23:48 | amalloy | Kowboy: not as far as i've seen |
| 23:49 | amalloy | if you're defining a multi you usually expect methods to come from all over, so having a way to consolidate is not useful most of the time |
| 23:50 | Kowboy | you lost me there |
| 23:52 | amalloy | multimethods let anyone add methods at any time |
| 23:52 | brehaut | a multimethod that is not open to extension is probably better served by (say) cond |
| 23:54 | tomoj | defn: ##(.getPath (java.io.File. "foo//bar")) |
| 23:54 | sexpbot | ⟹ "foo/bar" |
| 23:54 | tomoj | &(.getParent (java.io.File. "http://google.com")) |
| 23:54 | sexpbot | ⟹ "http:" |
| 23:54 | tomoj | should be removed from the example as it's terribly misleading |
| 23:54 | amalloy | haha tomoj that is awful |
| 23:57 | amalloy | brehaut: more likely case or a raw map than cond, but i agree with your general point |
| 23:58 | amalloy | (not surprising since you were kindly making my point for me) |
| 23:58 | Kowboy | ok, chat with you guys later |