#clojure log - Aug 20 2011

The Joy of Clojure
Main Clojure site
Google Group
List of all logged dates

0:00 srid: eg: here's the most voted question with [clojure] tag asked last week, http://stackoverflow.com/questions/7064389/

1:58 dabd: I did require [incanter.core :as i] but when I try to load a file in the repl it says Could not locate incanter/core__init.class or incanter/core.clj on classpath:

2:01 I pulled the deps with lein deps I don't know why it cannot find incanter.core

2:01 any ideas?

2:47 srid: 'lein new' generates a basic project layout; are their alternative layouts? eg: a command-line project with opt parser and such.

2:50 Pupeno: srid: there might be plugins for that, lein-noir for example generates a web app by lein noir new, but it's not really an alternative layout, just another task.

2:51 amalloy: i don't know about lein, but cake lets you store project templates in ~/.cake, and you can specify which template to use when you new one up

2:51 ibdknox: srid: I've thought about potentially making a general purpose project template plugin

2:51 I actually thought someone had

2:51 srid: something like python's pastetemplate

2:51 ibdknox: though I can't remember what it's called now

2:52 srid: i don't seem to find it in https://github.com/technomancy/leiningen/wiki/Plugins either.

2:54 ibdknox: ah

2:54 here it is

2:54 https://github.com/levand/spawn

2:55 Pupeno: In a lein plugin I'm writing, I'm doing (eval-in-project project `(do (require 'lobos.config) (println lobos.config/db))) but it fails saying that lobos.config can't be found. But it's there, lein repl and (require 'lobos.config) works. What am I missing?

2:56 amalloy: &`'lobos.config

2:56 lazybot: ⇒ (quote lobos.config)

2:56 amalloy: k, just testing

2:57 srid: what is the currently fashionable way to get a clojure app running on appengine? there are a quite a few, eg: https://github.com/sethtrain/beget

2:58 ah, i'm beginning to feel eye strain and head ache ... must get some sleep!

2:59 ibdknox: srid: here's the relevant noir post

2:59 about appengine

2:59 https://groups.google.com/d/topic/clj-noir/5a-3mYzs8dA/discussion

3:01 Pupeno: srfixed.

3:01 srid: fixed.

3:02 amalloy: hah, the hidden dangers of tab completion

3:51 MasseR: Is anyone of you using slimv? Has the cw command changed for you?

4:09 babilen: MasseR: I use it for paredit (and vimclojure for the rest) -- The cw command works as expected.

4:16 MasseR: babilen: Normally cw deletes a word until space. Now it removes the space too

4:17 babilen: MasseR: I know, but as I said: It is working as expected here.

4:18 MasseR: So you still get the behaviour, but it's something you want?

4:20 babilen: If "this behaviour" == "deletes the space" then no. cw behaves as it should and does everywhere else.

4:26 MasseR: Ok

4:32 Pupeno: In a lein plugin I can do (require 'lobos.config) but when I do (println lobos.config/db) I get an error which, as usual, doesn't help at all (Exception in thread "main" java.lang.ClassNotFoundException: lobos.config (NO_SOURCE_FILE:1)). It doesn't mention lobos.clj anywhere in the stack trace, which is the only file in the lein plug in. Any ideas what's going on?

5:33 Netpilgrim: Hi. I'm still in the process of learning the basics. Are there cases where (some_map k) and (some_set e) instead of (get some_map k) and (contains? some_set e) don't work? And which versions are considered more ideomatic/better style?

5:34 s/ideomatic/idiomatic/

5:34 lazybot: <Netpilgrim> Hi. I'm still in the process of learning the basics. Are there cases where (some_map k) and (some_set e) instead of (get some_map k) and (contains? some_set e) don't work? And which versions are considered more idiomatic/better style?

5:35 Netpilgrim: Cool feature. I didn't know the bot would do that. :)

6:05 thorwil: Netpilgrim: i'm not even aware of (get some_map k), while (some_map k) is common

6:12 Netfeed: oh, and contains? will evaluate to true or false, not deliver an element or nil

6:12 Netpilgrim: thorwil: OK, thanks. I thought that the shorter variant is probably more widespread but to me as a beginner the longer form looks more readable. It's probably just a matter of getting used to the syntax.

6:13 thorwil: I know that (contains? s e) is not a replacement for (s e) but it works the other way around.

6:15 thorwil: The use of (s e) for conditions also seems consistent with a somewhat similar case I've read somewhere, namely using (seq coll) instead of (not (empty? coll)).

6:16 thorwil: the (:k m) and (m :k) is certainly one of the things you have to know, but once you do, it makes for lovely concise code.

6:18 Netpilgrim: thorwil: The (m :k) variant is probably better because it works with all datatypes as keys?

6:19 thorwil: Netpilgrim: i actually keep forgetting that both orders do not work for all cases, as most of the times i only have keywords :)

6:20 * thorwil -> lunch

6:20 Netpilgrim: thorwil: Thanks for your input.

9:34 dabd: If you change project.clj by adding a new depency do you have to stop the swank server and run lein swank again or there is another way? lein deps seems to not work because I get class not found error when loading a source file containing a require from the new dependency.

9:41 tufflax: I think lein deps, then restart swank should work, if not check spelling :P

12:56 * srid has got 3 invites to irccloud.com if anybody wants

13:01 schlechtv: How can I make this not fail: (use clojure.contrib.strint) (def tmplt "Here is a silly string with a number ~(int x)") (let [x 5] (<< tmplt))

13:22 dnolen: so anyone use Erlang bit pattern matching much?

13:32 KirinDave: In erlang?

13:32 Yes.

13:32 It's frikkin' amazing and Erlang programmers love it.

13:33 You haven't really enjoyed writing streaming byte protocol code until you've done it in Erlang and realized your code actually is fairly descriptive of the binary protocol.

13:33 dnolen: KirinDave: so I'm think doing the same thing in match would be trivial.

13:34 KirinDave: do you have any public code lying around where you've used it? I've looked over the Erlang syntax but curious to see some real examples.

13:34 KirinDave: Uhhh….

13:34 I actually don't have any public code

13:35 It was custom protocol stuff for powerset.

13:35 Sorry!

13:41 dnolen: np, should be fun in Clojure.

13:59 robonobo: hi guys

14:00 does the fact that some results are seqs and others are vectors in the unittests for http://4clojure.com/problem/39#prob-title seems strange to anyone?

14:05 opqdonut: yeah, but:

14:05 ,(= [1 2 3] '(1 2 3))

14:05 clojurebot: true

14:43 belun: hello.

14:43 know any small well writen open source java projects that i could write in clojure ?

14:43 as in translate

14:44 (for fun)

14:44 tufflax: why don't you solve a new problem instead? :p

14:45 belun: must not be bothered with the details

14:45 of business

14:45 logc

14:45 tufflax: of business?

14:46 belun: um... what the app does

14:46 business logic

14:47 jli: dnolen: are you working on bit patterns for match?

15:07 csquared: howdy guys — i'm having a real tough time setting a response cookie using compojure

15:07 docs are kind of thin

15:07 can anyone point me to an example?

15:07 or how i would add a cookie to this line?

15:07 (-> (response "You're in!") (status 200))

15:08 i've got the route wrapping it (wrap-cookies)

15:08 fyi i'm a clojure n00b as well : |

15:10 mdeboard: think most people are :P

15:10 csquared: heh

15:10 yeah i was working with a friend and doing OK with passing back the hash maps

15:10 then this "->" thing showed up

15:11 i think i just need to get a :cookies key into the reponse

15:11 mdeboard: that's actually a really awesome macro ;)

15:11 csquared: not knocking it

15:11 it just took things out of my level of understanding atm

15:11 i know its the "threading marco"

15:11 mdeboard: yeah i'm not real familiar with using HTTP in Clojure,so I can't help :(

15:12 csquared: maybe we can help me understand that line though

15:12 or what its doing?

15:12 or just a link to a doc?

15:12 i've been googling "clojure ->"

15:13 ok Other macros re-arrange forms in useful ways, like the -> macro, which recursively inserts each expression as the first argument of the next expression:

15:14 tufflax: csquared u got it now? :p

15:14 csquared: so its kinda of like an inject?

15:14 i'm thinking it need an (assoc :cookies …) at the end

15:14 tufflax: ,(-> 2 - str)

15:14 clojurebot: "-2"

15:15 tufflax: same as (str (- 2))

15:15 ,(-> 2 (- 5) (str "!"))

15:15 clojurebot: "-3!"

15:16 csquared: ,(-> {:body ""})

15:16 clojurebot: {:body ""}

15:16 tufflax: same as (str (- 2 5) "!")

15:17 it doesn't do anything with just 1 argument :p

15:17 csquared: ,(-> {:body ""} (assoc :cookies {:name "cookie-value"}))

15:17 clojurebot: {:cookies {:name "cookie-value"}, :body ""}

15:18 csquared: this looks promising

15:18 also, clojurebot is aweseom!

15:18 tufflax: hehe

15:18 csquared: HOLY SHIT IT WORKED!

15:18 tufflax: ,(doc ->)

15:18 clojurebot: "([x] [x form] [x form & more]); Threads the expr through the forms. Inserts x as the second item in the first form, making a list of it if it is not a list already. If there are more forms, inserts the first form as the second item in second form, etc."

15:18 csquared: thanks gentlemen!

15:18 or ladies

15:19 tufflax: no problem :)

15:19 belun: or bots

15:19 csquared: lol shouldn't always assume CS people are men...

15:19 hahah

15:19 turing test FTW

15:20 fyi this is what worked:

15:20 (-> (response "You're in!") (status 200) (assoc :cookies {:name "value"}))

15:21 tufflax: ,(doc ->>)

15:21 clojurebot: "([x form] [x form & more]); Threads the expr through the forms. Inserts x as the last item in the first form, making a list of it if it is not a list already. If there are more forms, inserts the first form as the last item in second form, etc."

15:21 tufflax: If you ever need it :p

15:38 dnolen: jli: yes

16:04 srid: where do people generally host their Clojure web apps?

16:08 chouser: srid: I've used heroku, looked at CloudBees and heard about ways to use Google's appengine

16:18 ibdknox: srid: EC2

16:18 srid: Heroku and elastic beanstalk are probably the easiest

16:18 beanstalk is significantly cheaper

16:19 * srid takes a look at beanstalk

16:39 srid: i'll go with appengine for now.

16:40 what would be the rake-like tool for clojure?

16:40 ruby's rake or node's cake

16:43 amalloy: srid: cake and lein are the main tools for that

16:44 srid: there doesn't seem to be a obvious way to define tasks in lein, but there is apparently in cake: http://stackoverflow.com/questions/3906276/whats-the-difference-between-cake-and-leiningen

16:47 patchwork: It's easy to add tasks to lein. You create a src/leiningen/command.clj with a function named "command" and you can call it from the command line:

16:47 > lein command

16:47 hsbot: Not in scope: `lein'Not in scope: `command'

16:47 patchwork: oops, triggered evaluation

16:47 what is this hsbot? I am new to the channel

16:47 amalloy: haskell

16:48 patchwork: ah nice!

16:48 amalloy: nobody knows why he hangs out in here

16:48 $heval [1..5]

16:48 lazybot: ⟹ [1,2,3,4,5]

16:48 amalloy: especially since lazybot does haskell too

16:49 patchwork: is there a clojurebot as well?

16:50 srid: $(+ 2 3)

16:50 amalloy: ,(inc 2)

16:50 clojurebot: 3

16:50 amalloy: &(inc 2)

16:50 lazybot: ⇒ 3

16:50 srid: $pyeval raise SystemExit

16:50 heh

16:51 patchwork: we're still here

16:52 ,(defn yoyo [a] (* a 3))

16:52 clojurebot: #<Exception java.lang.Exception: SANBOX DENIED>

16:53 patchwork: aha

16:53 srid: patchwork: can't find docs for writing command.clj in lein docs; is there a sample?

16:54 * srid tries it out first

16:55 srid: wait, should the actual command name be in the filename (command.clj) or in the function name?

16:55 patchwork: srid: not sure where I found it, but I have a couple of commands in my project

16:56 it should be a command named "command" in a file called command.clj

16:56 or better yet, the function name should have the same name as the file

16:56 srid: so if I want to have a command called "lein serv" - i should create a function called "serv" in src/leiningen/serv.clj?

16:56 patchwork: Yep

16:57 that works for me at least

16:58 coopernurse: srid: yep. note that you can also dispatch on a 2nd argument if you want to support sub-commands from a single lein plugin. e.g. lein ring uberwar

16:58 srid: $ lein serv 1 ↵

16:58 Exception in thread "main" java.lang.Exception: No namespace: leiningen.serv found (NO_SOURCE_FILE:0)

16:58 oops; sorry for the whitespace.

16:59 coopernurse: as an example of a working plugin, take a look at: https://github.com/weavejester/lein-ring/blob/master/src/leiningen/ring.clj

16:59 srid: what dir are you executing lein in? I assume the project dir that contains your 'src' dir?

17:01 srid: correct; the error was due to my forgetting to include a (ns ...) statement.

17:01 coopernurse: ah

17:01 patchwork: so it worked then?

17:01 srid: yes, worked for a simple `println` function.

17:03 the slow startup time of java apps seems annoying.

17:04 coopernurse: yeah, jvm startup time is rough on lein. but for regular development you can write code in the REPL

17:06 srid: ,#'foo

17:06 clojurebot: #<CompilerException java.lang.RuntimeException: Unable to resolve var: foo in this context, compiling:(NO_SOURCE_PATH:0)>

17:07 amalloy: you can also start a lein shell, which is supposed to reduce startup time pain

17:07 patchwork: so, I am having a problem with exceptions using postgres through jdbc

17:07 coopernurse: amalloy: ah, didn't know that.. good to know

17:07 patchwork: whenever something goes wrong with the db call, I get something like this:

17:07 amalloy: lein int

17:07 patchwork: java.lang.Exception: Call getNextException to see the cause.

17:08 but when I try to call (.getNextException e)

17:08 I can't, because it is not a SQLException?

17:09 I feel like the jdbc library is throwing everything up as java.lang.Exception, even if it is a java.sql.SQLException

17:09 coopernurse: patchwork: try (.getCause e)

17:09 patchwork: so that I can't find out what the actual problem was

17:09 coopernurse: haven't tried it, but that should give you the next exception down

17:09 patchwork: coopernurse: thanks, I'll try that

17:10 coopernurse: Aha, so I need to say (.getNextException (.getCause e))

17:10 the cause is the sqlexception

17:10 not the original one

17:10 coopernurse: patchwork: ah, there you go

17:11 patchwork: thank you much

17:11 wrestling with that one for awhile

17:13 coopernurse: no problem - error message was misleading

17:13 srid: I can't seem to specify https://github.com/clojure/tools.cli as a dependency in project.clj; `lein deps` cannot find it. is it because, tools.cli was never uploaded to clojars.org?

17:17 coopernurse: srid: yeah, looks like it's not in clojars

17:18 you could try clojure.contrib.command-line instead - http://clojuredocs.org/clojure_contrib/clojure.contrib.command-line/with-command-line

17:18 amalloy: clojure/core stuff never goes on clojars, does it?

17:20 coopernurse: amalloy: oops, good point

17:20 amalloy: to be fair, i checked too

17:21 coopernurse: I don't see it bundled in 1.2. Perhaps it's a 1.3 addition?

17:23 srid: wasn' clojure.contrib.command-line replaced with tools.cli?

17:25 raek: the official clojure libs are not usually on clojars, but in some other repo

17:30 srid: how would I then define tools.cli as a dependency to be fetched via 'lein deps'?

17:32 found it http://mvnrepository.com/artifact/org.clojure/tools.cli -- [org.clojure/tools.cli "0.1.0"]

17:36 polypus74: i haven't looked into this in over six months. any news on the async http front? what would currently be the best way of doing websockets in clojure?

17:37 srid: amalloy: 'lein shell' doesn't work; shell is not a command.

17:37 amalloy: lein int

17:38 polypus74: aleph has websockets, doesn't it?

17:39 polypus74: amalloy: i believe it does, was just wondering if there had been any more recent developments. there is a branch of ring with async, but it doesn't look like it's moved much. was hoping for some simple solution i could just drop into a regular ring app. maybe ontop of jetty or even netty

17:40 aleph might just be the way to go though

17:47 coopernurse: is there any equivalent to (time) that monitors heap usage? I want to do some crude memory profiling of my code.

17:49 now that I ask that aloud I'm not sure exactly how it would work. perhaps just return heap size delta before/after the inner function executes..

17:49 looks like I could roll my own using java's Runtime class

17:53 srid: interesting, clojure core doesn't include a http client, and I need to use clj-http.

17:54 amalloy: coopernurse: so long as you don't mind that gc will generally not happen right away, so heap size will continue to go up even if you've discarded all the temporary objects you allocated

17:54 coopernurse: right

17:54 perhaps you could run gc manually

17:54 before/after

17:55 amalloy: depends on what you want to measure

17:55 if you care about churn, then don't gc; you can see how much was allocated during the run

17:55 if you care about depletion, then you want to see if the function uses any "permanent" memory

17:58 coopernurse: right.. and of course, if it does anything non-trivial, gc will get run concurrently, making it hard to measure

18:02 amalloy: yep. that's what profilers are for

18:04 but getting out something as fine-grained as you want will probably be hard

18:08 coopernurse: yeah, well, this gives me an excuse to learn how to write a macro, even if it's a useless one :-)

18:09 srid: apparently clj-http seems to be unmaintained.

18:20 memothy: Hello everyone. I've never used Clojure before, but I'm familiar with java and scheme. I'm just starting to feasibility-test some algorithms for the android platform. REPL sounds appealing for quick and dirty prototyping, but I'd like to make sure that I'm barking up the right tree here.

18:22 With Clojure coupled to the jvm, can I integrate numeric libraries from java trivially, or are some sort of bindings required?

18:26 And poking around online, I noticed someone complaining that Clojure paused an android device for ~10s before necessary bootstrapping code loaded. While I would ultimately remove Clojure from the final result, after this bootstrap process would benchmarks run on an android device approximate performance in a pure java setting (and maybe even provide worst case performance data)?

18:30 I'm just starting to read `the joy of Clojure', but as I said, I'd like to know whether the language is suitable as a prototyping language. I anticipate quick prototypes that use the same libraries that I would later incorporate into a pure java project hosted on the android platform.

18:37 coopernurse: memothy: you can invoke java libs directly from clojure without bindings

18:37 so it should be suitable for prototyping java apps

18:39 example of calling java swing classes from clojure w/o clojure specific bindings: http://clojure.org/jvm_hosted

18:39 memothy: sweet. do you know of any performance data comparing java performance to clojure performance under different numeric (and maybe string) libraries?

18:40 coopernurse: hmm.. I'm aware of this site: http://shootout.alioth.debian.org/

18:41 which has general language benchmarks.. java and clojure are represented

18:41 but I'm not sure if that's what you're after

18:45 memothy: at a glance the testing schema is confusing ('fastest program versus fastest program'...huh?). but if I'm calling without bindings, then I imagine that performance under Clojure reflects worst case performance under java. that's a sufficient condition at least, right?

18:46 polypus74: memothy: note links under performance bullet here: http://disclojure.org/2011/08/15/today-in-the-intertweets-aug-15th-ed/

18:48 coopernurse: yes, it's hard to speak precisely, but clojure compiles your .clj source to jvm bytecode, just like javac would for .java source. so it sort of comes down to your implementations in the two languages

18:48 my guess is if you profiled the swing example I linked to above and compared it to the same code in java, the resulting byte codes are probably similar

18:49 since the clojure code is written in a largely imperative style, and is just invoking java classes for the most part

18:49 but if you compared solutions to a mathematical problem, say a project euler problem

18:50 then the code you'd write in clojure vs java would likely be really different, so the resulting bytecode would be quite different too

18:51 Netpilgrim: I'm trying to get the hang of seqs. What is the rationale behind (seq '()) being nil when there are in fact empty seqs like the return value of (rest '())?

18:52 memothy: so writing solutions within the idioms of each language, performance is a toss-up, but so long as I'm simply filling java data structures and operating on them with java libraries, then I can expect similar performances, yeah?

18:53 And thanks polypus74 for that I link. I'll probably be exploring that domain in general, as well.

18:54 coopernurse: memothy: I suspect that's right. if you used clojure as a tool to script java libraries, I suspect you'd get pretty similar perf -- but perhaps with some reflection overhead. there are some type hints you can throw in to help the clojure compile avoid reflection

18:55 you mentioned android

18:55 memothy: Well thanks, coop. I'm off to the library. In a month or so I ought to have some results specifically on Clojure as a java prototyping tool.

18:56 Oh, yeah.

18:56 coopernurse: I'm not sure how the dalvik vm compares, or how jvm bytecode is translated to run on dalvik

18:56 so that may introduce some differences, not sure

18:57 to clarify: the converted bytecode written in clojure should work (folks have written android apps in clojure) but I'm not sure if it changes the perf profile at all

18:58 memothy: My motivation for ultimately working with Clojure--I figure if I use the same libraries that I will eventually use in my project, then the coding should be much cleaner (and anything but Octave/MatLab for prototyping).

18:59 Of course I'll research it better before I throw away my prototypes and code the project's core, but I already have sufficient motivation to learn Clojure as a prototyping tool.

18:59 coopernurse: memothy: makes sense. it's definitely a fun language to learn

19:00 memothy: I'm sure I'll eventually find my way back to that ~10s claim, but for now I feel comfortable proceeding.

19:00 coopernurse: REPL makes experimentation way faster

19:00 memothy: Thanks for the help. I'll probably become a regular around here, so I'll see you around.

19:01 coopernurse: cool, see you

19:36 chewbranca: anyone have a recommendation for a reliable http request clojar?

19:37 everytime I come back to clj-http something different has happened, and now the getwoven repo is gone

19:43 ibdknox: technomancy: ping

20:44 srid: chewbranca: i wonder if there is even an alternative http lib.

20:45 i was battling with myself as to writing a gzip decompress code in clojure to decode a gzip encoded http response. my java knowledge seems insufficient.

20:57 chewbranca: srid: yeah I dealth with the same thing a few months ago, the getwoven/clj-http had a bug in it breaking gzip responses, and hadn't been updated in quite a while, so I found a fork that fixed the gzip issue but wasn't on clojars, then I saw a few months ago that get-woven brought in the pull requests fixing things, now the repo is gone :/

20:57 srid: let me see if I can find that fork that worked, just a sec

20:59 srid: getwoven doesn't have a clj-http repo

20:59 chewbranca: srid: heh.. yeah that's my point

20:59 srid: clj-http doesn't seem be maintained; there are a bunch of pull requests here without any update - https://github.com/mmcgrana/clj-http/pulls

20:59 chewbranca: srid: getwoven created clj-http, repo is no longer there

21:00 srid: 28 forks, but only 5 people watching?

21:00 that's strange, usually more people watch a repo with less forks.

21:02 C was my first programming language, and whilst learning it (2001) I remember spending whooping two hours just to write a program to print the multiplication table. something like that is happening with me when writing Clojure. :-)

21:03 chewbranca: srid: haha clojure is good times, really enjoying working with it

21:15 zmaril: How does one go about creating an infinite sequence?

21:19 srid: ,(iterate inc 1)

21:19 clojurebot: (1 2 3 4 5 ...)

21:22 wastrel: clojurebot, botsnack

21:22 clojurebot: Thanks! Can I have chocolate next time

21:23 joshuahickman: Where precisely did clojurebot come from?

21:23 I know he can do code eval and such

21:23 And it seems every time I visit I see a new thing someone programmed him to do

21:23 Which is to say, is he open source?

21:24 On a more clojure related note:

21:25 #() syntax macroexpands, it seems, to (fn [%] ...), but does not make a function literal at compile time

21:25 I presume this is for simplicity's sake?

21:26 wastrel: i sure don't know

21:26 re clojurebot

21:26 joshuahickman: Because it confused me right good earlier

21:27 Oh, yeah :)

21:27 That #() confused me earlier, because I did a

21:27 (-> 2 #(+ 2 %))

21:27 Basically

21:27 wastrel: i dunno from clojure either :]

21:28 joshuahickman: And I thought it would work, not unreasonably, imo

21:28 srid: could somebody explain why I keep getting "Not in GZIP format" error when gzip decompressing a gzip-encoded HTTP response? here's the code: https://gist.github.com/1159952

21:29 i'm pretty the implementation of gzcat is ugly. just trying to get something working first.

21:29 *pretty sure

21:30 zmaril: srid: thanks. I was trying to do a prime list and I was trying to think of the right question to ask. It works sort of now: https://gist.github.com/1159955

21:30 joshuahickman: I might be looking at old docs, but it seems like that read function might take more arguments

21:38 srid: client/get returns String; shouldn't that be Bytes?

21:38 maybe that's why the original gzipped bytes are lost.

21:39 note my use of (.getBytes string) -- I believe that uses utf16, and unicode makes no sense with bytes.

21:39 * srid goes out for a dinner break

21:48 toast`: ah, so you got ascii -> unicode string -> utf16le bytes… yeah, that's not an identity

21:50 tufflax: josh what did you think would be the result of (-> 2 #(+ 2 %))?

21:50 joshuahickman

21:50 joshuahickman: 2

21:50 *4


21:50 *TYPO

21:50 Wow

21:50 I am not actually stupid

21:50 tufflax: lol

21:50 joshuahickman: I wish to convey this

21:50 tufflax: lol

21:51 why 4? i mean, it doesn't give the previous result as an argument, it simply inserts it into the next form

21:51 joshuahickman: Yeah, I was anticipating I would get a function literally just like (-> :a {:a 4})

21:52 darevay: Question: there's a saying something like "write code that shows how to solve the problem, not what to do", or something like that. Anyone got a reference or at least, less mangled quote?

21:52 joshuahickman: Yeah, but when I put a symbol (as in, not a list), it applies that to the previous argument

21:53 tufflax: no

21:53 joshuahickman: Perhaps I'm not articulating

21:53 tufflax: it builds a list and puts it second

21:53 joshuahickman: Yeah

21:53 It does this for all non-lists

21:53 tufflax: it has nothing to do with arguments, just with putting things in lists

21:54 joshuahickman: Yeah, I understand that's how it's implemented

21:54 I'm just saying it violated expectations because it looks like a literal syntax

21:54 Like sets and maps

21:54 It does not look like a macro

21:54 Does that make sense as a reaction?

21:54 Perhaps I am insane

21:55 dnolen: ,(-> 2 (+ 2))

21:55 clojurebot: 4

21:55 tufflax: you mean #() looks like literal syntax?

21:56 joshuahickman: The example I was actually trying to do was #(.split % "\\.") , but that's neither here nor there

21:56 It does

21:56 I anticipated it resolving, at compile time, to an object

21:56 Although it being a closure might make that tricky

21:56 I was just curious if this is something people had thought about

21:58 dnolen: ,(-> "foo.bar" (.split "\\.") vec)

21:58 clojurebot: ["foo" "bar"]

21:58 tufflax: But -> does not handle objects, it handles syntax. And so, if #(+ 2 %) counted as a list, it would have become #(+ 2 2 %), and if it would #() would expand first then, (fn 2 [%] (+ 2 %)), neither of which is 4

21:59 but maybe you got that already :p

21:59 joshuahickman: Yeah, I noticed it was the second one

21:59 Which, by the by, has one of the more confusing compile errors until I got it

21:59 dnolen: joshuahickman: the problem is not #(), it's ->

21:59 tufflax: hehe

22:00 joshuahickman: See, dnolen, it depends on what you think the problem is

22:00 I just changed it to (.split ""), but I was actually hoping the #() syntax acted more like {}

22:00 Where it is not a list at all

22:01 dnolen: joshuahickman: what I mean is, you don't understand -> does. if you do, you know you don't need #()

22:01 joshuahickman: And then -> makes it into (#() xxx)

22:01 Not in this case, no, but when I saw that I got curious, is all

22:01 tufflax: oh now i see what you mean

22:01 joshuahickman: I would prefer you not assume I don't know how these things work

22:02 tufflax: when you said object i though you ment like

22:02 ,+

22:02 clojurebot: #<core$_PLUS_ clojure.core$_PLUS_@1cd022c>

22:02 dnolen: joshuahickman: I'm not assuming anything.

22:02 tufflax: I misunderstood you josh :p

22:03 joshuahickman: Yeah, I was just pondering why the #() reader macro is the only one that *doesn't* output an object

22:04 I mean, {} could easy expand to (make-map key val key val)

22:04 But it doesn't

22:04 That's all I was thinking

22:04 tufflax: I see

22:05 well, object is a very vague term here i think :p

22:05 joshuahickman: That's true enough

22:05 I suppose I mean not a list

22:05 dnolen: ,(macroexpand '(-> foo #()))

22:05 clojurebot: (fn* foo [] ())

22:05 joshuahickman: Clojure is really my first lisp where there are semantically meaningful non-list compile time constructs, so excuse the vagueries

22:06 ibdknox: dnolen: sadly it appears I can't do the cljs-watch stuff as a leiningen plugin

22:06 dnolen: ibdknox: darn.

22:06 ibdknox: dnolen: since it would require lein to run as 1.3.0

22:07 I did, however, get it as a single shell script

22:09 dnolen: ,(macroexpand '(-> foo (#())))

22:09 clojurebot: ((fn* [] ()) foo)

22:11 joshuahickman: yes, precisely

22:11 ,(macroexpand '(-> :a #{:a}))

22:11 clojurebot: (#{:a} :a)

22:12 joshuahickman: ,(macroexpand '(-> :a {:a :b}))

22:12 clojurebot: ({:a :b} :a)

22:12 dnolen: ,(-> :a #{:a})

22:12 clojurebot: :a

22:12 joshuahickman: Right

22:12 dnolen: ,(-> :a {:a :b})

22:12 clojurebot: :b

22:12 dnolen: ,(-> {:a {:b {:c 1}}} :a :b :c)

22:12 joshuahickman: But you see how the macroexpansions I just did behave differently than the one for #()?

22:12 clojurebot: 1

22:13 joshuahickman: The one for #() doesn't wrap in a list because the #() produces a list, not an IFn

22:14 dnolen: ,(macroexpand '(-> 0 (for [x (range 10)] x)))

22:14 clojurebot: #<ExecutionException java.util.concurrent.ExecutionException: clojure.lang.ArityException: Wrong number of args (3) passed to: core$for>

22:15 dnolen: it's no different for anything else that would expand.

22:15 joshuahickman: Yes, but it *should* be different, and it should be different in the same way {}, [], and #{} are

22:16 This is the purpose of literal syntax

22:16 tufflax: well josh here http://clojure.org/reader the data structures are under "reader forms" while # without { following are under "macro characters", but yeah... :p

22:17 is*

22:17 dnolen: joshuahickman: except #() is not literal syntax. It's sugar. fn is the literal syntax.

22:17 joshuahickman: according to the link above:

22:17 Anonymous function literal (#())

22:17 But I see your point

22:18 I mean, the regexes seem to be literals, too

22:19 dnolen: joshuahickman: #() is listed under the real list of literals. but yes, that's a bit confusing.

22:19 s/is/is not

22:19 lazybot: <dnolen> joshuahickman: #() is not lis notted under the real lis nott of literals. but yes, that's a bit confusing.

22:19 dnolen: erg

22:19 joshuahickman: But regexes aren't either

22:19 tufflax: :p

22:19 joshuahickman: yeah

22:19 But regexes work this way, albeit less usefully for ->, as they aren't IFn, as far as I know

22:20 lobotomy: haha, lazybot does s/foo/bar/g when someone says s/foo/bar?

22:20 bug spotted ;p

22:20 joshuahickman: Hold on a sec, I have to retreat to my code-lab

22:23 yeah, okay

22:23 ,(macroexpand (-> 2 #"" quote))

22:23 clojurebot: (#"" 2)

22:23 joshuahickman: Deliberately contrived example

22:23 Which is to say, we should probably figure out how to either clean up the docs

22:24 Or add in this feature to the next version of clojure

22:25 Because it seems #() is the odd one out here, but not in a way that is documented, predictable, or advantageous

22:25 dnolen: joshuahickman: it's probably too minor a point to draw much interest. your one of the few I've seen talk about it much.

22:25 joshuahickman: Of course, I imagine this is likely the most inane silly detail

22:25 yeah lol

22:26 tufflax: '() acts the same way

22:27 ,(macroexpand '(-> 1 '(a)))

22:27 clojurebot: (quote 1 (a))

22:27 tufflax: but, maybe that is not documented the same

22:28 joshuahickman: Well, that's interesting behavior

22:28 I mean, I'm not surprised by it

22:28 But it never occurred to me

22:28 That one makes sense, though -- you are producing a list

22:28 And -> looks for lists

22:29 It certainly isn't the list you would like

22:29 But at least the macroexpansion doesn't get muddled, as odd as that opinion sounds

22:29 I mean, the quote has to go somewhere

22:30 Anyhow, I always imagined '() working like @var

22:30 That is was contracted to be identical to the function call

22:30 So that's a plus

22:31 tufflax: but it does work like @

22:31 ,(macroexpand '(-> 1 @(a)))

22:31 clojurebot: (clojure.core/deref 1 (a))

22:31 tufflax: :p

22:31 joshuahickman: That looks the same

22:31 I'm confused

22:32 I mean, it's just deref vs quote

22:32 tufflax: but @(a) looks a bit strange

22:33 not something one often sees i suppose

22:33 joshuahickman: But to the lisp reader, it doesn't matter if it is a list or a var, in terms of function or macro application

22:34 I mean, the deliberately contrived examples might be confusing :)

22:34 dnolen: all which is this too illustrate that -> is syntax transformation applied after other forms have expanded. there be goodness and there be dragons :)

22:34 tufflax: yeah

22:34 joshuahickman: lol Indeed, sir

22:35 I believe I'll use that to describe macros from now on

22:45 tufflax: by the way joshuahickman you said you were trying to use #(.split % "\\.") in the ->, but I guess you realize by now that (.split "\\.") would work

22:45 joshuahickman: yeah

22:46 Actually, I think at the moment I just did a (let [splitByDot #(.split % "\\\.")] ...)

22:46 Because I was tired

22:46 But yeah, this wasn't a technical road-blocking issue

22:46 It was quite surreal to hunt down that bug, though

22:46 tufflax: camelCase? eww

22:47 joshuahickman: Oh no! I got brainwashed by my java day job! :(

22:47 I'll use dashes next time

22:47 :)

22:47 tufflax: hehe

23:12 ibdknox: hey folks

23:12 if you're doing cljs stuff, you might find this useful: https://github.com/ibdknox/cljs-watch

23:23 dnolen: ibdknox: does it avoid the jvm restart overhead?

23:23 ibdknox: yessir

23:23 dnolen: ibdknox: sweet, are you going to submit this to ClojureScript?

23:24 ibdknox: I probably need to change it a little first

23:24 dnolen: ibdknox: do it!

23:24 ibdknox: but yes, it probably should be :)

23:24 dnolen: :)

Logging service provided by n01se.net