#clojure logs

2011-07-10

00:01scottjmdeboard`: http://www.youtube.com/watch?v=lf_xI3fZdIg http://www.youtube.com/watch?v=kH0gOE7rj7g
00:02scottj+ ritz + clojure-refactoring
00:09sa125Hi - how do I reverse a string? I tried (reverse "hello") and got (\\o \\l \\l \\e \\h).
00:09sa125[single backslash]
00:10hiredman,(clojure.string/reverse "foo")
00:10clojurebot"oof"
00:11sa125hiredman - thanks!
00:13hiredmanthats like 4
00:13mdeboard`Whoops.
00:34ihodesi'm (also) looking into covering Clojure & Java. what are the main pain points? should i be aiming it at Java programmers, or people without Java experience (though this will partially be based on what cemerick releases from The State of Clojure II)
01:00pcavs,(doc source)
01:00clojurebotI don't understand.
01:01amalloy$mail mdeboard` to get the slime repl to recognize [] and {} as parens, try https://gist.github.com/1074292
01:01sexpbotMessage saved.
01:03amalloypcavs: source is in clojure.repl, which the bots don't load
01:03pcavsyeah, I keep reaching for clojure.contrib.repl-utils and keep remembering (eventually) that it's clojure.repl =\
01:07pcavs$findfn 5 4 false
01:07sexpbot[clojure.core/== clojure.core/identical? clojure.core/isa? clojure.core/< clojure.core/= clojure.core/<= clojure.core/contains? clojure.core/bit-test]
01:07pcavsI guess I'm down to using (not (= ...)) then?
01:09amalloypcavs: uh, are you looking for not=? if so, you probably meant
01:09amalloy$findfn 5 4 true
01:09sexpbot[clojure.core/not= clojure.core/distinct? clojure.core/> clojure.core/>=]
01:10pcavsgod dammit I'm stupid =\
01:13taliosanyone know if theres an updated version of clojure.contrib.gen-html-docs thats 1.3 compatible?
01:13zodiakdoes anyone have a newb friendly clojureql and sqlite3 example ?
01:23amalloytalios: would marginalia be acceptable? it's probably 1.3-compatible, but i don't use it
01:23Blackfootif I take a class as a function arg, how can I instantiate it?
01:25taliosamalloy: I'm looking to roll a new clojure-maven-plugin and the IT tests fail on the gendoc goal under 1.3. I could switch it to the marginalia goal ( should test that works as well ). Tempted to just deprecate and remove both goals actually.
01:26amalloyBlackfoot: you have to use reflection
01:26amalloy&(let [c Integer] (.newInstance c 5))
01:26sexpbotjava.lang.IllegalArgumentException: No matching method found: newInstance for class java.lang.Class
01:26amalloy&(let [c Integer] (.newInstance c (into-array Object [5])))
01:26sexpbotjava.lang.IllegalArgumentException: No matching method found: newInstance for class java.lang.Class
01:26amalloyfeh. something like that
01:27taliosits a static method so needs a different invovation
01:28talios&(let [c Integer.class] (.newInstance c (into-array Object [5])))
01:28sexpbotjava.lang.ClassNotFoundException: Integer.class
01:28amalloytalios: that's 100% wrong. Integer.class is java syntax
01:29taliosyeh
01:29Blackfootamalloy: ah yea, i see where you're going, thanks. i'll play around with the function calls
01:29Blackfootah Class.newInstance can only invoke zero arg ctor
01:30Blackfootjava.lang.Reflect may work
01:30amalloy&(.newInstance (.getDeclaredConstructor Integer (into-array Class [Integer/TYPE])) (into-array Object [5]))
01:30sexpbotjava.lang.SecurityException: You tripped the alarm! package java.lang.reflect, Java Platform API Specification, version 1.6 is bad!
01:30taliosBlackfoot: a class has a getConstrutors(Object, Object) method that'll return a Constructor instance you can us
01:30amalloyor there's clojure.lang.Reflector, which simplifies a lot of this stuff
01:30amalloy,(.newInstance (.getDeclaredConstructor Integer (into-array Class [Integer/TYPE])) (into-array Object [5]))
01:30clojurebot5
01:30taliosdoh - declaredConstructor actually
01:42replacatalios: (looking back over history) No one has done anything to make gendoc work on 1.3 nor does there seem to be any plan to
01:42taliosreplaca: yeh, was just reading over the mailing list and came to the same conclusion
01:43replacaBasically, if there ain't a new-style contrib library, it ain't coming
01:43replacaalthough there is plenty of room to mmake a case for stuff
01:50amalloytalios: because new-contrib isn't one huge package with the clojure.org seal on it, if you want a 1.3 version of a contrib library, you can publish it yourself. i mean, you can't call it contrib without their permission, but you can easily make it available even if core isn't interested in it
02:02taliostechnomancy: around? Any chance of publishing swank-clojure 1.3.1 to maven-central? http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.github.technomancy%22 only shows 1.2.1
02:58mdeboard`Ok, I think I'm going to tear my hair out.
02:58mdeboard`I've been trying to get SLIME repl working in emacs for hours now, I'm exhausted.
02:58mdeboard`but I keep getting the same issue as here: https://github.com/technomancy/swank-clojure/issues/49
02:59hiredmanmy guess is you have the wrong slime
02:59hiredmanare you using clojure-jack-in ?
02:59mdeboard`yeah, clojure-jack-in, then I get a "Lisp lost connection" message as soon as I do anything at all.
02:59mdeboard`Do I really have to get a 2-year-old release?
02:59mdeboard`*branch
02:59hiredmanwhat do you mean two year old release?
03:00mdeboard`Well, I grabbed the release from ELPA, thinking that would solve the problem
03:00hiredmanno no
03:00mdeboard`Yeah this is really fucking confusing.
03:00hiredmanfollow the usage instructions https://github.com/technomancy/swank-clojure
03:01mdeboard`Right, but what slime do I use?
03:01hiredmanit is pretty simple if you follow the instructions, if you don't it's your own fault
03:01mdeboard`No, no
03:01mdeboard`That part is fine.
03:01mdeboard`It connects to the REPL fine.
03:01hiredmanyou don't need a slime
03:01mdeboard`what.
03:01replacamdeboard`: technomancy ha a blog post here that shows how
03:01hiredmanclojure-jack-in actually loads a budled slime from the swank-clojure jar
03:01replacahttp://technomancy.us/149
03:02mdeboard`Ok
03:02mdeboard`That
03:02hiredmanmdeboard`: you did the three things in the usage instructions for swank-clojure? and still get the error?
03:02mdeboard`hiredman: Yeah, but I was still requiring slime
03:02mdeboard`and since I had slime installed
03:02mdeboard`it was fucking everything up, maybe? I dunno, let me go fix up emacs config
03:02replacamdeboard`: but make *absolutely* sure you don't have a swank in you project.clj or anywhere else in your classpath
03:03replacamdeboard`: yeah, that's your problem
03:03replacaI had the same problem when I followed those instructions
03:06talioswow - google ran out of diskspace. Never saw that one coming - http://venturebeat.com/2011/07/09/google-on-massive-google-spam-influx-we-ran-out-of-disk-space/
03:08mdeboard`Alright, that did it.
03:08mdeboard`That has been really frustrating.
03:10hiredmanmdeboard`: for future reference #clojure is generally pg or pg13 language wise
03:10mdeboard`thanks, guy who pointed out that issue and hiredman
03:10mdeboard`Did I cuss? Sorry.
03:10mdeboard`I'm usually pg or pg13 language wise.
03:11replacamdeboard`: :)
03:11hiredman:)
03:12talios...so there we have it. slime is more of a hindrance to clojure newbies than hiredman. hiredman++
03:12Blackfootis there a way to use alias namespaces in keywords? eg (:require really.long.ns :as lns) then use :lns/kw later?
03:13hiredmanit's hard to say if technomancy's relentless pace of changes (aimed to make it easier) actually makes it harder or not
03:13hiredmanblog posts have a half life of a week or so it seems like
03:14taliosright - going to go hunt some thai takeaway dinner whilst this clojure-maven-plugin release runs - back later.
03:14scgilardiBlackfoot: it looks like the alias is not effective there. seems to me that it should be.
03:15hiredmanBlackfoot: ::some-alias/word
03:15hiredman,(require '[clojure.zip :as z])
03:15clojurebotnil
03:15hiredman,::z/foo
03:15clojurebot:clojure.zip/foo
03:15scgilardinice
03:15zodiakwhy does this http://pastie.org/2190990 in repl give me java.lang.Exception: Unable to resolve symbol: rs in this context (NO_SOURCE_FILE:17) ?
03:15Blackfoothiredman: ooh nice, thanks
03:16zodiakwell, I mean, I can guess why, I mean rather what's the solution and why :) :)
03:16hiredmanzodiak: you have a lot of quoted symbols there
03:16hiredmando you know what quoting does?
03:17zodiakhiredman: it's similar to a symbol in ruby/haskell .. no ?
03:17hiredmanzodiak: if you don't know what quoting does then I suggest you a. stop doing it until you b. read up on it
03:18zodiakfine, but how do I solve that error in the meantime ? :)
03:18hiredmanI just told you how
03:18scgilardiyou also probably want (require '[clojure.contrib.sql :as sql]) at the top rather than ns and in-ns
03:18scgilardi(and do follow hiredman's advice)
03:19zodiakscgilardi: but if I do that, doesn't the whole namespace get potentially polluted by the methods/def's from contrib.sql ?
03:19taliosmmm, that paste mentions an error on line 17, but only 10 lines pasted .. there no symbol rs even mentioned in the paste
03:19hiredmanzodiak: I suggest reading docs on namespaces etc (and all the other docs, in order) linked to on the left sidebar of clojure.org
03:20scgilardino. they would be pulled in if you used "use". require loads the namespace if not loaded. and the :as makes an alias that goes along with the code you posted (if fixed)
03:20zodiakhiredman: well, yes, I am trying to learn .. ergo.. why I am asking what's wrong
03:20zodiakscgilardi: alrighty, that makes sense
03:20hiredmanzodiak: you don't know what quoting does, and you are quoting stuff, so of course it doesn't do what you want
03:21zodiak*sighs gently*
03:25taliosgrr stupid irc client - shows that pastie.org content inline in the chat client, and only showed me 1/2 of it. Now I see all the quoting which makes hiredman's comments make sense to me.
03:25taliosbut I was going for food... bbl
03:26hiredmantalios: thats pretty slick
03:27talioshiredman: yeh, its good for image links, but for a moment I thought he'd actually pasted the content INTO the channel :) all I was was the mydb definition and I was sitting there thinking "quoted.... he's only quoting strings... whats hiredman on about?"
03:27talioser, all I was seeing
03:28amalloytalios: "all i was was the mydb connection": someone who's meditating about how to write a function?
03:28zodiakoh. quote delays evaluation
03:28hiredmanI should see about getting my growler thing to open pastebin links
03:28amalloyzodiak: no, it prevents it
03:28zodiakamalloy: fairy snuff :)
03:28hiredmanfunctions delay evaluation (and delay binding) and so do delays
03:29scgilardiman I like functions
03:29taliosamalloy: I am a database connection, nothing more, nothing less. a conduit to information for the rest of you :)
03:29scgilardiyeoman's work, t-man
03:30hiredman#9
03:30hiredman~#9
03:30clojurebot9. It is better to have 100 functions operate on one data structure than 10 functions on 10 data structures.
03:31hiredman~#94
03:31clojurebot94. Interfaces keep things tidy, but don't accelerate growth: Functions do.
03:33ihodes~#42
03:33clojurebot42. You can measure a programmer's perspective by noting his attitude on the continuing vitality of FORTRAN.
03:34ihodes*goes to cbots source*
03:34amalloy$google alan perlis quotes fortran
03:34sexpbotFirst out of 618 results is: Perlisisms - "Epigrams in Programming" by Alan J. Perlis
03:34sexpbothttp://www.cs.yale.edu/quotes.html
03:34amalloyihodes: ^
03:35hiredmanvery apropos, the code that grabs the epigrams uses a delay
03:35ihodesamalloy: excellent; i couldn't remember the name of the list
03:35zodiakday 2 of clojure, and I managed to get sqlite spitting out tuples onto a webpage. spiffy :)
03:35zodiakthanks everyone.
03:35amalloyihodes: i can't either. but remembering another alan's last name is easy enough
03:36ihodes~#113
03:36clojurebot113. The only constructive theory connecting neuroscience and psychology will arise from the study of software.
03:36ihodes= my life plan
04:12amalloyanyone know of a way to look at a java.lang.reflect.Method object and tell whether it's got varargs?
04:13amalloyoh uhm. i'll try the isVarArgs method
04:13taliosvarargs under the covers is just an array.
04:13amalloytalios: i know
04:13taliosor that :)
04:13amalloybut i'm writing a javadoc facility, and the anchor links are different
04:19taliosahh - generating javadoc from clojure or just in clojure?
04:19amalloy$javadoc Class
04:19sexpbothttp://download.oracle.com/javase/6/docs/api/java/lang/Class
04:20amalloytalios: wrote this earlier tonight, and trying to get it to generate the right method anchors as well
04:20taliosah cool
04:27amalloy$javadoc Class getMethod
04:27sexpbothttp://download.oracle.com/javase/6/docs/api/java/lang/Class.html#getMethod(java.lang.String,%20java.lang.Class...)
04:27amalloytalios: look at this horrible anchor link you have to build
04:28taliosoh lovely
04:30amalloyand that still doesn't handle everything: generic types, for example
04:37hsaliaktalios: thanks for that :) i use the plugin
04:38talioshsaliak: cool. I'm thinking I need to trim it down. esp. given that gendoc isn't available in 1.3 I'm tempted to remove clojure:gendoc - going to look at killing clojure:test as well ( using the new surefire extensions mechanism ).
04:41hsaliaktalios: not aware of the surefire extensions.. :-/
04:42talioshsaliak: its a recent addition, allows you a thirdparty test framework or something to introduce new "tests" to run as part of the standard test goal/test reports
04:42talios( and test counts )
04:42hsaliaktalios: i mainly use it for getting clojure on android it integrates nicely with the android plugin, otherwise i use lein
04:42hsaliaki see
04:43taliosneat. any problems with clojure on android? i assume you need everything AOT'd?
04:44hsaliaktalios: yes everything AOTd :)
04:44hsaliaktalios: well, the memory usage needs to be reigned in, sometimes i need to be careful on using list comprehensions as you would normally, but i think overall its OK. The annoying thing is to wrap all the java libraries
04:45hsaliakbut its worth it
04:45hsaliakdynamic functional languages make it a little hard to optimize on memory i'd suspect
04:46taliosmm, technically if everything is AOT'd, is it still dynamic..
04:46hsaliakhave not tried introducing type hints and the like into whatver little code i have written
04:46hsaliakof course
04:46hiredmanwell, android is a new vm, they just turned on the jit for it, so it will be a while till matches hotspot
04:48hsaliaki think biggest issue is the load time for the app
04:48hsaliaka few seconds is bad
04:49taliosI'd be happy with a few seconds. My android is sooooooo friggen slow now :( Old school HTC Magic running 2.2 cyanogen, no JIT, and seems to get more flaky everyday
04:51taliosbrb
04:53amalloy$javadoc java.util.Collection add ;; you even have to say E here, despite that being mostly a figment of the compiler's imagination
04:53sexpbothttp://download.oracle.com/javase/6/docs/api/java/util/Collection.html#add(E)
09:18the-kennyclojure.test/are needs destructuring for the argv-vector
09:19the-kennyto do something like (are [[x y] v] (= v (get (coord x y) ...)) ...)
09:35jimi_hendrixis there a good guide to setting up clojure with slime? everything i have found via google is out of date
11:06Netfeedwhat's the best way to print what's inside a map? something simillar to perls Data::Dumper
11:08Netfeeds/map/hash
11:08sexpbot<Netfeed> what's the best way to print what's inside a hash? something simillar to perls Data::Dumper
11:11jimi_hendrixwhere do you guys install lein?
11:11mdeboard`I did in /home/me/
11:12Vinzentscript in /usr/local/bin
11:19ScriptorC:\lein :/
11:20mdeboard`god, why
11:20mdeboard`WHY
11:21mdeboard`@ Scriptor
11:21mdeboard`I cannot even imagine
11:21mdeboard`windows is for games and watching Netflix
11:21Scriptormdeboard`: and when spilling coffee somehow only breaks your osx partition
11:22mdeboard`Ew
11:23Scriptoractually, it's not *too* bad, I've got emacs for windows, gvim, and mingw32 so it's ok enough
11:23mdeboard`Yeah it's just so much extra work getting a dev env set up
11:27mdeboard`Does anyone here use paredit for emacs? It's been annoying for me but recommended everywhere.
11:28sritchiemdeboard`: yup, I'm a big dan
11:28sritchies/dan/fan
11:28sexpbot<sritchie> mdeboard`: yup, I'm a big fan
11:29sritchieM-( and M-s are my two favorites -- M-( wraps parens around the following s-expression, and M-s breaks the parens from around the current s-expression
11:29mdeboard`sritchie: Ok, I'll ask you then. I've got like {:foo {:bar baz}}. I want to instead do something like {:foo bar :baz x}
11:29mdeboard`ah
11:29sritchieyeah, so, go into :bar :baz, somewhere along there, and type M-s
11:30mdeboard`Vinzent: I've got paren highlighting and the normal "mismatched parens" emacs warning
11:30sritchiemdeboard`: yeah, that'll happen if you use kill-word-backward, and accidentally jump over a paren
11:30sritchiethe solution is to use M-delete instead -- it ignores parens, just killing words
11:30mdeboard`Cool
11:31mdeboard`M-s is what I needed :)
11:32mdeboard`And then a more basic Clojure question. In {:foo bar}, if foo is a passed-in arg with a value, how do I make the output of the function display the value of foo, instead of literally "foo"
11:32Vinzentbtw, I personally prefer paredit-splice-sexp-killing-backward over just splice-sexp (bound to C-M-i (I'm using M-i,j,k,l for cursor movements))
11:32mdeboard`I assume some token before foo
11:33sritchieVinzent: it's bound to M-up too, I think
11:33sritchiemdeboard`: that code you have there is a map data structure, mapping the keyword :foo to the value bar
11:33mdeboard`Oh, right
11:34sritchiekeywords evaluate to themselves, like numbers
11:34sritchie(defn apply-foo-to-bar [foo] (foo bar)) will do the trick
11:35Vinzentsritchie, but arrow keys are so slow! :)
11:35sritchiehaha, good point
11:36sritchie,(let [foo +, bar 10] (foo 2 bar))
11:36clojurebot12
11:36sritchie(let [foo +, bar 10] {:foo bar})
11:36sritchie,(let [foo +, bar 10] {:foo bar})
11:36clojurebot{:foo 10}
11:37mdeboard`hm not quite what I mae uh
11:37mdeboard`mean, uh
11:37mdeboard`if I could figure out how to wrap an exp in braces I'd paste it up for you :)
11:37sritchiemake a brace -- {} -- then go inside, and hit C-<right> a few times
11:37sritchiethat'll grab the s-expressions to the right, one at a time
11:37mdeboard`Oh, ok.
11:38mdeboard`ಠ_ಠ
11:38mdeboard`I'll give it a chance, but seems like needless complication.
11:38sritchie{} :foo (+ 1 2), {:foo} (+ 1 2), {:foo (+ 1 2)}
11:38sritchieor, you can kill (C-k), make some braces, then yank again
11:41Vinzentwrap an exp in braces? M-{ ?
11:42mdeboard`Didn't work for me
11:42mdeboard`but re: value mapping, here's a snipper of what I mean
11:42mdeboard`http://p.mattdeboard.net/cloj.html
11:42Vinzenthm, it's working here...
11:43mdeboard`amount-tendered is a passed-in arg, and I want `:amount-tendered` to be replaced with `:80` or whatever.
11:43Vinzentah, I have (define-key paredit-mode-map (kbd "M-{") 'paredit-wrap-curly) in my paredit config
11:43mdeboard`Do I need to do like (let [x amount-tendered] {:x ....)
11:44mdeboard`M-{ is move cursor between functions
11:44mdeboard`(seek whitespace)
11:44sritchiehttps://gist.github.com/1074636
11:44mdeboard`no : necessary?
11:45sritchiethe keyword function converts it to a keyword
11:45mdeboard`Ah got it.
11:45sritchie,(-> 100 str keyword)
11:45clojurebot:100
11:45sritchie,(keyword "100")
11:45clojurebot:100
11:45mdeboard`Very cool. Very, very cool. :)
11:45mdeboard`little more verbose than I'm used to
11:45mdeboard`(don't hit me)
11:46sritchiehaha, no worries
11:47sritchie,(zipmap [:mod :dividend] ((juxt mod (comp int /)) 10 100))
11:47clojurebot{:dividend 0, :mod 10}
11:48sritchiea less verbose way would be to simply use the number as the key in the map
11:50sritchiehttps://gist.github.com/1074636
11:50mdeboard`Oh.
11:50mdeboard`facepalm
12:05mdeboard`Ok, I need some help because recursion is hurting my brain. Please.
12:05mdeboard`http://p.mattdeboard.net/recursionhelp.html
12:05mdeboard`I'm trying to rewrite an old "make change" program I wrote originally in Python, in Clojure
12:06mdeboard`Basically you have a "Price", "Amount paid" and "Denominations" (using US denoms here) for this project.
12:07gfrlogwhat's the clos function supposed to do?
12:07mdeboard`Well, right now it's just a mechanism that loops over the denominations
12:07mdeboard`20 = $20 bill, 10 = $10 bill, 5= $5 bill and so one
12:08mdeboard`so on*
12:08mdeboard`For each denomination, find the modulo and dividend
12:08gfrlogalright. So what do you need help with?
12:09mdeboard`Subtract (* dividend denomination) from the Price, then on the next pass, instead of using Price, you use the modulo of the previous denomination
12:10gfrlogwhat should the return value of clos be?
12:10gfrloga map from denominations to counts?
12:10gfrlog{20 1, 5 1, 0.10 2}+
12:10mdeboard`Yeah, like how many of each bill it took to uh
12:10gfrlogs/+/?
12:10clojurebotmake a note of http://scienceblogs.com/goodmath/2006/11/the_c_is_efficient_language_fa.php it is yet another article about picking c or c++ for performance being naive
12:11gfrlogclojurebot: shut up
12:11clojurebotTitim gan éirí ort.
12:11mdeboard`How many of each bill it took to make change
12:11gfrlogmdeboard`: okay. I think this is a natural use for loop
12:11gfrloginstead of for
12:11mdeboard`Like if the price is $74.99 and I pay $100, how many of each bill does it take to render the difference between 100 and 74.99
12:12gfrlogin that case, the argument to clos would be 15.01, right?
12:12gfrlog25.01 I mean
12:12mdeboard`Right
12:12gfrlogokay. Ignoring any potential pitfalls of using floats...
12:13gfrlogI would replace the for with
12:13mdeboard`yeah
12:13gfrlogoh wait we can do this with reduce
12:13gfrlogthat's cleaner
12:13mdeboard`can we? o.O
12:13gfrlogare you familiar with reduce?
12:14mdeboard`Yeah
12:15gfrlogso what makes it maybe slightly tricky is that as we process the sequence of denominations, we have two things to keep track of -- the remaining amount, and the coins computed so far
12:15mdeboard`In that I know generally wha tit does. But I'm coming from Python where using reduce is silly. :(
12:15gfrlogbut that just means our reduce-value needs to be a pair
12:15gfrlogits starting value will be [amount {}]
12:15gfrlogand we process the list of denoms, updating both parts of the pair as we go
12:16gfrlogso the reduce function could be:
12:16mdeboard`Whew.
12:16mdeboard`I definitely need to see that in a snippet
12:16gfrlogkay I'll pastie it
12:17gfrlogI think it takes some practice to see how to use reduce effectively
12:18gfrloghttps://gist.github.com/1074657
12:19gfrlogso that would go under the (let [denoms ...]), replacing the for
12:19mdeboard`I think you just gave me a concussion
12:19gfrlogoh dear
12:19sritchietry running through it with just one value
12:20sritchiereduce calls the supplied function with the following args, in pairs. So, first, that function gets [amount {}] and the first thing in denoms
12:22sritchiehttps://gist.github.com/1074659
12:22sritchiehere are the first few steps of that first call
12:22mdeboard`http://p.mattdeboard.net/nullpointer.html that code threw a null pointer exception
12:23gfrlogoh ah ha
12:24gfrlogI misused the return value from calc-coins
12:24mdeboard`is it supposed to be denoms?
12:24mdeboard`or?
12:24gfrlogone fix is to change calc-coins so it just returns {:mod ..., :dividend ...}
12:25gfrlogi.e., instead of {:0.20 {:mod 0.07, :dividend 3}}, return {:mod 0.07, :dividend 3}
12:26mdeboard`ya that did it
12:26mdeboard`it being removing the np
12:27gfrlogif you really want the keys to be keywords instead of numbers, you can change (assoc coins denom dividend) to (assoc coins (-> denom str keyword) dividend)
12:27sritchiegfrlog: that doesn't quite work, since each mod and dividend knocks out the previous one
12:27gfrlogbut I think the numbers make more sense
12:27gfrlogsritchie: eh?
12:27mdeboard`Yeah right now it just returns the dividend
12:27mdeboard`http://p.mattdeboard.net/dividends.html
12:28sritchieah, never mind
12:28gfrlogoh you'd also want to wrap that in (last)
12:28gfrlogor (second)
12:28gfrlogsince ultimately you're only interested in the second part of the reduce value
13:07mdeboard`gfrlog: http://p.mattdeboard.net/dividends.html What's "amount-left" in your example?
13:09gfrlogmdeboard`: that's what the mod gets assigned to each time
13:09gfrlogso...it's the amount left :)
13:11gfrlogby the end of the reduction it should be 0
13:12mdeboard`u rite
13:15gfrlogmdeboard`: is it making sense?
13:15mdeboard`Oh, so the line that starts with (fn [[amount-left...) is just an encapsulation. An anonymous function?
13:15mdeboard`er, not the line, but that block of code
13:15gfrlog(fn [...] ...) is the syntax for an anonymous function, yes
13:16mdeboard`I'm justgetting hung up on amount-left
13:16gfrlogamount-left starts out as the full amount
13:16mdeboard`Where is mod getting assigned to it?
13:17mdeboard`ohhhh
13:17gfrlogyou see how the if expression will evaluate to one of two vectors?
13:17mdeboard`ok
13:17mdeboard`hang on
13:17mdeboard`Sorry I slip out of polish notation mode sometimes
13:17gfrlogit could be done without the if, but then the return map would have all of the denominations in it instead of just the ones that matter
13:19mdeboard`(let [{:keys [mod dividend]} (calc-coins amount-left denom)] --> that's assigning the values of the ... array? dict? ... that's being returned by calc-coins to variables, mod and dividend
13:20gfrlogyep. It's syntactic sugar for a couple longer expressions
13:20mdeboard`map*
13:20mdeboard`s/array\?\ dict\?/map
13:20gfrlogthe longest way to do it is (let [x (calc-coins amount-left denom), mod (:mod x), dividend (:dividend x)] ...)
13:20mdeboard`ahhh
13:20mdeboard`ok
13:20mdeboard`is that destructuring?
13:21mdeboard`the first way
13:21gfrlogthe plain destructuring way to do it is to replace x with a map of pairs, like:
13:21gfrlog(let [{amount-left :amount-left, denom :denom} (calc-coins amount-left denom)] ...)
13:22gfrlogthe way in the code is a shorter sugary version that avoids the repetition
13:22mdeboard`is :keys a keyword or what?
13:22mdeboard`I mean I get that it's a keyword
13:22gfrlogyeah, it has special meaning in a destructuring map
13:22mdeboard`stupid question
13:22mdeboard`Yeah that was my questino
13:22mdeboard`if it had a special meaning :P
13:22gfrlogthere are I think three keywords that have special meaning there
13:22gfrlog:keys, :as, and :or
13:23gfrlog:as also works when destructuring a list
13:27mdeboard`I feel like I'm still missing something with 'amount-left'. `fn [[amount-left coins] denom` is the setup for an anon func, and I get that. But I don't get the vector-of-vectors [[amount-left coins] denom]
13:27gfrlogthe function has two arguments
13:27gfrlog(any reduce function does)
13:27gfrlogthe first argument is expected to be a pair
13:27gfrlogand we're destructuring it
13:28gfrlogso [amount-left coins] is the first argument to the function, and denom is the second
13:28mdeboard`so let's say we're on the first pass, and denom == 20, what're the values of [amount-left coins] going to be
13:29gfrlogon the first pass it will be equal to the "start pair" that we passed as the second argument to reduce, which is [amount {}]
13:34mdeboard`oh, oh
13:34mdeboard`oh
13:35mdeboard`lightbulbs, i has htem
13:36gfrlog\o/
13:36amalloymdeboard`: just woke up, but this looks like a job for ##(doc reductions)
13:36sexpbot⟹ "([f coll] [f init coll]); Returns a lazy seq of the intermediate values of the reduction (as per reduce) of coll by f, starting with init."
13:36mdeboard`amalloy: God please no, I'm just grokking this
13:36mdeboard`:P
13:36gfrlogamalloy: are you contradicting me?
13:36mdeboard`nerd fight
13:36gfrlogamalloy: or are you saying that reductions is helpful for understanding how reduce works?
13:36amalloygfrlog: the scrollback was long. i skimmed it
13:37gfrlogmdeboard`: reductions will return for you all the intermediate values of reduce, so that might be a good idea, whether or not it's what amalloy meant
13:37mdeboard`speaking of Cloj 1.2, why is only 1.1 available in aptitude?
13:38amalloymdeboard`: package managers are always behind on shiny new toys
13:38mdeboard`I did, but then just went back and installed from source
13:38amalloymdeboard`: go back and don't install at all; let lein pull it down as a project dep
13:38mdeboard`Maybe at a later date
13:38amalloyyeah
13:38amalloyno rush on that
13:40mdeboard`Yeah forgiving some issues with float, reductions is a big cognitive help
13:41mdeboard`I also exploded the {:keys [foo bar]} syntax to "the long way"
13:41gfrlogmdeboard`: whatever helps. You'll compress it back down after you do it the long way a hundred times.
13:41mdeboard`sure
13:41mdeboard`just like list comprehensions
13:42amalloygfrlog: btw, :strs and :syms also have special meaning in the :keys position
13:42mdeboard`so is this recursive?
13:42mdeboard`Or iterative?
13:42mdeboard`It seems iterative
13:42gfrlogamalloy: I figured I was missing some, but there was nobody around to help :)
13:42gfrlogmdeboard`: it's not explicitely recursive
13:43amalloymdeboard`: reduce is certainly implemented recursively
13:43gfrlogmdeboard`: using the higher-order-functions in clojure lets avoid using (loop) and explicit recursion 98% of the time
13:43amalloygfrlog: you win this round
13:43mdeboard`lol
13:43mdeboard`oh right I read something about that last night
13:43mdeboard`maybe in JoC
13:44gfrlogamalloy: :strs lets you use :keys with string keys?
13:44amalloyyeah
13:44gfrlogand :syms is the default behavior?
13:44amalloyer
13:44gfrlogoh wait
13:44gfrlogno
13:44amalloyno
13:44gfrlogI mix up "symbols" and "keywords" sometimes, thanks to dang other programming languages
13:45amalloy&(let [{:strs [a b]} {"a" 1 "b" 2}] [a b])
13:45sexpbot⟹ [1 2]
13:56amalloymdeboard`, you mentioned floats. if you're using floats for this currency problem, let me recommend you do everything with integer pennies instead of fractional dollars
13:57amalloyor, i guess, clojure's rational types would probably be okay
13:57mdeboard`i.e. $1 = 100?
13:57amalloyyes
13:57gfrlogamalloy: I was wondering what common opinion of that was
13:57gfrlogI've taken that approach with javascript
13:57amalloy$google currency floating point
13:57sexpbotFirst out of 473000 results is: Floating Point Currency
13:57sexpbothttp://c2.com/cgi/wiki?FloatingPointCurrency
13:57amalloyjust googled that at random, don't really know if it supports my point
13:57mdeboard`reduce
13:57mdeboard`wrong buffer
13:58amalloygfrlog: javascript doesn't have ints anyway though, right?
13:58amalloyso it hardly matters
13:58gfrlogamalloy: correct, but if you only use integer-valued floats then I don't think you can get into trouble
13:58amalloydepends if you ever do any division
13:58gfrlogright
13:58amalloyadding em together you'll be fine
13:59gfrlogand multiplying
13:59amalloymmmmm
13:59gfrlogby integers :)
13:59mdeboard`Did I write out what this function is doing properly?
13:59mdeboard`http://p.mattdeboard.net/docs.html
13:59amalloydoubles don't have as large a range as longs
13:59amalloyso you can run into a problem
14:00gfrlogamalloy: right, so you have to make sure you don't have very much money
14:00gfrlogI guess overflow would be awfully silent
14:00gfrlogthere's a bigint library I've used for javascript. I guess that'd be the ultimate solution
14:00gfrlogif you like writing a.multiply(b.add(c))
14:01gfrlogwhich of course I do
14:01amalloymdeboard`: i don't buy your last comment
14:01gfrlognow that I think about it, if I ever have to do that again I'd probably write a function called sexp for which I can sexp("(* a (+ b c))")
14:02mdeboard`amalloy: Me either, hence the (???)
14:02amalloyif i start with ten cents, the second branch of the if will be hit for all the denominations until you get to dimes
14:02amalloygfrlog: cause the only way you could slow down a bigint library is with eval?
14:03gfrlogamalloy: because premature optimization is evil :P
14:03gfrlogactually eval wouldn't even work there would it? since you'd lose the scope. Would have to be pre-processed, which I wouldn't mind doing
14:04gfrlogif there's enough arithmetic
14:04amalloygfrlog: javascript eval has access to lexical scope
14:05gfrlogamalloy: right. So if sexp is defined somewhere else...
14:05amalloyummm...? just define sexp to return a string, and eval that string
14:05gfrlogso repeat the call to eval everywhere
14:06gfrlogI see
14:06amalloybut writing a sexp->javascript precompiler is probably simpler
14:06gfrlogand avoids the eval
14:07mdeboard`How about extracting the final value of that function? I assume there's a more efficient way than: `(def result (first (rest (last (clos 1693)))))`
14:07amalloywell, second is (comp first last)
14:08gfrlogamalloy: why is he using reductions if all he wants is the final value?
14:08dnolen_mdeboard`: thanks, nice example of mutually recursive yield in Python. As you said that is crazy slow in Python.
14:08amalloyer, (comp first rest)
14:08mdeboard`oh, right
14:08mdeboard`derp
14:08mdeboard`forgot to take out reductions :)
14:08gfrlogah
14:09gfrlogI assumed since it was still there amalloy must have been recommending you keep it
14:09amalloymdeboard`: do you care if the keys of the map are in order? they probably are in your impl, but it's only coincidental
14:09mdeboard`dnolen_: You're welcome
14:09mdeboard`amalloy: Not really, but I suppose I should.
14:11amalloyif so you should either use a sorted-map (since sorting by key is what you want) or a vector of pairs that you just append to
14:12amalloythough it probably sorts in reverse order? ##(into (sorted-map) [1 4 9 2]) vs ##(into (sorted-map-by -) [1 4 9 2])
14:12sexpbot (into (sorted-map) [1 4 9 2]) java.lang.IllegalArgumentException: Don't know how to create ISeq from: java.lang.Integer
14:12sexpbot (into (sorted-map-by -) [1 4 9 2]) java.lang.IllegalArgumentException: Don't know how to create ISeq from: java.lang.Integer
14:12amalloymutter
14:13mdeboard`baby steps
14:13mdeboard`premature optimization chat
14:13gfrlogbased on the first word of your last two statements I'd say this is a conversation about infants.
14:14mdeboard`gfrlog: Based on that statement I'd say you work on machien learning
14:14gfrlogha
14:30amalloymdeboard`: https://gist.github.com/1074808 is a version that seems to involve less tedious bookkeeping
14:31amalloyand (make-change 167/100) yields {:penny 2, :nickel 1, :dime 1, :quarter 2, :dollar 1}, demonstrating that it works and that order isn't maintained :P
14:33gfrlogamalloy: no YOU win this round
14:33mdeboard`I dropped it into my clj and commented it out, once I've got gfrlog's version snuggled in my brain I'll look at yours
14:35mdeboard`(assoc foo x y) -> (def foo {x y}) ?
14:36gfrlognope
14:36gfrlogit associates the key x with the value y in the map foo
14:36amalloymdeboard`: def has side effects, so very few built-ins are equivalent to a def
14:36gfrlog&(assoc {:a 2 :c 4} :b 5)
14:36sexpbot⟹ {:b 5, :a 2, :c 4}
14:36gfrlog&(assoc {:a 2 :b 12} :b 5)
14:36sexpbot⟹ {:a 2, :b 5}
14:37mdeboard`,(assoc {:a 2 :b 12} :b 5)
14:37clojurebot{:a 2, :b 5}
14:37mdeboard`:')
14:37gfrlogwe both picked twelve because we're soul mates?
14:37mdeboard`lol no, just beign smug about knowing the syntax
14:38mdeboard`Dunno if either of you are familiar with Python, but it seems like (assoc map key val) is analogous to Python's dict key-val pair setting
14:38dnolen_mdeboard`: amalloy: my version, https://gist.github.com/1074818
14:38mdeboard`e.g. dict = {} \ dict['foo'] = 'bar' \ dict --> {'foo': 'bar'}
14:39mdeboard`1e-6 ?
14:39amalloygfrlog: what do you think about https://gist.github.com/1074808 - i'm not sure if the threaded version is more or less readable
14:39mdeboard`is that engineering notation?
14:39amalloyscientific
14:39amalloy(though they happen to be the same here)
14:39mdeboard`that too
14:39amalloymdeboard`: yes, assoc is like that, except without side effects
14:40gfrlogoh threaded. I was thinking "why the heck is he making this multi-threaded??"
14:40amalloyoh. the threaded version is also totally wrong
14:40amalloynever mind, sigh
14:40mdeboard`persistence > perfection amalloy
14:40mdeboard`unless you're actually perfect then persistence is unnecessary
14:41gfrlogmdeboard`: it's different from python dicts because clojure maps are immutable
14:41mdeboard`right
14:41mdeboard`I mean it's impossible to have a REAL 1:1 correlation but the spirit of my question isn't as deep as that.
14:41gfrloggotcha
14:42mdeboard`state mutability notwithstanding
14:42mdeboard`god Joy of Closure has an absolutely epic explanation of state
14:42mdeboard`I might go back and re-read it
14:42amalloymdeboard`: dnolen's used update-in, which is a fantastic tool for working with maps. keep it in mind
14:43amalloy(and it goes great with fnil)
14:43gfrlogfnil: there's always something else I've forgotten exists :|
14:43mdeboard`Ya I've got them both appended at the end of my clj, commented out
14:50mdeboard`Here's my problem, I think gfrlog's solution is pretty straightforward now that I grok it, but I have trouble thinking in the way that would be required to come up with such a solution. Recursive thinking, i guess? I mean, once you've broken the problem down atomically, what element do you start with to start building a solution in your head?
14:50dnolen_mdeboard`: amalloy: and because I hate slow code, https://gist.github.com/1074818
14:51gfrlogmdeboard`: I think of reduce whenever I have a collection of elements (denominations) that I need to loop over, while keeping track of something
14:52amalloydnolen_: the 1e-6 check looks kinda silly to me. if the amount ever gets below 0.01 due to a rounding error, you'll get a NPE during subtraction
14:52amalloyso i'd put the termination test in the drop-while
14:52amalloy(and use ints instead of doubles, especially if you care about performance)
14:53dnolen_amalloy: ints for currency?
14:53amalloyyes
14:53dnolen_1e-6 check is straight out of what I've seen done in graphics code.
14:53amalloyif you use floating-point at a bank they murder you in the spot
14:53amalloy*on
14:53dnolen_amalloy: did know that, never done any financial work.
14:54dnolen_did not.
14:54gfrlogamalloy: any clue what they do when they want to keep track of fractional cents?
14:54amalloydnolen_: sure, in general for testing floats you want to use a delta like 1e-6
14:54amalloybut for money you should use ints, and the way you're using drop-while the test could cause NPE on rounding error *anyway*
14:55amalloygfrlog: work with integer thousandths of cents :P
14:55gfrlogamalloy: that was my guess
14:55gfrlogdnolen_: I think when handling money it's always cleanest to be discrete
14:55dnolen_amalloy: Yeah, I see what you mean about the 1e-6 test and rounding error.
14:56gfrlogfloats are good for things that don't have to be perfectly accurate
14:56amalloygfrlog: that is both edutational and punnerific
14:56dnolen_suddenly this is an exercise on Enterprise Financial Programming instead of a lesson on recursion ;)
14:56gfrlogamalloy: I strive to edutate!
14:56amalloyhaha ouch
14:57mdeboard`amalloy: Why do you use a vector of vectors instead of a map in your example?
14:57TimMcgfrlog: and wash your hands afterward
14:57amalloyto preserve ordering
14:57gfrlogTimMc: :)
14:57mdeboard`ah ok
14:57amalloyif the map happened to be 10+ elements (say we track fifties and half-dollars), it no longer (coincidentally) preserves order
14:58mdeboard`so how do you retrieve the value of, say, :twenty?
14:58mdeboard`(I'm trying this stuff out in repl before I ask btw)
14:59gfrlogmdeboard`: :twenty is a function that can do that
14:59amalloyit's in change-denom's destructuring-let
15:01mdeboard`Oh, gotcha. Smart
15:02amalloydnolen_: out of curiosity, is the repeated-subtraction faster than division because the numbers are small enough?
15:02amalloyor is it just more convenient to write?
15:03amalloyit seems to me that calling update-in more times ought to incur an uncomfortable about of memory allocation, but i guess i don't know whether that's more expensive than division
15:03mdeboard`honestly I don't think order matters here
15:03amalloymdeboard`: of the final result, no. but for the list of denominations, yes
15:04mdeboard`lol, got it. Why does learning a new language & programming paradigm turn me into a huge idiot
15:04amalloy~#19
15:04clojurebot19. A language that doesn't affect the way you think about programming, is not worth knowing.
15:05mdeboard`A+
15:06mdeboard`so yeah mapping hashes they k/v pair I assume, which tosses out any ability to sort on keys at a low level?
15:06dnolen_amalloy: is this more sound? https://gist.github.com/1074818
15:06mdeboard`except sorted-map-by
15:07mdeboard`also as long as they're in order in the original list, isn't reduce always going to walk over them in order?
15:07gfrlogmdeboard`: yes, reduce goes in order
15:07mdeboard`it's just once they're assoc'd into the map then they're not necessarily in order. But if they're mapped I can just call the key to return the value, so order doesn't really matter
15:08mdeboard`(aka the whole point of maps)
15:08mdeboard`vis a vis speed
15:08amalloydnolen_: hah, that's a clever way to use rename-keys
15:09mdeboard`gist doesn't either apparently
15:09amalloygithub syntax-colors clojure code at random, or something like it
15:09mdeboard`lol, what.
15:10mdeboard`I just mean that I guess "rename-keys" isnt in its table of identified built-ins
15:10amalloymdeboard`: but make-change is?
15:10mdeboard`well once it's defn'd
15:10gfrlogI've been using clojure.core/make-change for months now
15:10amalloyi'd be astonished if they were parsing the source for defns
15:11dnolen_mdeboard`: probably because rename-keys is in clojure.set
15:11amalloydnolen_: anyway, that looks like it passes muster for banks :)
15:11dnolen_amalloy: sweeeet
15:11amalloynah, because drop-while isn't colored either
15:11mdeboard`probably a bit of code in gist source that puts "foo" in ID'd functions table when it sees `defn foo`
15:11mdeboard`dnolen_: oic
15:11amalloymaybe so
15:12amalloyhttps://gist.github.com/1074857 indicates that they have no such defn parser
15:13mdeboard`I suspect that's an engineering oversight
15:13mdeboard`on forked gists
15:13amalloyhttps://gist.github.com/ba4079175d8d5eda81cb
15:13mdeboard`or on edits
15:14mdeboard`huh. I bet they cache them :)
15:14amalloyhaha prepare to be strangled
15:15mdeboard`https://gist.github.com/1074861
15:15gfrlognerd fight!
15:15mdeboard`https://gist.github.com/1074862
15:15mdeboard`I win :)
15:16amalloywhat's your point?
15:17mdeboard`lol just that they cache function names :P Look I'm clearly the dumbest person in this chat room, I need this.
15:17amalloyhttps://gist.github.com/ba4079175d8d5eda81cb is a disproof :P
15:17mdeboard`Huh
15:17mdeboard`I guess it IS random!
15:17amalloy*chuckle*
15:19gfrlogmaybe it dispatches on the hash code of the symbol modulo some value
15:19mdeboard`Which is unreliable enough to be indiscerinable from random
15:20mdeboard`But yeah maybe they drop [^a-zA-Z0-9]
15:20mdeboard`or something, who cares, I'm trying to learn Clojure
15:20mdeboard`:)
15:22mdeboard`(I was joking, btw, you guys have been a huge help)
15:48gfrlogamalloy: it just occurred to me that a third no-eval-or-precompile option for the javascript problem could be done by passing the variables to sexp: sexp("(+ %1 (* %2 %3))", a, b, c)
15:48gfrlogman it took a lot of effort to type those commas...
15:51dnolen_mdeboard`: amalloy: re, arithmetic vs division, yeah that was silly. https://gist.github.com/1074818, code is very short now, updated one last time.
15:55gfrlogthere's not anything like clojure.core/*rand* is there?
15:59amalloygfrlog: clojure.core/inc seems to meet all of the requirements you've stated so far
16:00gfrlogamalloy: you mean being a qualified symbol?
16:00gfrlogin the clojure.core ns?
16:02mdeboard`Hrm, prob a dumb question but I uninstalled clojure, to allow lein to install. I did "lein self-install" but er
16:03mdeboard`No clojure dl? idgi
16:03gfrlogmdeboard`: yes clojure dl. odxt
16:03amalloymdeboard`: it gets downloaded in projects you start
16:03gfrlogmdeboard`: try "lein repl"
16:04mdeboard`Oh
16:04mdeboard`So clojure isn't dl'd system-wide, just in particular projects?
16:04amalloyright
16:05gfrlogmdeboard`: I think it keeps a version in your maven dir that it copies to new projects
16:05mdeboard`Kind of like rvm I suppose
16:05amalloyor virtualenv
16:05amalloykinda
16:05mdeboard`kinda but wihtout the path hack
16:05amalloyi don't really know anything about python or ruby, so read these analogies at your own risk
16:05mdeboard`haha
16:07mdeboard`so I just do lein self-install for each project or just one time for the system?
16:07amalloyjust once
16:08gfrlogmdeboard`: "lein new foobar" creates a new project for you
16:16jimi_hendrixis there a clojure lib for asynchronous server sockets, or should i poke arond the java library?
16:16gfrlogjimi_hendrix: (or aleph "I don't know what I'm talking about")
16:17jimi_hendrixgfrlog, should i be reading that as a lisp statement :P
16:17gfrlogsorta
16:19amalloy(inc aleph)
16:19sexpbot⟹ 1
16:20mdeboard`lol
16:20gfrlogamalloy: is there a sexpbot karma read command?
16:20jimi_hendrixlol
16:20gfrlog(deref amalloy)
16:20amalloygfrlog: yes, but afaict it's broken
16:21amalloy$help karma
16:21sexpbotamalloy: Checks the karma of the person you specify.
16:21mdeboard`$help mail
16:21sexpbotmdeboard`: Send somebody a message. Takes a nickname and a message to send. Will alert the person with a notice.
16:21Scriptor$karma Scriptor
16:21amalloygfrlog: feel free to fork&fix it for me, cause i don't see what's broken
16:21gfrlogamalloy: it should work the way Scriptor just used it?
16:21amalloyyeah
16:21gfrlogokay
16:21Scriptordoes it not print anything if the karma is 0?
16:22amalloy$karma aleph
16:24Scriptorin clojure's source, what does the variable 'sv' usually stand for?
16:24ScriptorI'm guessing something like seq value
16:24mdeboard`The leiningen tutorial seems really incomplete
16:24mdeboard`Big gaps
16:25midshow would I best go about attacking this stacktrace? https://gist.github.com/1074930
16:26mdeboard`I mean, for me. Like, so I put clojure-contrib in my project's project.clj. Do I just automatically have that? Or do I need to run another command? lein install? I did that and it says it can't find change__init.class or change.clj on my classpath.
16:26gfrlogmdeboard`: lein deps will populate your lib dir
16:27mdeboard`aha
16:27Scriptormdeboard`: there's a clojure tutorial about setting up slime/swank/lein...buuut it's for windows :p
16:28mdeboard`I mean, I just really want a step-by-step walkthrough. lein deps doesn't get mentioned until the very end of the third PARAGRAPH in the second section of the tutorial
16:32mdeboard`I'm spoiled by python, sorry.
16:42amalloyScriptor: i wouldn't be surprised if it were a sort of hungarian: "this variable has already had seq called on it"
16:44Scriptoramalloy: hmm, not sure it's the result of seq(), it's set by sval() (there's the answer for the name, I guess)
16:44amalloyah
16:44Scriptorfor reference: https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/LazySeq.java#L37
16:46technomancyfor the record, the next version of lein will automatically detect changes to :dependencies in project.clj and run deps for you. you can turn on this behaviour in current versions with :checksum-deps true in project.clj
16:46technomancymdeboard`: ^^
16:46mdeboard`technomancy: smashing
16:47technomancyactually I could use some more folks testing that feature as the only reason it's not on by default is it hasn't seen wide use
16:47technomancybut if I don't tell people about it, it will never see wide use.
16:48mdeboard`That seems like something that should be on by default for new users
16:48mdeboard`imo
16:48mdeboard`as a new user
16:48technomancyyes, assuming it works correctly
16:48technomancywhich I have not yet determined
16:49technomancyhence the need for testing
16:51hiredmanhttp://www.thinkwithportals.com/music.php "songs to test by"
16:51keithwysstechnomancy: Is it a plugin currently?
16:51technomancykeithwyss: no, it's built-in. just needs :checksum-deps true in project.clj to enable it
16:52gfrloghiredman: :)
16:52technomancyand if you're in the mood for testing features that will hopefully be default later, you could also add :local-repo-classpath true to project.clj
16:52technomancythat will make the classpath reference ~/.m2 instead of copying everything into lib
16:53keithwyssCool. I'll jot those down.
16:53mdeboard`Editing my newb project.clj right now.
16:53jimi_hendrixwhere exactly does lein pull deps from?
16:54technomancyclojurebot: look at me still talking when there's science to do
16:54clojurebotscience is http://sunpig.com/martin/images/2008/10/iwilldosciencetoit.jpg
16:54technomancyclojurebot: a thousand botsnacks
16:54clojurebotTitim gan éirí ort.
16:54technomancyjimi_hendrix: by default: http://clojars.org and http://search.maven.org
16:54wilfredhis there a compojure equivalent of Django's reverse()?
16:55wilfredhi.e. something that takes a function and returns the corresponding URL
16:55gfrlogdoubt it
16:55gfrlognot sure that really makes sense for compojure
16:56zakwilsonI'm looking at sandbar.auth, and it seems to have a good thing going wtih the ability to have a role-based security policy. I'm a bit confused about how I might use it to do something more fancy though, like say that the person editing an item must own that item (or be an admin).
16:56wilfredhI must be missing something -- why doesn't it make sense?
16:57gfrlogwilfredh: you're using (defroutes ...)?
16:57amalloywell, it assumes a one-to-one correspondence between functions and URLs, which seems pretty foreign
16:57technomancygfrlog: http://p.hagelb.org/cake.gif
16:58gfrlogtechnomancy: I want to elect that president.
16:58wilfredhgfrlog: yes, I'm using defroutes
16:58amalloyit also supposes that compojure does a lot of things it doesn't actually do, like keep track of the routes in a table somewhere once you define them
16:58keithwyssOne thing that I'd like to see in lein is the ability to enter some tags like :latest or :latest-stable in project.clj and have a plugin rewrite the project file so that a developer doesn't have to check every version.
16:58gfrlogwilfredh: everything amalloy said.
16:58gfrlogwilfredh: not to mention a lot of routes are globby and so don't correspond to just one url
16:58keithwyssI'd be willing to take a stab at it assuming there's not something like this already I missed out on.
16:58amalloykeithwyss: :dependencies [[clojure "[1.2.0,)"]]
16:59technomancykeithwyss: it's a lot easier to check now with lein search too.
16:59Scriptornoob question, but is there a lein command to have it update itself? I always suck at googling for that one
16:59amalloylein upgrade
16:59Scriptorah
16:59gfrlogthis is awesome I just ran "lein upgrade" and it worked.
16:59Scriptordamnit, not available on windows
17:00gfrlogI guess I shouldn't have celebrated. It was insensitive to windows users.
17:00keithwyssamalloy: what does "[1.2.0,)" mean. I'm not used to seeing parens that aren't matched.
17:00amalloy$google mathematics interval notation
17:00sexpbotFirst out of 710000 results is: Interval Notation
17:00sexpbothttp://regentsprep.org/REgents/math/ALGEBRA/AP1/IntervalNot.htm
17:01gfrlogI figured it meant the version number was winking
17:01technomancykeithwyss: there's a link in "lein help tutorial" about version ranges
17:01Scriptoris 1.6.1 the latest version number? I want to try technomancy's automatic dep installation
17:01technomancyScriptor: it is
17:01keithwyssThanks for the help. That's exactly what I wanted.
17:02wilfredhgfrlog: Django handles the fact that there isn't a one-to-one correspondence. I can do {% url app_name.views.foo id=3 %} and Django replaces it with /foo/view/3 rather than me hard-coding URLs everywhere. But if I can't do this, never mind.
17:03technomancyScriptor: but that feature is in 1.5 iirc
17:04gfrlogwilfredh: I think it sounds theoretically possible, if instead of how defroutes works it had you just describe pairs of routes and functions. But because defroutes essentially creates inline (anonymous) functions, I don't think it's compatible. In any case I don't think it exists right now.
17:04gfrlogwilfredh: I agree it'd be nice though.
17:05Scriptortechnomancy: must have missed it before, does it install the dependencies whenever you compile?
17:05technomancyScriptor: it looks at the checksums every time code has to be evaluated inside the project's context
17:08Scriptortechnomancy: checksums for the dependency?
17:09ScorchinCan someone help explain the following code for me please? It's being passed a "board" similar to a X by Y grid: http://pastebin.com/40Lp7EYk
17:09zakwilsonThe idea of being able to link to a function rather than a URL seems higher-level than Compojure, as Compojure doesn't have a very rigid idea of what sort of thing a route is connected to.
17:11technomancyScriptor: right; it serializes :dependencies and :dev-dependencies to a string and checksums that
17:12gfrlogzakwilson: I can imagine an alternative to (defroutes) that provides reversal without too much trouble
17:12amalloyScorchin: whatever it's doing, it's written badly in a few ways, making it hard to understand
17:12gfrlogyeah that's pretty weird code
17:12amalloyit seems to be checking whether it is the case that all but the first and last column are nil
17:12Scriptortechnomancy: ah! But how does lein know when code is evaluated? Sorry, not very familiar with how it works
17:12Scorchinamalloy: I'm trying to imitate it to build a way to check if a tetris grid has hit a "game over" state
17:13zakwilsongfrlog: so can I, but it requires a more rigid structuring of the app that Compojure currently requires. That may not be in keeping with the project's goals.
17:15amalloytotally agree there. i wonder if moustache has that more rigid structure? i haven't used it but have heard that sort of thing
17:16ibdknoxNoir, doesn't really help here, but if you want a stricter structure, more akin to Rails or Django, look at wakeful
17:16ibdknoxit maps urls directly the namepsace structure
17:16ibdknoxto*
17:16gfrlogzakwilson: I think the added structure would be pretty isolated
17:16gfrlogzakwilson: say if the reverse-routing function were not a built in compojure function but just a function that's returned from (def-reversible-routes)
17:16technomancyScriptor: things like repl, test, and compile have to run code in your project's process to have access to its dependencies
17:17zakwilsongfrlog: then do it. It sounds useful; I'd probably start using it right away in production client code if it didn't require me to make many changes.
17:18gfrlogoh I'm not THAT motivated, I just wanted to make the point that I don't think it's incompatible with compojure :)
17:19hiredmanhttps://github.com/hiredman/graft
17:19zakwilsonDamn. I was hoping somebody would do it for me so I don't have to figure out a good way.
17:21ibdknoxzakwilson: I guess you assume the URL is going to change a lot?
17:22zakwilsonibdknox: no. I just don't like code that generates anything with semantic meaning using string concatenation.
17:23gfrlog:)
17:23gfrlogyeah it lets your bugs leak farther...
17:23zakwilsonWell, string concatenation can happen somewhere, but I don't want magic strings in my code.
17:24ibdknoxlol
17:24gfrlogzakwilson: exactly
17:24ibdknoxI don't see the difference really
17:24hiredmanyou prefer magic code?
17:24gfrlogibdknox: the difference is what happens when you make a typo
17:24ibdknoxgfrlog: it's a location
17:24ibdknoxgfrlog: locations are inherently strings
17:24ibdknoxin this case
17:25ibdknoxhiredman: no, I don't :)
17:25ibdknoxbut the solution of reverse calling a url is no different than using its string representation :)
17:25zakwilsonTo give a simple example, (go-home) is better than (redirect "/") because it's possible that the app might end up being somewhere other than the root... is directory even the right word here? You know what I mean though.
17:25gfrlogibdknox: just because they're exposed as strings doesn't mean that's how you have to refer to them as a programmer
17:26ibdknoxzakwilson: that is fair
17:26ibdknoxzakwilson: usually that's taken care of by setting an app root though
17:26zakwilsonEven though right now (defn go-home [] (redirect "/"))
17:26zakwilsonSure, that's another way to do it
17:27ibdknoxgfrlog: sure, you don't have to, but I'm not sure I see the value in the abstraction, that's all :)
17:29gfrlogibdknox: one value is that if you're using vars instead of strings, the compiler can point out your mistakes
17:30ibdknoxgfrlog: that's fair
17:31ibdknoxgfrlog: it becomes more personal preference I think
17:31ihodeswhat's a really cool data structure that can be useful to hold something a sparse matrix normally would?
17:32hiredmana map?
17:32amalloyhiredman: no, he said really cool
17:34wilfredhI've always thought a Fibonacci heap was pretty cool</tongue-in-cheek>
17:40gfrlogfinger trees of vectors of arrays of refs
17:40ibdknoxlol
17:40ibdknox^^ best solution there
17:42ihodeshiredman: a map is basically the underlying implementation of a sparsematrix (can't think of a better one, anyway).
17:42ihodesyou guys are no fun :P
17:43ihodesthere a good # on freenode for data structures?
17:44ihodeshiredman: by the way, i'm using visor mode in iterm now, and i love it.
17:45gfrlogihodes: what is "something a sparse matrix normally would"?
17:45gfrlogwhat does .lein-failures do?
17:46hiredmantracks test failures for lein retest
17:46dnolen_ihodes: ITerm2 is pure awesomeness, I'm giving Cocoa Emacs the boot.
17:46gfrloglein retest will run all tests listed in .lein-failures?
17:47technomancygfrlog: aye
17:47gfrlog(inc technomancy)
17:47sexpbot⟹ 11
17:48ihodesdnolen_: i've been using emacs -nw forever. i was too much of a snob regarding the ugly frames in cocoa-emacs. also. i'm a bit of a showsman.
17:48hiredmanI think my fullscreen cocoa-emacs is rather fetching
17:49ihodesgfrlog: provide the same sort of access and representation of a matrix (just 2d in my case, but nD would be nice) without having to store empty positions
17:49gfrlogihodes: I'm not sure why you find a map so disappointing
17:49ihodeshiredman: it probably is. and i bet it can handle real themes, too. which mine can't (AFAIK...) so I just set the colors i like with iTerm's profiles. jank.
17:49ihodesgfrlog: i don't at all! i love maps
17:50ihodesgfrlog: i just was wondering if there was anything different/weird/interesting
17:50ihodesgfrlog: doesn't have to be better (could there even be a better data structure for that use case?)
17:50ihodesgfrlog: in fact, the structure would probably be isomorphic to a map in order to get similar performance.
17:51dnolen_ihodes: ITerm2 has 256, Emacs colors themes look perfect.
17:51ihodesdnolen_: how do you get emacs to display those themes? my themes don't match up; they use my profiles' colors, and swap them around sometimes...
17:52ihodesdnolen_: i tried zenburn, for e.g., but it just mixed up the colors i had already set from iTerm's GUI
17:52dnolen_ihodes: Preferences > Profiles > Terminal > Report Terminal Type: xterm-256color, zeburn looks flawless
17:53dnolen_with ITerm2 mouse reporting you can even click to set the cursor position in Emacs.
17:58ihodesdnolen_: IT WORKS. the profile i was using was reporting just xterm, for some reason i guess that's the default. thanks :)
17:59dnolen_ihodes: no problem
18:14mdeboard`technomancy: This might interest you re: science http://i.imgur.com/W7Fcl.jpg
18:39zodiakso, I understand from last night that a quote means 'do not execute' or stop execution, why then in require does it have ' before a symbol (or list, or etc etc) ?
18:42opqdonutwell you don't want to fetch the value in the variable foo.bar.baz
18:42opqdonutyou want to give the symbol foo.bar.baz to identify the namespace
18:42opqdonutrequire could work with strings too, for example
18:44zakwilsonor you might actually want the value of a variable: (let [the-thing-to-require 'clojure.contrib.sql] (require the-thing-to-require))
18:44ihodeszodiak: also, for instance, if you tried (first (1 2 3)), you'd be "calling" 1. which can't be called, as it's not a function. so you want to prevent its evaluation with a quote: (first '(1 2 3))
18:44gfrlogor use a vector literal :)
18:45ihodesgfrlog: grrrrrrrr. the idea was to explain the ' :P
18:45zakwilsonI have some code that does (apply require the-list-of-requirements)
18:45gfrlogihodes: I know I know I know...
18:45zakwilsonThe ' means "I want the NAME foo, not the value of foo"
18:46zodiakwell, part of my confusion was thinking that 'symbol was basically saying ' makes things as a 'symbol'
18:46zakwilsonIt's a symbol either way, but the ' means you want the symbol itself, not the thing it references.
18:46zodiakso, seeing it as '(1 2 3) and then getting told (in the books) that's a vector literal didn't help
18:47ihodeszodiak: [1 2 3] is a vector
18:47zodiakzakwilson: well, I come from the whole 'a symbol is a symbol' .. there is no difference between what the symbol points to and the symbol itself
18:47ihodeszodiak: '(1 2 3) is a list.
18:47zodiakihodes: correction then. lit.
18:47ihodeszodiak: (1 2 3) is a function application
18:47zodiaklist.
18:48ihodeszodiak: applying the function 1 to the operands 2 and 3. but 1 isn't a function... so you get a kaboom.
18:49zodiakihodes: gotcha. although I still fail to see the logical distinction between what a symbol references and the symbol itself, since a symbol of 'hello can only ever have hello (at least, that was my mathematical understanding of symbols :)
18:49ihodeszodiak: (quote (1 2 3)) tells the reader not to try to look up 1 in the local or global scope, and to not treat it as a function. instead, ' (or quote) tells the reader that the following symbol or sexp should be taken as a literal whatever. and not evaluate it.
18:49gfrlogihodes: I don't think it's the reader, I think it's the compiler
18:49ihodeszodiak: the thing to understand is that in functional lisp, everything has a value. symbols are all references to values of literals
18:50ihodesgfrlog: ah yeah, sorry.
18:50zodiakhuh. symbols have values eh. okay. interesting :)
18:50zakwilsonYou can have a symbol that isn't a reference to anything.
18:50gfrlogzodiak: it's a bit more complex than that
18:50ihodeszodiak: right, so first refers to the function first--think of the compiler as replacing alllll references in your code to first with the actual code for the definition of the function.
18:51zodiakso, that makes the require more understandable. I think :)
18:51ihodeszodiak: and doing that recursively with everything it find when it looks up the symbols it encounters. it can't, of course, replace values.
18:51zakwilson,'this-is-an-unbound-symbol
18:51clojurebotthis-is-an-unbound-symbol
18:51ihodeszodiak:
18:51zakwilson,this-is-an-unbound-symbol
18:51clojurebotjava.lang.Exception: Unable to resolve symbol: this-is-an-unbound-symbol in this context
18:51ihodes,`(~'hah)
18:51clojurebot(hah)
18:52ihodescause i'm a jerk. anyway, need to hack some
18:52ihodesl
18:53jimi_hendrixlien deps wont download clojure-contrib for me. it complains about a missing artifact. is this to be expected?
18:53gfrlogjimi_hendrix: what's it look like in the project.clj?
18:54jimi_hendrixgfrlog, [org.clojars.jhowarth/clojure-contrib "1.2.0-RC3"] (copied from clojars)
18:55gfrlogtry [org.clojure/clojure-contrib "1.2.0"]
18:55jimi_hendrixgfrlog, oh nvm i found it
18:55jimi_hendrixi just got it to work
18:55gfrlogokay
19:00ihodesgfrlog: what would you explain re: vars? I don't know how much they'd add
19:00ihodesgfrlog: to zodiak's understanding
19:00gfrlogihodes: I know it could be confusing to a beginner, but they're definitely relevant to the topic
19:01ihodesgfrlog: i mean, how would you explain it? i can't think of a great way to
19:03gfrlogihodes: I think I would say that the compiler, when processing a non-quoted symbol, first checks the local scope (i.e., let and fn-arguments), and if it doesn't find the symbol there then it checks the current namespace to see what var the symbol refers to. The compiled code then contains a reference to that var (I think), the value of which can vary (but normally doesn't)
19:04gfrlogso for example saying that the compiler replaces the symbol with the source of the function could be quite misleading
19:05ihodesgfrlog: to be fair, i didn't say that happened. i just think it's a good way to think about it to begin with. but you're right, more explicitely explainng vars could be useful. i think, though, you'd then need to explain other reference types like refs.
19:05hiredmanthe movement from the substitution model to the environment model is a big one
19:05hiredmanmove
19:06gfrloghiredman: so do you think it's helpful to discuss vars with beginners?
19:06ihodesgfrlog: actually, i think first you'd need to explain the difference between the reader and compiler
19:06gfrlogihodes: true
19:06ihodesmy example/explanation conflates them. which i think is actually useful for a beginner, for reasoning about code
19:07hiredmangfrlog: they have to learn about them sometime
19:07zodiakspeaking as a beginner (to clojure anyway) going -that- in depth is going to turn off people
19:07gfrlogI did a lot with clojure before understanding reader vs compiler
19:07ihodesgfrlog: and, to be clear, i'm totally interested in having this conversation. i'm very interested in teaching more people about Clojure, so if it seems like i'm challenging you it's not because i'm being a jerk, but trying to figure it out
19:07gfrlogI'm definitely not sure about this either way, which is why I didn't really interject about it during the conversation
19:08ihodeshiredman: that's like saying "you've got to learn about eax sometimes. might as well start with x86"
19:08ihodeshiredman: there needs to be an abstract understanding first, if you want to quickly get up to speed. else you do need to start very low and move up.
19:09hiredmanihodes: *shrug*
19:09ihodesit's useful to think about a program as text, and then think of what happens when you run it as text transformation. then imagine the computer is running your transformed text. and, on a level, that is what's happening. then you can start to understand the different levels of indirection and transformation.
19:10ihodeshiredman: i feel ya
19:12pcavs$findfn -1 1
19:12sexpbot[clojure.core/unchecked-negate clojure.core/-]
19:12pcavs$findfn 100 100
19:12sexpbot[clojure.set/union clojure.set/intersection clojure.set/difference clojure.core/time clojure.core/dosync clojure.core/long clojure.core/short clojure.core/+ clojure.core/* clojure.core/with-loading-context clojure.core/doto clojure.core/float clojure.core/macroexpan... http://gist.github.com/1075077
19:13ihodes,(Math/abs -1)
19:13clojurebot1
19:26wilfredhI'm getting an error "Call getNextException to see the cause." but trying to call that with (.getNextException e) just gives me "No matching field found: getNextException for class java.lang.Exception"
19:26wilfredhwhat am I doing wrong?
19:27hiredmane is most likely a runtime exception wrapping whatever exception has the getNextException method
19:28wilfredhhow would I unwrap it?
19:43wilfredhah, I needed getCause
20:00jimi_hendrixi am :require ing clojure.contrib.string, but it says split is not being found. what is up?
20:02sritchiejimi_hendrix: make sure you use the prefix you specified --
20:02jimi_hendrixsritchie, prefix?
20:02sritchietwo things -- one, trying requiring clojure.string
20:03sritchiethe two options for this sort of thing are use and require
20:03sritchieuse pulls all functions from the use'd namespace into the current namespace -- (use 'clojure.string) (join "," [1 2 3]), for example
20:04sritchierequire allows you to assign a prefix to functions from that namespace -- (require '[clojure.string :as s]) (s/join "," [1 2 3])
20:04jimi_hendrixah
20:04jimi_hendrixi was using this to include it: (ns your-namespace
20:04jimi_hendrix (:require clojure.contrib.string))
20:04sritchieyeah, that makes everything available with the full namespace as a prefix
20:04jimi_hendrixi see
20:04zodiakjimi_hendrix: for the love of the gods, don't get people started about ' before the module again ;p
20:04sritchie(:require clojure.string) lets you do (clojure.string/join "," [1 2 3])
20:05jimi_hendrixzodiak, uhh
20:05jimi_hendrixis there a difference?
20:05jimi_hendrixsritchie, is there a :use option then?
20:05sritchieyeah
20:05zodiakjimi_hendrix: joke, kinda, I am learning clojure as well ;)
20:05sritchieyou don't need that ' when you're inside the namespace macro, (ns ...), because macros don't evaluate their arguments
20:06sritchieuse and require are functions, so they need their arguments quoted, for this stuff
20:06zodiakI dare say that namespaces/requires/use is were most news trip up
20:06zodiaks/news/newbs/
20:06sexpbot<zodiak> I dare say that namespaces/requires/use is were most newbs trip up
20:06zodiaksexplot +karma
20:07zodiakgood gods.. this autocorrect is annoying. what's a 'sexplot' ?
20:07sritchie(inc sexpbot)
20:07sexpbot⟹ 0
20:08gfrlog(inc sexplot)
20:08sexpbot⟹ 1
20:19zakwilson(dec sexplot)
20:19sexpbot⟹ 0
20:19zakwilson(inc sexplot)
20:19sexpbotYou want me to leave karma the same? Fine, I will.
20:19zakwilsonHeh
20:25sritchiejimi_hendrix, if you're interested, here's some code for blackjack that I wrote in clojure: https://github.com/sritchie/blackjack/blob/develop/src/blackjack/core.clj
20:26sritchiethis has some uses, requires, and tests in a self-contained project that might be helpful to look at
20:27jimi_hendrixsritchie, cool, will check out
21:16amalloysummary of quoting: (let [x 1] (print x 'x)). here the symbol x has been given the local value of 1, which is the first thing printed. the quote on the second one prevents evaluation, printing the actual *symbol* x instead of its value
21:53pcavswhat's the idiomatic clojure constant naming convention? ALLCAPS? CL *ALLCAPS* ?
21:56TimMcpcavs: Most things are constants, yeah?
21:56Scriptor`I'm not sure if constants are idiomatic in clojure
21:57Scriptor`right, since most things are immutable anyways
21:57TimMcI think people tend to emphasize the things that *aren't*.
21:57TimMc ^^^^^^^^
21:57TimMc:-)
21:58pcavsI mean more along the lines of constant strings for various purposes or constant magic numbers
21:58pcavsI'll just go with CL earmuffs
21:59TimMcpcavs: In Clojure, earmuffs are generally used for stuff that can be rebound.
21:59hiredmanhttp://dev.clojure.org/display/design/Library+Coding+Standards
21:59hiredman"Use *earmuffs* only for things intended for rebinding. Don't use a special notation for constants; everything is assumed a constant unless specified otherwise."
22:02pcavswell no earmuffs it is!
22:05ViciousPlantdoes earmuff has special meaning here
22:07amalloyViciousPlant: *foo* looks like a foo wearing earmuffs
22:11ViciousPlantget it, thanks
22:42pcavs#findfn (fn [x] (< x 2)) [3 4 5] false
22:43amalloy$findfn (fn [x] (< x 2)) [3 4 5] false
22:43sexpbot[clojure.core/identical? clojure.core/isa? clojure.core/= clojure.core/contains? clojure.core/every?]
22:43pcavsamalloy: thanks
22:50pcavsI just want some to return false, thoughts?
22:50pcavsfalse instead of nil that is
22:50pcavswithout resorting to (not (nil?
22:51amalloypcavs: suggestion: stop caring about the difference between false and nil except in rare cases
22:51amalloywhy do you think you need false?
22:51pcavslemme check
22:51pcavs,(if nil "wtf" "ok")
22:51clojurebot"ok"
22:51pcavsguess I don't ;)
22:52amalloypcavs: there are exactly two things that are treated as false in an (if) test: false and nil
22:52pcavsthought it was just false
22:52amalloynah, that's java
22:53pcavsbut I'm thinking of scheme I think, cause nil doesn't exist right?
22:53amalloypretty sure scheme has nil
22:54seancorfieldnice to be home and on a nice high speed network after spotty hotel wifi all weekend! :)
23:12pcavsamalloy: scheme does not have nil, it just has the empty list as annotated as (quote ())
23:12pcavsa somewhat pedantic difference, but I forget the reasoning behind it...
23:21amalloywell, fair enough. that's what i get for learning CL instead of scheme
23:33hiredmanclojure does not require the emtpy list to be quoted
23:33hiredman,(= () '())
23:33clojurebottrue
23:34pcavs,()
23:34clojurebot()
23:34pcavs,(= () nil)
23:34clojurebotfalse
23:36amalloyhiredman: based on my brief study just now, it looks like scheme didn't standardize on whether () has to be quoted?
23:37hiredmanno idea, I would expect most schemers would prefer the regularity of it being quoted
23:51ihodesamalloy: i'm pretty sure you need to quote it
23:56amalloyihodes: yeah, certainly that's the most portable. i ran across http://wiki.wordaligned.org/sicp/published/FrequentlyAskedQuestions, which suggests some impls don't make you