2012-07-06
| 00:09 | TimMc | Is there a fn like take-while but that will take one more element? |
| 00:12 | TimMc | For instance, (___ odd? [1 3 5 8 10 12]) => (1 3 5 8) |
| 00:16 | TimMc | (Well, I don't need it anymore.) |
| 00: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? |
| 00:40 | arohner | arrdem: you can use set! inside a binding call, but that's threadlocal only, and not very idiomatic |
| 00:40 | arohner | if your goal is to do things "the clojure way", you should probably rethink the design |
| 00: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. |
| 00:43 | arohner | you could also use atoms, but it's poor clojure to use numerous atoms |
| 00:43 | arohner | inside a binding block, you can set! (binding [foo (bar)] (set! foo 42)) |
| 00:43 | arohner | the variable will mutate, but it's thread-local only, and will revert to it's old value outside the binding |
| 00:44 | arrdem | Ah. thanks, I had never heard of the (binding) expression. |
| 00:44 | arohner | oh, and the variable needs to be declared dynamic |
| 00:44 | arohner | (def ^:dynamic foo) |
| 00:44 | arrdem | noted. presumably [binding it's use is descuraged? |
| 00:45 | arrdem | * noted. presumably binding's use is descuraged? |
| 00:45 | arohner | all of these exist to be used. What's discouraged is using a lot of mutable state |
| 00:45 | arohner | clojure emphasizes reducing the amount of mutable state, and being clear about when/how things change |
| 00:47 | arohner | binding is typically used for "configuration", rather than computation |
| 00:48 | arrdem | why is that? Oh. create local state and then invoke stateful routines from the compartmentalized scope... that makes sense |
| 00:48 | arrdem | Cool! learned something today... thanks for the help! |
| 00: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 |
| 00:50 | arohner | so the clojure "boxes", var, ref, atom, agent each hold mutable state, in a different, safe, way |
| 00:51 | arohner | vars can only be mutated thread-locally, refs mutate globally, but through the STM, etc |
| 00: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)) ? |
| 00:54 | noidi | is abusing map for side effects OK, or can I do this somehow with doseq? |
| 00: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) |
| 00:54 | arohner | noidi: (dorun (map..)) is fine |
| 00:54 | nicholasf | surely I don't have to define register-device *above* n-devices? |
| 00:55 | noidi | nicholasf, unfortunately you do :( |
| 00:55 | arrdem | nicholasf: you do in fact have to |
| 00:55 | nicholasf | noidi: wow, ok |
| 00:55 | noidi | or at least (declare register-device) |
| 00:55 | arohner | noidi: you can also (doseq [[one two] (map vec arg-1s arg2s)] (impure one two)) |
| 00:55 | arrdem | Clojure's base CompilationUnit is an s expression |
| 00:55 | arrdem | not a file |
| 00:55 | arrdem | so order matters |
| 00:55 | nicholasf | thanks mate |
| 00:55 | arrdem | np |
| 00:56 | arohner | nicholasf: you can also use declare |
| 00:56 | arohner | (declare register-device) (defn n-devices ...) (defn register-device ...) |
| 00:56 | arrdem | arohner: why use (declare) not (def)? |
| 00:56 | arohner | arrdem: expresses intent more clearly |
| 00:56 | arrdem | (doc declare) |
| 00:56 | clojurebot | "([& names]); defs the supplied var names with no bindings, useful for making forward declarations." |
| 00:56 | arrdem | Oh. shiny! |
| 00:57 | arohner | declare also supports (declare foo bar) |
| 00:57 | noidi | (declare foo bar baz) vs. (def foo)(def bar)(def baz) |
| 00:57 | nicholasf | arohner: yup, thanks |
| 00: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) |
| 00:58 | nicholasf | ok, so that's what declare means |
| 00:58 | nicholasf | it's like a deferred define |
| 00: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) |
| 01:09 | noidi | nicholasf, damnit, I forgot the link :D http://news.ycombinator.com/item?id=2467809 |
| 01:09 | nicholasf | thanks noidi |
| 01:11 | nicholasf | yeh that helps set the situation in context thanks |
| 02:45 | nicholasf | anyone using a redis client that will support publishing to channels? redis-clojure doesn't seem to |
| 02:53 | nkkarthik | excuse me... is this the right place to ask a question on swank-clojure plugin? |
| 02:53 | amalloy | ~swank |
| 02:53 | clojurebot | swank is trust the readme and the readme only. all others will lead you astray. |
| 02:54 | nkkarthik | :) ok thanks... i will keep searching then |
| 02:54 | amalloy | nkkarthik: nah, you can ask in here. just don't trust any blogs or whatever |
| 02: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 |
| 02:57 | nkkarthik | 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 |
| 02:58 | nkkarthik | I am not sure why clojure-jack-in clears the class files and doesn't compile them again |
| 02:58 | nkkarthik | any clue? |
| 03:19 | nkkarthik | I think I got that... lein-swank 1.4.4 has this problem... I changed to 1.4.3 and it works! |
| 04:46 | noidi | are there any guidelines on when to :use vs. :require other namespaces? |
| 04: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. |
| 04:49 | noidi | yeah, nowadays I tend to :use everything (with :only, of course), and only use :require when the names would clash otherwise |
| 04:50 | noidi | I was just wondering if that's common practice |
| 04:51 | noidi | the reason I avoid :require is that having a prefix namespace prefix on every symbol kind of defeats the point of namespaces |
| 04:51 | noidi | it's almost like programming in c :) |
| 04: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 |
| 04:57 | amalloy | 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 |
| 05:02 | noidi | oh, cool |
| 05:02 | noidi | I didn't know about the :refer option to 'require |
| 05:06 | AWizzArd | use is very nice for the repl. |
| 05:06 | AWizzArd | What I find unfortunate is that doc and apropos reside in the clojure.repl ns. I constantly have to use it. |
| 05:11 | Raynes | If you use lein2's repl, you don't have to. |
| 05:11 | Raynes | And if you use slime, you don't even need it. |
| 06:03 | ro_st | anyone using cemerick's friend? how do i access the authenticated user data once a user has signed in? |
| 06:18 | mystiiq | has anyone used clj-ssh? how can I disable all that INFO logging that is displayed in terminal? |
| 06:28 | wingy | didnt know about this one: https://github.com/halgari/clojure-py |
| 06:28 | wingy | is there a good reason for why we would like it to run on python? |
| 06:28 | wingy | i can understand the js implementation since we need it in the browsers. also allowing better scripting support |
| 06:31 | jeremyheiler | wingy: the README for the project explains why they started the project |
| 06:33 | wingy | always read first |
| 06:34 | wingy | technomancy: there are no plans for lein to be run on node.js instead for eliminating start up time for various tasks? |
| 06:36 | jalatera_ | what' the best way to search a nested hash map structure |
| 06:40 | xumingmingv | jalatera_: search a nested map? search for a value in the nested map? |
| 06:44 | ro_st | wingy: java folks are working on jvm start up time. the problem will go away eventuall |
| 06:44 | ro_st | i doubt very much that lein will move to node.js :) |
| 06:45 | wingy | ro_st: but there will always be a startup time on jvm? |
| 06:45 | ro_st | yes |
| 06:45 | ro_st | what repetitive tasks are you using lein for? |
| 06:46 | wingy | lein repl :) |
| 06:46 | wingy | but also i would like to install my own tasks |
| 06:47 | wingy | eg saving project with git |
| 06:48 | wingy | 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? |
| 06:49 | wingy | one i can think of is that people dont need to install node.js |
| 06:49 | wingy | perhaps its better for me to script in node.js myself |
| 06:57 | ordnungswidrig | wingy: nice idea, lein on node |
| 07:02 | yonatane | there's a js implementation of clojure?! |
| 07:02 | wingy | yonatane: are you kidding |
| 07:02 | yonatane | you mean clojurescript or something else? |
| 07:03 | wingy | clojurescript |
| 07:03 | yonatane | oh |
| 07:03 | yonatane | i should do more reading :) |
| 07: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. |
| 07:24 | wingy | special anonymous function can not be used as fn call? |
| 07:24 | wingy | ,(#(%) "hello") |
| 07:24 | clojurebot | #<ClassCastException java.lang.ClassCastException: java.lang.String cannot be cast to clojure.lang.IFn> |
| 07:24 | unnali | ("hello") |
| 07:24 | unnali | wingy: ^this wouldn't work either |
| 07:25 | wingy | oh yeah i forgot |
| 07:26 | wingy | thought the anonymous function wasnt run |
| 07:26 | unnali | :D |
| 07:26 | wingy | (#(do %) "hello") |
| 07:27 | unnali | ,(#(do %) "hello") |
| 07:27 | clojurebot | "hello" |
| 07:27 | wingy | special anonymous fns look so concise |
| 07:27 | wingy | very handsome |
| 07:27 | unnali | handsome?? |
| 07:27 | lazybot | unnali: What are you, crazy? Of course not! |
| 07:28 | unnali | lazybot: ... |
| 07: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)? |
| 07:51 | ro_st | with friend |
| 07:52 | ro_st | 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) |
| 07:58 | ro_st | cemerick: also, how do i access the signed-in user from within my compojure routed fns? |
| 07:58 | jeremyheiler | unnali: if you (load-file "test/project_name/core_test.clj") you can then run (run-tests 'project_name.core_test) |
| 07:59 | cemerick | ro_st: Sure; any code that isn't protected by an authorization middleware/expression will remain accessible to anonymous users. |
| 07: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! |
| 08:00 | cemerick | ro_st: See cemerick.friend/identity and cemerick.friend/*identity* to get access to the signed-in user |
| 08:01 | jeremyheiler | unnali: nice |
| 08:02 | jeremyheiler | that makes a little more sense :-P |
| 08: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? |
| 08:03 | cemerick | yup |
| 08: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 |
| 08:06 | ro_st | best way to learn, though, ain't it :-) |
| 08:06 | ro_st | i found writing my own md5 fn to be really easy |
| 08:07 | ro_st | to support legacy user accounts |
| 08:07 | ro_st | going to put a bcrypt re-encrypt-on-login-or-reset system into place so that over time the md5 passwords fall away |
| 08:12 | cemerick | well, having an api shouldn't (on its own) require a custom workflow |
| 08:13 | ro_st | which workflow should i use, then? interactive-form is going to do redirects which i don't want |
| 08:14 | ro_st | http basic with ssl, probably? |
| 08: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. |
| 08:29 | mystiiq | can clj-json make a JSON string out of {:foo "bar"} or should I use cheshire |
| 08:29 | ro_st | both can do it |
| 08:30 | ro_st | with cheshire: (generate-string {:foo "bar"}) |
| 08:31 | cmiles74 | mystiiq: I've been using Cheshire for a whie and am happy with it. |
| 08:32 | ro_st | do i need to restart my emacs repl if i change project.clj deps? |
| 08:32 | xumingmingv | does maven have a similar command to `lein uberjar`? |
| 08:32 | ro_st | i do at the moment, but i'm not sure if i do actually have to |
| 08: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. |
| 08:33 | ro_st | thanks |
| 08:35 | mystiiq | how can I prevent the java browser from opening when using "lein ring server" |
| 08:35 | ro_st | server-headless |
| 08: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 |
| 08:36 | mystiiq | ro_st: thanks |
| 08: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 |
| 08:36 | cmiles74 | cemerick: Ha! I was just looking at that page. :P I've had the bookmark in there forever. |
| 08:38 | xumingmingv | I found the uberjar plugin: http://maven.apache.org/maven-1.x/plugins/uberjar/ |
| 08:38 | ro_st | whoa, that's handy! |
| 08:41 | ro_st | 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? |
| 08: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 |
| 08:42 | ro_st | ok super. authenticate is wrapping the whole lot |
| 08:43 | ro_st | thanks for your patience. so totally going to produce and share sample code once i've got it all working |
| 08:43 | ro_st | which'll probably have several large holes poked in it, but hey :-) |
| 09: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 |
| 09:49 | ro_st | look into agents mystiiq |
| 09:50 | the-kenny | mystiiq: You can easily spawn a thread or use agents |
| 09:50 | mdeboard | Is that what aleph is for btw? |
| 09: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 |
| 09: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) |
| 09:54 | duck1123 | it also works really well for streaming requests and websockets |
| 09:54 | mdeboard | I see; I guess in my mind aleph ~= celery (python library) |
| 09:54 | mdeboard | that's wrong apparently |
| 09:56 | antares_ | mdeboard: yes, aleph is definitely not a "job queue/workers" kind of thing |
| 09: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: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: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 | qubit[01] | test/core.clj |
| 12:37 | qubit[01] | compiling with C-c C-c |
| 12:38 | qubit[01] | if I omit the namespace, it just says no such namespace: '<blank>' |
| 12:41 | qubit[01] | 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 | madsy | 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 | oskarth | 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 | oskarth | ok, thanks :) |
| 12:51 | dnolen | oskarth: yep |
| 12:52 | qubit[01] | gah |
| 12:52 | qubit[01] | so much to learn |
| 12:52 | qubit[01] | how do I kill the f'n repl because my recurse function wont stop because I cant figure out to use paraedit |
| 12:52 | qubit[01] | 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 | madsy | 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 | madsy | 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 | ieure | Use the right tool for the job. |
| 13:05 | ieure | Personally, lots of the things I do are best served by the innate Runnable-ness of functions. |
| 13:05 | ieure | 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 | bhenry | 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 | sjl | (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 | dnolen | 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 | dnolen | 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 | qubit[01] | 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 | ieure | 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 | augustl | 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 | augustl | 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 | amalloy | 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 | tyre771 | 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 | tyre771 | 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 | augustl | 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 | tyre771 | 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 | augustl | 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 | ieure | Yeah. |
| 14:11 | ieure | 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 | augustl | 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 | dnolen | 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 | augustl | 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 | amalloy | 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 | augustl | 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 | yonatane | augustl: yes |
| 14:24 | augustl | yonatane: yes, a macro can expand into any kind of code |
| 14:25 | augustl | 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 | augustl | 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 | duck1123 | 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 | augustl | another example of something that might be relevant |
| 14:32 | augustl | a namespace has a pool of objects, other namespaces calls a factory function to get objects from that pool |
| 14:32 | augustl | 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 | augustl | 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 | augustl | 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 | antares_ | 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 | augustl | its map of error messages have sets for keys |
| 14:38 | augustl | 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 | antares_ | 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 | cljs_newb_29582 | to convince apple to remake them again |
| 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 | madsy | For example when using WebGL: (swap! vertexShader (. gl creatShader)) could create N new shaders while swap retries. |
| 14:46 | madsy | 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 | raek | madsy: ^ |
| 14:49 | raek | 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 | madsy | 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 | ToxicFrog | 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 | raek | 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 | raek | 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 | ToxicFrog | *do. |
| 15:06 | ToxicFrog | 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 | ToxicFrog | (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 | augustl | 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 | amalloy | 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 | Cheiron | 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 | jweiss | 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 | Cheiron | since the performance is an issue. do you suggest to use type hints? |
| 15:25 | Cheiron | 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: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 | uvtc | 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 | S11001001 | 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 | uvtc | 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 | ToxicFrog | 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 | Gnosis- | 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 | uvtc | 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 | amalloy | (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 | amalloy | eg, in the comment i just made |
| 15:53 | uvtc | Oh, you commented on the gist. Thanks. |
| 15:53 | uvtc | 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 | S11001001 | 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 | uvtc | ,(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 | amalloy | 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 | amalloy | match iterates over what re-seq returned |
| 16:08 | amalloy | which is nil |
| 16:08 | amalloy | therefore, it iterates over no entries, and does nothing |
| 16:09 | uvtc | amalloy, Ah. |
| 16:10 | uvtc | It's not getting set to the return value, it's iterating over what's returned. Ok. Thanks again. :) |
| 16:11 | uvtc | ,(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 | uvtc | ,(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 | nDuff | such that the reader can't deal with, for instance, #{:t} |
| 16:59 | nDuff | ...ooh. Running an old lein-cljsbuild, thus an old cljs |
| 17:00 | nDuff | ...okay, fixed in current releases. |
| 17:02 | dnolen | amalloy: I'm curious what those numbers look like with primitive taking / returning fns |
| 17:03 | dnolen | "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 | sirsublime | 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 | 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 | sirsublime | 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 | amalloy | dnolen: line 94 of core/protocols.clj |
| 17:19 | amalloy | 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 | amalloy | 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 | mattmoss | 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 | dnolen | 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 | amalloy | 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 | amalloy | so you can't make that things implementation of reduce assume, say, a double accumulator |
| 17:28 | amalloy | 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 | nDuff | (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 | nDuff | 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 | arohner | 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 | Raynes | Also, if you need it right now, you can just call that method yourself. |
| 18:19 | Raynes | Something like (.getCollectionNames monger.core/*mongodb-database*) should work, I think,. |
| 18:19 | Raynes | Don't hold me to it though. |
| 18:20 | augustl | Raynes: (monger.core/command {:collStats "system.namespaces"}) seems to be working |
| 18:20 | augustl | 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 | yonatane | (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 | gnarmis | 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 | augustl | of* |
| 18:40 | yonatane | augustl: are you destructuring that coll over there? |
| 18:40 | augustl | am I? :) |
| 18:41 | augustl | 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 | fenton | 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 | amalloy | &(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 | ToxicFrog | nvm, found it |
| 19:04 | ToxicFrog | Wasn't (use)ing properly |
| 19:04 | augustl | yonatane: you are right, I was not using doseq correctly |
| 19:27 | augustl | 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 | augustl | 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 | aperiodic | 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 | augustl | in imperative languages, I'd write a list of if statements and "return", then my main logic at the bottom |
| 20:08 | augustl | predicates, so to speak |
| 20:08 | nullptr | http://clojuredocs.org/clojure_core/clojure.core/if-let |
| 20:08 | nullptr | http://clojuredocs.org/clojure_core/clojure.core/cond |
| 20:09 | augustl | nullptr: ah, thanks |
| 20:22 | ToxicFrog | rgrgrgr |
| 20:23 | ToxicFrog | 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 | ToxicFrog | 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 | augustl | weavejester: my actual problem is that I have 3 handlers that I want to make into one |
| 20:33 | augustl | 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 | augustl | trying to wrap my head around it :) |
| 20:35 | augustl | 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 | ToxicFrog | Basically a sequence of // C++ style comments, key = value properties, and TYPE { ... } nested states. |
| 20:40 | ToxicFrog | So, pretty simple |
| 20:41 | ToxicFrog | However, I was hoping to be able to easily put something together using an existing parsing library |
| 20:44 | ToxicFrog | ohpauleez: did any of that get through? |
| 20:45 | ToxicFrog | 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 | mthvedt | 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 | mthvedt | yes, fnparse |
| 20:46 | mthvedt | 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 | arohner | 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 | ohpauleez | 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 | ToxicFrog | 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 | ToxicFrog | 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 | ToxicFrog | 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 | ToxicFrog | 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 | ToxicFrog | 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 | ToxicFrog | 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 | ToxicFrog | Then I thought it should be ca.ancilla/kessler.* |
| 21:43 | ToxicFrog | Now I don't know what it should be at all |
| 21:44 | ToxicFrog | mthvedt: Clearley's examples are quite, well, clear :) |
| 21:44 | mthvedt | thanks! |
| 21:54 | ToxicFrog | mthvedt: question |
| 21:54 | ToxicFrog | json.clj contains: ; TODO: should def and defrule be interchangable for the single rule case? |
| 21:54 | ToxicFrog | But core.clj implies that defrule already supports single rules |
| 21:55 | ToxicFrog | 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 | mthvedt | i |
| 21:56 | mthvedt | i'm working on refactoring the under the hood machinery |
| 21:59 | mthvedt | 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 | ToxicFrog | I'm working on the sfs parser now, we'll see how it goes |
| 22:06 | ToxicFrog | Ok, actually I'm a bit confused by scanner |
| 22:07 | ToxicFrog | json defines a string-char-scanner that accepts single string chars, ie, anything but \ or " |
| 22:08 | ToxicFrog | then the string-char rule accepts an escaped-char, or a unicode-hex, or something accepted by string-char-scanner... |
| 22:08 | ToxicFrog | But it expresses that as ([string-char-scanner] string-char-scanner] |
| 22:08 | ToxicFrog | I would have expected ([string-char-scanner] identity) |
| 22:14 | mthvedt | let me take a look |
| 22:16 | mthvedt | toxicfrog: the defrule bodies are like fn bodies |
| 22:16 | mthvedt | oh hang on... |
| 22:16 | mthvedt | yes, that's right |
| 22:17 | mthvedt | 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 | mthvedt | if you did ([string-char-scanner] identity), that would return 'identity |
| 22:19 | mthvedt | as its parse action |
| 22:20 | mthvedt | does that make sense? |
| 22:20 | ToxicFrog | Ok, my understanding was that the parse action was oh |
| 22:20 | ToxicFrog | I think I get it now |
| 22:21 | ToxicFrog | ([string-char-scanner] string-char-scanner) is: |
| 22:21 | ToxicFrog | - run the scanner |
| 22:21 | ToxicFrog | - if it succeeds, bind the value it returns to the symbolstring-char-scanner |
| 22:21 | ToxicFrog | - 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 | ToxicFrog | and the scanner itself returns the character scanned when it succeeds. |
| 22:22 | ToxicFrog | Yes? |
| 22:22 | clojurebot | yes isn't is |
| 22:22 | mthvedt | hat's correct |
| 22:22 | mthvedt | 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 | mthvedt | 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 | ToxicFrog | 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 | ToxicFrog | Oh this is quite remarkable! |
| 22:34 | ToxicFrog | Compiling ca.ancilla.kessler.core |
| 22:34 | ToxicFrog | 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 | ToxicFrog | mthvedt: ok, this is not at all expected and somewhat disconcerting |
| 22:35 | ToxicFrog | This works: |
| 22:36 | ToxicFrog | (def sfs-parser (build-parser sfs)) (defn -main [& args] (execute sfs-parser test-string)) |
| 22:36 | ToxicFrog | This causes the exception in the compiler mentioned above: |
| 22:36 | ToxicFrog | (defn -main [& args] (execute (build-parser sfs) test-string) |
| 22:36 | ToxicFrog | 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 | mthvedt | next step is probably to work on that |
| 22:41 | mthvedt | flesh out the docs, make the API more consistent |
| 22:50 | mthvedt | toxicfrog: found the problem… as you expected, it's macro-related insanity |
| 22:51 | mthvedt | so build-parser needs access to the current ns and environment, which is why it's a macro |
| 22:51 | mthvedt | clearly is designed so it's idiomatic to bind rules and defrules to symbols in your ns |
| 22:52 | mthvedt | it turns out, if you try to embed the macro environment variable (&env) in a defn, it doesn't work... |
| 22:53 | mthvedt | can you define and execute macros with clojurebot? if so i can show you |
| 22:53 | ToxicFrog | I think so |
| 22:53 | ToxicFrog | I'm pretty new to clojure and haven't really used cljbot |
| 22:53 | mthvedt | here's a gist |
| 22:53 | mthvedt | https://gist.github.com/3064055 |
| 22:53 | mthvedt | if you're interested in what's going on |
| 22:57 | ToxicFrog | Yay, I found a bug! |
| 22:58 | ToxicFrog | ...and now I've gotten the compiler to emit a null pointer exception |
| 22:58 | ToxicFrog | Fantastic |
| 23:02 | mthvedt | I'm just going to take out &env, since it's not a stable feature |
| 23:02 | mthvedt | of the clojure language |
| 23:15 | mthvedt | toxicfrog: pushed a fix |
| 23:15 | mthvedt | 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 | kenneth | https://gist.github.com/d0d038ff7303250bcb13 |
| 23:20 | kenneth | seems like binding works fine, but the crash occurs at recv time |
| 23:20 | ToxicFrog | mthvedt: thanks |
| 23:20 | ToxicFrog | 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 | ToxicFrog | 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 | kenneth | 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 | mthvedt | cu |
| 23:31 | mthvedt | 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 | amalloy | &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 | ToxicFrog | And yes I am. |
| 23:42 | Raynes | amalloy: Amusingly, we do rely on it in serializable-fn. |
| 23:42 | Raynes | 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 | Raynes | 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 | amalloy | yes, they're the symbol names |
| 23:48 | Raynes | Oh yeah, we're doing (.sym ..) |
| 23:48 | Raynes | 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 | mthvedt | doesn't appear to have anything to do with clearley :P |
| 23:51 | ToxicFrog | mthvedt: aha. Clojure bug, then? |
| 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 | mthvedt | i |
| 23:53 | mthvedt | 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 | ToxicFrog | Especially since I have in fact defrule'd sfs. |
| 23:54 | ToxicFrog | 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 | ToxicFrog | It goes from: Exception in thread "main" java.lang.IllegalArgumentException: Cannot resolve rule for head: sfs |
| 23:56 | ToxicFrog | To: Exception in thread "main" java.lang.IllegalArgumentException: Cannot resolve rule for head: typename, compiling:(core.clj:37) |
| 23:56 | ToxicFrog | Which I would actually expect, since I haven't defrule'd typename yet. |
| 23:56 | ToxicFrog | 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 | mthvedt | i should probably attach a warning to build-parser |
| 23:57 | mthvedt | warning: reads the value of *ns* |
| 23:57 | mthvedt | 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 | ToxicFrog | 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 |