#clojure logs

2012-07-06

00:09TimMcIs there a fn like take-while but that will take one more element?
00:12TimMcFor instance, (___ odd? [1 3 5 8 10 12]) => (1 3 5 8)
00:16TimMc(Well, I don't need it anymore.)
00:39arrdemhey 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?
00:40arohnerarrdem: you can use set! inside a binding call, but that's threadlocal only, and not very idiomatic
00:40arohnerif your goal is to do things "the clojure way", you should probably rethink the design
00:42arrdemarohner: 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.
00:43arohneryou could also use atoms, but it's poor clojure to use numerous atoms
00:43arohnerinside a binding block, you can set! (binding [foo (bar)] (set! foo 42))
00:43arohnerthe variable will mutate, but it's thread-local only, and will revert to it's old value outside the binding
00:44arrdemAh. thanks, I had never heard of the (binding) expression.
00:44arohneroh, and the variable needs to be declared dynamic
00:44arohner(def ^:dynamic foo)
00:44arrdemnoted. presumably [binding it's use is descuraged?
00:45arrdem* noted. presumably binding's use is descuraged?
00:45arohnerall of these exist to be used. What's discouraged is using a lot of mutable state
00:45arohnerclojure emphasizes reducing the amount of mutable state, and being clear about when/how things change
00:47arohnerbinding is typically used for "configuration", rather than computation
00:48arrdemwhy is that? Oh. create local state and then invoke stateful routines from the compartmentalized scope... that makes sense
00:48arrdemCool! learned something today... thanks for the help!
00:49arohnerRich 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
00:50arohnerso the clojure "boxes", var, ref, atom, agent each hold mutable state, in a different, safe, way
00:51arohnervars can only be mutated thread-locally, refs mutate globally, but through the STM, etc
00:53noidiI 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)) ?
00:54noidiis abusing map for side effects OK, or can I do this somehow with doseq?
00:54nicholasfhi, 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)
00:54arohnernoidi: (dorun (map..)) is fine
00:54nicholasfsurely I don't have to define register-device *above* n-devices?
00:55noidinicholasf, unfortunately you do :(
00:55arrdemnicholasf: you do in fact have to
00:55nicholasfnoidi: wow, ok
00:55noidior at least (declare register-device)
00:55arohnernoidi: you can also (doseq [[one two] (map vec arg-1s arg2s)] (impure one two))
00:55arrdemClojure's base CompilationUnit is an s expression
00:55arrdemnot a file
00:55arrdemso order matters
00:55nicholasfthanks mate
00:55arrdemnp
00:56arohnernicholasf: you can also use declare
00:56arohner(declare register-device) (defn n-devices ...) (defn register-device ...)
00:56arrdemarohner: why use (declare) not (def)?
00:56arohnerarrdem: expresses intent more clearly
00:56arrdem(doc declare)
00:56clojurebot"([& names]); defs the supplied var names with no bindings, useful for making forward declarations."
00:56arrdemOh. shiny!
00:57arohnerdeclare also supports (declare foo bar)
00:57noidi(declare foo bar baz) vs. (def foo)(def bar)(def baz)
00:57nicholasfarohner: yup, thanks
00:58noidiit 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)
00:58nicholasfok, so that's what declare means
00:58nicholasfit's like a deferred define
00:58noidinicholasf, here's a comment by Rich Hickey on Hacker News, in which he talks about forward references (or their lack in Clojure thereof)
01:09noidinicholasf, damnit, I forgot the link :D http://news.ycombinator.com/item?id=2467809
01:09nicholasfthanks noidi
01:11nicholasfyeh that helps set the situation in context thanks
02:45nicholasfanyone using a redis client that will support publishing to channels? redis-clojure doesn't seem to
02:53nkkarthikexcuse me... is this the right place to ask a question on swank-clojure plugin?
02:53amalloy~swank
02:53clojurebotswank is trust the readme and the readme only. all others will lead you astray.
02:54nkkarthik:) ok thanks... i will keep searching then
02:54amalloynkkarthik: nah, you can ask in here. just don't trust any blogs or whatever
02:56nkkarthikoh ok... I have a lein project... from emacs I did clojure-jack-in... it cleared all the java class files and complains about it
02:57nkkarthikI 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
02:58nkkarthikI am not sure why clojure-jack-in clears the class files and doesn't compile them again
02:58nkkarthikany clue?
03:19nkkarthikI think I got that... lein-swank 1.4.4 has this problem... I changed to 1.4.3 and it works!
04:46noidiare there any guidelines on when to :use vs. :require other namespaces?
04:49xumingmingvI 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.
04:49noidiyeah, nowadays I tend to :use everything (with :only, of course), and only use :require when the names would clash otherwise
04:50noidiI was just wondering if that's common practice
04:51noidithe reason I avoid :require is that having a prefix namespace prefix on every symbol kind of defeats the point of namespaces
04:51noidiit's almost like programming in c :)
04:56amalloynoidi: 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
04:57amalloypersonally 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
05:02noidioh, cool
05:02noidiI didn't know about the :refer option to 'require
05:06AWizzArduse is very nice for the repl.
05:06AWizzArdWhat I find unfortunate is that doc and apropos reside in the clojure.repl ns. I constantly have to use it.
05:11RaynesIf you use lein2's repl, you don't have to.
05:11RaynesAnd if you use slime, you don't even need it.
06:03ro_stanyone using cemerick's friend? how do i access the authenticated user data once a user has signed in?
06:18mystiiqhas anyone used clj-ssh? how can I disable all that INFO logging that is displayed in terminal?
06:28wingydidnt know about this one: https://github.com/halgari/clojure-py
06:28wingyis there a good reason for why we would like it to run on python?
06:28wingyi can understand the js implementation since we need it in the browsers. also allowing better scripting support
06:31jeremyheilerwingy: the README for the project explains why they started the project
06:33wingyalways read first
06:34wingytechnomancy: there are no plans for lein to be run on node.js instead for eliminating start up time for various tasks?
06:36jalatera_what' the best way to search a nested hash map structure
06:40xumingmingvjalatera_: search a nested map? search for a value in the nested map?
06:44ro_stwingy: java folks are working on jvm start up time. the problem will go away eventuall
06:44ro_sti doubt very much that lein will move to node.js :)
06:45wingyro_st: but there will always be a startup time on jvm?
06:45ro_styes
06:45ro_stwhat repetitive tasks are you using lein for?
06:46wingylein repl :)
06:46wingybut also i would like to install my own tasks
06:47wingyeg saving project with git
06:48wingywhy not move to node.js? lein doens't need the power of jvm or concurrecy i guess. are there reasons for staying on jvm?
06:49wingyone i can think of is that people dont need to install node.js
06:49wingyperhaps its better for me to script in node.js myself
06:57ordnungswidrigwingy: nice idea, lein on node
07:02yonatanethere's a js implementation of clojure?!
07:02wingyyonatane: are you kidding
07:02yonataneyou mean clojurescript or something else?
07:03wingyclojurescript
07:03yonataneoh
07:03yonatanei should do more reading :)
07:18unnaliAnyone 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.
07:24wingyspecial anonymous function can not be used as fn call?
07:24wingy,(#(%) "hello")
07:24clojurebot#<ClassCastException java.lang.ClassCastException: java.lang.String cannot be cast to clojure.lang.IFn>
07:24unnali("hello")
07:24unnaliwingy: ^this wouldn't work either
07:25wingyoh yeah i forgot
07:26wingythought the anonymous function wasnt run
07:26unnali:D
07:26wingy(#(do %) "hello")
07:27unnali,(#(do %) "hello")
07:27clojurebot"hello"
07:27wingyspecial anonymous fns look so concise
07:27wingyvery handsome
07:27unnalihandsome??
07:27lazybotunnali: What are you, crazy? Of course not!
07:28unnalilazybot: ...
07:50ro_stcemerick: 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)?
07:51ro_stwith friend
07:52ro_sti 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)
07:58ro_stcemerick: also, how do i access the signed-in user from within my compojure routed fns?
07:58jeremyheilerunnali: if you (load-file "test/project_name/core_test.clj") you can then run (run-tests 'project_name.core_test)
07:59cemerickro_st: Sure; any code that isn't protected by an authorization middleware/expression will remain accessible to anonymous users.
07:59unnalijeremyheiler: 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!
08:00cemerickro_st: See cemerick.friend/identity and cemerick.friend/*identity* to get access to the signed-in user
08:01jeremyheilerunnali: nice
08:02jeremyheilerthat makes a little more sense :-P
08:03ro_stcemerick: 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?
08:03cemerickyup
08:04ro_stok 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
08:06ro_stbest way to learn, though, ain't it :-)
08:06ro_sti found writing my own md5 fn to be really easy
08:07ro_stto support legacy user accounts
08:07ro_stgoing to put a bcrypt re-encrypt-on-login-or-reset system into place so that over time the md5 passwords fall away
08:12cemerickwell, having an api shouldn't (on its own) require a custom workflow
08:13ro_stwhich workflow should i use, then? interactive-form is going to do redirects which i don't want
08:14ro_sthttp basic with ssl, probably?
08:17cemerickro_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.
08:29mystiiqcan clj-json make a JSON string out of {:foo "bar"} or should I use cheshire
08:29ro_stboth can do it
08:30ro_stwith cheshire: (generate-string {:foo "bar"})
08:31cmiles74mystiiq: I've been using Cheshire for a whie and am happy with it.
08:32ro_stdo i need to restart my emacs repl if i change project.clj deps?
08:32xumingmingvdoes maven have a similar command to `lein uberjar`?
08:32ro_sti do at the moment, but i'm not sure if i do actually have to
08:33cmiles74ro_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.
08:33ro_stthanks
08:35mystiiqhow can I prevent the java browser from opening when using "lein ring server"
08:35ro_stserver-headless
08:36cemerickro_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
08:36mystiiqro_st: thanks
08:36cmiles74ro_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
08:36cmiles74cemerick: Ha! I was just looking at that page. :P I've had the bookmark in there forever.
08:38xumingmingvI found the uberjar plugin: http://maven.apache.org/maven-1.x/plugins/uberjar/
08:38ro_stwhoa, that's handy!
08:41ro_stsorry 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?
08:42cemerickro_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
08:42ro_stok super. authenticate is wrapping the whole lot
08:43ro_stthanks for your patience. so totally going to produce and share sample code once i've got it all working
08:43ro_stwhich'll probably have several large holes poked in it, but hey :-)
09:48mystiiqI'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
09:49ro_stlook into agents mystiiq
09:50the-kennymystiiq: You can easily spawn a thread or use agents
09:50mdeboardIs that what aleph is for btw?
09:51antares_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
09:53duck1123aleph is for when you want to get the request and a channel that you can enqueue the response into (from any thread)
09:54duck1123it also works really well for streaming requests and websockets
09:54mdeboardI see; I guess in my mind aleph ~= celery (python library)
09:54mdeboardthat's wrong apparently
09:56antares_mdeboard: yes, aleph is definitely not a "job queue/workers" kind of thing
09:56duck1123yeah, 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:04broquaintNeat, persistent data structures in ruby - https://github.com/harukizaemon/hamster/
11:55duck1123midje on cljs would be great
11:57_zachIs there a cljs command line tool to compile some cljs to js without a closure pass?
12:05stuartsierra_zach: Just compile with :optimizations :none
12:05_zachstuartsierra: Awesome, thanks!
12:34qubit[01]Does every file need a namespace ?
12:36_zachqubit[01]: Compilation shouldn't fail without one, but I see no reason you'd want to omit one
12:37qubit[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:37qubit[01]test/core.clj
12:37qubit[01]compiling with C-c C-c
12:38qubit[01]if I omit the namespace, it just says no such namespace: '<blank>'
12:41qubit[01]how do I get help in the repl ? I need a description of the rem function
12:41pendlepantsqubit[01]: (doc rem)
12:46qubit[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:47madsyqubit[01]: http://emacswiki.org/emacs/PareditCheatsheet
12:47madsyMaybe that helps?
12:47duck1123use C-right to wrap the current paren around the next form
12:47oskarthSo, 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:48oskarthseemed 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:49dnolenoskarth: there are 4 GSoC projects, Typed Clojure, ClojureScript/Lua, Clojure Android & Simple Overtone IDE
12:50oskarthdnolen: 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:51dnolenoskarth: not really, some threads on the Clojure and Clojure-dev mailing lists. You can follow the projects on GitHub
12:51oskarthdnolen: found a list at http://www.google-melange.com/gsoc/projects/list/google/gsoc2012
12:51oskarthok, thanks :)
12:51dnolenoskarth: yep
12:52qubit[01]gah
12:52qubit[01]so much to learn
12:52qubit[01]how do I kill the f'n repl because my recurse function wont stop because I cant figure out to use paraedit
12:52qubit[01]tired of killing emacs
12:53duck1123try C-c C-c
12:53madsyAnd if C-C C-c doesn't respond, kill the swank process instead
12:53dnolenqubit[01]: you can also try slime-quit-lisp
12:54qubit[01]should try learning lisp w/o paraedit ? seems to be more of a hindernace at my early stage of the game
12:54madsyqubit[01]: Whatever you feel is better
12:54duck1123try using paredit in a source buffer first, then try it in the repl
12:55madsyqubit[01]: Why use a tool which is only in the way?
12:55madsyqubit[01]: Don't be afraid to have your own opinion
12:55qubit[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:56madsyqubit[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:56madsyIt's two separate things
12:56duck1123I 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:58Gnosis-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:58duck1123Gnosis-: there are some libs that abstract it away (lamina) but it's easy enough manually
12:58Gnosis-before reading this, I was under the impression that Clojure programs automatically used all CPU cores efficiently
12:59ieurelol
12:59duck1123you have things like pmap, that make it easy to multi-core, but it doesn't do it by default
12:59Gnosis-ah, okay
13:00duck1123in many cases, the overhead of multi-core outweighs the benefit.
13:01Gnosis-do pcalls and pmap run all of the function calls in parallel at once, or only a limited number to reduce overhead?
13:01ieureGnosis-, https://github.com/clojure/clojure/blob/d0c380d9809fd242bec688c7134e900f0bbedcac/src/clj/clojure/core.clj#L6194
13:02Gnosis-ieure: n+2, got it
13:03qubit[01]duck1123: what would be an instance where it is beneficial ?
13:03uvtcMy impression so far is that you mostly do multithreading using futures and agents. Is this the case?
13:03ieureuvtc, For some values of "you."
13:04duck1123qubit[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:04uvtcs/you/folks/ ?
13:05ieureuvtc, "My impression so far is that you mostly do math using addition and subtraction."
13:05ieureUse the right tool for the job.
13:05ieurePersonally, lots of the things I do are best served by the innate Runnable-ness of functions.
13:05ieureThat is, (Thread. some-function)
13:05duck1123ieure: subtraction? I just add negative numbers
13:07uvtcSo, are `(Thread. some-function)`, futures, and agents the most-commonly employed means of spreading out work among multiple threads?
13:07ieureuvtc, Free yourself from the need to use the "most common" abstraction and focus on using the most appropriate abstraction.
13:08duck1123I don't find myself using agents too often anymore, but that may just be me
13:09uvtcduck1123, what have you been using instead? Or, in what way has your code changed making them less necessary?
13:10duck1123I 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:11bhenryi want to do setTimeout in clojurescript. something tells me it's not as easy as (js/setTimeout (fn …) 1000)
13:12dnolenbhenry: it is
13:12bhenrycoooool
13:15borkdudethe function executes immediately in himera: (js/setTimeout (fn [] (println "foo")) 10000)
13:16bhenryborkdude: that happened to me too
13:16dnolenbhenry: borkdude: setTimeout always executes immediately - returning a timer id.
13:17borkdudeah of course
13:17bhenrycan you show me an example that waits n milliseconds before executing the following line?
13:17borkdudeyup, this works: (js/setTimeout (fn [] (js/alert "foo")) 10000)
13:18uvtcduck1123, thanks!
13:18bhenryborkdude: what if the fn takes args?
13:19duck1123uvtc: if you're looking for options for multi-threaded joy. Give the lamina docs a once-over
13:19borkdudebhenry no idea
13:19oskarthis there something akin to (browse-url foo) for opening raw html in my default browser?
13:20bhenrydnolen: what if the inner function needs to take args?
13:20duck1123bhenry: where would the args come from? You could always use a closure
13:20uvtcduck1123, 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:20borkdudebhenry alert is a function, I call it with arg "foo"
13:20duck1123oskarth: take a look at clj-webdriver ?
13:21oskarthduck1123: thanks, will do
13:21bhenryi 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:21borkdudebhenry call the function from within a (fn [] …)
13:21bhenrygot it.
13:21bhenrythanks
13:22TimMcbhenry: Also see setInterval.
13:25sjl,(apply (fn [& {:keys [a b]}] (+ a b)) (apply concat {:a 1 :b 2}))
13:25clojurebot3
13:25sjlis there a more idiomatic way to do that?
13:26sjl(apply some-fn-taking-kwargs-style-options (apply concat some-map-of-options))
13:26dnolensjl: not really, it's why some people don't like fns that take keywords like that.
13:27sjldnolen: what's the alternative? make the fn take an actual map as a single param?
13:27dnolensjl: I think so.
13:28sjlI guess that's not too bad. More typing for users, but explicit is better than implicit.
13:30TimMc~mapply
13:30clojurebotYou could (defn mapply [f & args] (apply f (apply concat (butlast args) (last args))))
13:34botterWhy are the shootout.alioth tests for Clojure so unimpressive? Clojure consistently ranks the lowest for memory, and quite low in speed too
13:35TimMcbotter: because alioth is a lie
13:35Gnosis-it looks like there's no clojure.net... :(
13:35TimMc~alioth
13:35clojurebotTitim gan ?ir? ort.
13:35botterwhat
13:35hiredmanclojurebot: why you no utf?
13:35clojurebotexcusez-moi
13:36TimMcbotter: 19:09 < technomancy> alioth shootouts are pretty famous for being hugely biased against languages hosted on virtual machines
13:37dnolenbotter: because people don't work on them enough
13:37dnolenbotter: look at test.benchmark on Github, all the benchmarks in there are competitive with Java in space and time
13:38qubit[01]anyone use counterclockwise ?
13:38botterwill do
13:38qubit[01]looking for the format file key shortcut
13:40dnolenbotter: 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:40bottertest.benchmarks links to alioth too
13:41dnolenbotter: look at the source.
13:41dnolenbotter: it just links there to note what the benchmarks are based on.
13:42botterah i see
13:44Gnosis-is there a canonical way to do networking in Clojure?
13:44qubit[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:44qubit[01]I'm not sure what its telling me
13:44amalloysjl: 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:44TimMcGnosis-: Binary protocols, http client, http server... which?
13:44Gnosis-TimMc: how about an HTTP server
13:45amalloyring
13:45sjlamalloy: 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:45amalloy(on top of jetty or tomcat or whatever you want)
13:45TimMcGnosis-: Look at Ring, Compojure, and Noir (in order of increasing batteries-included)
13:45Gnosis-okay, thanks
13:45duck1123qubit[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:45qubit[01]how do I make it dynamic now ?
13:46nDuffqubit[01]: declare it with ^:dynamic
13:46duck1123(def ^:dynamic *db* ...)
13:46TimMcI suppose that warning is ambiguous about where you use ^:dynamic, but it is good enough for a web search.
13:48sjlTimMc: 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:54tyre771Struggling with defining a macro that defines a function if someone could take a look https://gist.github.com/3061613
13:55duck1123try wrapping the defn and def in a do
13:56amalloyyour swap! is also going to be wrong
13:58ieuretyre771, Consider using reduce instead of an atom.
13:59ieureUnclear if you want to coordinate these calls, but in the context of that gist, you do not need mutability, only concatenation.
13:59tyre771So the backtick doesn't run the code immediately?
13:59ieureOh boy
14:00tyre771Yes 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:00amalloytyre771: you don't really need a macro at all
14:00yonataneHow 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:01augustlyonatane: 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:01augustloh wait, I read that wrong, nvm
14:02yonatanein the case of facebook, you have an app identifier which doesn't change, unless you maybe handle multiple apps
14:02augustlyonatane: are you making an API where you authenticate with a token?
14:02augustls/you authenticate/your users authenticate/
14:02duck1123I would write my fns with multiple arities, and if the token isn't provided, it reads it from an external var
14:02dnolentyre771: 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:02tyre771@amalloy I was having an issue with sequencing through the vector of names I want to define
14:03amalloy(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:04amalloyor...maybe you don't use the tag name at all? i don't quite understand how this is supposed to work
14:05tyre771@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:05tyre771so given ["walrus" "bubbles] I would then be able to do (walrus {:a "b" :c "d"})
14:05dnolentyre771: but why you need named functions for this?
14:06amalloybut given your definition above, walrus and bubbles would be the exact same function, just with different names
14:06yonataneaugustl: users authenticate through the app, and you need to identify the app when redirecting to oauth, or decoding a cookie etc.
14:06tyre771damnit
14:06tyre771you are so right
14:07yonataneaugustl: so i have several functions that needs that app-id.
14:07ieuretyre771, Write one function, and use defalias to bind it to multiple names, if you merely want the convenience.
14:07yonatanein java i'd make an object and be done with it.
14:08augustlyonatane: 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:08augustlyonatane: if so, sounds like an appropriate use for Ring middlewares
14:08tyre771oh zout nevermind. I need the tag-name in there so (a {:color "blue"}) would return "a { color: blue;} "
14:08augustlthat is, wrap your main handler in another handler, and don't call your main handler if the request does not authenticate
14:08tyre771that's why I tried a macro
14:09tyre771so the beginning string to concatenate onto would be (str ~tag-name "{ ")
14:09augustlyonatane: a convention for Ring is to add extra stuff to the request map.
14:10duck1123yonatane: just store your key in an external atom, and have your fns read that atom to key the token
14:10augustlyonatane: so, you'd call your normal handler with something like (handler (assoc original-request :user (get-user-by-id id)))
14:10augustlyonatane: not sure if this (writing authentication code for a HTTP API) is what you're doing though :)
14:11duck1123I misread the original question
14:11yonataneaugustl: 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:11ipostelniktyre771, you can do (defn tag-fn [name & attrs] (str name "{" ..... partition attrs ... "}")) and then (def a (partial tag-fn "a")), etc....
14:11ieuretyre771, You still don't need macros. Write one function: (defn tag-fn [tag-name & props] …)
14:11ieureYeah.
14:11ieureWhat ipostelnik said.
14:11yonataneduck1123: it might be what i'm looking for. i'm not sure.
14:12augustlyonatane: (def my-db (set-up-db {:dbname "foo" :password "bar"})) you mean?
14:12duck1123yonatane: the advice still applies, I just had the wrong use case in my head
14:12yonataneaugustl: what does set-up-db returns?
14:12augustlyonatane: it would be useful if you could show us a concrete example of code you don't like
14:12ipostelniktyre771, better yet look at hiccup
14:12TimMcsjl: You can still do phrase searches.
14:13augustlyonatane: a function perhaps for querying perhaps
14:13augustlso, (my-db "foo") would perform the query for foo
14:14dnolentyre771: 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:14duck1123you could look at how korma or any of the other batteries-included db libs store their connections
14:15dnolentyre771: then they can be easily manipulated with the usually Clojure functions, with your approach not possible.
14:15dnolens/usually/usual
14:15tyre771@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:16yonataneok, thanks, i'll read some source
14:16augustlyonatane: got a sample of some "bad" code?
14:17yonatanei have my own embarrassing code
14:17augustlyonatane: in general, "factory" functions is something I use a lot
14:18tyre771@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:18amalloytyre771: 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:18dnolentyre771: it is possible. I but then you have a brittle DSL that no one will want to use.
14:18augustlyonatane: 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:18yonataneaugustl: what if you need several functions, and not just one? or are we in that point where we must talk about concrete example?
14:18amalloyif 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:19augustlyonatane: I'm thinking that you could return a map of functions. Not sure if that's idiomatic though.
14:19yonataneaugustl: yeah, that's kinda OO
14:20dnolentyre771: look at how Hiccup works for ideas.
14:20tyre771@amalloy how is that different then (a {color: "blue" :overflow "scroll"}), because it is function calls?
14:20yonataneaugustl: maybe something like (with-connection ....)
14:20augustlyonatane: you could also have a function that defines other functions in the namespace from where the original function was called afaik
14:21dnolentyre771: it's function call so it can no longer be manipulated as data.
14:21amalloybecause what you just described evaluates to a string, which i can't do anything useful with
14:21augustlyonatane: actually, you can't do that.. But a macro could :)
14:21amalloywhereas if you gave me that data structure, i could still add classes to it, or query what classes are present
14:21augustlyonatane: 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:22augustlyonatane: that way, you get a factory to create a full set of functions in a namespace
14:22tyre771then how does Hiccup go to HTML? Wouldn't it have to put that to a string at somepoint?
14:22amalloyyes
14:22amalloyyou're just doing it too soon
14:22duck1123there's a single fn that'll walk the entire tree and emit html
14:22dnolentyre771: (assoc-in rules [:p :div :color] "red") is pretty nice. Can't do that with your representation.
14:22tyre771okay, I see what you mean. I'm sorry I"m not trying to be obtuse
14:23yonataneaugustl: could it work for multiple configs?
14:23augustlyonatane: in my code, I don't do that, though. My "model" looks something like this. http://pastie.org/4211560
14:23tyre771@dnolen I see, I hadn't gotten to multiple rules but it would have been a nightmare
14:23augustlyonatane: not sure what you mean by configs
14:24augustlyonatane: something like make-insert, but with the ability to change which table it worked on run-time?
14:24yonataneaugustl: oh, so you have a namespace for users. Can a macro create a namespace?
14:24yonataneaugustl: yes
14:24augustlyonatane: yes, a macro can expand into any kind of code
14:25augustlyonatane: trying to come up with an example where that would make sense ;)
14:25duck1123augustl: do you have the rest of your code available anywhere? We're doing similar things and I'd like to compare/contrast
14:25tyre771okay I will begin again. So what I need is instead that just goes through data-structures and then turns them into strings
14:25yonataneaugustl: it might make sense when you write a client, no?
14:26duck1123yonatane: here's my nastiest function generating macro https://github.com/duck1123/ciste/blob/master/ciste-core/src/ciste/sections.clj#L65
14:27augustlduck1123: for the mongodb factory?
14:28augustlduck1123: 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:28duck1123augustl: that link isn't for mongo, but my question to you was
14:30duck1123you can't def into a different namespace by normal means. (was recently bitten by that)
14:31yonatanecan you temporarily switch to the different namespace and then do it?
14:31augustlyonatane: http://pastie.org/4211604
14:31augustlanother example of something that might be relevant
14:32augustla namespace has a pool of objects, other namespaces calls a factory function to get objects from that pool
14:32augustlthe 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:33augustlduck1123: I've written my own little "orm" on top of monger, if that's what you mean :)
14:34duck1123augustl: it was, I've been doing similar things with monger lately and looking for prior art
14:34augustlduck1123: I did the same.. Didn't find much
14:34augustlended up writing my own code for creating data validation functions, for example
14:37antares_augustl: oh nice. Is it open source?
14:37antares_augustl: have you seen validateur for validation?
14:37duck1123That's what I've been using
14:38augustlantares_: yeah I saw it, I wasn't able to make much sense out of it
14:38augustlits map of error messages have sets for keys
14:38augustland it assumes all errors are for specific attributes
14:38duck1123https://github.com/duck1123/jiksnu/blob/16d8df7753a672c655df3ee8ca9beab12861e046/src/jiksnu/model/activity.clj#L132
14:38augustl..it seems
14:39antares_augustl: I will document it next week
14:40antares_it definitely deserves a guide of its own, after almost a year of being neglected
14:40augustl:D
14:42cljs_newb_29582I wonder how many 17" mbps one needs to order
14:42cljs_newb_29582to convince apple to remake them again
14:45madsyFunctions 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:46madsyFor example when using WebGL: (swap! vertexShader (. gl creatShader)) could create N new shaders while swap retries.
14:46madsyBut calling a bunch of those functions in a let seems ugly too
14:49raekmattmoss: (let [shader (. gl creatShader)] (reset! vertexShader shader))
14:49raekmadsy: ^
14:49raekmattmoss: sorry, wrong nick... :)
14:50madsyraek: Yup, I guess I would have to use a big let
14:50raekmadsy: 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:51madsyraek: (. gl createShader (.-VERTEX_SHADER gl)) returns a handle/value for a shader. So I want to overwrite the old value of vertexShader
14:52madsyIn the WebGL spec, the handle is just a boring integer :)
14:53mattmossheh
14:54raekso 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:54ToxicFrogHuh. If I ask lein for a library, it creates a Clojure 1.4 project with some Github configuration set up.
14:54raeki.e. you don't use the old value that was in the atom for anything
14:54ToxicFrogIf I ask it for an app, it creates a 1.3 project with no git configuration.
14:54madsyraek: Yep, exactly
14:54ToxicFrogOh wait, no, there is some git.
14:55raekmadsy: ok, then let and reset! is the way to go :)
14:55madsythanks
14:57raekerhm, the rand-int example should of course use reset!, not swap!
14:57ToxicFrogOk, 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:57ToxicFrogShould these be four separate Lein projects?
15:01raekToxicFrog: 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:02duck1123there's lein-sub, but it has issues with lein2 IIRC
15:02raekyou can split off the projects as they get mature
15:04raekif 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:04raekToxicFrog: you can also use the "checkouts" lein feature to work on two projects in parallel
15:05madsyraek: Using screen sounds better ;-)
15:06raekmadsy: huh? better than what?
15:06ToxicFrograek: they're not tiny; the library is pretty much a (de)serializer for a custom format, the apps to the actual heavy lifting.
15:06ToxicFrog*do.
15:06ToxicFrogI don't see anything about checkouts in 'lein help'
15:06raekToxicFrog: do they share a lot code, except for the library?
15:07ToxicFrogNo.
15:07ToxicFrog(if they did, that code would be in the library)
15:08augustlwhy do some multimethods check for "APersistentVector" instead of just PersistentVector?
15:08augustlis APersistentVector a protocol perhaps?
15:08amalloyugh, they do? if they do that seems bad
15:08raekToxicFrog: it's not a task so it's documented elsewhere: https://github.com/technomancy/leiningen/blob/master/doc/FAQ.md
15:09augustlamalloy: I've seen it a lot
15:09raekfifth bullet point
15:09madsyraek: Rather than handling multiple projects with some leiningen plugin, just use screen and work with two lein instances
15:09amalloyaugustl: by people who know what they're doing? evidence/link?
15:09amalloychecking for IPersistentVector would be righteous and good; APersistentVector is likely to deserve a beating
15:10augustlamalloy: https://github.com/weavejester/compojure/blob/master/src/compojure/response.clj has APersistentMap
15:10CheironHi, what is the best way to provide an extra optional parameter to a function declaration?
15:10Cheirononly one extra optional parameter
15:11amalloyaugustl: yeah, send him a pull request, that's wrong
15:11antares_Cheiron: probably using two arities
15:11augustlamalloy: is there a document I should read about this? :)
15:11ToxicFrogHmm. Right. The apps would have to list the library as a dep.
15:11augustlCheiron: I'd use two arities too
15:11raekmadsy: with checkouts you only add one symlink and changes in both sources can be seen from a repl in the dependent project
15:11Cheironantares_: augustl Oh, true
15:11ToxicFrog(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:11stuartsierraIn 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:11antares_Cheiron: like here: https://github.com/michaelklishin/monger/blob/master/src/clojure/monger/collection.clj#L91-126
15:11madsyraek: aha
15:11amalloymeh. AFoo is basically always bad; IFoo is always good; Foo is often acceptable
15:12stuartsierraamalloy: yes
15:12yonataneis there a lein jenkins plugin yet?
15:12Cheironhow to represent bitmap data structure http://en.wikipedia.org/wiki/Bit_array in Clojure?
15:12antares_if Foo is guaranteed to implement IFoo, then there is no reason to not use IFoo
15:13duck1123There's a Lein Jenkins, but he's just some guy
15:13antares_Cheiron: there are Java implementations of bit array
15:13yonatane:)
15:13raekmadsy: but for two unrelated projects two instances is perfectly fine, of course
15:13amalloyCheiron: bitmaps are all in your head. the number 17 is a bitmap if you say it is
15:13stuartsierraMost type-predicates in clojure.core look like (defn foo? [x] (instance? IFoo x))
15:13amalloyantares_: that's true if you're checking inheritance, but not if you're, for example, constructing an instance
15:14antares_amalloy: true, I was thinking about implementing protocols for core types
15:14ToxicFrogLooking at the builtin help, lein is really giving off the vibe that it's mean for developing clojure libraries first and foremost
15:14jweiss"No matching method found: foo for class bar". is there a reason it doesn't print the argument types that didn't match?
15:14raekduck1123: hah! you beat me to it... :-) https://twitter.com/technomancy/status/203226678493851649
15:15jweiss,(.substring :foo)
15:15clojurebot#<IllegalArgumentException java.lang.IllegalArgumentException: No matching field found: substring for class clojure.lang.Keyword>
15:16jweisshm, /me not sure what the easiest way to throw that exception is
15:16Gnosis-(throw)?
15:16clojurebotdnolen: well feel free to throw some more in and send me a pull request. The format is pretty general
15:16jweiss,(.substring "foo" :bar)
15:16clojurebot#<ClassCastException java.lang.ClassCastException: clojure.lang.Keyword cannot be cast to java.lang.Number>
15:17jweissGnosis-: i meant "No matching method found"
15:17Gnosis-oh
15:19jweiss,(.lastIndexOf "asd" :foo)
15:19clojurebot#<IllegalArgumentException java.lang.IllegalArgumentException: No matching method found: lastIndexOf for class java.lang.String>
15:19jweissthere we go
15:20jweisscan't it say "No matching method found: lastIndexOf(clojure.lang.Keyword) for class java.lang.String"?
15:20Cheironthis is considered a good use of idiomatic clojure? http://pastie.org/4211830
15:22raekCheiron: (let [foo (make-foo)] (.method foo ...) (.method foo ...) foo) can be abbreviated as (doto (make-foo) (.method ...) (.method ...))
15:23Cheironoh very true
15:23Cheironsince the performance is an issue. do you suggest to use type hints?
15:25Cheironbecause I need to save to Cassandra as fast as possible
15:26ieureCheiron, Pop quiz: Which is slower? a) Reflection on a Java object b) Network latency
15:27Cheironb)
15:27ieureCongratulations.
15:28raekreflection and network latency affect throughput differently, through
15:29Cheironregarding my snippet, did I make a good use of function arity?
15:31uvtcI 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:31uvtcIncidentally, for a large generated sample, I found the Clojure version to run in about half the time as the Python version.
15:33S11001001uvtc: just non-use of #() syntax for lambdas
15:33S11001001you may also find extract-biggish-nums clearer if you either put everything in for, or use ->> to chain your seq ops
15:34uvtcS11001001, I wasn't sure what to do with those nil's that re-find returns if there's no match.
15:35S11001001if you switch to ->>, you could use keep instead of map-followed-by-filter
15:35uvtcSo I used filter, but thought maybe could've used something inside the `for` to do it...
15:35duck1123if you don't need to keep false, you could (filter identity ...)
15:36S11001001I 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:37ieureCheiron, Look at the doto macro; it'll clean that code up a bit.
15:37uvtcS11001001, Ah, `keep`. Thanks.
15:37uvtcduck1123, Oh, I see. That works nicely too (filter identity). Thanks.
15:38Cheironieure: I'm refactoring to use doto
15:38S11001001uvtc: be warned, filter identity is not quite keep
15:38ieureuvtc, Yeah; same as Python's filter(None, seq)
15:38jkkramer(for [st li :let [x (re-find #"[1-9]\d{2,}" st)] :when x] (Long/parseLong x)) is one way. there are many
15:38uvtcS11001001, gotcha.
15:40ToxicFrogIs 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:41duck1123I'd say that keep isn't quite (filter identity) all depends on what you want
15:41raekToxicFrog: (ns foo (:use [some-ns :rename {before after}]))
15:42uvtcieure, Ah, yes. I'd previously used a list comprehension (plus an "if" at the end of it) for those sorts of things.
15:42raekToxicFrog: use accepts the same options as both require and refer (since it's a combination of those two)
15:43uvtcieure, (in Python, I mean.)
15:43ToxicFrogAah, I missed that note in the docs
15:43ToxicFrogSorry
15:43clojurebotIt's greek to me.
15:43mattmossO_o
15:43Gnosis-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:44Gnosis-s/refer/recur/
15:44dnolenGnosis-: lazy sequences
15:45Gnosis-dnolen: I still don't understand... does this mean the stack is not consumed?
15:45dnolenGnosis-: stack is not consumed, http://clojure.org/sequences
15:45qubit[01]Thinking about working through this https://github.com/functional-koans/clojure-koans to help me learn, anyone done these ?
15:45uvtcjkkramer, thanks --- didn't know about using `:let [...]` inside a `for`. :)
15:45Gnosis-dnolen: okay, I'll read that
15:46amalloythere's nothing non-idiomatic about using (fn [x] (inc x)) instead of #(inc %)
15:46raekGnosis-: the keep function returns when it reaches lazy-seq
15:46jkkrameruvtc: you're also not extracting all the 3+ digit strings. e.g. in a string like "a123b456cd", you only get 123
15:47Gnosis-raek: ahhh
15:47jkkramer,(let [strs ["ab19da4890" "a123b456" "abcdefgh"]] (map #(Long/parseLong %) (mapcat #(re-seq #"[1-9]\d{2,}" %) strs)))
15:47clojurebot(4890 123 456)
15:47jkkramerutvc: ^
15:47raeklater, when the object that the lazy-seq call returned is used as a seq, the body will be evaluated
15:47amalloythough i agree that all of the lamdbas in uvtc's code would be better as a for-comprehension
15:47uvtcjkkramer, Yeah, guilty. :) I just wanted something to chew on strings so I could get a rough idea of how fast it ran.
15:48uvtcamalloy, do you mean replace the `(fn ...)`'s with `#(...)`'s? Or are you talking about something else?
15:49amalloyuvtc: S11001001 was telling you to replace them all, i'm saying that that's rubbish
15:49amalloy(and further that in this particular program you really don't need either)
15:52uvtcamalloy, 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:52amalloyuvtc: yes, in your code i would replace all of your sequence operations with for-comprehensions
15:52amalloyeg, in the comment i just made
15:53uvtcOh, you commented on the gist. Thanks.
15:53uvtcamalloy, ^^
15:57yonataneDamn. I hate having options. http://joxa.org/
15:59S11001001amalloy: #() aren't always appropriate, but usual clojure code features a mixture of fns and #()s
16:00amalloyof course
16:01S11001001am happy to discuss "how can I make my code fit S11001001's idiosyncratic standards" if people are interested in that though :)
16:02S11001001I would think not, though
16:03uvtcamalloy, 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:03amalloyno, re-seq returns a sequence, possibly of length zero, and then match iterates through that sequence
16:03duck1123Someone needs to write a lein plugin that'll send code to S11001001 and then block til he responds
16:04amalloylein cloud-compile
16:04uvtcamalloy, ohhhh. Of course. Thanks!
16:04S11001001duck1123: I have got second half right here: (dorun (repeatedly (constantly 42)))
16:06uvtcamalloy, Wait. re-seq seems to be returning nil here instead of an empty sequence:
16:07uvtc,(re-seq #"[1-9]\d{2,}" "aaaaabbbbbbcccc")
16:07clojurebotnil
16:07amalloyso?
16:07raeknil is the empty sequence. () is the empty persistent list
16:08amalloyuhhhhh, i'm not sure i'd go that far. nil and () are both empty in a sequential context
16:08amalloybut nil isn't the empty sequence, it represents nothing
16:08uvtcamalloy, 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:08amalloyno
16:08amalloymatch iterates over what re-seq returned
16:08amalloywhich is nil
16:08amalloytherefore, it iterates over no entries, and does nothing
16:09uvtcamalloy, Ah.
16:10uvtcIt's not getting set to the return value, it's iterating over what's returned. Ok. Thanks again. :)
16:11uvtc,(for [i (range 3) j nil] (str i j))
16:11clojurebot()
16:11uvtcas expected, since there's nothing for j to iterate over.
16:12uvtc,(for [i (range 3) j [nil]] (str i j))
16:12clojurebot("0" "1" "2")
16:55amalloy$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:55lazybotMessage saved.
16:57nDuffI'm seeing cljs.core.PersistentHashSet.fromArray undefined from the ClojureScript REPL
16:57nDuffsuch that the reader can't deal with, for instance, #{:t}
16:59nDuff...ooh. Running an old lein-cljsbuild, thus an old cljs
17:00nDuff...okay, fixed in current releases.
17:02dnolenamalloy: I'm curious what those numbers look like with primitive taking / returning fns
17:03dnolen"will look like"
17:03amalloydnolen: is that possible currently? i think reduce and fold still have to coerce the accumulator to an object
17:04dnolenamalloy: yes, "will look like" :)
17:04amalloydoes 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:05dnolenamalloy: the way he's talked about suggests it's not outside the realm of possibility
17:06amalloywell, 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:09dnolenamalloy: hmm what do you mean by "coerce the accumulator to an object"?
17:10amalloydnolen: well, the reducer source (eg, the thing that knows how to reduce a vector) doesn't know that your f takes primitives
17:10dnolenamalloy: why does it need to know?
17:11amalloyat some point it has to call (f acc new-val), and that's compiled using f.invoke(Object, Object)
17:11oskarthif I define a function called foo, how do I get the string foo in another ns by using the function as an argument?
17:11amalloyand it has to keep a local copy of your accumulator value in its loop/recur, which will necessarily be an Object reference
17:11hiredmanamalloy: in theory it could reflect on f and figure it out
17:12amalloyhiredman: agreed. but it won't have primitive ints in scope anyway
17:12oskarthso I have a fn "#<views$index clj_pages.views$index@2cdb03a1>" and want to reliably get "index" by using something like (CUSTOMstr index)
17:12duck1123`oskarth: functions don't know their names. If you need to get the name, pass around vars
17:12sirsublimesup peepz
17:13amalloyduck1123`: more like: functions don't have names; vars are named places to store functions
17:13sirsublimeA question about defrecord here. Easy stuff.
17:13sirsublimeSay I do (defrecord Point [x y])
17:13oskarthright, but the information is in the var, isn't it?
17:13sirsublimeThen I can create a point using (Point. 1 2)
17:14nDuffHmm.
17:14sirsublimeAFAIK, (defrecord...) also creates a (->Point ...) constructor.
17:14oskarthlike (:name (meta (var index))) sort of
17:14sirsublimeBut when I try to do (->Point 1 2) I get an exception. Like, in plan repl. Any ideas?
17:14sirsublimeWhat am I doing wrong?
17:15dnolenamalloy: hmm still don't follow ... line number?
17:17amalloydnolen: i think rich has moved stuff around since last time i looked at reducers - having trouble finding a relevant line
17:18amalloydnolen: line 94 of core/protocols.clj
17:19amalloyeach 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:22amalloyperhaps 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:23mattmoss(foo [1 2 3] [:a :b :c]) => [[1 :a] [2 :b] [3 :c]]
17:23amalloy~zip
17:23clojurebotzip 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:23mattmossWhat is foo? Am I missing a basic library func?
17:23mattmossAh.
17:24dnolenamalloy: 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:24dnolengeneric chunkable collection I mean, not generic type
17:25amalloydnolen: 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:26amalloyor 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:26dnolenamalloy: ? people will want to create vectors doubles / long
17:27amalloysure! sometimes they will. but when you reduce over those, your accumulator won't necessarily be a double or a long
17:28amalloyso you can't make that things implementation of reduce assume, say, a double accumulator
17:28amalloyit 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:30dnolenamalloy: oh sure, yes ... but my earlier point stands - seems entirely doable :)
17:30amalloyyes, between your suggestions and hiredman's it's probably possible
17:30nDuffIs there a mechanism to disable warnings in cljsc?
17:30nDuff(err, _specific_ warnings known to be false, that is)?
17:31dnolennDuff: if you're getting false positives that's a bug
17:33emezeskenDuff: I use variadic functions a lot without any spurious warnings; are you on cljsbuild 0.2.4 (clojurescript 0.0-1443)?
17:42nDuffemezeske: yes -- just moved to it a few minutes ago.
17:43nDuffdnolen / 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:46emezeskenDuff: Interesting... I only have one kwargs-style function in my project, but it's not emitting such a warning
17:46dnolennDuff: 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:13augustlanyone happen to know if there's an API to list all the collections of a db with the monger mongodb library?
18:17arohneraugustl: I dont know about monger, but congo definitely has that
18:17arohnerso it's possible
18:17Raynesaugustl: I don't see a way to, but I'd open an issue for it because the java driver has a getCollectionNames method.
18:18RaynesAlso, if you need it right now, you can just call that method yourself.
18:19RaynesSomething like (.getCollectionNames monger.core/*mongodb-database*) should work, I think,.
18:19RaynesDon't hold me to it though.
18:20augustlRaynes: (monger.core/command {:collStats "system.namespaces"}) seems to be working
18:20augustlthat's what the nodejs driver does
18:20RaynesWorks for me.
18:23augustlhow does monger compare to congo?
18:24yonatanewhat is a use case for redefining values or functions, other than magically decorating functions?
18:25yonatane(def)ing an existing symbol knowingly
18:26amalloytrying things out at the repl
18:28yonataneso def is not something you'll see in a function
18:28amalloy(almost) never
18:29Raynesaugustl: They're both totally viable. monger is a more all-in-a-box solution.
18:29yonatanewhere would you see it? in an interactive debugger?
18:29Raynesaugustl: 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:31amalloyyeah, stuff like that
18:33pbostromhey 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:33augustlhow do I work with a LinkedHashSet in clojure? Dong a "doseq" on it seems to yield characters, not the whole contents
18:34gnarmisHey, has anyone worked with the document categorizer in clj-opennlp?
18:34gnarmisI've made a model…but was wondering how to persist it so I don't have to retrain every time
18:34augustlhttp://pastie.org/4212669 to be specific ;)
18:38ToxicFrogIs it possible to configure 'lein deploy' or similar to upload to github?
18:40augustlRaynes: how do I work with the results og .getCollectionNames?
18:40augustlof*
18:40yonataneaugustl: are you destructuring that coll over there?
18:40augustlam I? :)
18:41augustlah, I am
18:48fentonI'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:49fentonShould 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:51yonataneaugustl: why not (doseq [coll (.getColl...
18:52amalloyfenton: it's certainly possible with lists, but it's certainly faster and easier with vectors or maps
18:53amalloy&(let [data [[[1 2 3] [4 5 6]] [[7 8 9] [10 11 12]]]] (update-in data [1 0 2] inc))
18:53lazybot⇒ [[[1 2 3] [4 5 6]] [[7 8 10] [10 11 12]]]
18:53gnarmisah nvm, I solved my issue. Forgot I already had it deserialized.
18:54fentonamalloy: lazybot: thanks guys, let me mull those over...
19:03ToxicFrogHow do I use (doc) to examine the docstrings of a third-party library like parsatron?
19:03ToxicFrognvm, found it
19:04ToxicFrogWasn't (use)ing properly
19:04augustlyonatane: you are right, I was not using doseq correctly
19:27augustlis it sensible to use metadata to annotate a HTTP request handler to "skip authentication"?
19:29amalloyaugustl: it's plausible, but it would be better to just not wrap that handler with your authentication middleware to begin with
19:30aperiodicfenton1: if you're working with tree structures, you should take a gander at zippers http://clojure.github.com/clojure/clojure.zip-api.html
19:30amalloyzippers 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:31augustlamalloy: yeah that makes sense actually
19:31augustlalso, the auth middleware gets the same handler at all times, so metadata can't really be used for this purpose anyway
19:34amalloywe all work with trees all the time, and zippers are only necessary/useful for a very small subsegment of tree-related tasks
19:35aperiodicyeah, 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:38aperiodicyou'll note i said 'take a gander at', not 'use' ;)
20:07augustlis there a way of writin this that doesn't require nesting if/else statements? http://pastie.org/4213040
20:08augustlin imperative languages, I'd write a list of if statements and "return", then my main logic at the bottom
20:08augustlpredicates, so to speak
20:08nullptrhttp://clojuredocs.org/clojure_core/clojure.core/if-let
20:08nullptrhttp://clojuredocs.org/clojure_core/clojure.core/cond
20:09augustlnullptr: ah, thanks
20:22ToxicFrogrgrgrgr
20:23ToxicFrogThe 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:23ToxicFrogBut I'm seriously considering it now
20:24ohpauleezToxicFrog: What are you parsing?
20:30augustla ring handler can return nil, right?
20:31weavejesteraugustl: In Compojure it can, but if it returns nil to an adapter it'll throw an exception.
20:31augustlweavejester: ah, I see
20:32augustlweavejester: my actual problem is that I have 3 handlers that I want to make into one
20:33augustlI 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:33augustltrying to wrap my head around it :)
20:35augustlhmm, that's what compojure.core/routes actually does, it seems, I'll just use that
20:36weavejesteraugustl: routes is usually the function used to combine handlers. The request cascades to each one until a non-nil response is found.
20:40ToxicFrogohpauleez: Kerbal Space Program Saved Flight State files
20:40ToxicFrogBasically a sequence of // C++ style comments, key = value properties, and TYPE { ... } nested states.
20:40ToxicFrogSo, pretty simple
20:41ToxicFrogHowever, I was hoping to be able to easily put something together using an existing parsing library
20:44ToxicFrogohpauleez: did any of that get through?
20:45ToxicFrogHmm. 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:46mthvedttoxicfrog: i assume you've tried fnparse
20:46mthvedtsorry not fnparse
20:46clojurebotexcusez-moi
20:46mthvedtuh
20:46ToxicFrogLast I checked fnparse was unmaintained and did not work in 1.4
20:46mthvedtwhats it called
20:46mthvedtyes, fnparse
20:46mthvedtit doesn't work?
20:47ToxicFrogNot according to its github or the people I asked for parser recommendations in here earlier this week
20:47mthvedtand you haven't found anything else?
20:47arohnerIMO, write your own
20:48arohnerfnparse, even when it did work, was an order of magnitude slower than a hand written parser
20:49ohpauleezToxicFrog: Anyway you can just modify one of the ANTLR grammars?
20:50ohpauleezOtherwise, just write a simple string parser, and push it all into a map
20:50ToxicFrogmthvedt: 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:50ToxicFrogParsatron is the most recent one I've tried, but it StackOverflows even on very simple grammars on inputs of a few dozen kB.
20:51hiredmanparsley
20:51mthvedtthe state of parsers in clojure sounds awful
20:51arohnerI'm not sure that parsing libraries are ever a good idea
20:51ToxicFroghiredman: yes! That's the one I couldn't remember the name of.
20:51ohpauleezarohner: +1
20:51ToxicFrogA decent parser combinator library can save you a lot of time and automatically gets you high-quality parse error reporting and whatnot
20:52ToxicFrogI've had a great time with scala.util.parsing.combinator, for example
20:53ohpauleezToxicFrog: port it and contribute it as a contrib lib? :)
20:53mthvedttoxicfrog: what was the issue with parsley?
20:53ToxicFrogI'm tempted.
20:53ToxicFrogmthvedt: 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:54mthvedttoxicfrog: and you wanted something more lightweight?
20:54ToxicFrogIt 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:54ToxicFrogYes.
20:55mthvedttoxicfrog: 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:56ToxicFrogPublished anywhere?
20:56ohpauleezIf 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:56mthvedtit's on github...
20:56ToxicFrognamed?
20:57mthvedthttps://github.com/mthvedt/clearley
20:57ToxicFrogohpauleez: if it were just kv pairs, I'd split on \n and then on = and then trim keys and values and bam, done
20:57ohpauleezexactly
20:57ToxicFrogExcept it can also include {} blocks nested arbitrarily
20:57ohpauleezahh
20:58ToxicFrogWhich, barring nonregular extensions like lua's %%b{}, means things get a bit more involved.
21:00ToxicFrogmthvedt: I'll give it a look
21:01mthvedttoxicfrog: caution, i'm still changing stuff around a bit
21:01hiredmanmthvedt: interesting, how flexible is clearley about input? the example just shows a string
21:02mthvedthiredman: it will take any seq… i don't have a robust set of test cases for that, however
21:05hiredmanmthvedt: neat
21:37ToxicFrogmthvedt: ok, I'm having trouble loading it, but it's a lein problem, not a clearley problem :/
21:41ToxicFrogI'm also getting progressively more confused about ns naming conventions with each new help/tutorial/example I read
21:42mthvedttoxicfrog: are you talking about clearley's examples?
21:42ToxicFrogmthvedt: lein's, actually
21:43mthvedttoxicfrog: oh ok
21:43ToxicFrogFor example, I used to think my project namespace should be ca.ancilla.kessler.{parser,core,client,server,...}
21:43ToxicFrogThen I thought it should be ca.ancilla/kessler.*
21:43ToxicFrogNow I don't know what it should be at all
21:44ToxicFrogmthvedt: Clearley's examples are quite, well, clear :)
21:44mthvedtthanks!
21:54ToxicFrogmthvedt: question
21:54ToxicFrogjson.clj contains: ; TODO: should def and defrule be interchangable for the single rule case?
21:54ToxicFrogBut core.clj implies that defrule already supports single rules
21:55ToxicFrogSo what's the difference in behaviour between using def and defrule?
21:55mthvedttoxicfrog: 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:55ToxicFrogAah
21:56mthvedtso it's possible i ran into a case where interchangeability didn't work
21:56mthvedti
21:56mthvedti'm working on refactoring the under the hood machinery
21:59mthvedttoxicfrog: 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:00ToxicFrogheh
22:00ToxicFrogI'm working on the sfs parser now, we'll see how it goes
22:06ToxicFrogOk, actually I'm a bit confused by scanner
22:07ToxicFrogjson defines a string-char-scanner that accepts single string chars, ie, anything but \ or "
22:08ToxicFrogthen the string-char rule accepts an escaped-char, or a unicode-hex, or something accepted by string-char-scanner...
22:08ToxicFrogBut it expresses that as ([string-char-scanner] string-char-scanner]
22:08ToxicFrogI would have expected ([string-char-scanner] identity)
22:14mthvedtlet me take a look
22:16mthvedttoxicfrog: the defrule bodies are like fn bodies
22:16mthvedtoh hang on...
22:16mthvedtyes, that's right
22:17mthvedtit's like (fn [x] x)
22:18ToxicFrogI don't follow
22:18mthvedtso defrule definitions are like defining functions
22:18mthvedtif you did ([string-char-scanner] identity), that would return 'identity
22:19mthvedtas its parse action
22:20mthvedtdoes that make sense?
22:20ToxicFrogOk, my understanding was that the parse action was oh
22:20ToxicFrogI think I get it now
22:21ToxicFrog([string-char-scanner] string-char-scanner) is:
22:21ToxicFrog- run the scanner
22:21ToxicFrog- if it succeeds, bind the value it returns to the symbolstring-char-scanner
22:21ToxicFrog- evaluate the expression: string-char-scanner (bound to the value returned by the actual scanner), and that's the result of the rule
22:22ToxicFrogand the scanner itself returns the character scanned when it succeeds.
22:22ToxicFrogYes?
22:22clojurebotyes isn't is
22:22mthvedthat's correct
22:22mthvedtthat's correct
22:23ToxicFrogOk
22:24mthvedtoccasionally, the json example uses rule instead of defrule… rule can take parse action fns directly
22:24mthvedtdefrule builds them from the forms you provide
22:31ToxicFrogHmm. What's the idiomatic way to do a zero-or-more?
22:31ToxicFrogjson 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:34ToxicFrogOh this is quite remarkable!
22:34ToxicFrogCompiling ca.ancilla.kessler.core
22:34ToxicFrogException 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:35ToxicFrogmthvedt: ok, this is not at all expected and somewhat disconcerting
22:35ToxicFrogThis works:
22:36ToxicFrog(def sfs-parser (build-parser sfs)) (defn -main [& args] (execute sfs-parser test-string))
22:36ToxicFrogThis causes the exception in the compiler mentioned above:
22:36ToxicFrog(defn -main [& args] (execute (build-parser sfs) test-string)
22:36ToxicFrogI suspect some kind of macro-related insanity, but my clojure isn't good enough to figure out what;.
22:37mthvedttoxicfrog: let me take a look
22:40ToxicFrogAlso, so far, by far the most confusing part of Clearley is when you should use def, when defn, when defrule, and when rule.
22:40mthvedttoxicfrog: agreed
22:41mthvedtnext step is probably to work on that
22:41mthvedtflesh out the docs, make the API more consistent
22:50mthvedttoxicfrog: found the problem… as you expected, it's macro-related insanity
22:51mthvedtso build-parser needs access to the current ns and environment, which is why it's a macro
22:51mthvedtclearly is designed so it's idiomatic to bind rules and defrules to symbols in your ns
22:52mthvedtit turns out, if you try to embed the macro environment variable (&env) in a defn, it doesn't work...
22:53mthvedtcan you define and execute macros with clojurebot? if so i can show you
22:53ToxicFrogI think so
22:53ToxicFrogI'm pretty new to clojure and haven't really used cljbot
22:53mthvedthere's a gist
22:53mthvedthttps://gist.github.com/3064055
22:53mthvedtif you're interested in what's going on
22:57ToxicFrogYay, I found a bug!
22:58ToxicFrog...and now I've gotten the compiler to emit a null pointer exception
22:58ToxicFrogFantastic
23:02mthvedtI'm just going to take out &env, since it's not a stable feature
23:02mthvedtof the clojure language
23:15mthvedttoxicfrog: pushed a fix
23:15mthvedtif you need it
23:19kennethhey, i'm trying to use zeromq from clojure, and am getting an unsatisfiedlinkerror at runtime that i can't seem to debug
23:19kennethhttps://gist.github.com/d0d038ff7303250bcb13
23:20kennethseems like binding works fine, but the crash occurs at recv time
23:20ToxicFrogmthvedt: thanks
23:20ToxicFrogTrying to create a minimal test case for the null pointer exception now
23:22kennethException in thread "main" java.lang.RuntimeException: java.lang.UnsatisfiedLinkError: org.zeromq.ZMQ$Socket.recv(J)[B
23:24ToxicFrogmthvedt: https://gist.github.com/a8e3a164b83182989231 causes the compiler to follow the null pointer in 1.4
23:25ToxicFrogI 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:26mthvedtyes, getting the compiler to NPE is very odd
23:26amalloykenneth: 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:28kennethamalloy: sure thing, but this is just a test project for me to get zmq to actually work, not production code
23:29kennethliterally, 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:30amalloymthvedt: &env is entirely stable, it's just that you're trying to do something impossible with it
23:31mthvedtamalloy: i found a blog post suggesting the types of the values might change
23:31mthvedtcu
23:31mthvedtrrently they're LocalBindings
23:31amalloythat's certainly true
23:31ToxicFrogmthvedt: impression so far: it'll be tops once it's less confusing and stops blowing up :/
23:31amalloyi wouldn't recommend relying on the values for much of anything
23:31amalloy&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:31lazybotjava.lang.RuntimeException: Unable to resolve symbol: env in this context
23:34mthvedttoxicfrog: you're AOT compiling? are you on 1.4?
23:35ToxicFrogmthvedt: yes; this is the result of 'lein run'
23:35ToxicFrogAnd yes I am.
23:42Raynesamalloy: Amusingly, we do rely on it in serializable-fn.
23:42RaynesBut hey, all bets are off with that thing.
23:44amalloyRaynes: 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:46Raynesamalloy: Well, what are the keys?
23:47amalloyi think they're the symbols
23:47RaynesHow would that work?
23:47RaynesAnd if it is possible, why don't we?
23:48amalloyall 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:48amalloyyes, they're the symbol names
23:48RaynesOh yeah, we're doing (.sym ..)
23:48RaynesWell aren't we just the cutest bunch.
23:50amalloyi'll send a pull req
23:51mthvedttoxicfrog: this will happen if you try to redef 'name
23:51mthvedtdoesn't appear to have anything to do with clearley :P
23:51ToxicFrogmthvedt: aha. Clojure bug, then?
23:52ToxicFrogA bit more feedback in 'cannot resolve rule for head' errors would be nice.
23:53mthvedtthis looks like a bug in the AOT compiler...
23:53mthvedti
23:53mthvedttoxicfrog: acknowledged
23:54ToxicFrogAt 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:54ToxicFrogEspecially since I have in fact defrule'd sfs.
23:54ToxicFrogOho, this is interesting
23:55mthvedtseveral references to this bug on the clojure list
23:55ToxicFrogSo I was testing your recent fix by using (execute (build-parser sfs) ...)
23:55mthvedtalong with the usual "you shouldn't be doing that anyway" jerks :(
23:55ToxicFrogIf 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:55ToxicFrogIt goes from: Exception in thread "main" java.lang.IllegalArgumentException: Cannot resolve rule for head: sfs
23:56ToxicFrogTo: Exception in thread "main" java.lang.IllegalArgumentException: Cannot resolve rule for head: typename, compiling:(core.clj:37)
23:56ToxicFrogWhich I would actually expect, since I haven't defrule'd typename yet.
23:56ToxicFrogSo it looks like using (build-parser grammar) inline still has some issues.
23:57mthvedtif you're doing build-parser inline, it's probably pulling *ns* from when it is run
23:57mthvedti should probably attach a warning to build-parser
23:57mthvedtwarning: reads the value of *ns*
23:57mthvedtor something
23:57ToxicFrogThe 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:59ToxicFrogHmm. It'd be nice if I could use regexes; stuff like rest-of-line would then become very simple.
23:59mthvedttoxicfrog: yes, but in my judgment it was a small amount of voodoo to enable easy defrules