#clojure logs

2011-02-10

00:03mec_is there a good way to map subvec across a vector for windowing?
00:08tomojmec__: what are you going to do with the windows?
00:08tomojI mean, do you really need vector windows?
00:09tomojvs something like ##(partition 3 1 [1 2 3 4 5 6]) ?
00:09sexpbot⟹ ((1 2 3) (2 3 4) (3 4 5) (4 5 6))
00:12mec__thats what i want, but i figured subvec would be a lot faster if I specifically had a vector
00:15tomojwell..
00:17tomojprobably depends on window size and what you do with the windows
00:17tomojfor window size 3, it looks like partition is faster at generating the windows
00:18tomojwhile for window size 10, subvec seems faster
00:19tomojmap is variadic, so you can (map #(subvec v %1 %2) x y) where x and y are seqs of the appropriate indices
00:20mec__oh didnt think of that at all, thanks
00:21tomojoh, wow
00:22tomoj(partition n 1 v) is O(n) for fixed v
00:23mec__how is that possible? it creates a seq that touches the whole thing
00:23tomojI mean, ignoring that factor
00:24mec__its O(n) or O(count v)
00:24tomojI think (partition w 1 v) is O(n*w) if v has n elements
00:24mec__ah
00:24tomoj'n' was a bad choice for window size
00:24tomojsubvec has a constant (or log32?) factor instead of w, I think, but for small w it's worse
00:25tomojconstant according to subvec's docs
00:26tomojcan you do better than O(n*w) on seqs in general for the step=1 case?
00:28mec__i wouldnt think so, but subvec is deffinitly constant
00:32tomojwell, 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:32amalloytomoj: 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:35tomojI've been thinking lately about doing something like that for permutations
00:36tomojsound feasible?
00:37mec__Hard to say if it would be any faster, wouldnt you need a map for the old to new indices?
00:37tomojyeah, but looking up the new index is practically constant while creating a new vector from scratch is O(n), yes?
00:38mec__true but would creating the map be O(n) anyway?
00:38tomojamalloy: thanks, I hadn't realized that's what subvec did, I'll look there for inspiration
00:38tomojwell, I only have one permutation
00:38tomojand its inverse
00:38tomojand need to apply them many times to many vectors with thousands of elements
00:38tomojso I can have the maps already sitting around beforehand
00:41tomojooh, even with more permutations (say, hundreds), I can memoize all the combinations to avoid multiplying the log32 vector access
00:54tomojoh, 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:55tomojmaybe I can get away with only implementing the read-only stuff for a while..
01:04no_mindhow do I produce html using compojure. When I call (html0 function, I get a compile time error
01:04no_mind(html)
01:04no_mind.(html)
01:10puredangerlet'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:10technomancypuredanger: it's simple, just use this logging abstraction framework
01:10puredangeris there a Clojure lib that does very basic logging? (not c.c.logging)
01:11technomancyyou can plug in any logging implementation or even other logging abstraction frameworks!
01:11puredangertechnomancy: <headdesk>
01:11technomancy(just ignore the fact that there are only two logging implementations in existence and at least three logging abstractions)
01:12puredangertechnomancy: I see you share my love of Java logging f/ws
01:13khaliGanyone familiar with miglayout? i wish to use the do-layout function, but the compiler says java.lang.IllegalAccessError: do-layout does not exist
01:14khaliGoh i see it's an internal function
01:34tomojwould 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:39amalloytomoj: that sounds exactly like extending a class: implementation inheritance
01:39amalloyso i suspect the two are equally evil
01:41tomojwhen you say it that way this sounds even more evil
01:50no_mindhow can I install enlive using lein ? It gives me an error for dependency on org.apache.maven:super-pom:jar:2.0
01:52rata_can you search for something like *blah* in emacs history?
01:54tomojno_mind: paste the entire output somewhere (not here)
01:55amalloytomoj: it was not an accident :)
02:17sritchiehey 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:17sritchiehttps://gist.github.com/5b33bae6bb3e28b7f815
02:18sritchiethe output is correct, but i suspect there's a cleaner way of doing this
02:22amalloysritchie: plus reduce and conj aren't lazy
02:22raeksritchie: check out the torus-window function: http://www.bestinclass.dk/index.clj/2009/10/brians-functional-brain.html
02:23sritchiethis 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:23sritchieawesome, thanks, raek
02:24amalloyexcept it sounds like you don't actually want a torus
02:25raekthen using a window function like this might work: (defn window [coll] (partition 3 1 coll))
02:26raekthe number of windows will then be (- (count coll) 2)
02:27sritchiethis is for a nearest neighbor analysis, so I do need to walk in both dimensions, with the window
02:27sritchiegetting a lazy sequence of 2d vectors, ideally
02:27sritchieraek: that'll let me walk along 1d, right?
02:28raekyes, but the 'step' function uses it twice to get 2d
02:29raekhrm. also consider using 'for' instead of 'map' + anonymous function
02:29raekIMHO the code tends to be easer to read then
02:30sritchieraek: okay, good advice
02:30amalloyraek: agreed, i was gonna put something together with for
02:31sritchieraek: for looks a lot clearer, that's great
02:32sritchieis torus window lazy, here?
02:32raekyes
02:32raekpartition is lazy
02:33rata_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:34sritchierata_: ah, so that gets rid of my reduce conj step
02:35rata_it does more than that I think
02:35amalloybrehaut: another one for the point-free brigade, it seems
02:36sritchierat sorry, I meant mapcat got rid of that
02:36rata_it's completely lazy and it doesn't use count
02:36rata_yes
02:37raekthe map vector step can't be lazy
02:37rata_amalloy: what's the point-free brigade? those that don't like/use java interop?
02:38rata_raek: but map is lazy
02:38amalloyrata_: heh, no. point-free is a style that is popular with haskell programmers. (partial (comp foo bar) 10) rather than #(foo (bar 10 %&))
02:39rata_ah hahaha ok =)
02:39amalloyie, "talking" about functions and gluing them together without mentioning their actual params
02:39rata_yes, I prefer that style... that % looks dirty
02:39raekyou have something like (1 2 3 4) and turn it into [1 2 3 4]?
02:40amalloyi like point-free myself, and brehaut and Raynes are always teasing me that i should try haskell
02:40rata_raek: no, that's vec
02:40rata_for what I know about haskell, I like it... but I haven't done a project in haskell yet
02:41amalloysame
02:42amalloy$heval take 10 $ let fib = 1 : 1 : zipWith (+) fib (tail fib) in fib
02:42sexpbot⟹ [1,1,2,3,5,8,13,21,34,55]
02:42amalloyrata_: brehaut tells me this is how all the cool kids generate fibonacci numbers
02:42rata_amalloy: yes, that's pure beauty =)
02:43rata_I loved it the first time I saw it
02:43amalloy*chuckle* well, i'm off to bed. i'll try to dream of parens instead of $ and .
02:44rata_hahahaha
02:44rata_good night amalloy
02:44rata_do you guys know what's the best way to do ajax with clojure?
02:45rata_best intended in a very subjective way of course
02:46Scriptorrata_: I prefer to just keep my server code strictly separated, jquery for the ajax calls, and maybe have a clojure handler return json
02:49rata_Scriptor: so make the website in html+javascript and maybe call some clojure fns?
02:49Scriptorer, the front-end is in html+js, the backend would still use clojure
02:50Scriptorso yes, just send an ajax request to a url and have that url be tied to whatever callback you want
02:51rata_have you any examples at which I could give a look?
02:51Scriptornot off the top of my head, and also not really with clojure
02:52Scriptorbut you don't have to learn much, just how to send a request using javascript and how to return json in clojure
02:53Scriptorsince otherwise a request is still just a request
02:54rata_yes... do you know where I can learn those things?
02:55raekin ring, you can just respond with {:status 200, :headers {"Content-Type" "application/json"} (clojure.contrib.json/json-str some-data)}
02:55raekrata_: have you done server-side web programming in clojure?
02:56rata_no... I know a bit of html and that's all
02:56Scriptorrata_: how much programming experience do you have in general?
02:57rata_~8 years
02:57clojurebotPardon?
02:57raek~test
02:57clojurebotlastest is 1135
02:57Fossi:D
02:58rata_I do "scientific" programming mainly (I don't know if that's a good name for what I do)
02:59Scriptorrata_: start off with some basic web apps using compojure or something like that, then start learning javascript and a little jquery
03:00Scriptoror whatever js framework you want
03:00rata_ok... do you use compojure?
03:00Scriptornot personally
03:00rata_what do you use?
03:00Scriptordon't really use clojure, really :p
03:00raekI usually use Ring + Moustache + Enlive
03:00Fossiyeah, any combination should do actually
03:00rata_Scriptor: ah ok =)
03:01raekRing + Compojure + Hiccup is another very common combo
03:01rata_Scriptor: which language do you use?
03:01raekweb programming in clojure is *very* modular
03:01rata_raek: what's moustache and enlive for?
03:01Scriptorrata_: mainly php and python, but I've been learning lisp on the side
03:01rata_ok
03:01Scriptorthe principles of web dev are often the same
03:01raekmoustache is for routing (mathcing URLs and HTTP methods), enlive is for html templating
03:02raekactually, enlive can do html scraping too
03:02rata_raek: I thought ring was for routing
03:02raekit reads html from a file into a clojure datastructure, lets you transform it and turn it back into a html stream again
03:03brehautrata_: ring is the HTTP to clj to HTTP translation layer
03:03raekring is the standard for what a request and a response looks like
03:03Fossiit's so awesome that clojure has ring
03:03raekit comes with a web server that implements that contract
03:03Fossijava containers are a mess :>
03:07rata_so, if I get it right, you put the html+js part in using enlive?
03:08raekif the html never changes, you don't pass it through enlive
03:08brehautraek: enlive is a much more strongly seperated `templating system` than is typical
03:08brehautyou put your html and js into an html file
03:09raek(i.e. the web site uses ajax to transfer *all* data)
03:09brehautand then you use ring to update that file for a particular resource
03:11brehautthat was at rata_ sorry
03:12rata_mmm... then if I'm using ajax I'm not going to need enlive raek?
03:13brehautrata_: ajax is a pretty vague term, but, as a term it usually refers to the client side program
03:13brehautyou dont 'need' anything on the server to do ajax
03:14brehautrata_: 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:14raekrata_: that can be true.
03:14raekdepends on how you do it.
03:15rata_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:15brehautrata_: correct
03:15rata_and route handlers are clojure fns?
03:16brehautyeah; you use either moustache or compojure to map a url to a fn
03:16brehautthat stage is route handling
03:17rata_ok, so the client request the result of a computation asking for a url?
03:17rata_and then renders it within the same page
03:17brehautrata_: it doesnt as for the result of a computation; it asks for a resource - all urls map to resources in http.
03:17brehautdont think of it as an RPC system
03:18brehauttheres 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:18brehautGET purely gets; its an idempotent action
03:18brehautPOST is server specific
03:19rata_resources sounds like there something in the server already... I need to compute something based on what the client put in the forms
03:19brehautrata_: they dont have to be
03:19rata_*there's
03:19rata_ok
03:19rata_so I do a GET or POST and get the result I need
03:19brehautrata_: does the result of the calculation ever change?
03:20rata_no, but there are infinite possible inputs
03:20brehautsorry, i wasnt clear.
03:20rata_(not sure if infinite, but huge anyway)
03:20khaliGthe indenting behaviour of slime is really annoying
03:21khaliGit keeps trying to push my fns all the way across the screen
03:21brehautrata_: if you pass the same inputs to the fun, will it always produce the same result
03:21rata_yes
03:21brehautthen a GET on a resource with query parameters is completely fine
03:21brehautwhich is nice because its super easy
03:21rata_=)
03:23rata_it's not a problem that the query parameters are long strings?
03:23brehauthow long?
03:24brehautfrom memory you can safely assume 1024 characters for your url on any compliant HTTP server or proxy
03:24rata_it can be longer than that I think
03:25brehautsad; safer to go with a post then
03:25brehauteven though you'd proably never run into it in the real world
03:26rata_there's no size limitation with post then
03:26brehautrata_: have you got a non-ajax version of the web app going ?
03:26rata_no... should I do that first?
03:26brehautrata_: nope, post you send the arguments in the body of the request
03:26brehautyeah i would recommend it
03:27brehautajax builds on all the basic ideas
03:27brehauttry http://mmcgrana.github.com/2010/07/develop-deploy-clojure-web-applications.html
03:27brehautas a tutorial
03:27rata_thanks =)
03:27brehautheres the thing: the difference between an 'ajax' resource and a 'web page' resource is the content type it sends back
03:28brehautyou can legitimately have a page say, /hello/name
03:28brehautthat returns "<html><h1>Hello, name!</h1></html>"
03:29brehautfor a web browser (or default)
03:29brehautand then returns "{"message":"Hello, name!"}" for 'ajax' requests
03:30rata_so it's easy to ajaxify a non-ajax webpage?
03:30brehautyes
03:30brehauttheres no reason your ajax version cant just consume the HTML version
03:30rata_ok, thanks a lot =)
03:31brehautand then just find the appropriate nodes in the DOM
03:31brehautno problem
03:31tomojwat
03:31brehauttomoj: ?
03:32tomojwere you recommending generating html, then parsing that to generate json?
03:32brehauttomoj: not recommending it per se
03:33tomojok
03:33brehauti just didnt want rata_ to think that ajax was somehow magical or something special
03:33Fossiit's pretty easy and nice to have two output methods for your data though
03:35rata_so then I'll have to make my fns to return json instead of html?
03:35brehautyeah 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:36brehautrata_ its really easy though; ring will provide you a request map which will have a key :headers which maps to a map
03:37brehautthat map will likely have an :accepts header, and maybe :x-requested-with
03:38rata_but the main difference is you use enlive to return html, but not for json
03:39Scriptorrata_: right, json is pretty easy to generate, you can find json libs online
03:40brehautc.c.json or clj-json will take standard clojure datastructures and generate json string for you
03:40rata_ok, thanks again
03:41brehautrata_: mmcgrana has another tutorial of interest http://mmcgrana.github.com/2010/08/clojure-rest-api.html
03:41brehautshows you how to do json-responses
03:42rata_I'll read it too
03:42tomojhuh. 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:43brehautwin :)
03:44tomojeh, I only considered it because it says "fast", but clojure-json isn't even close to a bottleneck anyway
03:44brehauti wonder if i should change necessary-evil to use the same terms as clj-json before anyone actually starts depending on it
03:45brehautparse and unparse are a bit clunky
03:46tomojI like em better than those long things with their "-string"s sticking out
03:48brehauti guess
03:48brehautnot particularly nice either way
03:52meltingwaxhi
03:52brehautnight
03:57meltingwaxis closure compatible with common lisp libraries?
03:58opqdonutno, it's a different language on a different platform
04:00meltingwaxwhat if i really needed it
04:01ejacksonyou can try prayer...
04:02meltingwaxthank you, i will try that
04:03opqdonut:D
04:03ejacksonmeltingwax: some claim it to be a pattern.
04:04opqdonut541052.14 meltingwax$ thank you, i will try that
04:04opqdonutoops
04:14rata_good night
04:14rata_see you
05:16fliebelmorning
05:23no_mindis there a working example of compojure and enlive ?
05:30boboi think most examples with enlive are with moustache instead of compojure :-/
05:31Dranikbobo, are there any?
05:33boboexamples of enlive + compojure? i have never seen any. but shouldnt be any problem reading about enlive with moustache and then change to compojure
05:33no_mindI think I have found the title for my next book... "Clojure for humans"
05:34no_mindbobo: they are not working with compojure...
05:34no_mindbtw suggestion for any other templating engine to be used with compojure ?
05:34no_mindpreferably something that can read files from hdd
05:35bobono_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:35no_mindbobo: take any example
05:35no_mindI am getting Null pointer exception
05:36bobois your template working without compojure? if you just call it?
05:36bobonull pointers with enlive usualy mean you point to a non existing .html
05:37no_mindthe .html is accesible from the route
05:38boboyes, but does enlive find it? thats not the same thing
05:38boboenlive looks from your src folder
05:38no_mindk
05:38clojurebotpackage.el is part of Emacs now: http://repo.or.cz/w/emacs.git/blob_plain/HEAD:/lisp/emacs-lisp/package.el
05:41Dranikbobo, how about mustache + enlive? are there any examples or tutorials?
05:42bobohttps://github.com/swannodette/enlive-tutorial/
05:42bobohttp://cleancode.se/2011/01/04/getting-started-with-moustache-and-enlive.html
05:42bobothe first is probably the better one, since i wrote the second :-p
05:43raekno_mind: it does not matter whether you use enlive with compojure or moustache.
05:43Dranikthanks
05:44raekI usually put my html templates in resources/ rather than src/, since they're not code
05:45FkCek|ahttp://www.bestinclass.dk/index.clj/2011/01/building-a-social-media-site.html
05:45Dranikbobo, the first is not available
05:47boboDranik: its not? im looking at it?
05:48Dranikwow!
05:48DranikThis webpage is not available
05:48Dranikthat's what I've got
05:48Dranikoh its working now
05:49bobono_mind: https://gist.github.com/820290
05:49boboindex.html is in my src folder there, but as raek said they should be in resources in the end.
05:50no_mindk
05:51boboraek: whats the best way to point the template to the resources folder?
05:51bobojust wrap-file ?
05:52raekdeftemplate looks for files on the classpath and both src/ and resources/ are on it
05:52boboah
05:52boboyou learn every day!
05:59raekit would be nice if wrap-file could look for static files on a subdirectory of the classpath too...
06:56cwbstartups
07:16TobiasRaedermorning
07:19gfrloggood morning
07:20gfrlog,(let [good-+ (fn [& args] (apply + (shuffle args)))] (good+ 7 8 9))
07:20clojurebotjava.lang.Exception: Unable to resolve symbol: good+ in this context
07:20gfrlog,(let [good+ (fn [& args] (apply + (shuffle args)))] (good+ 7 8 9))
07:20clojurebot24
07:22TobiasRaederis there some kind of idiomatic wrapper for dates in clojure?
07:23fliebelTobiasRaeder: I encountered Yoda-time a few times. It's used in sexpbot for example.
07:23TobiasRaederthen ill check that out how its done there, thanks
07:24fliebelTobiasRaeder: Oh, sorry, it's clj-time, which uses Yoda
07:25TobiasRaeder@fliebel clj-time looks nice :)
07:26bobothink its called joda-time with a j
07:54no_mindusing enlive, how can I create a list element <li> dynamically from database? Given the template has a placeholder <ul. eleement.
07:55fliebelno_mind: I think you define one placeholder li, and repeat-for on a snippet of that li..
07:57bobono_mind: https://gist.github.com/820462
08:09no_mindbobo: did you create a placeholder for <li> under <ul> in the template ?
08:10bobono_mind: eh yes i belive so
08:10no_mindthnxs
08:10bobohttps://gist.github.com/820477
08:10boboi stole it from my post about it
08:13jkdufairi'm looking for advice
08:13jkdufairi'm building a RESTful app on top of compojure
08:14jkdufairi need a way to represent data across this web app and also an iPhone app and an AJAXy web app
08:14jkdufairuse JSON or some representation of s-expressions?
08:16boboi would use json
08:17jkdufairbobo: are you aware of any clojure libs that serialize to JSON?
08:17boboclojure.contrib/json
08:18boboor something, there is one in contrib
08:18bobojson-str and read-sjon
08:18jkdufairsuper. thanks so much.
08:28Cozeyis it possible to do something like (let [field 'staticField] (. SomeClass field)) ?
08:28clgvHow can I make clojure inline a very often called function? I saw snippets somewhere - is there any documentation on that?
08:29jkdufairCozey: I would think you'd need to write a macro for that
08:30fliebelclgv: Sounds interesting. What does inlining do? I know some functions use :inline in the meta, but I doubt it's the same thing.
08:30clgvfliebel: I think that's what I saw too. But I didn't find documentation on it
08:31fliebelclgv: I did, somewhere on the assemba space I think.
08:31raekCozey: at runtime, you need reflection for that
08:31clgvI have function that is called around 4,000,000 times in 10 iterations. so it would be a good candidate ;)
08:32Cozeyjkdufair: 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:32jkdufairCozey: oh boy. that's when i usually start drinking to truly understand macro expansion
08:33Cozeyi know you're right
08:33Cozeybut i feel like i'm missing some 'deref' or something similar
08:33raekmacros are just functions that transform code in form of data structures
08:34fliebelclgv: http://www.assembla.com/spaces/clojure/search?q=inline
08:34raekCozey: . 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:34raek*compiled
08:34jkdufairyes and rockets are just tubes with propellants that go up in the sky :-)
08:35fliebelclgv: So, no direct documentation, but a few issues mentioning the feature.
08:35Cozeyso is it possible to get a field by name known during runtime, without resolving to eval ?
08:35raekCozey: 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:36clgvfliebel: guess I have to check clojure source to see where it is used
08:36Cozeyraek: ok thanks, this seems to be what i needed!
08:36fliebelclgv: https://github.com/clojure/clojure/blob/b578c69d7480f621841ebcafdfa98e33fcb765f6/src/clj/clojure/core.clj#L809
08:37clgvfliebel: exactly the one I just clicked ;)
08:37clgvso well. it seems I have to repeat the definition in the inline statement
08:37raekCozey: macros can be an alternative too (and would yield more performant code). it depends on how you are going to use it.
08:38clgvor define a macro for it ;)
08:38fliebelclgv: I think it's like definline for functions :)
08:39Cozeyraek: yes but with macros i would need to know all the fields on compile time?
08:39Cozeywithout using Reflector
08:39raek(defmacro field-accessor [field-name] `(fn [instance#] (. instance# ~field-name)))
08:40raekCozey: 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:40Cozeyagreed
08:42clgvfliebel: definline seems about right
08:42AWizzArddefinline is the correct choice.
08:52pdk(doc definline)
08:52clojurebot"([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:53clgvthe syntax is a bit odd. seems you have to wrap the body into syntaxquotes
08:54clgvand use unquotes for the params everywhere
08:55pdkmakes it just like macros already then!
08:56clgvI think it should be possible to do it without
08:58fliebel$source definline
08:58sexpbotdefinline is http://is.gd/bNmEu0
08:58fliebelIt actually adds the thing to the meta data.
08:59fliebelclgv: This just works: (definline blah [foo] (println foo))
09:00clgvfliebel: my code with let-statement and more, does not ;)
09:00fliebelcode?
09:00clojurebotpeepcode is a commercial screencast series; see the Clojure one at http://peepcode.com/products/functional-programming-with-clojure by technomancy
09:01clgvI did wrap it into syntax quotes now.
09:03clgvI have to check both versions for a performance comparison now
09:04chouserdefinline essentially defines both a macro and a function with the same name
09:05chouserthen Clojure chooses which to use at compile time based on how it's used.
09:06fliebelchouser: I guess that does not mean I can do macro tricks, and still use it as a function?
09:06fliebelAnd, in which cases is the macro used?
09:07clgvchouser: yes, that's what I saw. The question is: do I really need to use syntaxquotes? It didnt compile with out them
09:07chouseryou *can* do (some) macro tricks, but they may only do what you mean in the macro version
09:09clgvI don't need macro tricks - inlining is sufficient^^
09:09fliebelclgv: Can you paste an example of why you need syntax quotes?
09:10fliebelAh, I see...
09:11clgvclgv: 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:11fliebelclojure.lang.Symbol cannot be cast to java.lang.Number
09:12chouserthe macro version is used when the var is named literally at the head of a list
09:12chouserso (foo ...) uses the macro, (map foo ...) and ((identity foo) ...) use the fn
09:12clgvhmm performance benchmark show no significant improvement. seems the function call is no overhead for this case
09:13chouserclgv: the HotSpot JVM will inline function calls at runtime
09:13clgvI had about 230000 calls
09:13clgvchouser: it seems to do a pretty good job here.
09:14fliebelchouser: So what is a good use case for definline?
09:14chouserthe reason definline exists is to allow for unboxed primitives. Of course there's new support for those in 1.3a4
09:15fliebelSo, definline is useless as of 1.3?
09:15clojurebotI don't understand.
09:15chouserI wouldn't be shocked if Rich removes :inline, but I would miss it. It's fun to exploit.
09:15clgvlol poor bot ;)
09:16fliebelchouser: Exploit? You mean makinf the fn do something unexpected when inlined?
09:16chouseryeah.
09:18chouser(definline add [a b] (if (and (number? a) (number? b)) (+ a b) `(+ ~a ~b)))
09:19chousercan you see what that does?
09:20AWizzArdThis is evil!
09:20clgvgood question. first case adds the numbers second case returns code that is an add statement
09:21AWizzArdFirst case is doing the addition at macro expansion time.
09:21clgvsecond-case is only used in macroexpansion time
09:21chousereveryone's right!
09:21Chousukethat's evil.
09:21chouseryes, evil.
09:21AWizzArdThe second case calls a function + which is probably defined for a specific NS, where cores + is excluded.
09:21chouserwell, useless at least
09:22chouserAWizzArd: nah, that's fine as clojure.core/+
09:22Chousukebut hm
09:23Chousukehow does it work when you call it as a function?
09:23AWizzArdChousuke: second case.
09:23chouserdefinline uses the macro with symbol arguments it provides itself in order to create the function version
09:24AWizzArdIt is just a hack for something that the compiler potentially could do: replace literals.
09:24chouserIt is the compiler! :-D
09:24clgvon repl it seems to have a "good" behavior
09:24fliebelchouser: I can't get it to work wrong.
09:25chouseryeah, it may not be evil. Closer to useless.
09:25fliebelmakeing one of them * would be evil :)
09:25chouserso (add 1 2) does the addition at macroexpand time, putting 3 literally in the resulting code
09:26chouser(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:27chouserwith (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:28AWizzArdAnd Clojures + can not be optimized in such a way that (+ 1 2) is replaced by a literal 3.
09:29chouserI 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:29chouserAWizzArd: why is that?
09:30chouserthough 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:31AWizzArdClojure can not know what + means until the program runs, because there is no defconstant.
09:31AWizzArd(def + -)
09:31AWizzArd(+ 10 2)
09:31clojurebot*suffusion of yellow*
09:31AWizzArd,(let [+ -] (+ 10 2))
09:31clojurebot8
09:31AWizzArdDynamically typed.
09:32chouserthe compiler can tell the difference there
09:32chouserand in fact does so.
09:32AWizzArdWhat about (in-ns 'clojure.core) (def + -) (in-ns 'my.ns)
09:33AWizzArdFunctions can be changed at runtime in Clojure.
09:33AWizzArdThis means that during compile time it is not known what a call will actually do.
09:33chouserClojure assumes vars don't change from being macros to functions or vice-versa at runtime.
09:34AWizzArdYes okay, macros will stay macros, fns will stay fns. However, the value of the var may change.
09:35AWizzArdI can do a (defn foo [] 1) and then after this (defn foo [] 2)
09:35AWizzArdI 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:37chouserClojure could inline such things if it also inlined a check to make sure the value of the var hasn't changed.
09:38AWizzArd(foo x) could mean anything at runtime.
09:38AWizzArdIts meaning could change constantly.
09:38chouserno, foo must be either a var or a local
09:39AWizzArdVars can be def'ed.
09:39chouserif it's a var, it's known at compile time to be a specific var in a specific namespace
09:39AWizzArdYes, but it's value is not known.
09:40chouserusually it's value *is* known at compile time, and usually it won't change.
09:40chouserso Clojure could inline the current value, preceeding that inlined code with a check to make sure the var's value hasn't changed.
09:40chouserif it has, it would have to call out to a slower path instead of using the inlined version.
09:40AWizzArdusually yes, in nearly all cases
09:40fdaoudits value
09:41AWizzArdBut it is not known 100%.
09:41AWizzArdIn a loop foo could change constantly (if (= user-input 10) (defn foo [] 1) (defn foo [] 2))
09:41chouserin practice, Clojure doesn't have to do this because HotSpot already does.
09:41AWizzArdYes, HotSpot can do it at runtime.
09:42AWizzArdWith more (static) information during compiletime however it could be done by the compiler.
09:42chouserI just exaplained how it could be done at compile time by the compiler.
09:42AWizzArdFor example I sometimes wished there was a defconstan.
09:43AWizzArdYes, the compiler can add an if.
09:43AWizzArdIf it were known at compile time that a function could never change then this if would not be required too.
09:43chouserthis 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:44chousereven if you didn't know you were going to need it when you wrote that code
09:44AWizzArdYes.
09:45chouserClojure 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:45AWizzArdMy 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:46AWizzArdHow does it reduce an overhead in 'if'?
09:48mtopolniki'm having a hard time with lazy-xml
09:49mtopolnikas soon as i access an element, it eagerly parses its whole contents
09:49chouserthe 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:50mtopolnike.g. <root><first/><second><a/><a/><a/>......</second></root>
09:50mtopolnikas soon as i reach second, it parses all the a's
09:50mtopolnikeven if i just ask for the :tag of second
09:51mtopolniki've tried with xml-zip as well, but same problems
09:54mtopolnikis this behavior expected?
09:56AWizzArdchouser: I see.
10:45fliebel$seen dnolen
10:45sexpbotdnolen was last seen quitting 18 hours ago.
10:59mattmitchelli'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:59mattmitchelldoes that seem like an ok solution?
11:01fliebelmattmitchell: A let binding can refer to previous bindings. ##(let [a 1 b (+ 1 a)] b)
11:01sexpbot⟹ 2
11:01cemerickmattmitchell: probably, but others may be better. e.g. str ignores nil arguments, so…
11:01cemerick&(apply str ["foo" (when false "bar") "baz"])
11:01sexpbot⟹ "foobaz"
11:02mattmitchellinteresting
11:02pdkif 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:02fliebelYou should also look at -> ##(-> "foo" (str "bar") (str "baz"))
11:02sexpbot⟹ "foobarbaz"
11:02raekI 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:02pdkor 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:03mattmitchellwow thanks. good stuff.
11:03cemerickpdk: I can't say I've ever seen a scenario where that would make sense.
11:06raek(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:22mattmitchellraek: thanks. nice example.
11:25mattmitchell,(contains? [1 2] 1)
11:25clojurebottrue
11:25fliebelHas anyone here worked with Logos? I mean, you know, did some actual stuff with it.
11:25mattmitchell,(contains? [1] 1)
11:25clojurebotfalse
11:25mattmitchell... what's up with (contains? [1] 1) being false?
11:25fliebelmattmitchell: Common pitfall, contains? checks for index.
11:25mattmitchellfliebel: ah :)
11:26fliebelTry ##(some #{1} [3 4 5 1])
11:26sexpbot⟹ 1
11:26mattmitchell,(some [1] [1])
11:26clojurebotjava.lang.IndexOutOfBoundsException
11:27fliebelwith a set, not a vector.
11:28mattmitchell,(set [12])
11:28clojurebot#{12}
11:28mattmitchell,(some (set [1]) 1)
11:28clojurebotjava.lang.IllegalArgumentException: Don't know how to create ISeq from: java.lang.Integer
11:28fdaoud,(contains? [4 5] 1)
11:28clojurebottrue
11:28fdaoudgoof
11:28mattmitchell,(some (set [1]) [1])
11:28clojurebot1
11:29chouser,(#{4 5} 1)
11:29clojurebotnil
11:29chouser,(#{4 5} 5)
11:29clojurebot5
11:30sritchiepandora
11:30sritchiewhoops, sorry, quicksilver kind of abandoned me there
11:30fliebelAre there javadocs for clojure.core? I'd be interested in the "known subclasses", so I can tell everything in Clojure that implements IFn.
11:48VinzentIs it correct that (symbol "") returns something?
11:49Vinzentand not throws exception
11:50raek&(some (fn [x] (if (even? x) [:found-it x] nil))) [1 3 5 6 7])
11:50sexpbotjava.lang.IllegalArgumentException: Wrong number of args (1) passed to: core$some
11:50raek&(some (fn [x] (if (even? x) [:found-it x] nil)) [1 3 5 6 7])
11:50sexpbot⟹ [:found-it 6]
11:50raek&(symbol "")
11:50sexpbot
11:51raek&(class (symbol ""))
11:51sexpbot⟹ clojure.lang.Symbol
11:51raekVinzent: seems like it returns a symbol, whose name is the empty string...
11:51Fossinifty
11:51Fossi&(symbol "a")
11:51sexpbot⟹ a
11:52fliebel&@clojure.java.javadoc/*local-javadocs*
11:52sexpbotjava.lang.ClassNotFoundException: clojure.java.javadoc
11:53raek&(require 'clojure.java.javadoc)
11:53sexpbotjava.security.AccessControlException: access denied (java.util.PropertyPermission os.name read)
12:03fliebelAll 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:05fliebelWhat does a MapEntry do when called?
12:06dnolenwow, 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:07chouserwhoa, the readers are IFns? I had never noticed.
12:07fliebelHey dnolen! The Reasoned Schemer arrived yesterday. Could you shine some light on the differences between that and Logos?
12:08dnolenfliebel: 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:08dnolenClojure doesn't support pairs I mean.
12:09fliebeldnolen: what pairs?
12:09dnolenfliebel: (a . b) where b is not a proper tail is allowed in Scheme/Common-Lisp, not allowed in Clojure
12:09fliebelI also noticed that fresh seems to be replaced by exist?
12:14chouser(1 . 2) is what is returned by (cons 1 2)
12:14fliebelah
12:14chouserI've always found the syntax to be confusing
12:15chouser(1 2 3 4) is the same as (1 . (2 . (3 . (4 . nil)))) I believe
12:15fliebeldnolen: And what is this solution?
12:15fliebelchouser: In Scheme, or in Clojure as well?
12:15chouserClojure doesn't support dotted pairs. the "rest" of a seq is always a seq or nil, never a number or anything else.
12:16chouser,(cons 1 2)
12:16clojurebotjava.lang.IllegalArgumentException: Don't know how to create ISeq from: java.lang.Integer
12:16fliebel&(cons 1 (cons 2 nil))
12:16sexpbot⟹ (1 2)
12:17chouserright. well-behaved lists, not dotted pairs of arbitrary values.
12:17fliebelI still don't understand the dots, then we could just as well start writing (1 + 1)
12:17dnolenfliebel: 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:18chouserin general I think where you would use pairs in other lists, you use vectors in Clojure.
12:18dnolenfliebel: main differences, is fresh -> exist and they committed to interleaving search and abandoned Prolog depth-first option
12:18chouserfliebel: 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:19chouserwould be less confusing if pairs were written as <1 2> or something. So <1 <2 <3 nil>>> is (1 2 3)
12:20fliebeldnolen: Is the later an implementation detail, or something I'm going to need to worry about?
12:20dnolenfliebel: 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:20fliebelchouser: Yea.
12:20dnolenLConsSeq I mean.
12:21chouserdnolen: record or type?
12:21pdki thought clojure forced all lists to be proper lists
12:21dnolenfliebel: Prolog depth-first has issues. interleaving search prevents certain forms of divergence that exist in Prolog.
12:21chouserpdk: it does. Sorry to confuse, I'm talking about other lisps here.
12:21dnolenchouser: type. record adds a bunch of Seq stuff I don't want.
12:24fliebeldnolen: 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:24fdaoud,(let [a + + 2] (a + 4))
12:24clojurebot6
12:24dnolenfliebel: 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:26fliebeldnolen: What is it? Surely not the set/map unification mentioned in the issue on github.
12:27dnolenfliebel: 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:29fliebeldnolen: 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:30dnolenfliebel: 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:32dnolenfliebel: 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:34dnolenfliebel: I think my version is easier to follow, since Clojure has real type dispatch.
12:35dmiles_afkmy dream intepretor is LISP+PROLOG+CLOJURE on a JVM
12:35dmiles_afkor even .NET
12:35dmiles_afkoh but making it very efficient :)
12:39fliebeldnolen: 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:58fliebelWhat are RestFn and PersistentTreeMap?
12:58phenom_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:59fliebelphenom_: Casting?
13:00amalloyphenom_: i suggest telling him he is crazy
13:01__name__good morning
13:01Scriptormorning __name__
13:01phenom_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:02raekphenom_: like in java? if (x instanceof Foo) { Foo y = (Foo) x; ... }
13:02chouserwhere is casting being done? what's wrong with casting? what's wrong with a huge if/else check?
13:02chouserI'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:02amalloyphenom_: the difference is it's not centralized like an if/else
13:03phenom_but it still is just a large if/else check for any types i want to handle right ?
13:03amalloyif 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:03amalloytry doing that with a "real" if/else
13:03dmiles_afkif (x instanceof Foo) ((Foo)x).bar(); benches way faster than just ((Foo)x).bar(); btw
13:04phenom_so it's a sort of dynamic if/else
13:04dmiles_afkafter JIT
13:04phenom_i can add as I like
13:04raekphenom_: 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:05amalloydmiles_afk: really? that's surprising
13:05raekalso, the hierarchy used for selecting the method does not have to be the java class hierarchy
13:05amalloyeven if x is always a Foo?
13:05dmiles_afkamalloy: CHECKCAST is removed in the ifelse
13:05phenom_but to participate, for most scenarios I'll need to do a cast
13:05phenom_(eg. vector? seq? etc)
13:06raekclojure is dynamically typed, so you don't cast more than usual
13:06hiredmanthat is not a cast
13:06dmiles_afkbut what saddens me is that ((Foo)x).bar(); is faster than x.bar();
13:06chouserI'm so confused.
13:06dmiles_afkif "Foo" inherits the method
13:07raekphenom_: what do you mean by "cast"?
13:07phenom_eek, isn't a call to vector? a class check ?
13:07dnolenmultifns use a dispatch table and they cache lookups. I don't know where if/else or casting comes into the picture.
13:07dnolenphenom_: ^
13:08dmiles_afkso hopfully in bytecode clojure if/else casts to the actual implmneting type
13:09raekfor me, a (dynamic) cast is the operation of turning an Animal reference into a Cat reference when you know it is one
13:09dmiles_afkso hopfully in bytecode clojure if instanceofs and then casts to the actual implmneting type
13:10raekclojure does casts when doing java method invocations. clojure fns are Objects -> Object
13:10dmiles_afkthats good it does assume coercions
13:11dmiles_afkthats good it DoesNT assume coercions
13:11phenom_dnolen: i mean deciding which function to call is done with a class check (instanceof) ... get (vector?)
13:12amalloyphenom_: no
13:12raekphenom_: a multimethod has a dispatch function that yields a dispatch value when passed the arguments of the invocation. this function can be 'type'
13:12dmiles_afki'd kinda hope that (vector? ..) means it implements a IClojureVector or somesuch
13:12amalloypseudocode: (let [dispatch-fns {Vector vector-fn, List list-fn}] ((dispatch-fns (class arg)) arg))
13:13chouserphenom_: 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:13dmiles_afkas in instanecof IClojureVector
13:13amalloybut it doesn't have to be a class-based dispatch
13:13raekphenom_: then you define implementations for some dispatch values (e.g. String, Integer, Keyword, etc)
13:13dmiles_afkah thats nice its not bound to java class structure
13:14phenom_right, so I am checking the class ... i understand you can dispatch on anything and return any value also
13:14chouserif you ask for the class of the object, that's what you get. Note this is not instanceof.
13:14amalloysomewhere around here i have a multimethod that dispatches on the size of its argument with (defmulti blah count)
13:15chouserafter your dispatch fn returns something (such as a class), clojure does a (memoized) heirarchy lookup to find the appropriate defmethod to call.
13:15phenom_but even for functions like get .. internally it needs to check class type (PersistentVector or PersistentMap) to properly dispatch ?
13:15amalloychouser: as a side note, i imagine it dumps out the whole memoization cache if you add a new dispatch fn
13:16chouseramalloy: I believe that's correct. or if you change the heirarchy. :-)
13:16dmiles_afkone day i am sure it could be surgicall dumped
13:16phenom_is there a detailed book that goes into the internals? or is it just a learn by reading code kinda thing ?
13:17amalloyphenom_: the internals are not very interesting. you are ascribing properties to them that they do not have
13:17raekthe comparison would be more like x.getClass == c rathern than x instanceof C
13:17chouserphenom_: clojure.core/get is not a multimethod.
13:17amalloyin pseudo-java: switch (foo.getClass()) {case List: foo.length(); case Map: foo.size();}
13:18amalloyand 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:18chouserphenom_: 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:19amalloychouser: really? i would have expected that it casts to IAssociative and calls the interface method or something
13:19phenom_chouser: RT.get does instance checks no ?
13:19phenom_*class check
13:20dnolenphenom_: 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:20chouseramalloy: it does, but besides supporting ILookup and IPersistentSet, get supports java.util.Map, strings and arrays.
13:20dnolen,{(class []) :look-ma-a-class-as-a-key}
13:20clojurebot{clojure.lang.PersistentVector :look-ma-a-class-as-a-key}
13:20amalloychouser: yeah, i'm reading it now
13:21chouseramalloy: 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:23amalloychouser: hm, i wonder why IPersistentSet doesn't extend ILookup
13:23chouserIt may just be historical. I think ILookup is newer.
13:24chouserI need to write a ticket to extract Sequential from ISeq
13:32mattmitchell(doc select-keys)
13:32clojurebot"([map keyseq]); Returns a map containing only those entries in map whose key is in keys"
13:32mattmitchell,(select-keys {:one 1 :two 2 :three 3} [:two :one])
13:32clojurebot{:one 1, :two 2}
13:33mattmitchellhmm, is there a way to specify the keys you want, in order?
13:33mattmitchelloh oops... what i mean is, is there a way to specify the values you want, in order?
13:33chouser,(map {:one 1 :two 2 :three 3} [:two :one])
13:33clojurebot(2 1)
13:33mattmitchellchouser: awesome thanks
13:34amalloychouser, mattmitchell: also ##((juxt :two :one) {:one 1 :two 2 :three 3})
13:34sexpbot⟹ [2 1]
13:34mattmitchell,(doc juxt)
13:34clojurebot"([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:35mattmitchellcool
13:35amalloy&(doc juxt)
13:35sexpbot⟹ "([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:35mattmitchell,(prn "test")
13:35clojurebot"test"
13:35mattmitchell&(prn "test")
13:35sexpbot⟹ "test" nil
14:10markskilbeckHi, 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:10markskilbeckdotimes?
14:12amalloymarkskilbeck: do you actually want to change them in place, or return a modified copy?
14:12amalloy(if the former, reconsider because that is evil)
14:12markskilbeckA modified copy, I suppose.
14:12rata_hi
14:12markskilbeckAs is the way of clojure.
14:12markskilbeckSup, rata_.
14:12amalloyin that case, you don't want anything that starts with "do" - those usually just perform side effects
14:13markskilbeckNoted.
14:14amalloymarkskilbeck: 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:14dnolen,(-> [1 2 3 4] (assoc (rand-int 4) 'foo) (assoc (rand-int 4) 'bar))
14:14clojurebot[1 bar foo 4]
14:14dnolenno so thing as changing a vector in place anyway
14:14dnolens/so/such
14:14sexpbot<dnolen> no such thing as changing a vector in place anyway
14:14clojurebotGabh mo leithscéal?
14:15markskilbeckdnolen: That's fine, though if I then want to modify 3 indices, I've got to duplicate code.
14:15amalloymarkskilbeck: iterate
14:15markskilbeckAh!
14:15markskilbeckBob's your mother's brother.
14:16amalloy&(nth (iterate #(assoc % (rand-int (count %)) 'foo) [1 2 3 4 5 6] 3)
14:16sexpbotjava.lang.Exception: EOF while reading
14:16amalloy&(nth (iterate #(assoc % (rand-int (count %)) 'foo) [1 2 3 4 5 6]) 3)
14:16sexpbot⟹ [foo 2 foo 4 5 foo]
14:16amalloybut this might result in hitting up the same index multiple times, resulting in fewer than N elements changing
14:17markskilbeckThat's fine.
14:21markskilbeckSo the (nth ... 3) takes the third? iteration?
14:22amalloymarkskilbeck: it takes the fourth entry in the list, where the zeroth entry is the original vector
14:23amalloyhttps://gist.github.com/805747 is several different approaches to a very similar problem that you might be interested in
14:23amalloyand http://www.raynes.me/logs/irc.freenode.net/clojure/2011-02-01.txt contains a discussion of the above
14:24markskilbeckBrill. Thanks.
14:25markskilbeckWait, why the 4th entry? I wanted to modify only 2 indices, but wouldn't that modify (possibly) 4?
14:25amalloymarkskilbeck: it will modify up to three
14:26amalloy0th entry modifies 0, 1st entry 1, 2nd entry up to 2...
14:26amalloyi think my original statement was poorly worded
14:26markskilbeckI see, I see.
14:27amalloy&(take 5 (iterate #(conj % 10) []))
14:27sexpbot⟹ ([] [10] [10 10] [10 10 10] [10 10 10 10])
14:27markskilbeckamalloy: you're most helpful
14:28amalloymarkskilbeck: you're welcome!
14:31markskilbeckAnd that is a _long_ discussion.
14:32amalloymarkskilbeck: well it's an interesting topic :)
15:13rata_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:13LauJensenrata_: 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:18rata_LauJensen: oh ok =)
15:21rata_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:21LauJensenrata_: See Christophes follow-up posts for major performance boosts
15:21LauJensenHe made it even faster than the CL version
15:21rata_using clojure?
15:23rata_LauJensen: where can I find Christophes follow-up posts?
15:23rata_LauJensen: did he use clojure?
15:24LauJensenhttp://clj-me.cgrand.net/page/2/
15:26rata_thanks
16:10rata_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:10rata_interesting optimizations has done cgrand to your code btw
16:19amalloymarkskilbeck: out of curiosity what method did you end up using?
16:40edoloughlinIs there any hope of attaching clojure source to a referenced JAR file in Counterclockwise (e.g., clj-record)?
16:54cinchMoooooo
17:00_2x2ldo the TheDeadline guys hang out around here?
17:06cinch(whois _2x2l)
17:19TimMcI've been using the *warn-on-reflection* flag, and was surprised to see that @dereferences do not carry their :tag metadata through.
17:21amalloyTimMc: @foo is sugar for (deref foo). how would you type-hint the deref function to make that work?
17:21TimMcGood question.
17:22TimMcI guess I'm still kind of fuzzy on how type hinting works.
17:23amalloyTimMc: it would require type-inference that clojure doesn't really have (yet?)
17:25TimMcSo (. 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:26TimMcI suppose you'd have to have some mechanism to say "my type is the same as parameter 3's type" or somesuch. :-/
17:28amalloyTimMc: indeed, and java's generics do that
17:29amalloypublic <T> T deref(IDeref<T> obj) {return obj.deref();}
17:31TimMcOof, I really shouldn't be :tagging those (ref)s anyway -- it's their *contents* that I want to hint.
17:33dnolenTimMc: question is, what are you putting in refs that need type-hinting ?
17:33TimMcAffineTransform instances.
17:34dnolenTimMc: for what benefit?
17:34TimMcMy graphics app needs to update those as the viewport changes.
17:35TimMcI don't want my coordinate transforms to get out of sync with the rotation, scaling, etc.
17:35TimMcI suppose that as long as they are only modified from the event loop I don't really need the transactions...
18:01mattmitchellhow can i check if a string starts with a regexp?
18:02amalloy&(doc re-find)
18:02sexpbot⟹ "([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:02brehautuse an start anchor in the regexp
18:02amalloy&(map #(re-find #"^blah" %) ["blahtwer" "wablah"])
18:02sexpbot⟹ ("blah" nil)
18:10tomojxb
18:58TimMcI'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:59TimMcSo, question: Is there a way to keep the :doc metadata?
18:59TimMc(on the individual wads of state that I keep for the user)
19:00brehaut,(meta ^{:doc "foo"} {:a 1})
19:00clojurebot{:doc "foo"}
19:00tomojare you sure you want vars there?
19:00TimMcbrehaut: I want doc on :a. :-/
19:01TimMcAm I asking for something that doesn't exist?
19:02tomojyes, keywords can't have metadata
19:02brehautTimMc: if you want it on a keyword then yes
19:02TimMcThat is, by consolidating a bunch of (def ^{:doc "stuff"} foo ()) into (def userdata {:foo ()}), I lose individual docstrings?
19:03brehaut,^{:doc "foo"} :a
19:03brehautfor instance
19:03clojurebotMetadata can only be applied to IMetas
19:03TimMcHmm, OK.
19:03tomojare users of your program familiar with clojure?
19:03brehautis clojurebot going to throw me the exception?
19:03tomojthat's the only way it makes sense to me for that stuff to be in vars
19:03TimMctomoj: This is internal stuff.
19:04tomojbetter question: does your program include a clojure repl?
19:04TimMctomoj: What is the alternative? (This is an interactive graphics program using Swing, to give some context.)
19:05tomojso how do you change the data in response to the user?
19:05TimMcI have components that have event listeners that call functions (to update state) that need to refer to the components.
19:05tomojwhat I mean is, how do you update the state
19:06tomojdef, again? alter-var-root? what?
19:06TimMcdef
19:06TimMc(again)
19:06tomojok, pretty sure what you're doing is evil then
19:06TimMcHah, OK.
19:06tomojmaybe an atom would be better suited?
19:07tomojhard 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:08TimMcI'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:08tomojthe only reason you're even allowed to redef is for development
19:08TimMcOK, I will definitely keep that in mind!
19:08brehautim also wondering if you are abusing the metadata stuff?
19:09tomojthe other state abstractions to look into are atoms, refs, and agents
19:09brehautmetadata is largely for tooling (or so i understand)
19:10TimMcbrehaut: I doubt it. I just like using machine-discoverable doc syntax.
19:10TimMcIf I ever use a smart IDE to work on my code, this *should* make it easier to work with.
19:11TimMctomoj: 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:12tomojwith (def userdata (atom {:foo ()}))
19:12brehautTimMc: refs are always a good safe bet
19:13tomojyou can do things like (swap! userdata update-in [:foo] conj 3)
19:13tomojthen (:foo @userdata) is (3)
19:13brehautthey have additonal coordination semantics so if you ever need to access two refs, they can be transactional
19:14TimMcSTM, yeah
19:14brehauthowever, 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:15TimMczipper... heard of, but never used one of those before! Exciting.
19:15brehautTimMc: basically its a double linked singlely ended list
19:16TimMcAren't they more like tree+cursor?
19:16brehautdescibed as a pair of singly linked list
19:16brehautcompletely persistent
19:16brehauti think there may be a couple of things with the same name
19:17brehautor the tree version is a generalisation of the list version
19:18TimMchmm
19:18brehauti am trying to look it up to find some docs for you, but my internet is running slow as mollasas
19:20TimMcbrehaut: 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:24brehautTimMc: im not sure i understand; an undo / redo stack and current state in a world with persistent data structures is exactly this thing
19:25TimMcSure, but I can just use two lists and conj/rest.
19:25TimMcI'd effectively implement the same thing myself.
19:26brehautyeah thats the bit i dont understand
19:26TimMcWell, I don't know the name of the thing I'd want to use instead, or if Clojure has it.
19:29TimMcIf I find out, I'll happily switch to using it. :-)
19:30TimMc(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:42amalloybrehaut: i had a good non-tooling use of metadata. maybe it was evil, i dunno
19:42brehautamalloy: im sure they exist, but im sure its the minority
19:42amalloybrehaut: agreed. i think it's the first time i've had a reason
19:42amalloyfor meta of any kind
19:48amalloyif 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:17rata_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:17brehautrata_: my rule of thumb is 'is it actual data for my program'
20:19brehautif its actual data, then i'd use a map or record
20:20bytecolorrata_: isn't that sort of how clojure.zip is implemented?
20:20rata_it's not any additional data... it's computable from just the data it goes with
20:21rata_bytecolor: I don't know... haven't looked at clojure.zip implementation
20:27brehautbytecolor: 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:28bytecolorah, ok. I'd only peeked at the code a couple times.
20:28amalloybrehaut: "actual data" and "my program" seem almost too vague to be useful here
20:29bytecolorI think I've learned clojure mostly from reading the core and contrib source.
20:30bytecolorwaiting on the dead tree version of the joy of clojure to come out
20:30no_mindSomeone explain to me what exactly is this code snippet doing (map #(section-model % link-model) sections)
20:31no_mindwha tis % operator ? I cant find it even in cheatsheet
20:32amalloyno_mind: anonymous function shorthand
20:32phenom_how do i add classes or dirs to the class path when i launch cake's swank ?
20:32amalloy#(foo % 10) === (fn [x] (foo x 10))
20:33no_mindamalloy: is anonymous function shorthand #() ?
20:34amalloyer...yes, i guess? i don't understand the question
20:38TimMcno_mind: It's not an operator.
20:38no_mindk
20:39TimMcno_mind: #(... % ...) is equivalent to something like (fn [x] ... x ...)
20:39no_mindk
20:39TimMcIt's the single argument to the anonymous function.
20:39brehautno_mind: http://clojure.org/reader
20:39brehautunder macro characters, dispatch
20:41TimMcno_mind: Note that I forgot an important pair of parens in my expansion.
20:45TimMcbrehaut: 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:48TimMc(I should add a "n00b at work" warning in the readme.)
20:49brehautTimMc: im not sure why you need a seperate ref for past and future
20:50brehaut(def history (ref [[], []])) would suffice
20:50TimMcTrue. What's the advantage?
20:50brehautsimplicity
20:51TimMcAnd I suppose some conceptual atomicity as well.
20:51brehautyes
20:51brehauti dont think you need 3 ref-sets; you should be able to get by with one
20:52brehautffirst on your history ref will give you the current state
20:53TimMcYeah, I did debate on whether to have the current state as part of the undo history or not.
20:53TimMcI need to think about that some more.
20:53brehautit makes the updating of the undo and redo stack trivial
20:53brehautyou dont have to sidestep through the current state
20:56TimMcI've also been considering whether I want a more complex undo/redo system.
20:56brehautno, you want to get your program working first :P
20:56TimMcNotice how most word processors will undo chunks of typing at a time?
20:58TimMcTrue.
20:58pdkhey uh
20:58pdkwhich libraries are clojurebot/sexpbot using for irc interaction again
20:58TimMcI wasn't planning on doing fancy skiplist history quite yet.
21:00TimMcpdk: clojurebot appears to be using PircBot, a Java thingy.
21:01TimMcI bet both are open source on github.
21:02TimMcpdk: https://github.com/Raynes/sexpbot
21:09pppaulanyone home?
21:09pppauli'm feeling really stupid with a simple clojure problem i have regarding maping over a dictionary
21:10brehautpppaul: oh?
21:10pppaul(map identity (vals v))
21:10pppaul({:id 6822400, :name "Adam Tran"} {:id 43535, :name "Sdfsfsd"})
21:10pppaulsolve360.name-fixer> (map #({:id (:id %), :name (:name %)}) (vals v))
21:10pppaulthe last line gives an error
21:10brehautpppaul: maps return MapEntries for seqs
21:10brehautthey look like pairs
21:11pppaulum
21:11pppaulhow can i get a visual on that?
21:11pppaulor is there a better way to do what i want?
21:11brehaut,(map identity {:a 1 :b 2 :c 3})
21:11clojurebot([:a 1] [:b 2] [:c 3])
21:11pppaulwhich is transforming a map
21:12mattdwpppaul: also, #({..}) is going to try to call the map, I believe, not return it
21:12pppauloh
21:12brehautmattdw: correct
21:12pppaulok
21:13mattdwturn it into an (fn [v] ...) if you just want the map returned
21:14pppaulthanks
21:14gfrlog,(seq {:a 1 :b 2 :c 3})
21:14clojurebot([:a 1] [:b 2] [:c 3])
21:14pppauli want to transform the map into a new map
21:14pppaulwhat would be the best way to do this?
21:14gfrlogyou want to map the map?
21:14Kowboydon't confuse the map the function and map the datatype
21:14brehaut(into {} (map f m))
21:14pppauldatamap to datamap
21:15gfrlogyou want to change the keys, the values, or both?
21:15pppaullike XSLT
21:15brehautf needs to take a pair and return a pair
21:15pppaulcool
21:15Kowboythe function map will return a sequence, not a data map
21:15pppaula seq of datamaps is ok
21:16brehauteg ##(into {} (map (fn [[k v] [(dec k) (inc v)]) {1 2 3 4 5 6}))
21:16pppaulthat's what i'm starting with
21:16gfrlog,(into {} (map (fn [[k v] [(dec k) (inc v)]) {1 2 3 4 5 6}))
21:16clojurebotUnmatched delimiter: )
21:16gfrlog,(into {} (map (fn [[k v] [(dec k) (inc v)]) {1 2 3 4 5 6})
21:16clojurebotUnmatched delimiter: )
21:16Kowboycan you give us an example of a 1 entry map and what you want it transformed into?
21:16gfrlog,(into {} (map (fn [[k v] [(dec k) (inc v)]] {1 2 3 4 5 6}))
21:16clojurebotEOF while reading
21:16pppaul({:id :name :etc....},{}) -> ({:id :name},{})
21:16gfrlog,(into {} (map (fn [[k v] [(dec k) (inc v)]] {1 2 3 4 5 6})))
21:16clojurebotjava.lang.RuntimeException: java.lang.Exception: Unsupported binding form: (dec k)
21:17gfrlog,(into {} (map (fn [[k v]] [(dec k) (inc v)]) {1 2 3 4 5 6})))
21:17clojurebot{0 3, 2 5, 4 7}
21:17gfrlogah finally
21:17pppaulinteresting
21:18Kowboycan the bot tell me the doc string of (into)?
21:18gfrlog,(doc into)
21:18clojurebot"([to from]); Returns a new coll consisting of to-coll with all of the items of from-coll conjoined."
21:18gfrlogclojurebot: thanks
21:18clojurebotthanks for your suggestion, but as usual it is irrelevant
21:19gfrlogI think (into) is kind of an ugly function for these purposes. But I don't think there's anything better at the moment
21:19gfrlog,(into #{1 2 3} [2 3 4])
21:19clojurebot#{1 2 3 4}
21:20brehautgfrlog: you could use hash-map or array-map
21:20gfrlog(doc hash-map)
21:20clojurebot"([] [& keyvals]); keyval => key val Returns a new hash map with supplied mappings."
21:20Kowboycurious, what is the purpose of splitting a multi-entry map into a bunch of single-entry maps?
21:20gfrlogKowboy: I have no idea, who suggested that?
21:20Kowboywhy wouldn't you just use a sequence of tuples (2 element sequences)?
21:20gfrlog,(doc array-map)
21:20clojurebot"([] [& keyvals]); Constructs an array-map."
21:21Kowboypppaul is trying to do that
21:21pppaul({:id :name :etc....},{}) -> ({:id :name},{})
21:21pppaulthat is what i want
21:21gfrlogbrehaut: we were talking about mapping a map -- is that what you were suggesting hash-map for?
21:21pppauli'm braindead now, though
21:21Kowboywhat's the difference between {:a 1} and [:a 1] if you aren't going to have multiple keys?
21:21pppauli haven't worked with maps much
21:21brehautgfrlog: as a replacement for into {}
21:22gfrlogKowboy: I agree
21:22pdk(doc into)
21:22clojurebot"([to from]); Returns a new coll consisting of to-coll with all of the items of from-coll conjoined."
21:22gfrlogbrehaut: so if I want {"jack" 12, "jill" 15} to be mapped to {:jack, 13, :jill, 16}
21:22amalloy&(map hash-map {1 2 3 4})
21:22sexpbotjava.lang.IllegalArgumentException: No value supplied for key: [1 2]
21:22amalloy&(map (partial apply hash-map) {1 2 3 4})
21:22sexpbot⟹ ({1 2} {3 4})
21:22gfrloghow would hash-map make that easier?
21:23amalloybut i agree with the others, it's sorta silly to want this
21:24gfrlog,(into {} (fn [[k v]] [(keyword k) (inc v)]) {"jack" 12, "jill" 15})
21:24brehautgfrlog: 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:24clojurebotjava.lang.IllegalArgumentException: Wrong number of args (3) passed to: core$into
21:24gfrlog,(into {} (map (fn [[k v]] [(keyword k) (inc v)]) {"jack" 12, "jill" 15}))
21:24clojurebot{:jack 13, :jill 16}
21:24pppaul(map (fn [v] {:id (:id v) :name (:name v)} ) (vals v)) : my solution
21:24gfrlogbrehaut: I guess I'm thinking that using hash-map would be more cumbersome
21:24amalloygfrlog: (for) will be a lot cleaner than (map (fn))
21:24pppauli don't know what it didn't work with #(%) format
21:24brehauti think so to, hence my original use of into { }
21:24gfrlog,(doc for)
21:24clojurebot"([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:25gfrlogbrehaut: oh, okay -- I thought you were suggesting hash-map as better than into {}
21:25pppaulhow would i use for?
21:25gfrlogamalloy: I'm getting that feeling that I've been missing out on a whole function for a long time
21:25zakwilsonI'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:25amalloy&(into {} (for [[k v] {"jack" 11 "jill" 15}] {(keyword k) (inc v)}))
21:25sexpbot⟹ {:jack 12, :jill 16}
21:26pppaulwow, that is over my head
21:26pppaul"jack" -> :jack ???
21:26gfrlogpppaul: for isn't that bad
21:27pppauli would really like a tutorial on for
21:27brehautpppaul: ##(keyword "foo")
21:27sexpbot⟹ :foo
21:27gfrlogpppaul: are you wondering what the :jack syntax means?
21:27pppauli'm wondering how "jack" is transformed into :jack
21:27gfrlog,(for [x (range 5)] [x (inc x)])
21:27clojurebot([0 1] [1 2] [2 3] [3 4] [4 5])
21:28brehautpppaul: the keyword function
21:28gfrlog,(keyword "jack")
21:28clojurebotjava.lang.StackOverflowError
21:28pppauloooooooooh
21:28gfrlog,(keyword "jack")
21:28clojurebot:jack
21:28pppauldamn i'm tired
21:28amalloy&(map (juxt identity inc) (range 5))
21:28sexpbot⟹ ([0 1] [1 2] [2 3] [3 4] [4 5])
21:28pppaul:P
21:28gfrlogamalloy: I agree, I was trying to do a trivial use of (for)
21:28amalloykk
21:29gfrlogIt's juxt what I was trying to use for for
21:30Kowboy,(for [[k v] {:id 12 :name "Bob"}] {k v} )
21:30clojurebot({:id 12} {:name "Bob"})
21:30Kowboystill, I'd use a vector instead
21:30gfrlogI'd use a java.util.HashMap<String, String>
21:30brehautpppaul: http://clojuredocs.org/clojure_core/clojure.core/for go read that
21:31amalloygfrlog: barf
21:31Kowboy,(for [x {:id 12 :name "Bob"} ] x)
21:31clojurebot([:id 12] [:name "Bob"])
21:32pppaulreading
21:34Kowboynow I'm confusing myself on how map and for are different
21:35amalloyKowboy: they treat multiple sequences differently
21:36brehautpppaul: 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:36Kowboyand for takes an expression/form while map takes a function?
21:36brehautpppaul: the first example on that page shows a map and filter occuring in the same comprehension
21:36amalloyKowboy: sure, that's mostly syntax sugar
21:36brehautthe second and third examples are crossproduces
21:37brehautKowboy: for has more in common with mapcat than with map
21:37brehautKowboy: it happens that when there is only a single sequence, it looks like map
21:38arohnerhas anyone used cron4j? Is it any good?
21:39Kowboyok, found my equivalent expressions:
21:39Kowboy,(map (fn [x] x) {:id 12 :name "Bob"})
21:39clojurebot([:id 12] [:name "Bob"])
21:39Kowboy,(for [x {:id 12 :name "Bob"} ] x)
21:39clojurebot([:id 12] [:name "Bob"])
21:39Kowboynot sure if my map version can be done more simply
21:40brehautKowboy: use identity instead of (fn [x] x)
21:41amalloybrehaut: or vec
21:43Kowboy,(== (map identity {:id 12 :name "Bob"}) (for [x {:id 12 :name "Bob"} ] x))
21:43clojurebotjava.lang.ClassCastException: clojure.lang.LazySeq cannot be cast to java.lang.Number
21:44Kowboydarn
21:44amalloyKowboy: =, not ==
21:45Kowboy,(= (map identity {:id 12 :name "Bob"}) (for [x {:id 12 :name "Bob"} ] x))
21:45clojurebottrue
21:45Kowboywait, isn't = the assignment operator?
21:46Kowboy:-)
21:52amalloyat least clojure doesn't have ===
21:56Kowboy=== is for when you REALLY mean it
21:57Kowboythat's it, I'm going to define === and add it to the clojure.core ns
21:57shachafKowboy: And redefine == to randomly return the wrong answer 10% of the time.
21:59Kowboybrilliant!
21:59TimMcIt's not random! :-(
21:59TimMcI can't speak for PHP, though.
21:59Kowboyhow about !!=
22:00Kowboythe not-not-equal operator
22:00amalloyTimMc: php's implicit type conversions are even worse than javascript's, which are abominable
22:00TimMcamalloy: I think JS's == is not even transitive, which is awesome.
22:03amalloyreally? e.g.?
22:04TimMcUgh, can't find it now...
22:04TimMcI'll get back to you if I can reproduce it.
22:05TimMcamalloy: OK, here we go: '00' == 0 == '0'
22:05TimMcbut '00' != '0'
22:05amalloynice
22:06TimMcI had forgotten that JS did string parsing for integer equality. Yuck.
22:07amalloyTimMc: in php: '00' == 0 == 'ojhgfklh'
22:08TimMc(defn == [a b] true)
22:10rata_hahaahaha
22:10rata_how do you change the size of the slime history?
22:12gfrlogbarfbag2273
22:21pdk(doc read-line)
22:21clojurebot"([]); Reads the next line from stream that is the current value of *in* ."
22:30Kowboyok, I have a tough one
22:30KowboyI want a macro that can generate multiple functions
22:31Kowboy(make-call {:char-list "/chars" :foo "/foo" :bar "/bar" })
22:31Kowboyto result in definitions like: (defn foo [] (println "/foo"))
22:31tomojif there are no more arguments, may I suggest dropping the {}?
22:31Kowboybut for each pair in the map
22:31Kowboyok
22:32tomojnot that it matters much..
22:32Kowboyand bind them using let?
22:32Kowboyor for, rather
22:33KowboyI actually am close
22:33tomojno, just (defmacro make-call [& {:as foo}]) or whatever
22:33Kowboyright now, I get my defn's wrapped in a list
22:33tomojjust stick a 'do at the head
22:34Kowboyhmm...i tried that, maybe I did something wrong there
22:34KowboyI know what I did
22:34KowboyI should have done (list 'do ....
22:34KowboyI just did ('do
22:35tomojlist* is often useful in situations like that
22:35Kowboy,(doc list*)
22:35clojurebot"([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:36tomoj,(list* 'do (for [[k v] {:foo 3 :bar 4}] `(def ~k ~v)))
22:36clojurebotDENIED
22:36tomojhuh
22:36tomojoh, of course
22:37tomoj,(list* 'do (for [[k v] {:foo 3 :bar 4}] `(poop ~k ~v)))
22:37clojurebot(do (sandbox/poop :foo 3) (sandbox/poop :bar 4))
22:38Kowboyhah, it works!
22:38Kowboythanks
22:41Kowboytomoj: trying to strip the {}
22:41amalloy`(do ~@body) is a common idiom
22:41Kowboyso [& args]
22:41Kowboyhow to I bind that to pairs?
22:42amalloyKowboy: with the {} :P
22:42tomojpff
22:42amalloyor if you really prefer it, you can (partition 2 args)
22:43tomojI guess you probably don't want {:as crap} in your arglist
22:43amalloy&(partition 2 [1 2 3 4 5 6])
22:43sexpbot⟹ ((1 2) (3 4) (5 6))
22:43Kowboy(make-call :foo "/foo" :bar "/bar")
22:44Kowboyso I need to iterate over the args in pairs
22:44Kowboynot seeing it
22:44tomojwell destructuring can do it for you
22:45tomoj..better not though
22:46amalloy&(let [args [:foo "/foo" :bar "/bar"]] `(do ~(map str (partition 2 args))))
22:46sexpbot⟹ (do ("clojure.lang.LazySeq@5d847e33" "clojure.lang.LazySeq@5d2b26fe"))
22:46amalloy&(let [args [:foo "/foo" :bar "/bar"]] `(do ~(map (partial apply str) (partition 2 args))))
22:46sexpbot⟹ (do (":foo/foo" ":bar/bar"))
22:47amalloywhoops, forgot the @ in ~@
22:48tomojyou prefer `(do ~@x) to (list* 'do x)?
22:48Kowboyok, I get the :as option now
22:48Kowboy[& {:as calls}]
22:49amalloytomoj: not especially. but (cons 'do x) is better
22:49amalloyif you're going to do without `
22:50tomojcore.clj confirms this spectacularly
22:50tomoj(if name (list* 'fn* name new-sigs) (cons 'fn* new-sigs))
22:50amalloyheh
22:52tomojhas bit-seq left anyone else seriously confused?
22:52amalloy&(doc bit-seq)
22:52sexpbotjava.lang.Exception: Unable to resolve var: bit-seq in this context
22:52tomojfrom gloss, I should say
22:52Kowboyso, basically I am deciding whether to use a macro, or currying for my needs
22:52Kowboythey accomplish the same thing, with the macro approach being more DRY and the currying approach being a little clearer
22:53KowboyI am defining groups of functions which have similar arg lists, but each function is specifying one of the args
22:56amalloyKowboy: i don't follow
22:57Kowboyinstead of this: (geturl "/foo" 1 2 3) (geturl "/blah" 1 2 3), etc....
22:57KowboyI'm turning that into (foo 1 2 3) and (blah 1 2 3)
22:57Kowboyso, using currying
22:58Kowboy(def foo (partial geturl "/foo"))
22:58brehautKowboy: thats not currying
22:58brehautthats partial application
22:58KowboyI thought it was the same thing
22:58brehautno
22:58Kowboyclose?
22:58amalloythey're related, anyway
22:59brehautimplict partial application is a property of curried functions
22:59TimMcI don't think you can have currying and variadic functions in the same language.
22:59brehautTimMc: should i point you to the printf implemention in haskell?
23:00brehautcanonical example: (fn [a b c] (…)) curried would be
23:00TimMcbrehaut: How does it know when to stop?
23:00brehaut(fn [a] (fn [b] (fn [c] (…)))
23:00amalloyTimMc: someone posted automatic currying of non-variadic defns on the clojure ng a month or two ago
23:00brehautTimMc: the magic of type classes
23:00TimMcbrehaut: Hrmf. GO figure, it's more Haskell magic. :-P
23:00Kowboystill not sure I see the difference
23:01brehautKowboy: the former would be called as (f 1 2 3)
23:01brehautthe latter as (((f 1) 2) 3)
23:01Kowboyok, so currying is a chain of functions with a single argument
23:01brehautyes
23:02brehautwell
23:02brehauta curried function is
23:02Kowboysubtle difference
23:02brehautyes
23:02brehautbut its important
23:03brehautyou 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:03brehaut[end of curry/partial rant]
23:04amalloybrehaut: don't proclaim that so soon
23:04Kowboyok, so back to my decision, macros vs. partially applied functions
23:04Kowboy(def foo (partial geturl "/foo"))
23:04Kowboyvs
23:04Kowboy(make-call :foo "/foo" :bar "/bar")
23:05Kowboyany thoughts?
23:05amalloyKowboy: they both sound kinda crazy to me tbh
23:05TimMcI have heard "avoid using macros when functions will do" as good Clojure style.
23:05brehauthaskell printf btw http://hackage.haskell.org/packages/archive/base/latest/doc/html/Text-Printf.html#v:printf
23:05TimMcNot sure if that's just for debugging difficulty, readability, or what.
23:05Kowboywell, I would be doing a lot of code duplication otherwise
23:06amalloyTimMc: and reusability/composability
23:07TimMcooh, composability, right
23:07Kowboythe only reason to use partially applied functions is to avoid having to state the parameter list over and over again
23:07TimMcbrehaut: Ohhh, does it know when to stop by reading the format string?
23:07brehautTimMc: in this case yes but also magic ;)
23:07TimMchaha
23:07TimMcOf course magic.
23:08Kowboymagic - it's a feature of the language
23:11brehautthe primary piece of magic is actually 'pretty simple'; type classes can be polymorphic on the return type of functions
23:12Kowboyhaven't learned Haskell yet
23:12Kowboywill someday, though
23:12Kowboyit's on my list
23:14amalloyKowboy: i just don't think you need to do any top-level defs to get the partial/curried versions of your functions
23:14amalloythe eventual result you want is like (partial (partial (partial (partial get-url "/foo") 1) 10) 12), right?
23:15amalloythat looks like a job for reduce
23:16Kowboysorry, the args after the url are parameters to a web service
23:16amalloy(reduce partial get-url ["/foo" 1 10 12])
23:16KowboyI just used integers for readability
23:17Kowboyie, (get-url "/foo" username password account-num)
23:18amalloyKowboy: uh-huh...the type of the args doesn't really matter
23:18Kowboyso I'm making methods like (foo username password account-num)
23:18Kowboyand (bar username password account-num)
23:19Kowboywell, hell, why don't I just link the code ;-)
23:22Kowboyhttps://bitbucket.org/craigmcdaniel/clojureve/src/039d3260328f/src/clojureve/api.clj
23:22Kowboythis is my first attempt at useful clojure code
23:23Kowboyso be gentle ;-)
23:23technomancyclojurebot: arrows is http://ro-che.info/ccc/12.html
23:23clojurebotOk.
23:25amalloyKowboy: my point is why are you def-ing these to vars in the first place?
23:26Kowboyas opposed to?
23:28amalloy(def account-calls (into {} (for [[name url] {"character-list" "CharacterList" ...}] {name (partial account-call (str "/account/" url ".xml.aspx"))})))
23:29amalloyi 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:30RaynesI was going to be clever and say "Your first mistake is using Mercurial." but decided against it, because I'm a nice guy.
23:31KowboyI guess there's not much of an Emacs vs Vim flame here, so you have to go for the git vs Mercurial ;-)
23:31brehautRaynes: you are only allowed to use that joke with people still using svn
23:31RaynesKowboy: Don't tell me you're using Vim as well? God, I wont be able to contain myself.
23:32Kowboyno, I'm using emacs
23:32RaynesHighest of fives.
23:32brehautRaynes: yeah he uses vi, hg, win, and lein
23:32amalloyhahaha
23:32Kowboyis there a lein debate?
23:32amalloyKowboy: lein/cake
23:32TimMcIt is the only sexp-aware editor I could find that uses C-s for save. :-P
23:32brehautKowboy: raynes is young and polarised :P
23:33KowboyI know the type
23:33brehautKowboy: yeah, any nerd under the age of 55
23:33brehautthe ones over 55 arent polarised, just stuck in their ways
23:33Kowboyhey!
23:33KowboyI must be between the 2 then ;-)
23:34KowboyI see your point amalloy
23:34Kowboybut I'm writing an api others may use, and I think they may only care about a subset of the functions
23:35Kowboyin which case they will probably want to call the functions by name
23:35amalloyKowboy: i don't see why. they can write ((account-call "character-list") more-args)
23:36amalloyand if you want, you can wrap that up in some defns with a macro
23:36Kowboyhmmm
23:36amalloybut the underlying functionality should be a map or a multi or something
23:37Kowboya multi doesn't fit here does it?
23:37Kowboyunless you are talking about the different types of calls
23:37amalloymeh, i guess not
23:37Kowboyaccount, anonymous, character, etc
23:38amalloyyeah multi doesn't make a lot of sense here
23:38KowboyI could wrap all those into one api call with multis
23:38amalloybut a map!
23:43Kowboy(derive ::character-list ::account-call)
23:43KowboyI could use something like that for the dispatching
23:43amalloyKowboy: maybe so
23:44defnhttp://clojuredocs.org/clojure_core/clojure.java.io/file
23:44defnwhat's up with the http:/asdf.com ?
23:45defn(the single slash)
23:45KowboyI just recently learned about multis, so I may explore that
23:46Kowboyis there a shortcut version (macro) for derive that associates multiple child tags with a parent?
23:46amalloyKowboy: just use doseq. you don't need a specific macro
23:46Kowboywouldn't be much to write one
23:47Kowboyk
23:47amalloyit definitely shouldn't be a macro. a function is more than enough
23:47Kowboyyeah, not much to it really
23:48Kowboyjust seems like something that would be pretty common
23:48amalloyKowboy: not as far as i've seen
23:49amalloyif 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:50Kowboyyou lost me there
23:52amalloymultimethods let anyone add methods at any time
23:52brehauta multimethod that is not open to extension is probably better served by (say) cond
23:54tomojdefn: ##(.getPath (java.io.File. "foo//bar"))
23:54sexpbot⟹ "foo/bar"
23:54tomoj&(.getParent (java.io.File. "http://google.com&quot;))
23:54sexpbot⟹ "http:"
23:54tomojshould be removed from the example as it's terribly misleading
23:54amalloyhaha tomoj that is awful
23:57amalloybrehaut: more likely case or a raw map than cond, but i agree with your general point
23:58amalloy(not surprising since you were kindly making my point for me)
23:58Kowboyok, chat with you guys later