#clojure log - Jul 06 2012

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

0:09 TimMc: Is there a fn like take-while but that will take one more element?

0:12 For instance, (___ odd? [1 3 5 8 10 12]) => (1 3 5 8)

0:16 (Well, I don't need it anymore.)

0:39 arrdem: hey guys, I'm porting some CLISP code to Clojure and something that is really getting in the way is the different behavior of LET and SET!/SETF between the two languages. How should one create set!-able local variables or do I need to redesign the code to use Clojure-style imutable variables?

0:40 arohner: arrdem: you can use set! inside a binding call, but that's threadlocal only, and not very idiomatic

0:40 if your goal is to do things "the clojure way", you should probably rethink the design

0:42 arrdem: arohner: Understood on the "Clojure Way". What do you mean by a "binding call"? (loop) and (let) both have specific documentation prohibitions against set!ing the defined vars.

0:43 arohner: you could also use atoms, but it's poor clojure to use numerous atoms

0:43 inside a binding block, you can set! (binding [foo (bar)] (set! foo 42))

0:43 the variable will mutate, but it's thread-local only, and will revert to it's old value outside the binding

0:44 arrdem: Ah. thanks, I had never heard of the (binding) expression.

0:44 arohner: oh, and the variable needs to be declared dynamic

0:44 (def ^:dynamic foo)

0:44 arrdem: noted. presumably [binding it's use is descuraged?

0:45 * noted. presumably binding's use is descuraged?

0:45 arohner: all of these exist to be used. What's discouraged is using a lot of mutable state

0:45 clojure emphasizes reducing the amount of mutable state, and being clear about when/how things change

0:47 binding is typically used for "configuration", rather than computation

0:48 arrdem: why is that? Oh. create local state and then invoke stateful routines from the compartmentalized scope... that makes sense

0:48 Cool! learned something today... thanks for the help!

0:49 arohner: Rich Hickey argues that uncontrolled mutable state is a large source of bugs and complexity in programs. Reducing the amount of state makes your code easier to understand & less buggy. Clojure is strongly influenced by that

0:50 so the clojure "boxes", var, ref, atom, agent each hold mutable state, in a different, safe, way

0:51 vars can only be mutated thread-locally, refs mutate globally, but through the STM, etc

0:51 * arrdem starts digging for docs

0:53 noidi: I have to call an impure function with two arguments. I have the argument pairs in two lists: arg-1s and arg-2s. Is this the best way to do it: (dorun (map #(impure %1 %2) arg-1s arg-2s)) ?

0:54 is abusing map for side effects OK, or can I do this somehow with doseq?

0:54 nicholasf: hi, I'm in the first stages of learning clojure, apologies if this is a stupid question. Trying to compile this code - https://gist.github.com/9334e4f835657b2ed82b - I encounter an error: Unable to resolve symbol: register-device in this context, compiling:(util/device_emulator.clj:24)

0:54 arohner: noidi: (dorun (map..)) is fine

0:54 nicholasf: surely I don't have to define register-device *above* n-devices?

0:55 noidi: nicholasf, unfortunately you do :(

0:55 arrdem: nicholasf: you do in fact have to

0:55 nicholasf: noidi: wow, ok

0:55 noidi: or at least (declare register-device)

0:55 arohner: noidi: you can also (doseq [[one two] (map vec arg-1s arg2s)] (impure one two))

0:55 arrdem: Clojure's base CompilationUnit is an s expression

0:55 not a file

0:55 so order matters

0:55 nicholasf: thanks mate

0:55 arrdem: np

0:56 arohner: nicholasf: you can also use declare

0:56 (declare register-device) (defn n-devices ...) (defn register-device ...)

0:56 arrdem: arohner: why use (declare) not (def)?

0:56 arohner: arrdem: expresses intent more clearly

0:56 arrdem: (doc declare)

0:56 clojurebot: "([& names]); defs the supplied var names with no bindings, useful for making forward declarations."

0:56 arrdem: Oh. shiny!

0:57 arohner: declare also supports (declare foo bar)

0:57 noidi: (declare foo bar baz) vs. (def foo)(def bar)(def baz)

0:57 * arrdem goes to clean up 100 lines of preemptive defs in shame

0:57 nicholasf: arohner: yup, thanks

0:58 noidi: it also better communicates your intent. if you see a declare you know that the var is defined somewhere later in the file (and not e.g. set! during execution)

0:58 nicholasf: ok, so that's what declare means

0:58 it's like a deferred define

0:58 noidi: nicholasf, here's a comment by Rich Hickey on Hacker News, in which he talks about forward references (or their lack in Clojure thereof)

1:09 nicholasf, damnit, I forgot the link :D http://news.ycombinator.com/item?id=2467809

1:09 nicholasf: thanks noidi

1:11 yeh that helps set the situation in context thanks

2:45 anyone using a redis client that will support publishing to channels? redis-clojure doesn't seem to

2:53 nkkarthik: excuse me... is this the right place to ask a question on swank-clojure plugin?

2:53 amalloy: ~swank

2:53 clojurebot: swank is trust the readme and the readme only. all others will lead you astray.

2:54 nkkarthik: :) ok thanks... i will keep searching then

2:54 amalloy: nkkarthik: nah, you can ask in here. just don't trust any blogs or whatever

2:56 nkkarthik: oh ok... I have a lein project... from emacs I did clojure-jack-in... it cleared all the java class files and complains about it

2:57 I did 'lein compile' in the terminal... the class files are there... get back to emacs... clojure-jack-in... the class files are cleared... and jack-in fails

2:58 I am not sure why clojure-jack-in clears the class files and doesn't compile them again

2:58 any clue?

3:19 I think I got that... lein-swank 1.4.4 has this problem... I changed to 1.4.3 and it works!

4:46 noidi: are there any guidelines on when to :use vs. :require other namespaces?

4:49 xumingmingv: I use :use wherever i can, because it's convenient than :require, but sometimes you need to use :require because name clash, and you want to be clear which version you are using.

4:49 noidi: yeah, nowadays I tend to :use everything (with :only, of course), and only use :require when the names would clash otherwise

4:50 I was just wondering if that's common practice

4:51 the reason I avoid :require is that having a prefix namespace prefix on every symbol kind of defeats the point of namespaces

4:51 it's almost like programming in c :)

4:56 amalloy: noidi: well, that's not really true. you can (require '[clojure.string :as s]), and get the benefits of namespaces with only a very small amount of extra code

4:57 personally i still mostly 'use, but i feel like that's a habit i'll eventually grow out of, especially now that 1.4 supports a :refer option on 'require to get all the features that 'use currently has

5:02 noidi: oh, cool

5:02 I didn't know about the :refer option to 'require

5:06 AWizzArd: use is very nice for the repl.

5:06 What I find unfortunate is that doc and apropos reside in the clojure.repl ns. I constantly have to use it.

5:11 Raynes: If you use lein2's repl, you don't have to.

5:11 And if you use slime, you don't even need it.

6:03 ro_st: anyone using cemerick's friend? how do i access the authenticated user data once a user has signed in?

6:18 mystiiq: has anyone used clj-ssh? how can I disable all that INFO logging that is displayed in terminal?

6:28 wingy: didnt know about this one: https://github.com/halgari/clojure-py

6:28 is there a good reason for why we would like it to run on python?

6:28 i can understand the js implementation since we need it in the browsers. also allowing better scripting support

6:31 jeremyheiler: wingy: the README for the project explains why they started the project

6:33 wingy: always read first

6:34 technomancy: there are no plans for lein to be run on node.js instead for eliminating start up time for various tasks?

6:36 jalatera_: what' the best way to search a nested hash map structure

6:40 xumingmingv: jalatera_: search a nested map? search for a value in the nested map?

6:44 ro_st: wingy: java folks are working on jvm start up time. the problem will go away eventuall

6:44 i doubt very much that lein will move to node.js :)

6:45 wingy: ro_st: but there will always be a startup time on jvm?

6:45 ro_st: yes

6:45 what repetitive tasks are you using lein for?

6:46 wingy: lein repl :)

6:46 but also i would like to install my own tasks

6:47 eg saving project with git

6:48 why not move to node.js? lein doens't need the power of jvm or concurrecy i guess. are there reasons for staying on jvm?

6:49 one i can think of is that people dont need to install node.js

6:49 perhaps its better for me to script in node.js myself

6:57 ordnungswidrig: wingy: nice idea, lein on node

7:02 yonatane: there's a js implementation of clojure?!

7:02 wingy: yonatane: are you kidding

7:02 yonatane: you mean clojurescript or something else?

7:03 wingy: clojurescript

7:03 yonatane: oh

7:03 i should do more reading :)

7:18 unnali: Anyone have any ideas how to get tests to run with (clojure.test/run-tests blah) or (clojure.test/run-all-tests)? I'm trying to run Leiningen's tests from the lein repl (to avoid restarting the JVM over and over with repeated "lein test"s), but it doesn't seem to have the leiningen.test ns.

7:24 wingy: special anonymous function can not be used as fn call?

7:24 ,(#(%) "hello")

7:24 clojurebot: #<ClassCastException java.lang.ClassCastException: java.lang.String cannot be cast to clojure.lang.IFn>

7:24 unnali: ("hello")

7:24 wingy: ^this wouldn't work either

7:25 wingy: oh yeah i forgot

7:26 thought the anonymous function wasnt run

7:26 unnali: :D

7:26 wingy: (#(do %) "hello")

7:27 unnali: ,(#(do %) "hello")

7:27 clojurebot: "hello"

7:27 wingy: special anonymous fns look so concise

7:27 very handsome

7:27 unnali: handsome??

7:27 lazybot: unnali: What are you, crazy? Of course not!

7:28 unnali: lazybot: ...

7:50 ro_st: cemerick: is there a way to support both an anon user and a signed in user with a single set of routes (bundled into a context)?

7:51 with friend

7:52 i have a case where some api calls can be used by anon guests as well as by signed in users. to keep things DRY, i want the same code to handle both cases (as the difference is deep down in the monger queries)

7:58 cemerick: also, how do i access the signed-in user from within my compojure routed fns?

7:58 jeremyheiler: unnali: if you (load-file "test/project_name/core_test.clj") you can then run (run-tests 'project_name.core_test)

7:59 cemerick: ro_st: Sure; any code that isn't protected by an authorization middleware/expression will remain accessible to anonymous users.

7:59 unnali: jeremyheiler: ta! I had worked out that (require 'leiningen.tests.compile) (where that was the ns I wanted to test) ded the trick. thanks for your time, though!

8:00 cemerick: ro_st: See cemerick.friend/identity and cemerick.friend/*identity* to get access to the signed-in user

8:01 jeremyheiler: unnali: nice

8:02 that makes a little more sense :-P

8:03 ro_st: cemerick: so from within a compojure route handler i could check (friend/identity request) and either get nil or the map that my creds fn returns?

8:03 cemerick: yup

8:04 ro_st: ok cool. i'm not making things easy for myself; i have to write a custom workflow as well because this is all happening inside a json rest api

8:06 best way to learn, though, ain't it :-)

8:06 i found writing my own md5 fn to be really easy

8:07 to support legacy user accounts

8:07 going to put a bcrypt re-encrypt-on-login-or-reset system into place so that over time the md5 passwords fall away

8:12 cemerick: well, having an api shouldn't (on its own) require a custom workflow

8:13 ro_st: which workflow should i use, then? interactive-form is going to do redirects which i don't want

8:14 http basic with ssl, probably?

8:17 cemerick: ro_st: the workflow you choose is solely dictated by the way you want your users to authenticate, not whether you have an api or not. interactive-form doesn't do any redirects on its own; it delegates to :login-failure-handler (if provided) if authentication fails.

8:29 mystiiq: can clj-json make a JSON string out of {:foo "bar"} or should I use cheshire

8:29 ro_st: both can do it

8:30 with cheshire: (generate-string {:foo "bar"})

8:31 cmiles74: mystiiq: I've been using Cheshire for a whie and am happy with it.

8:32 ro_st: do i need to restart my emacs repl if i change project.clj deps?

8:32 xumingmingv: does maven have a similar command to `lein uberjar`?

8:32 ro_st: i do at the moment, but i'm not sure if i do actually have to

8:33 cmiles74: ro_st: Well, now's the time to put it to rest. I believe so, when I add dependencies my swank session doesn't see the additions to the classpath.

8:33 ro_st: thanks

8:35 mystiiq: how can I prevent the java browser from opening when using "lein ring server"

8:35 ro_st: server-headless

8:36 cemerick: ro_st, cmiles74: By default, no, new deps are not picked up. If you need to add dependencies to your Clojure runtime as an escape hatch, you can try https://github.com/cemerick/pomegranate

8:36 mystiiq: ro_st: thanks

8:36 cmiles74: ro_st: I've been meanign to look at Pomegranate for a while. It looks like it makes it easy to add a dependency (and all the dependency's dependencies) via the REPL. https://github.com/cemerick/pomegranate

8:36 cemerick: Ha! I was just looking at that page. :P I've had the bookmark in there forever.

8:38 xumingmingv: I found the uberjar plugin: http://maven.apache.org/maven-1.x/plugins/uberjar/

8:38 ro_st: whoa, that's handy!

8:41 sorry to beat a dead horse, cemerick, but just to confirm, even if a route isn't wrapped with wrap-authorize, i can still call (friend/identity req) to grab the user from the session?

8:42 cemerick: ro_st: the user data will be present if (a) the request in question has passed through the authenticate middleware, and (b) someone has logged in

8:42 ro_st: ok super. authenticate is wrapping the whole lot

8:43 thanks for your patience. so totally going to produce and share sample code once i've got it all working

8:43 which'll probably have several large holes poked in it, but hey :-)

9:48 mystiiq: I'm using noir and built a small API, so client sends a request, server processes it and sends back a response when its done. is it somehow possible to send back a reply right away and then proceed with more computing regarding that request

9:49 ro_st: look into agents mystiiq

9:50 the-kenny: mystiiq: You can easily spawn a thread or use agents

9:50 mdeboard: Is that what aleph is for btw?

9:51 antares_: mystiiq: start a new thread, use an agent, use a future, use execution services in java.util.concurrent, and this is just to name a few options

9:53 duck1123: aleph is for when you want to get the request and a channel that you can enqueue the response into (from any thread)

9:54 it also works really well for streaming requests and websockets

9:54 mdeboard: I see; I guess in my mind aleph ~= celery (python library)

9:54 that's wrong apparently

9:56 antares_: mdeboard: yes, aleph is definitely not a "job queue/workers" kind of thing

9:56 duck1123: yeah, close, but doesn't quite match up I thing. Lamina is for the message passing and queuing bit in the same application. A quick glance at that home page, looks like it's more like avout

11:04 broquaint: Neat, persistent data structures in ruby - https://github.com/harukizaemon/hamster/

11:46 * nDuff looks into the state of midje-on-cljs

11:55 duck1123: midje on cljs would be great

11:57 _zach: Is there a cljs command line tool to compile some cljs to js without a closure pass?

12:05 stuartsierra: _zach: Just compile with :optimizations :none

12:05 _zach: stuartsierra: Awesome, thanks!

12:06 * nDuff ponders extending the existing clojurescript wrapper around Jasmine (a native javascript testing library) to support its "spies" (beefed-up mocks, roughly).

12:34 qubit[01]: Does every file need a namespace ?

12:36 _zach: qubit[01]: Compilation shouldn't fail without one, but I see no reason you'd want to omit one

12:37 qubit[01]: im just starting out, when I try to compile the file, it says "no such namespace test.core" , (ns test.core ) , in the file core.clj

12:37 test/core.clj

12:37 compiling with C-c C-c

12:38 if I omit the namespace, it just says no such namespace: '<blank>'

12:41 how do I get help in the repl ? I need a description of the rem function

12:41 pendlepants: qubit[01]: (doc rem)

12:46 qubit[01]: so does everyone pretty much use clojure-mode and paraedit ? Having a hard time wrapping my head around ctrl+left/right, I want to wrap something with () but its proving impossible

12:47 madsy: qubit[01]: http://emacswiki.org/emacs/PareditCheatsheet

12:47 Maybe that helps?

12:47 duck1123: use C-right to wrap the current paren around the next form

12:47 oskarth: So, are these just project ideas or are people actually working on them as part of GSoC right now? http://dev.clojure.org/display/community/Google+Summer+of+Code+2012

12:48 seemed to me like just a list of project ideas, but it'd be kind of silly to duplicate someones effort if they are not

12:49 dnolen: oskarth: there are 4 GSoC projects, Typed Clojure, ClojureScript/Lua, Clojure Android & Simple Overtone IDE

12:50 oskarth: dnolen: I see, and that's people who got accepted to work on them? Is there any page with more information on this that you're aware of?

12:51 dnolen: oskarth: not really, some threads on the Clojure and Clojure-dev mailing lists. You can follow the projects on GitHub

12:51 oskarth: dnolen: found a list at http://www.google-melange.com/gsoc/projects/list/google/gsoc2012

12:51 ok, thanks :)

12:51 dnolen: oskarth: yep

12:52 qubit[01]: gah

12:52 so much to learn

12:52 how do I kill the f'n repl because my recurse function wont stop because I cant figure out to use paraedit

12:52 tired of killing emacs

12:53 duck1123: try C-c C-c

12:53 madsy: And if C-C C-c doesn't respond, kill the swank process instead

12:53 dnolen: qubit[01]: you can also try slime-quit-lisp

12:54 qubit[01]: should try learning lisp w/o paraedit ? seems to be more of a hindernace at my early stage of the game

12:54 madsy: qubit[01]: Whatever you feel is better

12:54 duck1123: try using paredit in a source buffer first, then try it in the repl

12:55 madsy: qubit[01]: Why use a tool which is only in the way?

12:55 qubit[01]: Don't be afraid to have your own opinion

12:55 qubit[01]: I dont know im new, it might be that it develops good habits but has a high learning curve -- I'm just going to come back to it

12:56 madsy: qubit[01]: As long as you learn the language in the right order, I'd say it is no ones business what helper tools or editor you use

12:56 It's two separate things

12:56 duck1123: I won't use paredit with slime because it's always submitting when I don't want it to. It's great in a .clj file though

12:58 Gnosis-: Is all thread creation manual in Clojure? this documentation suggests to me that it is, but I am unclear: http://clojure.org/concurrent_programming

12:58 duck1123: Gnosis-: there are some libs that abstract it away (lamina) but it's easy enough manually

12:58 Gnosis-: before reading this, I was under the impression that Clojure programs automatically used all CPU cores efficiently

12:59 ieure: lol

12:59 duck1123: you have things like pmap, that make it easy to multi-core, but it doesn't do it by default

12:59 Gnosis-: ah, okay

13:00 duck1123: in many cases, the overhead of multi-core outweighs the benefit.

13:01 Gnosis-: do pcalls and pmap run all of the function calls in parallel at once, or only a limited number to reduce overhead?

13:01 ieure: Gnosis-, https://github.com/clojure/clojure/blob/d0c380d9809fd242bec688c7134e900f0bbedcac/src/clj/clojure/core.clj#L6194

13:02 Gnosis-: ieure: n+2, got it

13:03 qubit[01]: duck1123: what would be an instance where it is beneficial ?

13:03 uvtc: My impression so far is that you mostly do multithreading using futures and agents. Is this the case?

13:03 ieure: uvtc, For some values of "you."

13:04 duck1123: qubit[01]: If the work you're doing isn't insignificant (ie. inc) then the startup time for the threads isn't as big of an issue

13:04 uvtc: s/you/folks/ ?

13:05 ieure: uvtc, "My impression so far is that you mostly do math using addition and subtraction."

13:05 Use the right tool for the job.

13:05 Personally, lots of the things I do are best served by the innate Runnable-ness of functions.

13:05 That is, (Thread. some-function)

13:05 duck1123: ieure: subtraction? I just add negative numbers

13:07 uvtc: So, are `(Thread. some-function)`, futures, and agents the most-commonly employed means of spreading out work among multiple threads?

13:07 ieure: uvtc, Free yourself from the need to use the "most common" abstraction and focus on using the most appropriate abstraction.

13:08 duck1123: I don't find myself using agents too often anymore, but that may just be me

13:09 uvtc: duck1123, what have you been using instead? Or, in what way has your code changed making them less necessary?

13:10 duck1123: I mostly use futures or the Runnable-ness of functions. Agents are a pain when you have errors and are rarely what I need most of the time. (I'm not collecting the result)

13:11 bhenry: i want to do setTimeout in clojurescript. something tells me it's not as easy as (js/setTimeout (fn …) 1000)

13:12 dnolen: bhenry: it is

13:12 bhenry: coooool

13:15 borkdude: the function executes immediately in himera: (js/setTimeout (fn [] (println "foo")) 10000)

13:16 bhenry: borkdude: that happened to me too

13:16 dnolen: bhenry: borkdude: setTimeout always executes immediately - returning a timer id.

13:17 borkdude: ah of course

13:17 bhenry: can you show me an example that waits n milliseconds before executing the following line?

13:17 borkdude: yup, this works: (js/setTimeout (fn [] (js/alert "foo")) 10000)

13:18 uvtc: duck1123, thanks!

13:18 bhenry: borkdude: what if the fn takes args?

13:19 duck1123: uvtc: if you're looking for options for multi-threaded joy. Give the lamina docs a once-over

13:19 borkdude: bhenry no idea

13:19 oskarth: is there something akin to (browse-url foo) for opening raw html in my default browser?

13:20 bhenry: dnolen: what if the inner function needs to take args?

13:20 duck1123: bhenry: where would the args come from? You could always use a closure

13:20 uvtc: duck1123, Ah, the wiki at https://github.com/ztellman/lamina/wiki . Thanks. I'm not necessarily looking for options; I just want to understand what the most common basic ways are of doing multithreading with Clojure.

13:20 borkdude: bhenry alert is a function, I call it with arg "foo"

13:20 duck1123: oskarth: take a look at clj-webdriver ?

13:21 oskarth: duck1123: thanks, will do

13:21 bhenry: i have a function that calls a remote and changes the dom. i want the function to wait 2 minutes and then call itself with its same args

13:21 borkdude: bhenry call the function from within a (fn [] …)

13:21 bhenry: got it.

13:21 thanks

13:22 TimMc: bhenry: Also see setInterval.

13:25 sjl: ,(apply (fn [& {:keys [a b]}] (+ a b)) (apply concat {:a 1 :b 2}))

13:25 clojurebot: 3

13:25 sjl: is there a more idiomatic way to do that?

13:26 (apply some-fn-taking-kwargs-style-options (apply concat some-map-of-options))

13:26 dnolen: sjl: not really, it's why some people don't like fns that take keywords like that.

13:27 sjl: dnolen: what's the alternative? make the fn take an actual map as a single param?

13:27 dnolen: sjl: I think so.

13:28 sjl: I guess that's not too bad. More typing for users, but explicit is better than implicit.

13:30 TimMc: ~mapply

13:30 clojurebot: You could (defn mapply [f & args] (apply f (apply concat (butlast args) (last args))))

13:34 botter: Why are the shootout.alioth tests for Clojure so unimpressive? Clojure consistently ranks the lowest for memory, and quite low in speed too

13:35 TimMc: botter: because alioth is a lie

13:35 Gnosis-: it looks like there's no clojure.net... :(

13:35 TimMc: ~alioth

13:35 clojurebot: Titim gan ?ir? ort.

13:35 botter: what

13:35 hiredman: clojurebot: why you no utf?

13:35 clojurebot: excusez-moi

13:36 TimMc: botter: 19:09 < technomancy> alioth shootouts are pretty famous for being hugely biased against languages hosted on virtual machines

13:37 dnolen: botter: because people don't work on them enough

13:37 botter: look at test.benchmark on Github, all the benchmarks in there are competitive with Java in space and time

13:38 qubit[01]: anyone use counterclockwise ?

13:38 botter: will do

13:38 qubit[01]: looking for the format file key shortcut

13:40 dnolen: botter: note that test.benchmarks is not representative of the type of the code you should be writing - it just illustrates that perf critical code can be written when you actually need it and it's not much of a hassle. idiomatic Clojure is usually plenty fast enough.

13:40 botter: test.benchmarks links to alioth too

13:41 dnolen: botter: look at the source.

13:41 botter: it just links there to note what the benchmarks are based on.

13:42 botter: ah i see

13:44 Gnosis-: is there a canonical way to do networking in Clojure?

13:44 qubit[01]: Warning: *db* not declared dynamic and thus is not dynamically rebindable, but its name suggests otherwise. Please either indicate ^:dynamic *db* or change the name ... I'

13:44 I'm not sure what its telling me

13:44 amalloy: sjl: it's fine to make your outermost user-facing function take keyword args, but once you get them you should usually treat them as a map from then on

13:44 TimMc: Gnosis-: Binary protocols, http client, http server... which?

13:44 Gnosis-: TimMc: how about an HTTP server

13:45 amalloy: ring

13:45 sjl: amalloy: yeah, in this case I have two functions, foo and bar, both of which are user facing, but foo does most of its work by calling bar

13:45 amalloy: (on top of jetty or tomcat or whatever you want)

13:45 TimMc: Gnosis-: Look at Ring, Compojure, and Noir (in order of increasing batteries-included)

13:45 Gnosis-: okay, thanks

13:45 duck1123: qubit[01]: post-1.3 vars are not dynamic by default. The pattern used to be that you marked dynamics like *this* it's warning you that *db* is not actually dynamic anymore

13:45 qubit[01]: how do I make it dynamic now ?

13:46 nDuff: qubit[01]: declare it with ^:dynamic

13:46 duck1123: (def ^:dynamic *db* ...)

13:46 TimMc: I suppose that warning is ambiguous about where you use ^:dynamic, but it is good enough for a web search.

13:48 sjl: TimMc: Google helpfully doesn't include punctuation in searches, so when you search for "clojure ^:dynamic" you get pages like "Clojure is a dynamic language!"

13:54 tyre771: Struggling with defining a macro that defines a function if someone could take a look https://gist.github.com/3061613

13:55 duck1123: try wrapping the defn and def in a do

13:56 amalloy: your swap! is also going to be wrong

13:58 ieure: tyre771, Consider using reduce instead of an atom.

13:59 Unclear if you want to coordinate these calls, but in the context of that gist, you do not need mutability, only concatenation.

13:59 tyre771: So the backtick doesn't run the code immediately?

13:59 ieure: Oh boy

14:00 tyre771: Yes I don't need it to be mutable, just couldn't figure it out the first time (coming from Ruby, so easing into it)

14:00 amalloy: tyre771: you don't really need a macro at all

14:00 yonatane: How would you design an api that requires a token for every call, like the facebook api? I'd like to be able to define that token once and not passing it as a parameter every time.

14:01 augustl: yonatane: so you'll hardcode the token into your application? As in, your app will only ever use one token, it doesn't change depending on the logged in user etc?

14:01 oh wait, I read that wrong, nvm

14:02 yonatane: in the case of facebook, you have an app identifier which doesn't change, unless you maybe handle multiple apps

14:02 augustl: yonatane: are you making an API where you authenticate with a token?

14:02 s/you authenticate/your users authenticate/

14:02 duck1123: I would write my fns with multiple arities, and if the token isn't provided, it reads it from an external var

14:02 dnolen: tyre771: it's not clear to me that you need a macro here ... why do you think you do? Or are you just trying to understand how they work?

14:02 tyre771: @amalloy I was having an issue with sequencing through the vector of names I want to define

14:03 amalloy: (defn tag-fn [tag-name] (fn [[k v]] (format "%s %s: %s; " (name tag-name) k v))) seems to do everything you were trying to do

14:04 or...maybe you don't use the tag name at all? i don't quite understand how this is supposed to work

14:05 tyre771: @amalloy I have a vector of strings, and I want to define a function whose name is that string, which takes in a hashmap as a parameter and cycles through it's key/value pairs

14:05 so given ["walrus" "bubbles] I would then be able to do (walrus {:a "b" :c "d"})

14:05 dnolen: tyre771: but why you need named functions for this?

14:06 amalloy: but given your definition above, walrus and bubbles would be the exact same function, just with different names

14:06 yonatane: augustl: users authenticate through the app, and you need to identify the app when redirecting to oauth, or decoding a cookie etc.

14:06 tyre771: damnit

14:06 you are so right

14:07 yonatane: augustl: so i have several functions that needs that app-id.

14:07 ieure: tyre771, Write one function, and use defalias to bind it to multiple names, if you merely want the convenience.

14:07 yonatane: in java i'd make an object and be done with it.

14:08 augustl: yonatane: so what exactly are you trying to do? Is it a HTTP server that needs to guard all calls with a check against an authentication token of some kind?

14:08 yonatane: if so, sounds like an appropriate use for Ring middlewares

14:08 tyre771: oh zout nevermind. I need the tag-name in there so (a {:color "blue"}) would return "a { color: blue;} "

14:08 augustl: that is, wrap your main handler in another handler, and don't call your main handler if the request does not authenticate

14:08 tyre771: that's why I tried a macro

14:09 so the beginning string to concatenate onto would be (str ~tag-name "{ ")

14:09 augustl: yonatane: a convention for Ring is to add extra stuff to the request map.

14:10 duck1123: yonatane: just store your key in an external atom, and have your fns read that atom to key the token

14:10 augustl: yonatane: so, you'd call your normal handler with something like (handler (assoc original-request :user (get-user-by-id id)))

14:10 yonatane: not sure if this (writing authentication code for a HTTP API) is what you're doing though :)

14:11 duck1123: I misread the original question

14:11 yonatane: augustl: i'm actually asking this as a general design question. Let's take a database api example, where you have a connection string / database name that you don't want to mention in each query.

14:11 ipostelnik: tyre771, you can do (defn tag-fn [name & attrs] (str name "{" ..... partition attrs ... "}")) and then (def a (partial tag-fn "a")), etc....

14:11 ieure: tyre771, You still don't need macros. Write one function: (defn tag-fn [tag-name & props] …)

14:11 Yeah.

14:11 What ipostelnik said.

14:11 yonatane: duck1123: it might be what i'm looking for. i'm not sure.

14:12 augustl: yonatane: (def my-db (set-up-db {:dbname "foo" :password "bar"})) you mean?

14:12 duck1123: yonatane: the advice still applies, I just had the wrong use case in my head

14:12 yonatane: augustl: what does set-up-db returns?

14:12 augustl: yonatane: it would be useful if you could show us a concrete example of code you don't like

14:12 ipostelnik: tyre771, better yet look at hiccup

14:12 TimMc: sjl: You can still do phrase searches.

14:13 augustl: yonatane: a function perhaps for querying perhaps

14:13 so, (my-db "foo") would perform the query for foo

14:14 dnolen: tyre771: I suspect you want to make some kind of DSL here ... other approach would be to take the hiccup approach and just write your rules as data structures [:a {:color "blue}]

14:14 duck1123: you could look at how korma or any of the other batteries-included db libs store their connections

14:15 dnolen: tyre771: then they can be easily manipulated with the usually Clojure functions, with your approach not possible.

14:15 s/usually/usual

14:15 tyre771: @dnolen yeah that is what I'm trying to do. Why is my approach not possible? I can do it in 8 lines of Ruby

14:16 yonatane: ok, thanks, i'll read some source

14:16 augustl: yonatane: got a sample of some "bad" code?

14:17 yonatane: i have my own embarrassing code

14:17 augustl: yonatane: in general, "factory" functions is something I use a lot

14:18 tyre771: @dnolen or is it just not the Clojure way of doing it? I'd like to learn the style of the language as well as getting it done

14:18 amalloy: tyre771: he's saying with your approach it's not easy to manipulate the output of your functions, because you go straight from opaque function calls to a mess of strings

14:18 dnolen: tyre771: it is possible. I but then you have a brittle DSL that no one will want to use.

14:18 augustl: yonatane: for my mongodb "models", for example, I have something like (defn insert (make-inserter "users" validator-fn data-processing-fn)), that returns a new function with an API that takes a map and returns true or a map with validation errors

14:18 yonatane: augustl: what if you need several functions, and not just one? or are we in that point where we must talk about concrete example?

14:18 amalloy: if you do what hiccup does (for example), and represent your intent with data structures like [:a {:name "foo" :href "bar"}], then it's easy to manipulate those in some way before transforming them to strings

14:19 augustl: yonatane: I'm thinking that you could return a map of functions. Not sure if that's idiomatic though.

14:19 yonatane: augustl: yeah, that's kinda OO

14:20 dnolen: tyre771: look at how Hiccup works for ideas.

14:20 tyre771: @amalloy how is that different then (a {color: "blue" :overflow "scroll"}), because it is function calls?

14:20 yonatane: augustl: maybe something like (with-connection ....)

14:20 augustl: yonatane: you could also have a function that defines other functions in the namespace from where the original function was called afaik

14:21 dnolen: tyre771: it's function call so it can no longer be manipulated as data.

14:21 amalloy: because what you just described evaluates to a string, which i can't do anything useful with

14:21 augustl: yonatane: actually, you can't do that.. But a macro could :)

14:21 amalloy: whereas if you gave me that data structure, i could still add classes to it, or query what classes are present

14:21 augustl: yonatane: so, it could expand (create-model "users") into a bunch of calls to "def" that used "users" as a config for which table to query, for example

14:22 yonatane: that way, you get a factory to create a full set of functions in a namespace

14:22 tyre771: then how does Hiccup go to HTML? Wouldn't it have to put that to a string at somepoint?

14:22 amalloy: yes

14:22 you're just doing it too soon

14:22 duck1123: there's a single fn that'll walk the entire tree and emit html

14:22 dnolen: tyre771: (assoc-in rules [:p :div :color] "red") is pretty nice. Can't do that with your representation.

14:22 tyre771: okay, I see what you mean. I'm sorry I"m not trying to be obtuse

14:23 yonatane: augustl: could it work for multiple configs?

14:23 augustl: yonatane: in my code, I don't do that, though. My "model" looks something like this. http://pastie.org/4211560

14:23 tyre771: @dnolen I see, I hadn't gotten to multiple rules but it would have been a nightmare

14:23 augustl: yonatane: not sure what you mean by configs

14:24 yonatane: something like make-insert, but with the ability to change which table it worked on run-time?

14:24 yonatane: augustl: oh, so you have a namespace for users. Can a macro create a namespace?

14:24 augustl: yes

14:24 augustl: yonatane: yes, a macro can expand into any kind of code

14:25 yonatane: trying to come up with an example where that would make sense ;)

14:25 duck1123: augustl: do you have the rest of your code available anywhere? We're doing similar things and I'd like to compare/contrast

14:25 tyre771: okay I will begin again. So what I need is instead that just goes through data-structures and then turns them into strings

14:25 yonatane: augustl: it might make sense when you write a client, no?

14:26 duck1123: yonatane: here's my nastiest function generating macro https://github.com/duck1123/ciste/blob/master/ciste-core/src/ciste/sections.clj#L65

14:27 augustl: duck1123: for the mongodb factory?

14:28 duck1123: or the function generator in namespace thingie? Never written that, just know clj-record does it. https://github.com/duelinmarkers/clj-record/blob/master/src/clj_record/core.clj#L193

14:28 duck1123: augustl: that link isn't for mongo, but my question to you was

14:30 you can't def into a different namespace by normal means. (was recently bitten by that)

14:31 yonatane: can you temporarily switch to the different namespace and then do it?

14:31 augustl: yonatane: http://pastie.org/4211604

14:31 another example of something that might be relevant

14:32 a namespace has a pool of objects, other namespaces calls a factory function to get objects from that pool

14:32 the reason I call this objects is that I took it from some code that instantiates Java objects ;) For "native" Clojure it would probably be a pool of functions or something else

14:33 duck1123: I've written my own little "orm" on top of monger, if that's what you mean :)

14:34 duck1123: augustl: it was, I've been doing similar things with monger lately and looking for prior art

14:34 augustl: duck1123: I did the same.. Didn't find much

14:34 ended up writing my own code for creating data validation functions, for example

14:37 antares_: augustl: oh nice. Is it open source?

14:37 augustl: have you seen validateur for validation?

14:37 duck1123: That's what I've been using

14:38 augustl: antares_: yeah I saw it, I wasn't able to make much sense out of it

14:38 its map of error messages have sets for keys

14:38 and it assumes all errors are for specific attributes

14:38 duck1123: https://github.com/duck1123/jiksnu/blob/16d8df7753a672c655df3ee8ca9beab12861e046/src/jiksnu/model/activity.clj#L132

14:38 augustl: ..it seems

14:39 antares_: augustl: I will document it next week

14:40 it definitely deserves a guide of its own, after almost a year of being neglected

14:40 augustl: :D

14:42 cljs_newb_29582: I wonder how many 17" mbps one needs to order

14:42 to convince apple to remake them again

14:42 * ToxicFrog pokes lein with a stick

14:45 madsy: Functions used with swap! must be without side effects. So in ClojureScript, what is the idiomatic way to update an atom with the return value from a mutable javascript function?

14:46 For example when using WebGL: (swap! vertexShader (. gl creatShader)) could create N new shaders while swap retries.

14:46 But calling a bunch of those functions in a let seems ugly too

14:49 raek: mattmoss: (let [shader (. gl creatShader)] (reset! vertexShader shader))

14:49 madsy: ^

14:49 mattmoss: sorry, wrong nick... :)

14:50 madsy: raek: Yup, I guess I would have to use a big let

14:50 raek: madsy: does (. gl creatShader) eval to a function you want to apply with the old value of vertexShader, or does it eval to a new value you want to replace the old one with?

14:51 madsy: raek: (. gl createShader (.-VERTEX_SHADER gl)) returns a handle/value for a shader. So I want to overwrite the old value of vertexShader

14:52 In the WebGL spec, the handle is just a boring integer :)

14:53 mattmoss: heh

14:54 raek: so if we pretend that shaders are numbers for a second, you want something like (let [x (rand-int)] (swap! a x)) rather than (swap! a inc) ?

14:54 ToxicFrog: Huh. If I ask lein for a library, it creates a Clojure 1.4 project with some Github configuration set up.

14:54 raek: i.e. you don't use the old value that was in the atom for anything

14:54 ToxicFrog: If I ask it for an app, it creates a 1.3 project with no git configuration.

14:54 madsy: raek: Yep, exactly

14:54 ToxicFrog: Oh wait, no, there is some git.

14:55 raek: madsy: ok, then let and reset! is the way to go :)

14:55 madsy: thanks

14:57 raek: erhm, the rand-int example should of course use reset!, not swap!

14:57 ToxicFrog: Ok, actual Lein question: I have a project that basically consists of three apps (a client, a server, and an editor) and one library used by all three.

14:57 Should these be four separate Lein projects?

15:01 raek: ToxicFrog: personally, I believe so. at least eventually. it might be more convenient to develop everything in one project at first before you have something fairly complete and working

15:02 duck1123: there's lein-sub, but it has issues with lein2 IIRC

15:02 raek: you can split off the projects as they get mature

15:04 if the client/server/editor is tiny, it could perhaps be included in the library as an example of usage until it gets a life on its own

15:04 ToxicFrog: you can also use the "checkouts" lein feature to work on two projects in parallel

15:05 madsy: raek: Using screen sounds better ;-)

15:06 raek: madsy: huh? better than what?

15:06 ToxicFrog: raek: they're not tiny; the library is pretty much a (de)serializer for a custom format, the apps to the actual heavy lifting.

15:06 *do.

15:06 I don't see anything about checkouts in 'lein help'

15:06 raek: ToxicFrog: do they share a lot code, except for the library?

15:07 ToxicFrog: No.

15:07 (if they did, that code would be in the library)

15:08 augustl: why do some multimethods check for "APersistentVector" instead of just PersistentVector?

15:08 is APersistentVector a protocol perhaps?

15:08 amalloy: ugh, they do? if they do that seems bad

15:08 raek: ToxicFrog: it's not a task so it's documented elsewhere: https://github.com/technomancy/leiningen/blob/master/doc/FAQ.md

15:09 augustl: amalloy: I've seen it a lot

15:09 raek: fifth bullet point

15:09 madsy: raek: Rather than handling multiple projects with some leiningen plugin, just use screen and work with two lein instances

15:09 amalloy: augustl: by people who know what they're doing? evidence/link?

15:09 checking for IPersistentVector would be righteous and good; APersistentVector is likely to deserve a beating

15:10 augustl: amalloy: https://github.com/weavejester/compojure/blob/master/src/compojure/response.clj has APersistentMap

15:10 Cheiron: Hi, what is the best way to provide an extra optional parameter to a function declaration?

15:10 only one extra optional parameter

15:11 amalloy: augustl: yeah, send him a pull request, that's wrong

15:11 antares_: Cheiron: probably using two arities

15:11 augustl: amalloy: is there a document I should read about this? :)

15:11 ToxicFrog: Hmm. Right. The apps would have to list the library as a dep.

15:11 augustl: Cheiron: I'd use two arities too

15:11 raek: madsy: with checkouts you only add one symlink and changes in both sources can be seen from a repl in the dependent project

15:11 Cheiron: antares_: augustl Oh, true

15:11 ToxicFrog: (at the moment, it's a Scala project with a bunch of submodules, with an IDEA configuration that just generates a jar for each module)

15:11 stuartsierra: In the Clojure Java sources, "IFoo" is usually the interface, "AFoo" is an abstract base class for internal use, and "Foo" is the concrete type.

15:11 antares_: Cheiron: like here: https://github.com/michaelklishin/monger/blob/master/src/clojure/monger/collection.clj#L91-126

15:11 madsy: raek: aha

15:11 amalloy: meh. AFoo is basically always bad; IFoo is always good; Foo is often acceptable

15:12 stuartsierra: amalloy: yes

15:12 yonatane: is there a lein jenkins plugin yet?

15:12 Cheiron: how to represent bitmap data structure http://en.wikipedia.org/wiki/Bit_array in Clojure?

15:12 antares_: if Foo is guaranteed to implement IFoo, then there is no reason to not use IFoo

15:13 duck1123: There's a Lein Jenkins, but he's just some guy

15:13 antares_: Cheiron: there are Java implementations of bit array

15:13 yonatane: :)

15:13 raek: madsy: but for two unrelated projects two instances is perfectly fine, of course

15:13 amalloy: Cheiron: bitmaps are all in your head. the number 17 is a bitmap if you say it is

15:13 stuartsierra: Most type-predicates in clojure.core look like (defn foo? [x] (instance? IFoo x))

15:13 amalloy: antares_: that's true if you're checking inheritance, but not if you're, for example, constructing an instance

15:14 antares_: amalloy: true, I was thinking about implementing protocols for core types

15:14 ToxicFrog: Looking at the builtin help, lein is really giving off the vibe that it's mean for developing clojure libraries first and foremost

15:14 jweiss: "No matching method found: foo for class bar". is there a reason it doesn't print the argument types that didn't match?

15:14 raek: duck1123: hah! you beat me to it... :-) https://twitter.com/technomancy/status/203226678493851649

15:15 jweiss: ,(.substring :foo)

15:15 clojurebot: #<IllegalArgumentException java.lang.IllegalArgumentException: No matching field found: substring for class clojure.lang.Keyword>

15:16 jweiss: hm, /me not sure what the easiest way to throw that exception is

15:16 Gnosis-: (throw)?

15:16 clojurebot: dnolen: well feel free to throw some more in and send me a pull request. The format is pretty general

15:16 jweiss: ,(.substring "foo" :bar)

15:16 clojurebot: #<ClassCastException java.lang.ClassCastException: clojure.lang.Keyword cannot be cast to java.lang.Number>

15:17 jweiss: Gnosis-: i meant "No matching method found"

15:17 Gnosis-: oh

15:19 jweiss: ,(.lastIndexOf "asd" :foo)

15:19 clojurebot: #<IllegalArgumentException java.lang.IllegalArgumentException: No matching method found: lastIndexOf for class java.lang.String>

15:19 jweiss: there we go

15:20 can't it say "No matching method found: lastIndexOf(clojure.lang.Keyword) for class java.lang.String"?

15:20 Cheiron: this is considered a good use of idiomatic clojure? http://pastie.org/4211830

15:22 raek: Cheiron: (let [foo (make-foo)] (.method foo ...) (.method foo ...) foo) can be abbreviated as (doto (make-foo) (.method ...) (.method ...))

15:23 Cheiron: oh very true

15:23 since the performance is an issue. do you suggest to use type hints?

15:25 because I need to save to Cassandra as fast as possible

15:26 ieure: Cheiron, Pop quiz: Which is slower? a) Reflection on a Java object b) Network latency

15:27 Cheiron: b)

15:27 ieure: Congratulations.

15:28 raek: reflection and network latency affect throughput differently, through

15:28 * duck1123 wants network hints now

15:29 Cheiron: regarding my snippet, did I make a good use of function arity?

15:31 uvtc: I have the same question as Cheiron. I'd written a crude little benchmark script in Python, then rewrote in Clojure to compare the two. The Clojure version is at https://gist.github.com/3062265 . Anything in there leap out as non-idiomatic?

15:31 Incidentally, for a large generated sample, I found the Clojure version to run in about half the time as the Python version.

15:33 S11001001: uvtc: just non-use of #() syntax for lambdas

15:33 you may also find extract-biggish-nums clearer if you either put everything in for, or use ->> to chain your seq ops

15:34 uvtc: S11001001, I wasn't sure what to do with those nil's that re-find returns if there's no match.

15:35 S11001001: if you switch to ->>, you could use keep instead of map-followed-by-filter

15:35 uvtc: So I used filter, but thought maybe could've used something inside the `for` to do it...

15:35 duck1123: if you don't need to keep false, you could (filter identity ...)

15:36 S11001001: I think you can put all the ops there in the for, but I hate for so wouldn't know how to do it, and you don't get `keep' with for

15:37 ieure: Cheiron, Look at the doto macro; it'll clean that code up a bit.

15:37 uvtc: S11001001, Ah, `keep`. Thanks.

15:37 duck1123, Oh, I see. That works nicely too (filter identity). Thanks.

15:38 Cheiron: ieure: I'm refactoring to use doto

15:38 S11001001: uvtc: be warned, filter identity is not quite keep

15:38 ieure: uvtc, Yeah; same as Python's filter(None, seq)

15:38 jkkramer: (for [st li :let [x (re-find #"[1-9]\d{2,}" st)] :when x] (Long/parseLong x)) is one way. there are many

15:38 uvtc: S11001001, gotcha.

15:40 ToxicFrog: Is there a way to :use in (ns) that renames some of the members being used? I thought :refer would be what I want, but (ns) doesn't support :refer, just :refer-clojure. Is there another way, or do I need to (refer) separately after the (ns)?

15:41 duck1123: I'd say that keep isn't quite (filter identity) all depends on what you want

15:41 raek: ToxicFrog: (ns foo (:use [some-ns :rename {before after}]))

15:42 uvtc: ieure, Ah, yes. I'd previously used a list comprehension (plus an "if" at the end of it) for those sorts of things.

15:42 raek: ToxicFrog: use accepts the same options as both require and refer (since it's a combination of those two)

15:43 uvtc: ieure, (in Python, I mean.)

15:43 ToxicFrog: Aah, I missed that note in the docs

15:43 Sorry

15:43 clojurebot: It's greek to me.

15:43 mattmoss: O_o

15:43 Gnosis-: I looked at the source code for keep, and it doesn't use loop/refer. Instead, it calls keep. Wouldn't this stack consumption be a problem?

15:44 s/refer/recur/

15:44 dnolen: Gnosis-: lazy sequences

15:45 Gnosis-: dnolen: I still don't understand... does this mean the stack is not consumed?

15:45 dnolen: Gnosis-: stack is not consumed, http://clojure.org/sequences

15:45 qubit[01]: Thinking about working through this https://github.com/functional-koans/clojure-koans to help me learn, anyone done these ?

15:45 uvtc: jkkramer, thanks --- didn't know about using `:let [...]` inside a `for`. :)

15:45 Gnosis-: dnolen: okay, I'll read that

15:46 amalloy: there's nothing non-idiomatic about using (fn [x] (inc x)) instead of #(inc %)

15:46 raek: Gnosis-: the keep function returns when it reaches lazy-seq

15:46 jkkramer: uvtc: you're also not extracting all the 3+ digit strings. e.g. in a string like "a123b456cd", you only get 123

15:47 Gnosis-: raek: ahhh

15:47 jkkramer: ,(let [strs ["ab19da4890" "a123b456" "abcdefgh"]] (map #(Long/parseLong %) (mapcat #(re-seq #"[1-9]\d{2,}" %) strs)))

15:47 clojurebot: (4890 123 456)

15:47 jkkramer: utvc: ^

15:47 raek: later, when the object that the lazy-seq call returned is used as a seq, the body will be evaluated

15:47 amalloy: though i agree that all of the lamdbas in uvtc's code would be better as a for-comprehension

15:47 uvtc: jkkramer, Yeah, guilty. :) I just wanted something to chew on strings so I could get a rough idea of how fast it ran.

15:48 amalloy, do you mean replace the `(fn ...)`'s with `#(...)`'s? Or are you talking about something else?

15:49 amalloy: uvtc: S11001001 was telling you to replace them all, i'm saying that that's rubbish

15:49 (and further that in this particular program you really don't need either)

15:52 uvtc: amalloy, personally, I find the `(fn ...)` a bit easier to read than the `#(...)`, and figured it was mostly personal preference. However, I don't see what you mean by "don't really need either". Are you saying that there's places where you could replace a `(fn ...)` ("lambda"?) with a `(for ...)` ("for-comprehension")?

15:52 amalloy: uvtc: yes, in your code i would replace all of your sequence operations with for-comprehensions

15:52 eg, in the comment i just made

15:53 uvtc: Oh, you commented on the gist. Thanks.

15:53 amalloy, ^^

15:57 yonatane: Damn. I hate having options. http://joxa.org/

15:59 S11001001: amalloy: #() aren't always appropriate, but usual clojure code features a mixture of fns and #()s

16:00 amalloy: of course

16:01 S11001001: am happy to discuss "how can I make my code fit S11001001's idiosyncratic standards" if people are interested in that though :)

16:02 I would think not, though

16:03 uvtc: amalloy, thanks for the comment. Your solution is nice, but I'm trying to figure out why `(Long/parseLong match)` doesn't fail when re-seq doesn't find any digits. In that case, `match` would be nil, and the call to Long/parseLong should throw an exception...

16:03 amalloy: no, re-seq returns a sequence, possibly of length zero, and then match iterates through that sequence

16:03 duck1123: Someone needs to write a lein plugin that'll send code to S11001001 and then block til he responds

16:04 amalloy: lein cloud-compile

16:04 uvtc: amalloy, ohhhh. Of course. Thanks!

16:04 S11001001: duck1123: I have got second half right here: (dorun (repeatedly (constantly 42)))

16:06 uvtc: amalloy, Wait. re-seq seems to be returning nil here instead of an empty sequence:

16:07 ,(re-seq #"[1-9]\d{2,}" "aaaaabbbbbbcccc")

16:07 clojurebot: nil

16:07 amalloy: so?

16:07 raek: nil is the empty sequence. () is the empty persistent list

16:08 amalloy: uhhhhh, i'm not sure i'd go that far. nil and () are both empty in a sequential context

16:08 but nil isn't the empty sequence, it represents nothing

16:08 uvtc: amalloy, so, in the for-comprehension you noted, `s` would be set to the string, and `match` would be set to what `re-seq` returned for that call. Which is nil.

16:08 amalloy: no

16:08 match iterates over what re-seq returned

16:08 which is nil

16:08 therefore, it iterates over no entries, and does nothing

16:09 uvtc: amalloy, Ah.

16:10 It's not getting set to the return value, it's iterating over what's returned. Ok. Thanks again. :)

16:11 ,(for [i (range 3) j nil] (str i j))

16:11 clojurebot: ()

16:11 uvtc: as expected, since there's nothing for j to iterate over.

16:12 ,(for [i (range 3) j [nil]] (str i j))

16:12 clojurebot: ("0" "1" "2")

16:55 amalloy: $mail dsantiago i did a little benchmarking of how reducers compare to lazy sequences as you layer on more transformers - not a pretty graph or anything, but my repl session is at https://gist.github.com/3062615 - i take a sequence of size len, wrap num-layers instances of (map inc) or (r/map inc) over it, and then reduce + (i also included fold for comparison)

16:55 lazybot: Message saved.

16:57 nDuff: I'm seeing cljs.core.PersistentHashSet.fromArray undefined from the ClojureScript REPL

16:57 such that the reader can't deal with, for instance, #{:t}

16:58 * nDuff pauses and blinks -- he's not sure if that really properly classifies as a reader issue.

16:59 nDuff: ...ooh. Running an old lein-cljsbuild, thus an old cljs

17:00 ...okay, fixed in current releases.

17:02 dnolen: amalloy: I'm curious what those numbers look like with primitive taking / returning fns

17:03 "will look like"

17:03 amalloy: dnolen: is that possible currently? i think reduce and fold still have to coerce the accumulator to an object

17:04 dnolen: amalloy: yes, "will look like" :)

17:04 amalloy: does rich have plans for making it possible, even? you seem to be suggesting he does, but i'm not sure how that would work

17:05 dnolen: amalloy: the way he's talked about suggests it's not outside the realm of possibility

17:06 amalloy: well, you could find out what the performance "would be" like for reduce, if not fold, simply by writing it as a loop/recur with (inc (inc (inc (inc x))))

17:09 dnolen: amalloy: hmm what do you mean by "coerce the accumulator to an object"?

17:10 amalloy: dnolen: well, the reducer source (eg, the thing that knows how to reduce a vector) doesn't know that your f takes primitives

17:10 dnolen: amalloy: why does it need to know?

17:11 amalloy: at some point it has to call (f acc new-val), and that's compiled using f.invoke(Object, Object)

17:11 oskarth: if I define a function called foo, how do I get the string foo in another ns by using the function as an argument?

17:11 amalloy: and it has to keep a local copy of your accumulator value in its loop/recur, which will necessarily be an Object reference

17:11 hiredman: amalloy: in theory it could reflect on f and figure it out

17:12 amalloy: hiredman: agreed. but it won't have primitive ints in scope anyway

17:12 oskarth: so I have a fn "#<views$index clj_pages.views$index@2cdb03a1>" and want to reliably get "index" by using something like (CUSTOMstr index)

17:12 duck1123`: oskarth: functions don't know their names. If you need to get the name, pass around vars

17:12 sirsublime: sup peepz

17:13 amalloy: duck1123`: more like: functions don't have names; vars are named places to store functions

17:13 sirsublime: A question about defrecord here. Easy stuff.

17:13 Say I do (defrecord Point [x y])

17:13 oskarth: right, but the information is in the var, isn't it?

17:13 sirsublime: Then I can create a point using (Point. 1 2)

17:14 nDuff: Hmm.

17:14 sirsublime: AFAIK, (defrecord...) also creates a (->Point ...) constructor.

17:14 * nDuff is getting spurious wrong-argument-count compile-time warnings from cljs on variadic functions.

17:14 oskarth: like (:name (meta (var index))) sort of

17:14 sirsublime: But when I try to do (->Point 1 2) I get an exception. Like, in plan repl. Any ideas?

17:14 What am I doing wrong?

17:15 dnolen: amalloy: hmm still don't follow ... line number?

17:17 amalloy: dnolen: i think rich has moved stuff around since last time i looked at reducers - having trouble finding a relevant line

17:18 dnolen: line 94 of core/protocols.clj

17:19 each reducer "source" needs to know how to reduce itself, so it has a loop/recur implementing reduce. and that loop needs a local slot to hold your accumulator; that slot is an Object because it has to be general

17:22 perhaps reduce could start off by reflecting on your function, seeing if its first argument and return value are both the same primitive type, and then switching tracks to a specialized loop/recur?

17:23 mattmoss: (foo [1 2 3] [:a :b :c]) => [[1 :a] [2 :b] [3 :c]]

17:23 amalloy: ~zip

17:23 clojurebot: zip is not necessary in clojure, because map can walk over multiple sequences, acting as a zipWith. For example, (map list '(1 2 3) '(a b c)) yields ((1 a) (2 b) (3 c))

17:23 mattmoss: What is foo? Am I missing a basic library func?

17:23 Ah.

17:24 dnolen: amalloy: that's an internal reduce for a generic type, I'm assuming a more specific internal reduce will be macrofied into reality for primitive holding collections.

17:24 generic chunkable collection I mean, not generic type

17:25 amalloy: dnolen: maybe. but i think in general you won't have a primitive-holding collection; you'll have some source that generates primitives, eg (repeat 4.5)

17:26 or perhaps you'll have (reduce + (map count coll)), where coll doesn't store primitives, but the ints coming out and being added up could be primitive longs

17:26 dnolen: amalloy: ? people will want to create vectors doubles / long

17:27 amalloy: sure! sometimes they will. but when you reduce over those, your accumulator won't necessarily be a double or a long

17:28 so you can't make that things implementation of reduce assume, say, a double accumulator

17:28 it has to inspect the function you gave it somehow, and special-case its loop/recur, just like any other collection type would have to

17:30 dnolen: amalloy: oh sure, yes ... but my earlier point stands - seems entirely doable :)

17:30 amalloy: yes, between your suggestions and hiredman's it's probably possible

17:30 nDuff: Is there a mechanism to disable warnings in cljsc?

17:30 (err, _specific_ warnings known to be false, that is)?

17:31 dnolen: nDuff: if you're getting false positives that's a bug

17:33 emezeske: nDuff: I use variadic functions a lot without any spurious warnings; are you on cljsbuild 0.2.4 (clojurescript 0.0-1443)?

17:42 nDuff: emezeske: yes -- just moved to it a few minutes ago.

17:43 dnolen / emezeske: It's not winnowed down to a standalone reproducer yet, but my code and the error are at https://gist.github.com/28671a8faefeb1451c4b

17:46 emezeske: nDuff: Interesting... I only have one kwargs-style function in my project, but it's not emitting such a warning

17:46 dnolen: nDuff: hmmm there might be a bug around variadic fns, please make a ticket w/ a minimal case - sounds like an easy one to fix.

18:13 augustl: anyone happen to know if there's an API to list all the collections of a db with the monger mongodb library?

18:17 arohner: augustl: I dont know about monger, but congo definitely has that

18:17 so it's possible

18:17 Raynes: augustl: I don't see a way to, but I'd open an issue for it because the java driver has a getCollectionNames method.

18:18 Also, if you need it right now, you can just call that method yourself.

18:19 Something like (.getCollectionNames monger.core/*mongodb-database*) should work, I think,.

18:19 Don't hold me to it though.

18:20 augustl: Raynes: (monger.core/command {:collStats "system.namespaces"}) seems to be working

18:20 that's what the nodejs driver does

18:20 Raynes: Works for me.

18:23 augustl: how does monger compare to congo?

18:24 yonatane: what is a use case for redefining values or functions, other than magically decorating functions?

18:25 (def)ing an existing symbol knowingly

18:26 amalloy: trying things out at the repl

18:28 yonatane: so def is not something you'll see in a function

18:28 amalloy: (almost) never

18:29 Raynes: augustl: They're both totally viable. monger is a more all-in-a-box solution.

18:29 yonatane: where would you see it? in an interactive debugger?

18:29 Raynes: augustl: Michael moved my website, refheap, to monger at my request recently and I'm pleased because it comes with a session store and mongo URI parsing.

18:31 amalloy: yeah, stuff like that

18:33 pbostrom: hey Raynes, if I try to run defrecord in clojail, like (defrecord Point [x y]), I get "java.lang.ClassNotFoundException: clojure.core.Point", I'm guessing the sandbox doesn't handle this?

18:33 augustl: how do I work with a LinkedHashSet in clojure? Dong a "doseq" on it seems to yield characters, not the whole contents

18:34 gnarmis: Hey, has anyone worked with the document categorizer in clj-opennlp?

18:34 I've made a model…but was wondering how to persist it so I don't have to retrain every time

18:34 augustl: http://pastie.org/4212669 to be specific ;)

18:38 ToxicFrog: Is it possible to configure 'lein deploy' or similar to upload to github?

18:40 augustl: Raynes: how do I work with the results og .getCollectionNames?

18:40 of*

18:40 yonatane: augustl: are you destructuring that coll over there?

18:40 augustl: am I? :)

18:41 ah, I am

18:48 fenton: I'm a little confused about how to modify (or create a new copy of) a complex data structure like a list of list of list of lists... Basically I have an arbitrarily complex tree, where I'd want to insert/remove, etc... nodes in the tree... Is there any general direction someone can suggest?

18:49 Should I look to modify the original data structure inside a transaction or something (agents?), am i looking to return a completely new tree...if so isn't it a tad difficult to reconstruct the whole tree?

18:51 yonatane: augustl: why not (doseq [coll (.getColl...

18:52 amalloy: fenton: it's certainly possible with lists, but it's certainly faster and easier with vectors or maps

18:53 &(let [data [[[1 2 3] [4 5 6]] [[7 8 9] [10 11 12]]]] (update-in data [1 0 2] inc))

18:53 lazybot: ⇒ [[[1 2 3] [4 5 6]] [[7 8 10] [10 11 12]]]

18:53 gnarmis: ah nvm, I solved my issue. Forgot I already had it deserialized.

18:54 fenton: amalloy: lazybot: thanks guys, let me mull those over...

19:03 ToxicFrog: How do I use (doc) to examine the docstrings of a third-party library like parsatron?

19:03 nvm, found it

19:04 Wasn't (use)ing properly

19:04 augustl: yonatane: you are right, I was not using doseq correctly

19:27 is it sensible to use metadata to annotate a HTTP request handler to "skip authentication"?

19:29 amalloy: augustl: it's plausible, but it would be better to just not wrap that handler with your authentication middleware to begin with

19:30 aperiodic: fenton1: if you're working with tree structures, you should take a gander at zippers http://clojure.github.com/clojure/clojure.zip-api.html

19:30 amalloy: zippers are really cool, but i think they get latched onto way too quickly by people who think "i'm working with a tree, so i need to figure out this zipper stuff"

19:31 augustl: amalloy: yeah that makes sense actually

19:31 also, the auth middleware gets the same handler at all times, so metadata can't really be used for this purpose anyway

19:34 amalloy: we all work with trees all the time, and zippers are only necessary/useful for a very small subsegment of tree-related tasks

19:35 aperiodic: yeah, i usually use a bunch of filter, remove, and map fns over zippers (that differentiate between branches/leaves), but sometimes it's useful to dip back down into clojure.zip

19:38 you'll note i said 'take a gander at', not 'use' ;)

20:07 augustl: is there a way of writin this that doesn't require nesting if/else statements? http://pastie.org/4213040

20:08 in imperative languages, I'd write a list of if statements and "return", then my main logic at the bottom

20:08 predicates, so to speak

20:08 nullptr: http://clojuredocs.org/clojure_core/clojure.core/if-let

20:08 http://clojuredocs.org/clojure_core/clojure.core/cond

20:09 augustl: nullptr: ah, thanks

20:14 * ToxicFrog stabs parsatron

20:22 ToxicFrog: rgrgrgr

20:23 The only reason I haven't rolled my own recursive descent parser already is that writing error handling is always a pain in the ass

20:23 But I'm seriously considering it now

20:24 ohpauleez: ToxicFrog: What are you parsing?

20:30 augustl: a ring handler can return nil, right?

20:31 weavejester: augustl: In Compojure it can, but if it returns nil to an adapter it'll throw an exception.

20:31 augustl: weavejester: ah, I see

20:32 weavejester: my actual problem is that I have 3 handlers that I want to make into one

20:33 I have one handler with a set of routes (made with compojure) that will 401 if not authenticated, one handler, also with routes, that processes authentications, and one catch-all 404 handler

20:33 trying to wrap my head around it :)

20:35 hmm, that's what compojure.core/routes actually does, it seems, I'll just use that

20:36 weavejester: augustl: routes is usually the function used to combine handlers. The request cascades to each one until a non-nil response is found.

20:40 ToxicFrog: ohpauleez: Kerbal Space Program Saved Flight State files

20:40 Basically a sequence of // C++ style comments, key = value properties, and TYPE { ... } nested states.

20:40 So, pretty simple

20:41 However, I was hoping to be able to easily put something together using an existing parsing library

20:44 ohpauleez: did any of that get through?

20:45 Hmm. This is a terrible idea, but I wonder if I could use string.replace to rewrite it into valid clojure and then parse it.

20:46 mthvedt: toxicfrog: i assume you've tried fnparse

20:46 sorry not fnparse

20:46 clojurebot: excusez-moi

20:46 mthvedt: uh

20:46 ToxicFrog: Last I checked fnparse was unmaintained and did not work in 1.4

20:46 mthvedt: whats it called

20:46 yes, fnparse

20:46 it doesn't work?

20:47 ToxicFrog: Not according to its github or the people I asked for parser recommendations in here earlier this week

20:47 mthvedt: and you haven't found anything else?

20:47 arohner: IMO, write your own

20:48 fnparse, even when it did work, was an order of magnitude slower than a hand written parser

20:49 ohpauleez: ToxicFrog: Anyway you can just modify one of the ANTLR grammars?

20:50 Otherwise, just write a simple string parser, and push it all into a map

20:50 ToxicFrog: mthvedt: Oh, a few. Lots are unmaintained, there was one I can't remember the name of that was absurdly heavyweight for what I wanted.

20:50 Parsatron is the most recent one I've tried, but it StackOverflows even on very simple grammars on inputs of a few dozen kB.

20:51 hiredman: parsley

20:51 mthvedt: the state of parsers in clojure sounds awful

20:51 arohner: I'm not sure that parsing libraries are ever a good idea

20:51 ToxicFrog: hiredman: yes! That's the one I couldn't remember the name of.

20:51 ohpauleez: arohner: +1

20:51 ToxicFrog: A decent parser combinator library can save you a lot of time and automatically gets you high-quality parse error reporting and whatnot

20:52 I've had a great time with scala.util.parsing.combinator, for example

20:53 ohpauleez: ToxicFrog: port it and contribute it as a contrib lib? :)

20:53 mthvedt: toxicfrog: what was the issue with parsley?

20:53 ToxicFrog: I'm tempted.

20:53 mthvedt: it's designed for high-speed incremental (re)parsing for things like interactive syntax hilighting, and has a lot of extra scaffolding to support that.

20:54 mthvedt: toxicfrog: and you wanted something more lightweight?

20:54 ToxicFrog: It also guarantees a complete parse tree for any input, which means error handling is more work because I then need to walk the tree and find out which parts went wrong, where, and why.

20:54 Yes.

20:55 mthvedt: toxicfrog: i'm interested in your input because i've been working on a parser library with emphasis on ease of use… it's super-pre-alpha right now, though

20:56 ToxicFrog: Published anywhere?

20:56 ohpauleez: If the blocks are uniform, and you can split them all on a character (say, if they're key-value pairs), I'd just use string functions and forget about parsing

20:56 mthvedt: it's on github...

20:56 ToxicFrog: named?

20:57 mthvedt: https://github.com/mthvedt/clearley

20:57 ToxicFrog: ohpauleez: if it were just kv pairs, I'd split on \n and then on = and then trim keys and values and bam, done

20:57 ohpauleez: exactly

20:57 ToxicFrog: Except it can also include {} blocks nested arbitrarily

20:57 ohpauleez: ahh

20:58 ToxicFrog: Which, barring nonregular extensions like lua's %%b{}, means things get a bit more involved.

21:00 mthvedt: I'll give it a look

21:01 mthvedt: toxicfrog: caution, i'm still changing stuff around a bit

21:01 hiredman: mthvedt: interesting, how flexible is clearley about input? the example just shows a string

21:02 mthvedt: hiredman: it will take any seq… i don't have a robust set of test cases for that, however

21:05 hiredman: mthvedt: neat

21:37 ToxicFrog: mthvedt: ok, I'm having trouble loading it, but it's a lein problem, not a clearley problem :/

21:41 I'm also getting progressively more confused about ns naming conventions with each new help/tutorial/example I read

21:42 mthvedt: toxicfrog: are you talking about clearley's examples?

21:42 ToxicFrog: mthvedt: lein's, actually

21:43 mthvedt: toxicfrog: oh ok

21:43 ToxicFrog: For example, I used to think my project namespace should be ca.ancilla.kessler.{parser,core,client,server,...}

21:43 Then I thought it should be ca.ancilla/kessler.*

21:43 Now I don't know what it should be at all

21:44 mthvedt: Clearley's examples are quite, well, clear :)

21:44 mthvedt: thanks!

21:54 ToxicFrog: mthvedt: question

21:54 json.clj contains: ; TODO: should def and defrule be interchangable for the single rule case?

21:54 But core.clj implies that defrule already supports single rules

21:55 So what's the difference in behaviour between using def and defrule?

21:55 mthvedt: toxicfrog: i'm not sure what i meant by that note, but the defrule syntax is a mess under the hood, there's some weird quirks

21:55 ToxicFrog: Aah

21:56 mthvedt: so it's possible i ran into a case where interchangeability didn't work

21:56 i

21:56 i'm working on refactoring the under the hood machinery

21:59 toxicfrog: feel free to email me if you encounter problems with the library; it'd be great to have a crash test dummy… i mean, early adopter

22:00 ToxicFrog: heh

22:00 I'm working on the sfs parser now, we'll see how it goes

22:06 Ok, actually I'm a bit confused by scanner

22:07 json defines a string-char-scanner that accepts single string chars, ie, anything but \ or "

22:08 then the string-char rule accepts an escaped-char, or a unicode-hex, or something accepted by string-char-scanner...

22:08 But it expresses that as ([string-char-scanner] string-char-scanner]

22:08 I would have expected ([string-char-scanner] identity)

22:14 mthvedt: let me take a look

22:16 toxicfrog: the defrule bodies are like fn bodies

22:16 oh hang on...

22:16 yes, that's right

22:17 it's like (fn [x] x)

22:18 ToxicFrog: I don't follow

22:18 mthvedt: so defrule definitions are like defining functions

22:18 if you did ([string-char-scanner] identity), that would return 'identity

22:19 as its parse action

22:20 does that make sense?

22:20 ToxicFrog: Ok, my understanding was that the parse action was oh

22:20 I think I get it now

22:21 ([string-char-scanner] string-char-scanner) is:

22:21 - run the scanner

22:21 - if it succeeds, bind the value it returns to the symbolstring-char-scanner

22:21 - evaluate the expression: string-char-scanner (bound to the value returned by the actual scanner), and that's the result of the rule

22:22 and the scanner itself returns the character scanned when it succeeds.

22:22 Yes?

22:22 clojurebot: yes isn't is

22:22 mthvedt: hat's correct

22:22 that's correct

22:23 ToxicFrog: Ok

22:24 mthvedt: occasionally, the json example uses rule instead of defrule… rule can take parse action fns directly

22:24 defrule builds them from the forms you provide

22:31 ToxicFrog: Hmm. What's the idiomatic way to do a zero-or-more?

22:31 json does it by having different productions for it, for example, one for [\" \"] and one for [\" string-content \"] where string-content is a one-or-more

22:34 Oh this is quite remarkable!

22:34 Compiling ca.ancilla.kessler.core

22:34 Exception in thread "main" java.lang.RuntimeException: Can't embed object in code, maybe print-dup not defined: clojure.lang.Compiler$LocalBinding@1766bfd8, compiling:(ca/ancilla/kessler/core.clj:23)

22:35 mthvedt: ok, this is not at all expected and somewhat disconcerting

22:35 This works:

22:36 (def sfs-parser (build-parser sfs)) (defn -main [& args] (execute sfs-parser test-string))

22:36 This causes the exception in the compiler mentioned above:

22:36 (defn -main [& args] (execute (build-parser sfs) test-string)

22:36 I suspect some kind of macro-related insanity, but my clojure isn't good enough to figure out what;.

22:37 mthvedt: toxicfrog: let me take a look

22:40 ToxicFrog: Also, so far, by far the most confusing part of Clearley is when you should use def, when defn, when defrule, and when rule.

22:40 mthvedt: toxicfrog: agreed

22:41 next step is probably to work on that

22:41 flesh out the docs, make the API more consistent

22:42 * ToxicFrog nods

22:50 mthvedt: toxicfrog: found the problem… as you expected, it's macro-related insanity

22:51 so build-parser needs access to the current ns and environment, which is why it's a macro

22:51 clearly is designed so it's idiomatic to bind rules and defrules to symbols in your ns

22:52 it turns out, if you try to embed the macro environment variable (&env) in a defn, it doesn't work...

22:53 can you define and execute macros with clojurebot? if so i can show you

22:53 ToxicFrog: I think so

22:53 I'm pretty new to clojure and haven't really used cljbot

22:53 mthvedt: here's a gist

22:53 https://gist.github.com/3064055

22:53 if you're interested in what's going on

22:57 ToxicFrog: Yay, I found a bug!

22:58 ...and now I've gotten the compiler to emit a null pointer exception

22:58 Fantastic

23:02 mthvedt: I'm just going to take out &env, since it's not a stable feature

23:02 of the clojure language

23:15 toxicfrog: pushed a fix

23:15 if you need it

23:19 kenneth: hey, i'm trying to use zeromq from clojure, and am getting an unsatisfiedlinkerror at runtime that i can't seem to debug

23:19 https://gist.github.com/d0d038ff7303250bcb13

23:20 seems like binding works fine, but the crash occurs at recv time

23:20 ToxicFrog: mthvedt: thanks

23:20 Trying to create a minimal test case for the null pointer exception now

23:22 kenneth: Exception in thread "main" java.lang.RuntimeException: java.lang.UnsatisfiedLinkError: org.zeromq.ZMQ$Socket.recv(J)[B

23:24 ToxicFrog: mthvedt: https://gist.github.com/a8e3a164b83182989231 causes the compiler to follow the null pointer in 1.4

23:25 I can't rule out the possibility that I'm doing something wrong there, but even if I am I wouldn't expect it to crash the compiler.

23:26 mthvedt: yes, getting the compiler to NPE is very odd

23:26 amalloy: kenneth: it's a very bad idea to do something side-effecty, like bind to a socket, at the top level of your namespace. do it inside of a function, and call that function from main

23:28 kenneth: amalloy: sure thing, but this is just a test project for me to get zmq to actually work, not production code

23:29 literally, i couldn't get it to work in my own project, so i made this new test project with just the zmq bit to figure it out :)

23:30 amalloy: mthvedt: &env is entirely stable, it's just that you're trying to do something impossible with it

23:31 mthvedt: amalloy: i found a blog post suggesting the types of the values might change

23:31 cu

23:31 rrently they're LocalBindings

23:31 amalloy: that's certainly true

23:31 ToxicFrog: mthvedt: impression so far: it'll be tops once it's less confusing and stops blowing up :/

23:31 amalloy: i wouldn't recommend relying on the values for much of anything

23:31 &env is a map representing the local lexical environment, for use by the compiler. what would it mean, to cause a macro to expand to that? how do you interpret that map as code?

23:31 lazybot: java.lang.RuntimeException: Unable to resolve symbol: env in this context

23:34 mthvedt: toxicfrog: you're AOT compiling? are you on 1.4?

23:35 ToxicFrog: mthvedt: yes; this is the result of 'lein run'

23:35 And yes I am.

23:42 Raynes: amalloy: Amusingly, we do rely on it in serializable-fn.

23:42 But hey, all bets are off with that thing.

23:44 amalloy: Raynes: yeah, i know. i don't think we actually have to though, right? we should really be able to just use the keys of &env

23:46 Raynes: amalloy: Well, what are the keys?

23:47 amalloy: i think they're the symbols

23:47 Raynes: How would that work?

23:47 And if it is possible, why don't we?

23:48 amalloy: all we're using is the symbols anyway, right? i think we're not just because whoever did the feature first (not sure if me or technomancy) was probably dumb

23:48 yes, they're the symbol names

23:48 Raynes: Oh yeah, we're doing (.sym ..)

23:48 Well aren't we just the cutest bunch.

23:50 amalloy: i'll send a pull req

23:51 mthvedt: toxicfrog: this will happen if you try to redef 'name

23:51 doesn't appear to have anything to do with clearley :P

23:51 ToxicFrog: mthvedt: aha. Clojure bug, then?

23:51 * ToxicFrog nods

23:52 ToxicFrog: A bit more feedback in 'cannot resolve rule for head' errors would be nice.

23:53 mthvedt: this looks like a bug in the AOT compiler...

23:53 i

23:53 toxicfrog: acknowledged

23:54 ToxicFrog: At the moment it says that it can't resolve rule for head: sfs and that's it, which makes tracking down the actual problem kind of hard.

23:54 Especially since I have in fact defrule'd sfs.

23:54 Oho, this is interesting

23:55 mthvedt: several references to this bug on the clojure list

23:55 ToxicFrog: So I was testing your recent fix by using (execute (build-parser sfs) ...)

23:55 mthvedt: along with the usual "you shouldn't be doing that anyway" jerks :(

23:55 ToxicFrog: If I change it back to (def sfs-parser (build-parser sfs)) ... and retry, I get a different "cannot resolve rule" error, referring to rules that I actually haven't defined yet, as I would expect

23:55 It goes from: Exception in thread "main" java.lang.IllegalArgumentException: Cannot resolve rule for head: sfs

23:56 To: Exception in thread "main" java.lang.IllegalArgumentException: Cannot resolve rule for head: typename, compiling:(core.clj:37)

23:56 Which I would actually expect, since I haven't defrule'd typename yet.

23:56 So it looks like using (build-parser grammar) inline still has some issues.

23:57 mthvedt: if you're doing build-parser inline, it's probably pulling *ns* from when it is run

23:57 i should probably attach a warning to build-parser

23:57 warning: reads the value of *ns*

23:57 or something

23:57 ToxicFrog: The fact that build-parser relies on all this hidden background state rather than just the grammar value itself kind of gives me the jibblies

23:59 Hmm. It'd be nice if I could use regexes; stuff like rest-of-line would then become very simple.

23:59 mthvedt: toxicfrog: yes, but in my judgment it was a small amount of voodoo to enable easy defrules

Logging service provided by n01se.net