2011-07-10
| 00:01 | scottj | mdeboard`: http://www.youtube.com/watch?v=lf_xI3fZdIg http://www.youtube.com/watch?v=kH0gOE7rj7g |
| 00:02 | scottj | + ritz + clojure-refactoring |
| 00:09 | sa125 | Hi - how do I reverse a string? I tried (reverse "hello") and got (\\o \\l \\l \\e \\h). |
| 00:09 | sa125 | [single backslash] |
| 00:10 | hiredman | ,(clojure.string/reverse "foo") |
| 00:10 | clojurebot | "oof" |
| 00:11 | sa125 | hiredman - thanks! |
| 00:13 | hiredman | thats like 4 |
| 00:13 | mdeboard` | Whoops. |
| 00:34 | ihodes | i'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:00 | pcavs | ,(doc source) |
| 01:00 | clojurebot | I don't understand. |
| 01:01 | amalloy | $mail mdeboard` to get the slime repl to recognize [] and {} as parens, try https://gist.github.com/1074292 |
| 01:01 | sexpbot | Message saved. |
| 01:03 | amalloy | pcavs: source is in clojure.repl, which the bots don't load |
| 01:03 | pcavs | yeah, I keep reaching for clojure.contrib.repl-utils and keep remembering (eventually) that it's clojure.repl =\ |
| 01:07 | pcavs | $findfn 5 4 false |
| 01:07 | sexpbot | [clojure.core/== clojure.core/identical? clojure.core/isa? clojure.core/< clojure.core/= clojure.core/<= clojure.core/contains? clojure.core/bit-test] |
| 01:07 | pcavs | I guess I'm down to using (not (= ...)) then? |
| 01:09 | amalloy | pcavs: uh, are you looking for not=? if so, you probably meant |
| 01:09 | amalloy | $findfn 5 4 true |
| 01:09 | sexpbot | [clojure.core/not= clojure.core/distinct? clojure.core/> clojure.core/>=] |
| 01:10 | pcavs | god dammit I'm stupid =\ |
| 01:13 | talios | anyone know if theres an updated version of clojure.contrib.gen-html-docs thats 1.3 compatible? |
| 01:13 | zodiak | does anyone have a newb friendly clojureql and sqlite3 example ? |
| 01:23 | amalloy | talios: would marginalia be acceptable? it's probably 1.3-compatible, but i don't use it |
| 01:23 | Blackfoot | if I take a class as a function arg, how can I instantiate it? |
| 01:25 | talios | amalloy: 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:26 | amalloy | Blackfoot: you have to use reflection |
| 01:26 | amalloy | &(let [c Integer] (.newInstance c 5)) |
| 01:26 | sexpbot | java.lang.IllegalArgumentException: No matching method found: newInstance for class java.lang.Class |
| 01:26 | amalloy | &(let [c Integer] (.newInstance c (into-array Object [5]))) |
| 01:26 | sexpbot | java.lang.IllegalArgumentException: No matching method found: newInstance for class java.lang.Class |
| 01:26 | amalloy | feh. something like that |
| 01:27 | talios | its a static method so needs a different invovation |
| 01:28 | talios | &(let [c Integer.class] (.newInstance c (into-array Object [5]))) |
| 01:28 | sexpbot | java.lang.ClassNotFoundException: Integer.class |
| 01:28 | amalloy | talios: that's 100% wrong. Integer.class is java syntax |
| 01:29 | talios | yeh |
| 01:29 | Blackfoot | amalloy: ah yea, i see where you're going, thanks. i'll play around with the function calls |
| 01:29 | Blackfoot | ah Class.newInstance can only invoke zero arg ctor |
| 01:30 | Blackfoot | java.lang.Reflect may work |
| 01:30 | amalloy | &(.newInstance (.getDeclaredConstructor Integer (into-array Class [Integer/TYPE])) (into-array Object [5])) |
| 01:30 | sexpbot | java.lang.SecurityException: You tripped the alarm! package java.lang.reflect, Java Platform API Specification, version 1.6 is bad! |
| 01:30 | talios | Blackfoot: a class has a getConstrutors(Object, Object) method that'll return a Constructor instance you can us |
| 01:30 | amalloy | or there's clojure.lang.Reflector, which simplifies a lot of this stuff |
| 01:30 | amalloy | ,(.newInstance (.getDeclaredConstructor Integer (into-array Class [Integer/TYPE])) (into-array Object [5])) |
| 01:30 | clojurebot | 5 |
| 01:30 | talios | doh - declaredConstructor actually |
| 01:42 | replaca | talios: (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:42 | talios | replaca: yeh, was just reading over the mailing list and came to the same conclusion |
| 01:43 | replaca | Basically, if there ain't a new-style contrib library, it ain't coming |
| 01:43 | replaca | although there is plenty of room to mmake a case for stuff |
| 01:50 | amalloy | talios: 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:02 | talios | technomancy: 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:58 | mdeboard` | Ok, I think I'm going to tear my hair out. |
| 02:58 | mdeboard` | I've been trying to get SLIME repl working in emacs for hours now, I'm exhausted. |
| 02:58 | mdeboard` | but I keep getting the same issue as here: https://github.com/technomancy/swank-clojure/issues/49 |
| 02:59 | hiredman | my guess is you have the wrong slime |
| 02:59 | hiredman | are you using clojure-jack-in ? |
| 02:59 | mdeboard` | yeah, clojure-jack-in, then I get a "Lisp lost connection" message as soon as I do anything at all. |
| 02:59 | mdeboard` | Do I really have to get a 2-year-old release? |
| 02:59 | mdeboard` | *branch |
| 02:59 | hiredman | what do you mean two year old release? |
| 03:00 | mdeboard` | Well, I grabbed the release from ELPA, thinking that would solve the problem |
| 03:00 | hiredman | no no |
| 03:00 | mdeboard` | Yeah this is really fucking confusing. |
| 03:00 | hiredman | follow the usage instructions https://github.com/technomancy/swank-clojure |
| 03:01 | mdeboard` | Right, but what slime do I use? |
| 03:01 | hiredman | it is pretty simple if you follow the instructions, if you don't it's your own fault |
| 03:01 | mdeboard` | No, no |
| 03:01 | mdeboard` | That part is fine. |
| 03:01 | mdeboard` | It connects to the REPL fine. |
| 03:01 | hiredman | you don't need a slime |
| 03:01 | mdeboard` | what. |
| 03:01 | replaca | mdeboard`: technomancy ha a blog post here that shows how |
| 03:01 | hiredman | clojure-jack-in actually loads a budled slime from the swank-clojure jar |
| 03:01 | replaca | http://technomancy.us/149 |
| 03:02 | mdeboard` | Ok |
| 03:02 | mdeboard` | That |
| 03:02 | hiredman | mdeboard`: you did the three things in the usage instructions for swank-clojure? and still get the error? |
| 03:02 | mdeboard` | hiredman: Yeah, but I was still requiring slime |
| 03:02 | mdeboard` | and since I had slime installed |
| 03:02 | mdeboard` | it was fucking everything up, maybe? I dunno, let me go fix up emacs config |
| 03:02 | replaca | mdeboard`: but make *absolutely* sure you don't have a swank in you project.clj or anywhere else in your classpath |
| 03:03 | replaca | mdeboard`: yeah, that's your problem |
| 03:03 | replaca | I had the same problem when I followed those instructions |
| 03:06 | talios | wow - 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:08 | mdeboard` | Alright, that did it. |
| 03:08 | mdeboard` | That has been really frustrating. |
| 03:10 | hiredman | mdeboard`: for future reference #clojure is generally pg or pg13 language wise |
| 03:10 | mdeboard` | thanks, guy who pointed out that issue and hiredman |
| 03:10 | mdeboard` | Did I cuss? Sorry. |
| 03:10 | mdeboard` | I'm usually pg or pg13 language wise. |
| 03:11 | replaca | mdeboard`: :) |
| 03:11 | hiredman | :) |
| 03:12 | talios | ...so there we have it. slime is more of a hindrance to clojure newbies than hiredman. hiredman++ |
| 03:12 | Blackfoot | is there a way to use alias namespaces in keywords? eg (:require really.long.ns :as lns) then use :lns/kw later? |
| 03:13 | hiredman | it's hard to say if technomancy's relentless pace of changes (aimed to make it easier) actually makes it harder or not |
| 03:13 | hiredman | blog posts have a half life of a week or so it seems like |
| 03:14 | talios | right - going to go hunt some thai takeaway dinner whilst this clojure-maven-plugin release runs - back later. |
| 03:14 | scgilardi | Blackfoot: it looks like the alias is not effective there. seems to me that it should be. |
| 03:15 | hiredman | Blackfoot: ::some-alias/word |
| 03:15 | hiredman | ,(require '[clojure.zip :as z]) |
| 03:15 | clojurebot | nil |
| 03:15 | hiredman | ,::z/foo |
| 03:15 | clojurebot | :clojure.zip/foo |
| 03:15 | scgilardi | nice |
| 03:15 | zodiak | why 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:15 | Blackfoot | hiredman: ooh nice, thanks |
| 03:16 | zodiak | well, I mean, I can guess why, I mean rather what's the solution and why :) :) |
| 03:16 | hiredman | zodiak: you have a lot of quoted symbols there |
| 03:16 | hiredman | do you know what quoting does? |
| 03:17 | zodiak | hiredman: it's similar to a symbol in ruby/haskell .. no ? |
| 03:17 | hiredman | zodiak: if you don't know what quoting does then I suggest you a. stop doing it until you b. read up on it |
| 03:18 | zodiak | fine, but how do I solve that error in the meantime ? :) |
| 03:18 | hiredman | I just told you how |
| 03:18 | scgilardi | you also probably want (require '[clojure.contrib.sql :as sql]) at the top rather than ns and in-ns |
| 03:18 | scgilardi | (and do follow hiredman's advice) |
| 03:19 | zodiak | scgilardi: but if I do that, doesn't the whole namespace get potentially polluted by the methods/def's from contrib.sql ? |
| 03:19 | talios | mmm, that paste mentions an error on line 17, but only 10 lines pasted .. there no symbol rs even mentioned in the paste |
| 03:19 | hiredman | zodiak: I suggest reading docs on namespaces etc (and all the other docs, in order) linked to on the left sidebar of clojure.org |
| 03:20 | scgilardi | no. 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:20 | zodiak | hiredman: well, yes, I am trying to learn .. ergo.. why I am asking what's wrong |
| 03:20 | zodiak | scgilardi: alrighty, that makes sense |
| 03:20 | hiredman | zodiak: you don't know what quoting does, and you are quoting stuff, so of course it doesn't do what you want |
| 03:21 | zodiak | *sighs gently* |
| 03:25 | talios | grr 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:25 | talios | but I was going for food... bbl |
| 03:26 | hiredman | talios: thats pretty slick |
| 03:27 | talios | hiredman: 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:27 | talios | er, all I was seeing |
| 03:28 | amalloy | talios: "all i was was the mydb connection": someone who's meditating about how to write a function? |
| 03:28 | zodiak | oh. quote delays evaluation |
| 03:28 | hiredman | I should see about getting my growler thing to open pastebin links |
| 03:28 | amalloy | zodiak: no, it prevents it |
| 03:28 | zodiak | amalloy: fairy snuff :) |
| 03:28 | hiredman | functions delay evaluation (and delay binding) and so do delays |
| 03:29 | scgilardi | man I like functions |
| 03:29 | talios | amalloy: I am a database connection, nothing more, nothing less. a conduit to information for the rest of you :) |
| 03:29 | scgilardi | yeoman's work, t-man |
| 03:30 | hiredman | #9 |
| 03:30 | hiredman | ~#9 |
| 03:30 | clojurebot | 9. It is better to have 100 functions operate on one data structure than 10 functions on 10 data structures. |
| 03:31 | hiredman | ~#94 |
| 03:31 | clojurebot | 94. Interfaces keep things tidy, but don't accelerate growth: Functions do. |
| 03:33 | ihodes | ~#42 |
| 03:33 | clojurebot | 42. You can measure a programmer's perspective by noting his attitude on the continuing vitality of FORTRAN. |
| 03:34 | ihodes | *goes to cbots source* |
| 03:34 | amalloy | $google alan perlis quotes fortran |
| 03:34 | sexpbot | First out of 618 results is: Perlisisms - "Epigrams in Programming" by Alan J. Perlis |
| 03:34 | sexpbot | http://www.cs.yale.edu/quotes.html |
| 03:34 | amalloy | ihodes: ^ |
| 03:35 | hiredman | very apropos, the code that grabs the epigrams uses a delay |
| 03:35 | ihodes | amalloy: excellent; i couldn't remember the name of the list |
| 03:35 | zodiak | day 2 of clojure, and I managed to get sqlite spitting out tuples onto a webpage. spiffy :) |
| 03:35 | zodiak | thanks everyone. |
| 03:35 | amalloy | ihodes: i can't either. but remembering another alan's last name is easy enough |
| 03:36 | ihodes | ~#113 |
| 03:36 | clojurebot | 113. The only constructive theory connecting neuroscience and psychology will arise from the study of software. |
| 03:36 | ihodes | = my life plan |
| 04:12 | amalloy | anyone know of a way to look at a java.lang.reflect.Method object and tell whether it's got varargs? |
| 04:13 | amalloy | oh uhm. i'll try the isVarArgs method |
| 04:13 | talios | varargs under the covers is just an array. |
| 04:13 | amalloy | talios: i know |
| 04:13 | talios | or that :) |
| 04:13 | amalloy | but i'm writing a javadoc facility, and the anchor links are different |
| 04:19 | talios | ahh - generating javadoc from clojure or just in clojure? |
| 04:19 | amalloy | $javadoc Class |
| 04:19 | sexpbot | http://download.oracle.com/javase/6/docs/api/java/lang/Class |
| 04:20 | amalloy | talios: wrote this earlier tonight, and trying to get it to generate the right method anchors as well |
| 04:20 | talios | ah cool |
| 04:27 | amalloy | $javadoc Class getMethod |
| 04:27 | sexpbot | http://download.oracle.com/javase/6/docs/api/java/lang/Class.html#getMethod(java.lang.String,%20java.lang.Class...) |
| 04:27 | amalloy | talios: look at this horrible anchor link you have to build |
| 04:28 | talios | oh lovely |
| 04:30 | amalloy | and that still doesn't handle everything: generic types, for example |
| 04:37 | hsaliak | talios: thanks for that :) i use the plugin |
| 04:38 | talios | hsaliak: 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:41 | hsaliak | talios: not aware of the surefire extensions.. :-/ |
| 04:42 | talios | hsaliak: 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:42 | talios | ( and test counts ) |
| 04:42 | hsaliak | talios: i mainly use it for getting clojure on android it integrates nicely with the android plugin, otherwise i use lein |
| 04:42 | hsaliak | i see |
| 04:43 | talios | neat. any problems with clojure on android? i assume you need everything AOT'd? |
| 04:44 | hsaliak | talios: yes everything AOTd :) |
| 04:44 | hsaliak | talios: 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:45 | hsaliak | but its worth it |
| 04:45 | hsaliak | dynamic functional languages make it a little hard to optimize on memory i'd suspect |
| 04:46 | talios | mm, technically if everything is AOT'd, is it still dynamic.. |
| 04:46 | hsaliak | have not tried introducing type hints and the like into whatver little code i have written |
| 04:46 | hsaliak | of course |
| 04:46 | hiredman | well, android is a new vm, they just turned on the jit for it, so it will be a while till matches hotspot |
| 04:48 | hsaliak | i think biggest issue is the load time for the app |
| 04:48 | hsaliak | a few seconds is bad |
| 04:49 | talios | I'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:51 | talios | brb |
| 04:53 | amalloy | $javadoc java.util.Collection add ;; you even have to say E here, despite that being mostly a figment of the compiler's imagination |
| 04:53 | sexpbot | http://download.oracle.com/javase/6/docs/api/java/util/Collection.html#add(E) |
| 09:18 | the-kenny | clojure.test/are needs destructuring for the argv-vector |
| 09:19 | the-kenny | to do something like (are [[x y] v] (= v (get (coord x y) ...)) ...) |
| 09:35 | jimi_hendrix | is there a good guide to setting up clojure with slime? everything i have found via google is out of date |
| 11:06 | Netfeed | what's the best way to print what's inside a map? something simillar to perls Data::Dumper |
| 11:08 | Netfeed | s/map/hash |
| 11:08 | sexpbot | <Netfeed> what's the best way to print what's inside a hash? something simillar to perls Data::Dumper |
| 11:11 | jimi_hendrix | where do you guys install lein? |
| 11:11 | mdeboard` | I did in /home/me/ |
| 11:12 | Vinzent | script in /usr/local/bin |
| 11:19 | Scriptor | C:\lein :/ |
| 11:20 | mdeboard` | god, why |
| 11:20 | mdeboard` | WHY |
| 11:21 | mdeboard` | @ Scriptor |
| 11:21 | mdeboard` | I cannot even imagine |
| 11:21 | mdeboard` | windows is for games and watching Netflix |
| 11:21 | Scriptor | mdeboard`: and when spilling coffee somehow only breaks your osx partition |
| 11:22 | mdeboard` | Ew |
| 11:23 | Scriptor | actually, it's not *too* bad, I've got emacs for windows, gvim, and mingw32 so it's ok enough |
| 11:23 | mdeboard` | Yeah it's just so much extra work getting a dev env set up |
| 11:27 | mdeboard` | Does anyone here use paredit for emacs? It's been annoying for me but recommended everywhere. |
| 11:28 | sritchie | mdeboard`: yup, I'm a big dan |
| 11:28 | sritchie | s/dan/fan |
| 11:28 | sexpbot | <sritchie> mdeboard`: yup, I'm a big fan |
| 11:29 | sritchie | M-( 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:29 | mdeboard` | 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:29 | mdeboard` | ah |
| 11:29 | sritchie | yeah, so, go into :bar :baz, somewhere along there, and type M-s |
| 11:30 | mdeboard` | Vinzent: I've got paren highlighting and the normal "mismatched parens" emacs warning |
| 11:30 | sritchie | mdeboard`: yeah, that'll happen if you use kill-word-backward, and accidentally jump over a paren |
| 11:30 | sritchie | the solution is to use M-delete instead -- it ignores parens, just killing words |
| 11:30 | mdeboard` | Cool |
| 11:31 | mdeboard` | M-s is what I needed :) |
| 11:32 | mdeboard` | 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:32 | Vinzent | btw, 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:32 | mdeboard` | I assume some token before foo |
| 11:33 | sritchie | Vinzent: it's bound to M-up too, I think |
| 11:33 | sritchie | mdeboard`: that code you have there is a map data structure, mapping the keyword :foo to the value bar |
| 11:33 | mdeboard` | Oh, right |
| 11:34 | sritchie | keywords evaluate to themselves, like numbers |
| 11:34 | sritchie | (defn apply-foo-to-bar [foo] (foo bar)) will do the trick |
| 11:35 | Vinzent | sritchie, but arrow keys are so slow! :) |
| 11:35 | sritchie | haha, good point |
| 11:36 | sritchie | ,(let [foo +, bar 10] (foo 2 bar)) |
| 11:36 | clojurebot | 12 |
| 11:36 | sritchie | (let [foo +, bar 10] {:foo bar}) |
| 11:36 | sritchie | ,(let [foo +, bar 10] {:foo bar}) |
| 11:36 | clojurebot | {:foo 10} |
| 11:37 | mdeboard` | hm not quite what I mae uh |
| 11:37 | mdeboard` | mean, uh |
| 11:37 | mdeboard` | if I could figure out how to wrap an exp in braces I'd paste it up for you :) |
| 11:37 | sritchie | make a brace -- {} -- then go inside, and hit C-<right> a few times |
| 11:37 | sritchie | that'll grab the s-expressions to the right, one at a time |
| 11:37 | mdeboard` | Oh, ok. |
| 11:38 | mdeboard` | ಠ_ಠ |
| 11:38 | mdeboard` | I'll give it a chance, but seems like needless complication. |
| 11:38 | sritchie | {} :foo (+ 1 2), {:foo} (+ 1 2), {:foo (+ 1 2)} |
| 11:38 | sritchie | or, you can kill (C-k), make some braces, then yank again |
| 11:41 | Vinzent | wrap an exp in braces? M-{ ? |
| 11:42 | mdeboard` | Didn't work for me |
| 11:42 | mdeboard` | but re: value mapping, here's a snipper of what I mean |
| 11:42 | mdeboard` | http://p.mattdeboard.net/cloj.html |
| 11:42 | Vinzent | hm, it's working here... |
| 11:43 | mdeboard` | amount-tendered is a passed-in arg, and I want `:amount-tendered` to be replaced with `:80` or whatever. |
| 11:43 | Vinzent | ah, I have (define-key paredit-mode-map (kbd "M-{") 'paredit-wrap-curly) in my paredit config |
| 11:43 | mdeboard` | Do I need to do like (let [x amount-tendered] {:x ....) |
| 11:44 | mdeboard` | M-{ is move cursor between functions |
| 11:44 | mdeboard` | (seek whitespace) |
| 11:44 | sritchie | https://gist.github.com/1074636 |
| 11:44 | mdeboard` | no : necessary? |
| 11:45 | sritchie | the keyword function converts it to a keyword |
| 11:45 | mdeboard` | Ah got it. |
| 11:45 | sritchie | ,(-> 100 str keyword) |
| 11:45 | clojurebot | :100 |
| 11:45 | sritchie | ,(keyword "100") |
| 11:45 | clojurebot | :100 |
| 11:45 | mdeboard` | Very cool. Very, very cool. :) |
| 11:45 | mdeboard` | little more verbose than I'm used to |
| 11:45 | mdeboard` | (don't hit me) |
| 11:46 | sritchie | haha, no worries |
| 11:47 | sritchie | ,(zipmap [:mod :dividend] ((juxt mod (comp int /)) 10 100)) |
| 11:47 | clojurebot | {:dividend 0, :mod 10} |
| 11:48 | sritchie | a less verbose way would be to simply use the number as the key in the map |
| 11:50 | sritchie | https://gist.github.com/1074636 |
| 11:50 | mdeboard` | Oh. |
| 11:50 | mdeboard` | facepalm |
| 12:05 | mdeboard` | Ok, I need some help because recursion is hurting my brain. Please. |
| 12:05 | mdeboard` | http://p.mattdeboard.net/recursionhelp.html |
| 12:05 | mdeboard` | I'm trying to rewrite an old "make change" program I wrote originally in Python, in Clojure |
| 12:06 | mdeboard` | Basically you have a "Price", "Amount paid" and "Denominations" (using US denoms here) for this project. |
| 12:07 | gfrlog | what's the clos function supposed to do? |
| 12:07 | mdeboard` | Well, right now it's just a mechanism that loops over the denominations |
| 12:07 | mdeboard` | 20 = $20 bill, 10 = $10 bill, 5= $5 bill and so one |
| 12:08 | mdeboard` | so on* |
| 12:08 | mdeboard` | For each denomination, find the modulo and dividend |
| 12:08 | gfrlog | alright. So what do you need help with? |
| 12:09 | mdeboard` | Subtract (* dividend denomination) from the Price, then on the next pass, instead of using Price, you use the modulo of the previous denomination |
| 12:10 | gfrlog | what should the return value of clos be? |
| 12:10 | gfrlog | a map from denominations to counts? |
| 12:10 | gfrlog | {20 1, 5 1, 0.10 2}+ |
| 12:10 | mdeboard` | Yeah, like how many of each bill it took to uh |
| 12:10 | gfrlog | s/+/? |
| 12:10 | clojurebot | make 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:11 | gfrlog | clojurebot: shut up |
| 12:11 | clojurebot | Titim gan éirí ort. |
| 12:11 | mdeboard` | How many of each bill it took to make change |
| 12:11 | gfrlog | mdeboard`: okay. I think this is a natural use for loop |
| 12:11 | gfrlog | instead of for |
| 12:11 | mdeboard` | 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:12 | gfrlog | in that case, the argument to clos would be 15.01, right? |
| 12:12 | gfrlog | 25.01 I mean |
| 12:12 | mdeboard` | Right |
| 12:12 | gfrlog | okay. Ignoring any potential pitfalls of using floats... |
| 12:13 | gfrlog | I would replace the for with |
| 12:13 | mdeboard` | yeah |
| 12:13 | gfrlog | oh wait we can do this with reduce |
| 12:13 | gfrlog | that's cleaner |
| 12:13 | mdeboard` | can we? o.O |
| 12:13 | gfrlog | are you familiar with reduce? |
| 12:14 | mdeboard` | Yeah |
| 12:15 | gfrlog | so 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:15 | mdeboard` | In that I know generally wha tit does. But I'm coming from Python where using reduce is silly. :( |
| 12:15 | gfrlog | but that just means our reduce-value needs to be a pair |
| 12:15 | gfrlog | its starting value will be [amount {}] |
| 12:15 | gfrlog | and we process the list of denoms, updating both parts of the pair as we go |
| 12:16 | gfrlog | so the reduce function could be: |
| 12:16 | mdeboard` | Whew. |
| 12:16 | mdeboard` | I definitely need to see that in a snippet |
| 12:16 | gfrlog | kay I'll pastie it |
| 12:17 | gfrlog | I think it takes some practice to see how to use reduce effectively |
| 12:18 | gfrlog | https://gist.github.com/1074657 |
| 12:19 | gfrlog | so that would go under the (let [denoms ...]), replacing the for |
| 12:19 | mdeboard` | I think you just gave me a concussion |
| 12:19 | gfrlog | oh dear |
| 12:19 | sritchie | try running through it with just one value |
| 12:20 | sritchie | reduce calls the supplied function with the following args, in pairs. So, first, that function gets [amount {}] and the first thing in denoms |
| 12:22 | sritchie | https://gist.github.com/1074659 |
| 12:22 | sritchie | here are the first few steps of that first call |
| 12:22 | mdeboard` | http://p.mattdeboard.net/nullpointer.html that code threw a null pointer exception |
| 12:23 | gfrlog | oh ah ha |
| 12:24 | gfrlog | I misused the return value from calc-coins |
| 12:24 | mdeboard` | is it supposed to be denoms? |
| 12:24 | mdeboard` | or? |
| 12:24 | gfrlog | one fix is to change calc-coins so it just returns {:mod ..., :dividend ...} |
| 12:25 | gfrlog | i.e., instead of {:0.20 {:mod 0.07, :dividend 3}}, return {:mod 0.07, :dividend 3} |
| 12:26 | mdeboard` | ya that did it |
| 12:26 | mdeboard` | it being removing the np |
| 12:27 | gfrlog | if 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:27 | sritchie | gfrlog: that doesn't quite work, since each mod and dividend knocks out the previous one |
| 12:27 | gfrlog | but I think the numbers make more sense |
| 12:27 | gfrlog | sritchie: eh? |
| 12:27 | mdeboard` | Yeah right now it just returns the dividend |
| 12:27 | mdeboard` | http://p.mattdeboard.net/dividends.html |
| 12:28 | sritchie | ah, never mind |
| 12:28 | gfrlog | oh you'd also want to wrap that in (last) |
| 12:28 | gfrlog | or (second) |
| 12:28 | gfrlog | since ultimately you're only interested in the second part of the reduce value |
| 13:07 | mdeboard` | gfrlog: http://p.mattdeboard.net/dividends.html What's "amount-left" in your example? |
| 13:09 | gfrlog | mdeboard`: that's what the mod gets assigned to each time |
| 13:09 | gfrlog | so...it's the amount left :) |
| 13:11 | gfrlog | by the end of the reduction it should be 0 |
| 13:12 | mdeboard` | u rite |
| 13:15 | gfrlog | mdeboard`: is it making sense? |
| 13:15 | mdeboard` | Oh, so the line that starts with (fn [[amount-left...) is just an encapsulation. An anonymous function? |
| 13:15 | mdeboard` | er, not the line, but that block of code |
| 13:15 | gfrlog | (fn [...] ...) is the syntax for an anonymous function, yes |
| 13:16 | mdeboard` | I'm justgetting hung up on amount-left |
| 13:16 | gfrlog | amount-left starts out as the full amount |
| 13:16 | mdeboard` | Where is mod getting assigned to it? |
| 13:17 | mdeboard` | ohhhh |
| 13:17 | gfrlog | you see how the if expression will evaluate to one of two vectors? |
| 13:17 | mdeboard` | ok |
| 13:17 | mdeboard` | hang on |
| 13:17 | mdeboard` | Sorry I slip out of polish notation mode sometimes |
| 13:17 | gfrlog | it 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:19 | mdeboard` | (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:20 | gfrlog | yep. It's syntactic sugar for a couple longer expressions |
| 13:20 | mdeboard` | map* |
| 13:20 | mdeboard` | s/array\?\ dict\?/map |
| 13:20 | gfrlog | the longest way to do it is (let [x (calc-coins amount-left denom), mod (:mod x), dividend (:dividend x)] ...) |
| 13:20 | mdeboard` | ahhh |
| 13:20 | mdeboard` | ok |
| 13:20 | mdeboard` | is that destructuring? |
| 13:21 | mdeboard` | the first way |
| 13:21 | gfrlog | the plain destructuring way to do it is to replace x with a map of pairs, like: |
| 13:21 | gfrlog | (let [{amount-left :amount-left, denom :denom} (calc-coins amount-left denom)] ...) |
| 13:22 | gfrlog | the way in the code is a shorter sugary version that avoids the repetition |
| 13:22 | mdeboard` | is :keys a keyword or what? |
| 13:22 | mdeboard` | I mean I get that it's a keyword |
| 13:22 | gfrlog | yeah, it has special meaning in a destructuring map |
| 13:22 | mdeboard` | stupid question |
| 13:22 | mdeboard` | Yeah that was my questino |
| 13:22 | mdeboard` | if it had a special meaning :P |
| 13:22 | gfrlog | there are I think three keywords that have special meaning there |
| 13:22 | gfrlog | :keys, :as, and :or |
| 13:23 | gfrlog | :as also works when destructuring a list |
| 13:27 | mdeboard` | 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:27 | gfrlog | the function has two arguments |
| 13:27 | gfrlog | (any reduce function does) |
| 13:27 | gfrlog | the first argument is expected to be a pair |
| 13:27 | gfrlog | and we're destructuring it |
| 13:28 | gfrlog | so [amount-left coins] is the first argument to the function, and denom is the second |
| 13:28 | mdeboard` | 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:29 | gfrlog | on the first pass it will be equal to the "start pair" that we passed as the second argument to reduce, which is [amount {}] |
| 13:34 | mdeboard` | oh, oh |
| 13:34 | mdeboard` | oh |
| 13:35 | mdeboard` | lightbulbs, i has htem |
| 13:36 | gfrlog | \o/ |
| 13:36 | amalloy | mdeboard`: just woke up, but this looks like a job for ##(doc reductions) |
| 13:36 | sexpbot | ⟹ "([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:36 | mdeboard` | amalloy: God please no, I'm just grokking this |
| 13:36 | mdeboard` | :P |
| 13:36 | gfrlog | amalloy: are you contradicting me? |
| 13:36 | mdeboard` | nerd fight |
| 13:36 | gfrlog | amalloy: or are you saying that reductions is helpful for understanding how reduce works? |
| 13:36 | amalloy | gfrlog: the scrollback was long. i skimmed it |
| 13:37 | gfrlog | mdeboard`: 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:37 | mdeboard` | speaking of Cloj 1.2, why is only 1.1 available in aptitude? |
| 13:38 | amalloy | mdeboard`: package managers are always behind on shiny new toys |
| 13:38 | mdeboard` | I did, but then just went back and installed from source |
| 13:38 | amalloy | mdeboard`: go back and don't install at all; let lein pull it down as a project dep |
| 13:38 | mdeboard` | Maybe at a later date |
| 13:38 | amalloy | yeah |
| 13:38 | amalloy | no rush on that |
| 13:40 | mdeboard` | Yeah forgiving some issues with float, reductions is a big cognitive help |
| 13:41 | mdeboard` | I also exploded the {:keys [foo bar]} syntax to "the long way" |
| 13:41 | gfrlog | mdeboard`: whatever helps. You'll compress it back down after you do it the long way a hundred times. |
| 13:41 | mdeboard` | sure |
| 13:41 | mdeboard` | just like list comprehensions |
| 13:42 | amalloy | gfrlog: btw, :strs and :syms also have special meaning in the :keys position |
| 13:42 | mdeboard` | so is this recursive? |
| 13:42 | mdeboard` | Or iterative? |
| 13:42 | mdeboard` | It seems iterative |
| 13:42 | gfrlog | amalloy: I figured I was missing some, but there was nobody around to help :) |
| 13:42 | gfrlog | mdeboard`: it's not explicitely recursive |
| 13:43 | amalloy | mdeboard`: reduce is certainly implemented recursively |
| 13:43 | gfrlog | mdeboard`: using the higher-order-functions in clojure lets avoid using (loop) and explicit recursion 98% of the time |
| 13:43 | amalloy | gfrlog: you win this round |
| 13:43 | mdeboard` | lol |
| 13:43 | mdeboard` | oh right I read something about that last night |
| 13:43 | mdeboard` | maybe in JoC |
| 13:44 | gfrlog | amalloy: :strs lets you use :keys with string keys? |
| 13:44 | amalloy | yeah |
| 13:44 | gfrlog | and :syms is the default behavior? |
| 13:44 | amalloy | er |
| 13:44 | gfrlog | oh wait |
| 13:44 | gfrlog | no |
| 13:44 | amalloy | no |
| 13:44 | gfrlog | I mix up "symbols" and "keywords" sometimes, thanks to dang other programming languages |
| 13:45 | amalloy | &(let [{:strs [a b]} {"a" 1 "b" 2}] [a b]) |
| 13:45 | sexpbot | ⟹ [1 2] |
| 13:56 | amalloy | mdeboard`, 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:57 | amalloy | or, i guess, clojure's rational types would probably be okay |
| 13:57 | mdeboard` | i.e. $1 = 100? |
| 13:57 | amalloy | yes |
| 13:57 | gfrlog | amalloy: I was wondering what common opinion of that was |
| 13:57 | gfrlog | I've taken that approach with javascript |
| 13:57 | amalloy | $google currency floating point |
| 13:57 | sexpbot | First out of 473000 results is: Floating Point Currency |
| 13:57 | sexpbot | http://c2.com/cgi/wiki?FloatingPointCurrency |
| 13:57 | amalloy | just googled that at random, don't really know if it supports my point |
| 13:57 | mdeboard` | reduce |
| 13:57 | mdeboard` | wrong buffer |
| 13:58 | amalloy | gfrlog: javascript doesn't have ints anyway though, right? |
| 13:58 | amalloy | so it hardly matters |
| 13:58 | gfrlog | amalloy: correct, but if you only use integer-valued floats then I don't think you can get into trouble |
| 13:58 | amalloy | depends if you ever do any division |
| 13:58 | gfrlog | right |
| 13:58 | amalloy | adding em together you'll be fine |
| 13:59 | gfrlog | and multiplying |
| 13:59 | amalloy | mmmmm |
| 13:59 | gfrlog | by integers :) |
| 13:59 | mdeboard` | Did I write out what this function is doing properly? |
| 13:59 | mdeboard` | http://p.mattdeboard.net/docs.html |
| 13:59 | amalloy | doubles don't have as large a range as longs |
| 13:59 | amalloy | so you can run into a problem |
| 14:00 | gfrlog | amalloy: right, so you have to make sure you don't have very much money |
| 14:00 | gfrlog | I guess overflow would be awfully silent |
| 14:00 | gfrlog | there's a bigint library I've used for javascript. I guess that'd be the ultimate solution |
| 14:00 | gfrlog | if you like writing a.multiply(b.add(c)) |
| 14:01 | gfrlog | which of course I do |
| 14:01 | amalloy | mdeboard`: i don't buy your last comment |
| 14:01 | gfrlog | now 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:02 | mdeboard` | amalloy: Me either, hence the (???) |
| 14:02 | amalloy | if i start with ten cents, the second branch of the if will be hit for all the denominations until you get to dimes |
| 14:02 | amalloy | gfrlog: cause the only way you could slow down a bigint library is with eval? |
| 14:03 | gfrlog | amalloy: because premature optimization is evil :P |
| 14:03 | gfrlog | actually 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:04 | gfrlog | if there's enough arithmetic |
| 14:04 | amalloy | gfrlog: javascript eval has access to lexical scope |
| 14:05 | gfrlog | amalloy: right. So if sexp is defined somewhere else... |
| 14:05 | amalloy | ummm...? just define sexp to return a string, and eval that string |
| 14:05 | gfrlog | so repeat the call to eval everywhere |
| 14:06 | gfrlog | I see |
| 14:06 | amalloy | but writing a sexp->javascript precompiler is probably simpler |
| 14:06 | gfrlog | and avoids the eval |
| 14:07 | mdeboard` | 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:07 | amalloy | well, second is (comp first last) |
| 14:08 | gfrlog | amalloy: why is he using reductions if all he wants is the final value? |
| 14:08 | dnolen_ | mdeboard`: thanks, nice example of mutually recursive yield in Python. As you said that is crazy slow in Python. |
| 14:08 | amalloy | er, (comp first rest) |
| 14:08 | mdeboard` | oh, right |
| 14:08 | mdeboard` | derp |
| 14:08 | mdeboard` | forgot to take out reductions :) |
| 14:08 | gfrlog | ah |
| 14:09 | gfrlog | I assumed since it was still there amalloy must have been recommending you keep it |
| 14:09 | amalloy | mdeboard`: do you care if the keys of the map are in order? they probably are in your impl, but it's only coincidental |
| 14:09 | mdeboard` | dnolen_: You're welcome |
| 14:09 | mdeboard` | amalloy: Not really, but I suppose I should. |
| 14:11 | amalloy | if 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:12 | amalloy | though it probably sorts in reverse order? ##(into (sorted-map) [1 4 9 2]) vs ##(into (sorted-map-by -) [1 4 9 2]) |
| 14:12 | sexpbot | (into (sorted-map) [1 4 9 2]) java.lang.IllegalArgumentException: Don't know how to create ISeq from: java.lang.Integer |
| 14:12 | sexpbot | (into (sorted-map-by -) [1 4 9 2]) java.lang.IllegalArgumentException: Don't know how to create ISeq from: java.lang.Integer |
| 14:12 | amalloy | mutter |
| 14:13 | mdeboard` | baby steps |
| 14:13 | mdeboard` | premature optimization chat |
| 14:13 | gfrlog | based on the first word of your last two statements I'd say this is a conversation about infants. |
| 14:14 | mdeboard` | gfrlog: Based on that statement I'd say you work on machien learning |
| 14:14 | gfrlog | ha |
| 14:30 | amalloy | mdeboard`: https://gist.github.com/1074808 is a version that seems to involve less tedious bookkeeping |
| 14:31 | amalloy | and (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:33 | gfrlog | amalloy: no YOU win this round |
| 14:33 | mdeboard` | 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:35 | mdeboard` | (assoc foo x y) -> (def foo {x y}) ? |
| 14:36 | gfrlog | nope |
| 14:36 | gfrlog | it associates the key x with the value y in the map foo |
| 14:36 | amalloy | mdeboard`: def has side effects, so very few built-ins are equivalent to a def |
| 14:36 | gfrlog | &(assoc {:a 2 :c 4} :b 5) |
| 14:36 | sexpbot | ⟹ {:b 5, :a 2, :c 4} |
| 14:36 | gfrlog | &(assoc {:a 2 :b 12} :b 5) |
| 14:36 | sexpbot | ⟹ {:a 2, :b 5} |
| 14:37 | mdeboard` | ,(assoc {:a 2 :b 12} :b 5) |
| 14:37 | clojurebot | {:a 2, :b 5} |
| 14:37 | mdeboard` | :') |
| 14:37 | gfrlog | we both picked twelve because we're soul mates? |
| 14:37 | mdeboard` | lol no, just beign smug about knowing the syntax |
| 14:38 | mdeboard` | 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:38 | dnolen_ | mdeboard`: amalloy: my version, https://gist.github.com/1074818 |
| 14:38 | mdeboard` | e.g. dict = {} \ dict['foo'] = 'bar' \ dict --> {'foo': 'bar'} |
| 14:39 | mdeboard` | 1e-6 ? |
| 14:39 | amalloy | gfrlog: what do you think about https://gist.github.com/1074808 - i'm not sure if the threaded version is more or less readable |
| 14:39 | mdeboard` | is that engineering notation? |
| 14:39 | amalloy | scientific |
| 14:39 | amalloy | (though they happen to be the same here) |
| 14:39 | mdeboard` | that too |
| 14:39 | amalloy | mdeboard`: yes, assoc is like that, except without side effects |
| 14:40 | gfrlog | oh threaded. I was thinking "why the heck is he making this multi-threaded??" |
| 14:40 | amalloy | oh. the threaded version is also totally wrong |
| 14:40 | amalloy | never mind, sigh |
| 14:40 | mdeboard` | persistence > perfection amalloy |
| 14:40 | mdeboard` | unless you're actually perfect then persistence is unnecessary |
| 14:41 | gfrlog | mdeboard`: it's different from python dicts because clojure maps are immutable |
| 14:41 | mdeboard` | right |
| 14:41 | mdeboard` | 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:41 | gfrlog | gotcha |
| 14:42 | mdeboard` | state mutability notwithstanding |
| 14:42 | mdeboard` | god Joy of Closure has an absolutely epic explanation of state |
| 14:42 | mdeboard` | I might go back and re-read it |
| 14:42 | amalloy | mdeboard`: dnolen's used update-in, which is a fantastic tool for working with maps. keep it in mind |
| 14:43 | amalloy | (and it goes great with fnil) |
| 14:43 | gfrlog | fnil: there's always something else I've forgotten exists :| |
| 14:43 | mdeboard` | Ya I've got them both appended at the end of my clj, commented out |
| 14:50 | mdeboard` | 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:50 | dnolen_ | mdeboard`: amalloy: and because I hate slow code, https://gist.github.com/1074818 |
| 14:51 | gfrlog | mdeboard`: I think of reduce whenever I have a collection of elements (denominations) that I need to loop over, while keeping track of something |
| 14:52 | amalloy | dnolen_: 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:52 | amalloy | so i'd put the termination test in the drop-while |
| 14:52 | amalloy | (and use ints instead of doubles, especially if you care about performance) |
| 14:53 | dnolen_ | amalloy: ints for currency? |
| 14:53 | amalloy | yes |
| 14:53 | dnolen_ | 1e-6 check is straight out of what I've seen done in graphics code. |
| 14:53 | amalloy | if you use floating-point at a bank they murder you in the spot |
| 14:53 | amalloy | *on |
| 14:53 | dnolen_ | amalloy: did know that, never done any financial work. |
| 14:54 | dnolen_ | did not. |
| 14:54 | gfrlog | amalloy: any clue what they do when they want to keep track of fractional cents? |
| 14:54 | amalloy | dnolen_: sure, in general for testing floats you want to use a delta like 1e-6 |
| 14:54 | amalloy | but for money you should use ints, and the way you're using drop-while the test could cause NPE on rounding error *anyway* |
| 14:55 | amalloy | gfrlog: work with integer thousandths of cents :P |
| 14:55 | gfrlog | amalloy: that was my guess |
| 14:55 | gfrlog | dnolen_: I think when handling money it's always cleanest to be discrete |
| 14:55 | dnolen_ | amalloy: Yeah, I see what you mean about the 1e-6 test and rounding error. |
| 14:56 | gfrlog | floats are good for things that don't have to be perfectly accurate |
| 14:56 | amalloy | gfrlog: that is both edutational and punnerific |
| 14:56 | dnolen_ | suddenly this is an exercise on Enterprise Financial Programming instead of a lesson on recursion ;) |
| 14:56 | gfrlog | amalloy: I strive to edutate! |
| 14:56 | amalloy | haha ouch |
| 14:57 | mdeboard` | amalloy: Why do you use a vector of vectors instead of a map in your example? |
| 14:57 | TimMc | gfrlog: and wash your hands afterward |
| 14:57 | amalloy | to preserve ordering |
| 14:57 | gfrlog | TimMc: :) |
| 14:57 | mdeboard` | ah ok |
| 14:57 | amalloy | if the map happened to be 10+ elements (say we track fifties and half-dollars), it no longer (coincidentally) preserves order |
| 14:58 | mdeboard` | so how do you retrieve the value of, say, :twenty? |
| 14:58 | mdeboard` | (I'm trying this stuff out in repl before I ask btw) |
| 14:59 | gfrlog | mdeboard`: :twenty is a function that can do that |
| 14:59 | amalloy | it's in change-denom's destructuring-let |
| 15:01 | mdeboard` | Oh, gotcha. Smart |
| 15:02 | amalloy | dnolen_: out of curiosity, is the repeated-subtraction faster than division because the numbers are small enough? |
| 15:02 | amalloy | or is it just more convenient to write? |
| 15:03 | amalloy | it 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:03 | mdeboard` | honestly I don't think order matters here |
| 15:03 | amalloy | mdeboard`: of the final result, no. but for the list of denominations, yes |
| 15:04 | mdeboard` | lol, got it. Why does learning a new language & programming paradigm turn me into a huge idiot |
| 15:04 | amalloy | ~#19 |
| 15:04 | clojurebot | 19. A language that doesn't affect the way you think about programming, is not worth knowing. |
| 15:05 | mdeboard` | A+ |
| 15:06 | mdeboard` | so yeah mapping hashes they k/v pair I assume, which tosses out any ability to sort on keys at a low level? |
| 15:06 | dnolen_ | amalloy: is this more sound? https://gist.github.com/1074818 |
| 15:06 | mdeboard` | except sorted-map-by |
| 15:07 | mdeboard` | also as long as they're in order in the original list, isn't reduce always going to walk over them in order? |
| 15:07 | gfrlog | mdeboard`: yes, reduce goes in order |
| 15:07 | mdeboard` | 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:08 | mdeboard` | (aka the whole point of maps) |
| 15:08 | mdeboard` | vis a vis speed |
| 15:08 | amalloy | dnolen_: hah, that's a clever way to use rename-keys |
| 15:09 | mdeboard` | gist doesn't either apparently |
| 15:09 | amalloy | github syntax-colors clojure code at random, or something like it |
| 15:09 | mdeboard` | lol, what. |
| 15:10 | mdeboard` | I just mean that I guess "rename-keys" isnt in its table of identified built-ins |
| 15:10 | amalloy | mdeboard`: but make-change is? |
| 15:10 | mdeboard` | well once it's defn'd |
| 15:10 | gfrlog | I've been using clojure.core/make-change for months now |
| 15:10 | amalloy | i'd be astonished if they were parsing the source for defns |
| 15:11 | dnolen_ | mdeboard`: probably because rename-keys is in clojure.set |
| 15:11 | amalloy | dnolen_: anyway, that looks like it passes muster for banks :) |
| 15:11 | dnolen_ | amalloy: sweeeet |
| 15:11 | amalloy | nah, because drop-while isn't colored either |
| 15:11 | mdeboard` | probably a bit of code in gist source that puts "foo" in ID'd functions table when it sees `defn foo` |
| 15:11 | mdeboard` | dnolen_: oic |
| 15:11 | amalloy | maybe so |
| 15:12 | amalloy | https://gist.github.com/1074857 indicates that they have no such defn parser |
| 15:13 | mdeboard` | I suspect that's an engineering oversight |
| 15:13 | mdeboard` | on forked gists |
| 15:13 | amalloy | https://gist.github.com/ba4079175d8d5eda81cb |
| 15:13 | mdeboard` | or on edits |
| 15:14 | mdeboard` | huh. I bet they cache them :) |
| 15:14 | amalloy | haha prepare to be strangled |
| 15:15 | mdeboard` | https://gist.github.com/1074861 |
| 15:15 | gfrlog | nerd fight! |
| 15:15 | mdeboard` | https://gist.github.com/1074862 |
| 15:15 | mdeboard` | I win :) |
| 15:16 | amalloy | what's your point? |
| 15:17 | mdeboard` | lol just that they cache function names :P Look I'm clearly the dumbest person in this chat room, I need this. |
| 15:17 | amalloy | https://gist.github.com/ba4079175d8d5eda81cb is a disproof :P |
| 15:17 | mdeboard` | Huh |
| 15:17 | mdeboard` | I guess it IS random! |
| 15:17 | amalloy | *chuckle* |
| 15:19 | gfrlog | maybe it dispatches on the hash code of the symbol modulo some value |
| 15:19 | mdeboard` | Which is unreliable enough to be indiscerinable from random |
| 15:20 | mdeboard` | But yeah maybe they drop [^a-zA-Z0-9] |
| 15:20 | mdeboard` | or something, who cares, I'm trying to learn Clojure |
| 15:20 | mdeboard` | :) |
| 15:22 | mdeboard` | (I was joking, btw, you guys have been a huge help) |
| 15:48 | gfrlog | amalloy: 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:48 | gfrlog | man it took a lot of effort to type those commas... |
| 15:51 | dnolen_ | 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:55 | gfrlog | there's not anything like clojure.core/*rand* is there? |
| 15:59 | amalloy | gfrlog: clojure.core/inc seems to meet all of the requirements you've stated so far |
| 16:00 | gfrlog | amalloy: you mean being a qualified symbol? |
| 16:00 | gfrlog | in the clojure.core ns? |
| 16:02 | mdeboard` | Hrm, prob a dumb question but I uninstalled clojure, to allow lein to install. I did "lein self-install" but er |
| 16:03 | mdeboard` | No clojure dl? idgi |
| 16:03 | gfrlog | mdeboard`: yes clojure dl. odxt |
| 16:03 | amalloy | mdeboard`: it gets downloaded in projects you start |
| 16:03 | gfrlog | mdeboard`: try "lein repl" |
| 16:04 | mdeboard` | Oh |
| 16:04 | mdeboard` | So clojure isn't dl'd system-wide, just in particular projects? |
| 16:04 | amalloy | right |
| 16:05 | gfrlog | mdeboard`: I think it keeps a version in your maven dir that it copies to new projects |
| 16:05 | mdeboard` | Kind of like rvm I suppose |
| 16:05 | amalloy | or virtualenv |
| 16:05 | amalloy | kinda |
| 16:05 | mdeboard` | kinda but wihtout the path hack |
| 16:05 | amalloy | i don't really know anything about python or ruby, so read these analogies at your own risk |
| 16:05 | mdeboard` | haha |
| 16:07 | mdeboard` | so I just do lein self-install for each project or just one time for the system? |
| 16:07 | amalloy | just once |
| 16:08 | gfrlog | mdeboard`: "lein new foobar" creates a new project for you |
| 16:16 | jimi_hendrix | is there a clojure lib for asynchronous server sockets, or should i poke arond the java library? |
| 16:16 | gfrlog | jimi_hendrix: (or aleph "I don't know what I'm talking about") |
| 16:17 | jimi_hendrix | gfrlog, should i be reading that as a lisp statement :P |
| 16:17 | gfrlog | sorta |
| 16:19 | amalloy | (inc aleph) |
| 16:19 | sexpbot | ⟹ 1 |
| 16:20 | mdeboard` | lol |
| 16:20 | gfrlog | amalloy: is there a sexpbot karma read command? |
| 16:20 | jimi_hendrix | lol |
| 16:20 | gfrlog | (deref amalloy) |
| 16:20 | amalloy | gfrlog: yes, but afaict it's broken |
| 16:21 | amalloy | $help karma |
| 16:21 | sexpbot | amalloy: Checks the karma of the person you specify. |
| 16:21 | mdeboard` | $help mail |
| 16:21 | sexpbot | mdeboard`: Send somebody a message. Takes a nickname and a message to send. Will alert the person with a notice. |
| 16:21 | Scriptor | $karma Scriptor |
| 16:21 | amalloy | gfrlog: feel free to fork&fix it for me, cause i don't see what's broken |
| 16:21 | gfrlog | amalloy: it should work the way Scriptor just used it? |
| 16:21 | amalloy | yeah |
| 16:21 | gfrlog | okay |
| 16:21 | Scriptor | does it not print anything if the karma is 0? |
| 16:22 | amalloy | $karma aleph |
| 16:24 | Scriptor | in clojure's source, what does the variable 'sv' usually stand for? |
| 16:24 | Scriptor | I'm guessing something like seq value |
| 16:24 | mdeboard` | The leiningen tutorial seems really incomplete |
| 16:24 | mdeboard` | Big gaps |
| 16:25 | mids | how would I best go about attacking this stacktrace? https://gist.github.com/1074930 |
| 16:26 | mdeboard` | 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:26 | gfrlog | mdeboard`: lein deps will populate your lib dir |
| 16:27 | mdeboard` | aha |
| 16:27 | Scriptor | mdeboard`: there's a clojure tutorial about setting up slime/swank/lein...buuut it's for windows :p |
| 16:28 | mdeboard` | 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:32 | mdeboard` | I'm spoiled by python, sorry. |
| 16:42 | amalloy | Scriptor: i wouldn't be surprised if it were a sort of hungarian: "this variable has already had seq called on it" |
| 16:44 | Scriptor | amalloy: hmm, not sure it's the result of seq(), it's set by sval() (there's the answer for the name, I guess) |
| 16:44 | amalloy | ah |
| 16:44 | Scriptor | for reference: https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/LazySeq.java#L37 |
| 16:46 | technomancy | for 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:46 | technomancy | mdeboard`: ^^ |
| 16:46 | mdeboard` | technomancy: smashing |
| 16:47 | technomancy | actually 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:47 | technomancy | but if I don't tell people about it, it will never see wide use. |
| 16:48 | mdeboard` | That seems like something that should be on by default for new users |
| 16:48 | mdeboard` | imo |
| 16:48 | mdeboard` | as a new user |
| 16:48 | technomancy | yes, assuming it works correctly |
| 16:48 | technomancy | which I have not yet determined |
| 16:49 | technomancy | hence the need for testing |
| 16:51 | hiredman | http://www.thinkwithportals.com/music.php "songs to test by" |
| 16:51 | keithwyss | technomancy: Is it a plugin currently? |
| 16:51 | technomancy | keithwyss: no, it's built-in. just needs :checksum-deps true in project.clj to enable it |
| 16:52 | gfrlog | hiredman: :) |
| 16:52 | technomancy | and 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:52 | technomancy | that will make the classpath reference ~/.m2 instead of copying everything into lib |
| 16:53 | keithwyss | Cool. I'll jot those down. |
| 16:53 | mdeboard` | Editing my newb project.clj right now. |
| 16:53 | jimi_hendrix | where exactly does lein pull deps from? |
| 16:54 | technomancy | clojurebot: look at me still talking when there's science to do |
| 16:54 | clojurebot | science is http://sunpig.com/martin/images/2008/10/iwilldosciencetoit.jpg |
| 16:54 | technomancy | clojurebot: a thousand botsnacks |
| 16:54 | clojurebot | Titim gan éirí ort. |
| 16:54 | technomancy | jimi_hendrix: by default: http://clojars.org and http://search.maven.org |
| 16:54 | wilfredh | is there a compojure equivalent of Django's reverse()? |
| 16:55 | wilfredh | i.e. something that takes a function and returns the corresponding URL |
| 16:55 | gfrlog | doubt it |
| 16:55 | gfrlog | not sure that really makes sense for compojure |
| 16:56 | zakwilson | I'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:56 | wilfredh | I must be missing something -- why doesn't it make sense? |
| 16:57 | gfrlog | wilfredh: you're using (defroutes ...)? |
| 16:57 | amalloy | well, it assumes a one-to-one correspondence between functions and URLs, which seems pretty foreign |
| 16:57 | technomancy | gfrlog: http://p.hagelb.org/cake.gif |
| 16:58 | gfrlog | technomancy: I want to elect that president. |
| 16:58 | wilfredh | gfrlog: yes, I'm using defroutes |
| 16:58 | amalloy | it 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:58 | keithwyss | One 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:58 | gfrlog | wilfredh: everything amalloy said. |
| 16:58 | gfrlog | wilfredh: not to mention a lot of routes are globby and so don't correspond to just one url |
| 16:58 | keithwyss | I'd be willing to take a stab at it assuming there's not something like this already I missed out on. |
| 16:58 | amalloy | keithwyss: :dependencies [[clojure "[1.2.0,)"]] |
| 16:59 | technomancy | keithwyss: it's a lot easier to check now with lein search too. |
| 16:59 | Scriptor | noob question, but is there a lein command to have it update itself? I always suck at googling for that one |
| 16:59 | amalloy | lein upgrade |
| 16:59 | Scriptor | ah |
| 16:59 | gfrlog | this is awesome I just ran "lein upgrade" and it worked. |
| 16:59 | Scriptor | damnit, not available on windows |
| 17:00 | gfrlog | I guess I shouldn't have celebrated. It was insensitive to windows users. |
| 17:00 | keithwyss | amalloy: what does "[1.2.0,)" mean. I'm not used to seeing parens that aren't matched. |
| 17:00 | amalloy | $google mathematics interval notation |
| 17:00 | sexpbot | First out of 710000 results is: Interval Notation |
| 17:00 | sexpbot | http://regentsprep.org/REgents/math/ALGEBRA/AP1/IntervalNot.htm |
| 17:01 | gfrlog | I figured it meant the version number was winking |
| 17:01 | technomancy | keithwyss: there's a link in "lein help tutorial" about version ranges |
| 17:01 | Scriptor | is 1.6.1 the latest version number? I want to try technomancy's automatic dep installation |
| 17:01 | technomancy | Scriptor: it is |
| 17:01 | keithwyss | Thanks for the help. That's exactly what I wanted. |
| 17:02 | wilfredh | gfrlog: 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:03 | technomancy | Scriptor: but that feature is in 1.5 iirc |
| 17:04 | gfrlog | wilfredh: 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:04 | gfrlog | wilfredh: I agree it'd be nice though. |
| 17:05 | Scriptor | technomancy: must have missed it before, does it install the dependencies whenever you compile? |
| 17:05 | technomancy | Scriptor: it looks at the checksums every time code has to be evaluated inside the project's context |
| 17:08 | Scriptor | technomancy: checksums for the dependency? |
| 17:09 | Scorchin | Can 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:09 | zakwilson | The 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:11 | technomancy | Scriptor: right; it serializes :dependencies and :dev-dependencies to a string and checksums that |
| 17:12 | gfrlog | zakwilson: I can imagine an alternative to (defroutes) that provides reversal without too much trouble |
| 17:12 | amalloy | Scorchin: whatever it's doing, it's written badly in a few ways, making it hard to understand |
| 17:12 | gfrlog | yeah that's pretty weird code |
| 17:12 | amalloy | it seems to be checking whether it is the case that all but the first and last column are nil |
| 17:12 | Scriptor | technomancy: ah! But how does lein know when code is evaluated? Sorry, not very familiar with how it works |
| 17:12 | Scorchin | amalloy: I'm trying to imitate it to build a way to check if a tetris grid has hit a "game over" state |
| 17:13 | zakwilson | gfrlog: 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:15 | amalloy | totally agree there. i wonder if moustache has that more rigid structure? i haven't used it but have heard that sort of thing |
| 17:16 | ibdknox | Noir, doesn't really help here, but if you want a stricter structure, more akin to Rails or Django, look at wakeful |
| 17:16 | ibdknox | it maps urls directly the namepsace structure |
| 17:16 | ibdknox | to* |
| 17:16 | gfrlog | zakwilson: I think the added structure would be pretty isolated |
| 17:16 | gfrlog | zakwilson: 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:16 | technomancy | Scriptor: things like repl, test, and compile have to run code in your project's process to have access to its dependencies |
| 17:17 | zakwilson | gfrlog: 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:18 | gfrlog | oh I'm not THAT motivated, I just wanted to make the point that I don't think it's incompatible with compojure :) |
| 17:19 | hiredman | https://github.com/hiredman/graft |
| 17:19 | zakwilson | Damn. I was hoping somebody would do it for me so I don't have to figure out a good way. |
| 17:21 | ibdknox | zakwilson: I guess you assume the URL is going to change a lot? |
| 17:22 | zakwilson | ibdknox: no. I just don't like code that generates anything with semantic meaning using string concatenation. |
| 17:23 | gfrlog | :) |
| 17:23 | gfrlog | yeah it lets your bugs leak farther... |
| 17:23 | zakwilson | Well, string concatenation can happen somewhere, but I don't want magic strings in my code. |
| 17:24 | ibdknox | lol |
| 17:24 | gfrlog | zakwilson: exactly |
| 17:24 | ibdknox | I don't see the difference really |
| 17:24 | hiredman | you prefer magic code? |
| 17:24 | gfrlog | ibdknox: the difference is what happens when you make a typo |
| 17:24 | ibdknox | gfrlog: it's a location |
| 17:24 | ibdknox | gfrlog: locations are inherently strings |
| 17:24 | ibdknox | in this case |
| 17:25 | ibdknox | hiredman: no, I don't :) |
| 17:25 | ibdknox | but the solution of reverse calling a url is no different than using its string representation :) |
| 17:25 | zakwilson | To 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:25 | gfrlog | ibdknox: just because they're exposed as strings doesn't mean that's how you have to refer to them as a programmer |
| 17:26 | ibdknox | zakwilson: that is fair |
| 17:26 | ibdknox | zakwilson: usually that's taken care of by setting an app root though |
| 17:26 | zakwilson | Even though right now (defn go-home [] (redirect "/")) |
| 17:26 | zakwilson | Sure, that's another way to do it |
| 17:27 | ibdknox | gfrlog: sure, you don't have to, but I'm not sure I see the value in the abstraction, that's all :) |
| 17:29 | gfrlog | ibdknox: one value is that if you're using vars instead of strings, the compiler can point out your mistakes |
| 17:30 | ibdknox | gfrlog: that's fair |
| 17:31 | ibdknox | gfrlog: it becomes more personal preference I think |
| 17:31 | ihodes | what's a really cool data structure that can be useful to hold something a sparse matrix normally would? |
| 17:32 | hiredman | a map? |
| 17:32 | amalloy | hiredman: no, he said really cool |
| 17:34 | wilfredh | I've always thought a Fibonacci heap was pretty cool</tongue-in-cheek> |
| 17:40 | gfrlog | finger trees of vectors of arrays of refs |
| 17:40 | ibdknox | lol |
| 17:40 | ibdknox | ^^ best solution there |
| 17:42 | ihodes | hiredman: a map is basically the underlying implementation of a sparsematrix (can't think of a better one, anyway). |
| 17:42 | ihodes | you guys are no fun :P |
| 17:43 | ihodes | there a good # on freenode for data structures? |
| 17:44 | ihodes | hiredman: by the way, i'm using visor mode in iterm now, and i love it. |
| 17:45 | gfrlog | ihodes: what is "something a sparse matrix normally would"? |
| 17:45 | gfrlog | what does .lein-failures do? |
| 17:46 | hiredman | tracks test failures for lein retest |
| 17:46 | dnolen_ | ihodes: ITerm2 is pure awesomeness, I'm giving Cocoa Emacs the boot. |
| 17:46 | gfrlog | lein retest will run all tests listed in .lein-failures? |
| 17:47 | technomancy | gfrlog: aye |
| 17:47 | gfrlog | (inc technomancy) |
| 17:47 | sexpbot | ⟹ 11 |
| 17:48 | ihodes | dnolen_: 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:48 | hiredman | I think my fullscreen cocoa-emacs is rather fetching |
| 17:49 | ihodes | gfrlog: 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:49 | gfrlog | ihodes: I'm not sure why you find a map so disappointing |
| 17:49 | ihodes | hiredman: 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:49 | ihodes | gfrlog: i don't at all! i love maps |
| 17:50 | ihodes | gfrlog: i just was wondering if there was anything different/weird/interesting |
| 17:50 | ihodes | gfrlog: doesn't have to be better (could there even be a better data structure for that use case?) |
| 17:50 | ihodes | gfrlog: in fact, the structure would probably be isomorphic to a map in order to get similar performance. |
| 17:51 | dnolen_ | ihodes: ITerm2 has 256, Emacs colors themes look perfect. |
| 17:51 | ihodes | dnolen_: 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:52 | ihodes | dnolen_: i tried zenburn, for e.g., but it just mixed up the colors i had already set from iTerm's GUI |
| 17:52 | dnolen_ | ihodes: Preferences > Profiles > Terminal > Report Terminal Type: xterm-256color, zeburn looks flawless |
| 17:53 | dnolen_ | with ITerm2 mouse reporting you can even click to set the cursor position in Emacs. |
| 17:58 | ihodes | dnolen_: IT WORKS. the profile i was using was reporting just xterm, for some reason i guess that's the default. thanks :) |
| 17:59 | dnolen_ | ihodes: no problem |
| 18:14 | mdeboard` | technomancy: This might interest you re: science http://i.imgur.com/W7Fcl.jpg |
| 18:39 | zodiak | so, 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:42 | opqdonut | well you don't want to fetch the value in the variable foo.bar.baz |
| 18:42 | opqdonut | you want to give the symbol foo.bar.baz to identify the namespace |
| 18:42 | opqdonut | require could work with strings too, for example |
| 18:44 | zakwilson | or you might actually want the value of a variable: (let [the-thing-to-require 'clojure.contrib.sql] (require the-thing-to-require)) |
| 18:44 | ihodes | zodiak: 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:44 | gfrlog | or use a vector literal :) |
| 18:45 | ihodes | gfrlog: grrrrrrrr. the idea was to explain the ' :P |
| 18:45 | zakwilson | I have some code that does (apply require the-list-of-requirements) |
| 18:45 | gfrlog | ihodes: I know I know I know... |
| 18:45 | zakwilson | The ' means "I want the NAME foo, not the value of foo" |
| 18:46 | zodiak | well, part of my confusion was thinking that 'symbol was basically saying ' makes things as a 'symbol' |
| 18:46 | zakwilson | It's a symbol either way, but the ' means you want the symbol itself, not the thing it references. |
| 18:46 | zodiak | so, seeing it as '(1 2 3) and then getting told (in the books) that's a vector literal didn't help |
| 18:47 | ihodes | zodiak: [1 2 3] is a vector |
| 18:47 | zodiak | zakwilson: 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:47 | ihodes | zodiak: '(1 2 3) is a list. |
| 18:47 | zodiak | ihodes: correction then. lit. |
| 18:47 | ihodes | zodiak: (1 2 3) is a function application |
| 18:47 | zodiak | list. |
| 18:48 | ihodes | zodiak: applying the function 1 to the operands 2 and 3. but 1 isn't a function... so you get a kaboom. |
| 18:49 | zodiak | ihodes: 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:49 | ihodes | zodiak: (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:49 | gfrlog | ihodes: I don't think it's the reader, I think it's the compiler |
| 18:49 | ihodes | zodiak: the thing to understand is that in functional lisp, everything has a value. symbols are all references to values of literals |
| 18:50 | ihodes | gfrlog: ah yeah, sorry. |
| 18:50 | zodiak | huh. symbols have values eh. okay. interesting :) |
| 18:50 | zakwilson | You can have a symbol that isn't a reference to anything. |
| 18:50 | gfrlog | zodiak: it's a bit more complex than that |
| 18:50 | ihodes | zodiak: 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:51 | zodiak | so, that makes the require more understandable. I think :) |
| 18:51 | ihodes | zodiak: and doing that recursively with everything it find when it looks up the symbols it encounters. it can't, of course, replace values. |
| 18:51 | zakwilson | ,'this-is-an-unbound-symbol |
| 18:51 | clojurebot | this-is-an-unbound-symbol |
| 18:51 | ihodes | zodiak: |
| 18:51 | zakwilson | ,this-is-an-unbound-symbol |
| 18:51 | clojurebot | java.lang.Exception: Unable to resolve symbol: this-is-an-unbound-symbol in this context |
| 18:51 | ihodes | ,`(~'hah) |
| 18:51 | clojurebot | (hah) |
| 18:52 | ihodes | cause i'm a jerk. anyway, need to hack some |
| 18:52 | ihodes | l |
| 18:53 | jimi_hendrix | lien deps wont download clojure-contrib for me. it complains about a missing artifact. is this to be expected? |
| 18:53 | gfrlog | jimi_hendrix: what's it look like in the project.clj? |
| 18:54 | jimi_hendrix | gfrlog, [org.clojars.jhowarth/clojure-contrib "1.2.0-RC3"] (copied from clojars) |
| 18:55 | gfrlog | try [org.clojure/clojure-contrib "1.2.0"] |
| 18:55 | jimi_hendrix | gfrlog, oh nvm i found it |
| 18:55 | jimi_hendrix | i just got it to work |
| 18:55 | gfrlog | okay |
| 19:00 | ihodes | gfrlog: what would you explain re: vars? I don't know how much they'd add |
| 19:00 | ihodes | gfrlog: to zodiak's understanding |
| 19:00 | gfrlog | ihodes: I know it could be confusing to a beginner, but they're definitely relevant to the topic |
| 19:01 | ihodes | gfrlog: i mean, how would you explain it? i can't think of a great way to |
| 19:03 | gfrlog | ihodes: 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:04 | gfrlog | so for example saying that the compiler replaces the symbol with the source of the function could be quite misleading |
| 19:05 | ihodes | gfrlog: 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:05 | hiredman | the movement from the substitution model to the environment model is a big one |
| 19:05 | hiredman | move |
| 19:06 | gfrlog | hiredman: so do you think it's helpful to discuss vars with beginners? |
| 19:06 | ihodes | gfrlog: actually, i think first you'd need to explain the difference between the reader and compiler |
| 19:06 | gfrlog | ihodes: true |
| 19:06 | ihodes | my example/explanation conflates them. which i think is actually useful for a beginner, for reasoning about code |
| 19:07 | hiredman | gfrlog: they have to learn about them sometime |
| 19:07 | zodiak | speaking as a beginner (to clojure anyway) going -that- in depth is going to turn off people |
| 19:07 | gfrlog | I did a lot with clojure before understanding reader vs compiler |
| 19:07 | ihodes | gfrlog: 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:07 | gfrlog | I'm definitely not sure about this either way, which is why I didn't really interject about it during the conversation |
| 19:08 | ihodes | hiredman: that's like saying "you've got to learn about eax sometimes. might as well start with x86" |
| 19:08 | ihodes | hiredman: 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:09 | hiredman | ihodes: *shrug* |
| 19:09 | ihodes | it'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:10 | ihodes | hiredman: i feel ya |
| 19:12 | pcavs | $findfn -1 1 |
| 19:12 | sexpbot | [clojure.core/unchecked-negate clojure.core/-] |
| 19:12 | pcavs | $findfn 100 100 |
| 19:12 | sexpbot | [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:13 | ihodes | ,(Math/abs -1) |
| 19:13 | clojurebot | 1 |
| 19:26 | wilfredh | I'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:26 | wilfredh | what am I doing wrong? |
| 19:27 | hiredman | e is most likely a runtime exception wrapping whatever exception has the getNextException method |
| 19:28 | wilfredh | how would I unwrap it? |
| 19:43 | wilfredh | ah, I needed getCause |
| 20:00 | jimi_hendrix | i am :require ing clojure.contrib.string, but it says split is not being found. what is up? |
| 20:02 | sritchie | jimi_hendrix: make sure you use the prefix you specified -- |
| 20:02 | jimi_hendrix | sritchie, prefix? |
| 20:02 | sritchie | two things -- one, trying requiring clojure.string |
| 20:03 | sritchie | the two options for this sort of thing are use and require |
| 20:03 | sritchie | use pulls all functions from the use'd namespace into the current namespace -- (use 'clojure.string) (join "," [1 2 3]), for example |
| 20:04 | sritchie | require allows you to assign a prefix to functions from that namespace -- (require '[clojure.string :as s]) (s/join "," [1 2 3]) |
| 20:04 | jimi_hendrix | ah |
| 20:04 | jimi_hendrix | i was using this to include it: (ns your-namespace |
| 20:04 | jimi_hendrix | (:require clojure.contrib.string)) |
| 20:04 | sritchie | yeah, that makes everything available with the full namespace as a prefix |
| 20:04 | jimi_hendrix | i see |
| 20:04 | zodiak | jimi_hendrix: for the love of the gods, don't get people started about ' before the module again ;p |
| 20:04 | sritchie | (:require clojure.string) lets you do (clojure.string/join "," [1 2 3]) |
| 20:05 | jimi_hendrix | zodiak, uhh |
| 20:05 | jimi_hendrix | is there a difference? |
| 20:05 | jimi_hendrix | sritchie, is there a :use option then? |
| 20:05 | sritchie | yeah |
| 20:05 | zodiak | jimi_hendrix: joke, kinda, I am learning clojure as well ;) |
| 20:05 | sritchie | you don't need that ' when you're inside the namespace macro, (ns ...), because macros don't evaluate their arguments |
| 20:06 | sritchie | use and require are functions, so they need their arguments quoted, for this stuff |
| 20:06 | zodiak | I dare say that namespaces/requires/use is were most news trip up |
| 20:06 | zodiak | s/news/newbs/ |
| 20:06 | sexpbot | <zodiak> I dare say that namespaces/requires/use is were most newbs trip up |
| 20:06 | zodiak | sexplot +karma |
| 20:07 | zodiak | good gods.. this autocorrect is annoying. what's a 'sexplot' ? |
| 20:07 | sritchie | (inc sexpbot) |
| 20:07 | sexpbot | ⟹ 0 |
| 20:08 | gfrlog | (inc sexplot) |
| 20:08 | sexpbot | ⟹ 1 |
| 20:19 | zakwilson | (dec sexplot) |
| 20:19 | sexpbot | ⟹ 0 |
| 20:19 | zakwilson | (inc sexplot) |
| 20:19 | sexpbot | You want me to leave karma the same? Fine, I will. |
| 20:19 | zakwilson | Heh |
| 20:25 | sritchie | jimi_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:26 | sritchie | this has some uses, requires, and tests in a self-contained project that might be helpful to look at |
| 20:27 | jimi_hendrix | sritchie, cool, will check out |
| 21:16 | amalloy | summary 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:53 | pcavs | what's the idiomatic clojure constant naming convention? ALLCAPS? CL *ALLCAPS* ? |
| 21:56 | TimMc | pcavs: Most things are constants, yeah? |
| 21:56 | Scriptor` | I'm not sure if constants are idiomatic in clojure |
| 21:57 | Scriptor` | right, since most things are immutable anyways |
| 21:57 | TimMc | I think people tend to emphasize the things that *aren't*. |
| 21:57 | TimMc | ^^^^^^^^ |
| 21:57 | TimMc | :-) |
| 21:58 | pcavs | I mean more along the lines of constant strings for various purposes or constant magic numbers |
| 21:58 | pcavs | I'll just go with CL earmuffs |
| 21:59 | TimMc | pcavs: In Clojure, earmuffs are generally used for stuff that can be rebound. |
| 21:59 | hiredman | http://dev.clojure.org/display/design/Library+Coding+Standards |
| 21:59 | hiredman | "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:02 | pcavs | well no earmuffs it is! |
| 22:05 | ViciousPlant | does earmuff has special meaning here |
| 22:07 | amalloy | ViciousPlant: *foo* looks like a foo wearing earmuffs |
| 22:11 | ViciousPlant | get it, thanks |
| 22:42 | pcavs | #findfn (fn [x] (< x 2)) [3 4 5] false |
| 22:43 | amalloy | $findfn (fn [x] (< x 2)) [3 4 5] false |
| 22:43 | sexpbot | [clojure.core/identical? clojure.core/isa? clojure.core/= clojure.core/contains? clojure.core/every?] |
| 22:43 | pcavs | amalloy: thanks |
| 22:50 | pcavs | I just want some to return false, thoughts? |
| 22:50 | pcavs | false instead of nil that is |
| 22:50 | pcavs | without resorting to (not (nil? |
| 22:51 | amalloy | pcavs: suggestion: stop caring about the difference between false and nil except in rare cases |
| 22:51 | amalloy | why do you think you need false? |
| 22:51 | pcavs | lemme check |
| 22:51 | pcavs | ,(if nil "wtf" "ok") |
| 22:51 | clojurebot | "ok" |
| 22:51 | pcavs | guess I don't ;) |
| 22:52 | amalloy | pcavs: there are exactly two things that are treated as false in an (if) test: false and nil |
| 22:52 | pcavs | thought it was just false |
| 22:52 | amalloy | nah, that's java |
| 22:53 | pcavs | but I'm thinking of scheme I think, cause nil doesn't exist right? |
| 22:53 | amalloy | pretty sure scheme has nil |
| 22:54 | seancorfield | nice to be home and on a nice high speed network after spotty hotel wifi all weekend! :) |
| 23:12 | pcavs | amalloy: scheme does not have nil, it just has the empty list as annotated as (quote ()) |
| 23:12 | pcavs | a somewhat pedantic difference, but I forget the reasoning behind it... |
| 23:21 | amalloy | well, fair enough. that's what i get for learning CL instead of scheme |
| 23:33 | hiredman | clojure does not require the emtpy list to be quoted |
| 23:33 | hiredman | ,(= () '()) |
| 23:33 | clojurebot | true |
| 23:34 | pcavs | ,() |
| 23:34 | clojurebot | () |
| 23:34 | pcavs | ,(= () nil) |
| 23:34 | clojurebot | false |
| 23:36 | amalloy | hiredman: based on my brief study just now, it looks like scheme didn't standardize on whether () has to be quoted? |
| 23:37 | hiredman | no idea, I would expect most schemers would prefer the regularity of it being quoted |
| 23:51 | ihodes | amalloy: i'm pretty sure you need to quote it |
| 23:56 | amalloy | ihodes: 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 |