2014-10-19
| 00:04 | MrJones98 | how would one apply #’ via map/mapv? |
| 00:04 | MrJones98 | in other words, i have a seq of symbols |
| 00:04 | MrJones98 | and would like to that into vars |
| 00:07 | justin_smith | MrJones98: var is a macro, you can't map with it |
| 00:07 | justin_smith | you probably want resolve |
| 00:08 | justin_smith | ,(map resolve '[+ - *]) |
| 00:08 | clojurebot | (#'clojure.core/+ #'clojure.core/- #'clojure.core/*) |
| 00:09 | MrJones98 | justin_smith: hmm… that makes sense |
| 00:09 | MrJones98 | now i just need to figure out why resolve is returning nil |
| 00:10 | justin_smith | what are you trying to resolve? |
| 00:10 | MrJones98 | playing around with a lein plugin |
| 00:10 | MrJones98 | so basically… i’m using lein-ring and when it starts the nrepl server, it ignores :nrepl-middleware |
| 00:10 | justin_smith | I mean, is the thing you are trying to resolve in a namespace you have loaded? are you sure that namespace is loaded, etc. |
| 00:10 | MrJones98 | my guess is the namespace isn’t loaded |
| 00:11 | MrJones98 | what’s the proper way for loading a namespace at runtime? |
| 00:12 | justin_smith | require |
| 00:12 | MrJones98 | is a (require ..) |
| 00:12 | MrJones98 | hahaha, ok |
| 00:12 | MrJones98 | thanks |
| 00:12 | justin_smith | (doc require) |
| 00:12 | clojurebot | "([& args]); Loads libs, skipping any that are already loaded. Each argument is either a libspec that identifies a lib, a prefix list that identifies multiple libs whose names share a common prefix, or a flag that modifies how all the identified libs are loaded. Use :require in the ns macro in preference to calling this directly. Libs A 'lib' is a named set of resources in classpath whose contents define a library of |
| 00:12 | justin_smith | it's similar to the :require block in an ns form, but not identical |
| 00:13 | justin_smith | and actually, you should be putting anything you need in the :require block of the ns, using require directly is just for the repl, or weird meta stuff |
| 00:13 | MrJones98 | problem is these middlewares are specified in project.clj |
| 00:14 | justin_smith | right |
| 00:14 | MrJones98 | so i need to requre them then resolve them, i think |
| 00:14 | MrJones98 | would this be safe for the fn to pass to map: (fn [s] (require (namespace s)) (resolve s)) |
| 00:14 | MrJones98 | (trying it now) |
| 00:14 | justin_smith | so you are trying to manually parse something in project.clj? |
| 00:15 | justin_smith | there has to be a sane way to do this, and that is not it... |
| 00:15 | MrJones98 | effectively, yeah… extract it out of project.clj and pass it off to a handler |
| 00:15 | MrJones98 | it doesn’t feel right |
| 00:15 | MrJones98 | but i’m trying to make the various components play nice |
| 00:15 | MrJones98 | letting them all do what they originally attempt |
| 00:15 | MrJones98 | our project uses lein-ring and i’m trying to get simple-brepl working with it |
| 00:15 | justin_smith | you don't actually need lein-ring you know |
| 00:16 | MrJones98 | justin_smith: interesting... |
| 00:16 | MrJones98 | that might make my life easier |
| 00:16 | justin_smith | it will likely be easier to just directly create and start a ring handler, and then let the regular lein stuff work like normal |
| 00:16 | MrJones98 | ok |
| 00:16 | MrJones98 | i’ll look into that now |
| 00:17 | MrJones98 | my current efforts just feel like i’m trying to squish a square peg into a round hole |
| 00:17 | justin_smith | right |
| 00:17 | egghead | yay, just pushed a small clj project to the docker registry |
| 00:20 | MrJones98 | justin_smith: is it realy as simple as (run-jetty handler {:port 3000}) |
| 00:22 | pdmct | how do I apply a list of functions to a single set? eg (??? [:a :b] {:a 1 :b 2 :c 3}) --> [1 2] |
| 00:23 | justin_smith | MrJones98: that is pretty much it, yeah |
| 00:23 | egghead | pdmct: juxt |
| 00:23 | justin_smith | MrJones98: that's why accepting any inconvenience from lein-ring is kind of silly |
| 00:23 | MrJones98 | justin_smith: no kidding |
| 00:24 | egghead | pdmct: ,((juxt :a :b) {:a 1 :b 2 :c 3}) |
| 00:24 | pdmct | egghead: thanks |
| 00:24 | justin_smith | MrJones98: the difference being also that you need the jetty handler (or some other standalone handler) explicitly in your deps, and lein ring kind of abstracts over running an embedded server vs. running in a container, but it's not a huge thing |
| 00:25 | MrJones98 | so we’re running it in immutant in production |
| 00:25 | MrJones98 | i just checked the immutant docs though… seems we can still have the :ring{} options in project.clj |
| 00:25 | MrJones98 | but not necessarily use lein-ring |
| 00:27 | justin_smith | yeah, there is a little bit of env specific config to sort out, but it's not as big as "hacking together middleware that should just work" |
| 00:27 | MrJones98 | justin_smith: agreed |
| 00:28 | MrJones98 | now i’m hoping adding an nrepl is as easy as getting jetty up |
| 00:29 | MrJones98 | looks simple enough |
| 00:43 | justin_smith | also you could just run lein repl and start up the jetty server from the repl |
| 01:28 | dysfun_ | how does clojure rewrite unicode names? |
| 01:28 | dysfun_ | are the translation rules written down anywhere? |
| 01:28 | justin_smith | ,(munge "☃") ; often it doesn't at all |
| 01:28 | clojurebot | "☃" |
| 01:28 | justin_smith | munge |
| 01:28 | justin_smith | (doc munge) |
| 01:28 | clojurebot | "([s]); " |
| 01:28 | justin_smith | ugh |
| 01:28 | justin_smith | $source munge |
| 01:28 | lazybot | munge is http://is.gd/OckYZt |
| 01:29 | dysfun_ | so if i generate a java class, it's got a unicode-named funciton? |
| 01:29 | justin_smith | right, which is legal in java |
| 01:29 | justin_smith | munge guarantees it's a valid java name |
| 01:29 | dysfun_ | ah. right |
| 01:29 | dysfun_ | ah right, thanks |
| 01:29 | justin_smith | ,(munge "my-ns") |
| 01:29 | clojurebot | "my_ns" |
| 01:29 | justin_smith | that's what it's really about |
| 01:29 | justin_smith | ,(munge "this->that") |
| 01:29 | clojurebot | "this__GT_that" |
| 01:30 | dysfun_ | and of course ? -> _q |
| 01:30 | justin_smith | yup |
| 01:30 | dysfun_ | that one is a particularly nice touch |
| 01:30 | justin_smith | ,(munge "really?!?!") |
| 01:30 | clojurebot | "really_QMARK__BANG__QMARK__BANG_" |
| 01:30 | justin_smith | ,(munge "!!!on the door baby love shack") |
| 01:30 | clojurebot | "_BANG__BANG__BANG_on the door baby love shack" |
| 01:31 | dysfun_ | ,(munge "really?") |
| 01:31 | clojurebot | "really_QMARK_" |
| 01:31 | justin_smith | heh |
| 01:31 | justin_smith | funny that it leaves spaces- since they don't make much sense in clojure either I guess |
| 01:32 | dysfun_ | *sigh* i wish i could find an actual definition of what characters are valid in a symbol. the reader allows invalid symbols that will fail to compile |
| 01:32 | dysfun_ | or invalid patterns |
| 01:32 | dysfun_ | isn't there a handy regex somewhere? |
| 01:38 | justin_smith | ,(symbol "hey, the reader don't care") |
| 01:38 | clojurebot | hey, the reader don't care |
| 01:38 | dysfun_ | yes, sadly i care in this case |
| 01:40 | justin_smith | http://clojure.org/reader |
| 01:40 | dysfun_ | that's totally inaccurate |
| 01:40 | dysfun_ | reading the source fared much better |
| 01:40 | justin_smith | "Symbols begin with a non-numeric character and can contain alphanumeric characters and *, +, !, -, _, and ?" |
| 01:40 | justin_smith | that's what's *officially* supported |
| 01:41 | dysfun_ | right, except we all use characters like > automatically because we use records |
| 01:41 | dysfun_ | not to mention threading |
| 01:41 | justin_smith | right, that documentation is a bit odd |
| 01:41 | dysfun_ | and > and < |
| 01:41 | justin_smith | and ' definitely gets used when people want to get mathy |
| 01:41 | justin_smith | x, x', x'' |
| 01:42 | dysfun_ | yup |
| 01:54 | amalloy | justin_smith: that documentation was invalid when it was written |
| 01:54 | amalloy | >= is a function in clojure.core, for example |
| 01:57 | justin_smith | yeah |
| 01:57 | justin_smith | silly me for thinking it would be helpful :) |
| 01:59 | andyf | dysfun_: justin_smith: If you care about getting it fixed, I?d recommend voting on this ticket: http://dev.clojure.org/jira/browse/CLJ-1527 |
| 01:59 | andyf | It can make a difference in how soon such things are addressed. |
| 02:00 | dysfun_ | voted |
| 02:13 | justin_smith | andyf: thanks |
| 02:15 | justin_smith | voted |
| 02:19 | arrdem | andyf: voted. thanks. |
| 03:00 | Jaood | what version of Java is used to develop Clojure? |
| 03:03 | Jaood | looks like Java 6 |
| 03:04 | knosys | Clojure requires only Java 1.6 or greater, plus the Clojure JAR file itself. |
| 03:04 | knosys | pasted from clojure.org |
| 03:08 | Jaood | knosys: yeah, I was more curious about what version/api is used develop clojure as opposed to what runtime is required |
| 03:08 | dysfun_ | ,(munge "a'") ; really ?! |
| 03:08 | clojurebot | "a_SINGLEQUOTE_" |
| 03:08 | dysfun_ | that's verbose as hell |
| 03:10 | dysfun_ | well to support java 1.6, you have to use java 1.6 |
| 03:10 | dysfun_ | otherwise you can't be sure |
| 03:10 | Jaood | dysfun_: won't java 1.5 bytecode run on java 1.6? |
| 03:10 | knosys | Aaahh sorry Jaood! |
| 03:11 | dysfun_ | Jaood: yes, but how can you be sure that your code will run on 1.5 if you've got 1.6 available? |
| 03:11 | dysfun_ | or at least some step that runs tests has to have 1.6 available |
| 03:12 | dysfun_ | you could do it on newer java and religiously check every time you import something new, i suppose |
| 03:13 | dysfun_ | anyway, having multiple copies of the jvm lying around isn't terribly difficult |
| 03:14 | Jaood | dysfun_: sure, I was nitpicking there, does clojure uses any java 1.6 features? the changelog only mentions that clojure now builds with java 1.6 |
| 03:14 | dysfun_ | i don't honestly know. i try to avoid reading java as a rule. sadly i did have to dive into the code the other day to figure something out |
| 03:15 | Jaood | k |
| 03:15 | Jaood | good rule ;) |
| 03:15 | dysfun_ | java is never going to make me happy |
| 03:17 | Jaood | is good to know java to appreciate just how simple clojure makes things |
| 03:17 | dysfun_ | i didn't say i don't know java, merely that it won't make me happy :) |
| 03:17 | Jaood | oh I didn't imply that, just saying |
| 03:19 | dysfun_ | it's all just syntax. and annoying restrictions in the case of java. |
| 03:20 | Jaood | to much rules also |
| 03:23 | dysfun_ | i mostly hate the verbosity |
| 03:23 | dysfun_ | i don't like IDEs and a lot of java seems to involve pressing buttons in IDEs |
| 03:24 | dysfun_ | also the attitude is different. in the java world, it's all about heavyweight design patterns. clojure is quite the opposite. |
| 03:25 | Jaood | I partly know java but yeah, clojure is way more slick :) |
| 03:28 | Jaood | dysfun_: but still, for non-java people like me, you have to get familiar with java.lang, java.util and java.io for practical reasons |
| 03:40 | dysfun_ | not really. there are nice clojure wrappers for most things |
| 03:42 | dysfun_ | however if you want to experience the true nature of hell, simply try programming javafx in clojure and trying to follow the javadocs |
| 03:43 | Jaood | dysfun_: why are you doing that? |
| 03:43 | dysfun_ | i wanted a webkit control |
| 03:44 | dysfun_ | but it's so tedious that i put that idea on hold. i got my webkit, but the next steps are harder |
| 03:45 | Jaood | could you not build your UI in cljs? |
| 03:46 | dysfun_ | a) i want to program clojure, not cljs b) no, cljs would not be suitable for either of those projects |
| 03:47 | dysfun_ | especially the one where i wanted to manipulate the dom from clojure specifically |
| 03:48 | Jaood | dysfun_: manipulating the dom sever side? |
| 03:49 | dysfun_ | indeed |
| 03:49 | dysfun_ | although in this case i wanted a webkit to paint my UI in and control it from the clojure side |
| 03:50 | dysfun_ | of course there are lots of cljs libraries for dealing with the dom and not many clojure libraries... |
| 03:52 | dysfun_ | anyway, the idea tickles me because it's basically bringing visual basic levels of 'GTD' without the horror that is visual basic as the base language |
| 05:02 | hellofunk | any Om users in here at the moment? |
| 05:03 | hellofunk | is it acceptable to use om/update! in a function that is not a component, but is called from a component and receives the "app" var from the component (but no "owner")? |
| 05:35 | the-kenny | yes. |
| 05:36 | the-kenny | hellofunk: ^ |
| 05:37 | hellofunk | the-kenny thanks |
| 05:37 | hellofunk | lots of things work find in Om even if they are not advised. |
| 05:37 | the-kenny | hellofunk: there's no magic going on. `app' is a cursor which you can pass around just like any other data structure. You only need to be careful when using its value (there's a difference inside and outside of a render phase) |
| 05:37 | hellofunk | *fine |
| 05:39 | SagiCZ1 | what is om for? im having trouble googling it |
| 05:39 | SagiCZ1 | just wondering.. |
| 05:39 | dysfun_ | it's a facebook react wrapper for cljs |
| 05:39 | SagiCZ1 | thanks, cool |
| 05:39 | dysfun_ | but it's been made somewhat more clojurey |
| 05:40 | the-kenny | Not really a wrapper - it uses React as its backend. It brings nice stuff by itself |
| 05:41 | hellofunk | Om is a library that uses React but actually does quite a bit more. |
| 05:41 | the-kenny | SagiCZ1: In general it's a clojurescript library allowing you to write UIs in a functional way. You don't need to handle all the stateful stuff in the DOM itself. You just write fuctions/component and om/react handles updating the dom (and much other stuff) for you. |
| 05:41 | dysfun_ | okay, a library for react |
| 05:42 | hellofunk | It's worth noting that Om adds the efficiency of persistant data structures to the React pipeline, and some tests show it triples the performance of React because of these cljs features |
| 05:43 | SagiCZ1 | the-kenny: wait what? your description isnt mentionnig facebook? |
| 05:43 | the-kenny | haha :D |
| 05:43 | hellofunk | SagCZ1 React is officially a FB library but I think it was born out of the Instagram team |
| 05:43 | SagiCZ1 | alright i missed that.. |
| 05:43 | SagiCZ1 | so it would be for web apps? |
| 05:43 | hellofunk | SagiCZ1 yes |
| 05:43 | the-kenny | Yes. For the UI layer. |
| 05:44 | SagiCZ1 | cool |
| 05:44 | hellofunk | It cleverly solves some weakness in how browsers render pages by taking matters into its own hands before the browser gets any information about what to render |
| 05:44 | SagiCZ1 | i only have experience with javas vaadin, and with swing, in clojure seesaw.. |
| 05:48 | the-kenny | It's really nice - and 0.8.0 solves another weakness by supporting a non-tree component/data structure :) |
| 05:49 | hellofunk | the-kenny can you elaborate? |
| 05:49 | the-kenny | hellofunk: https://github.com/swannodette/om/wiki/Advanced-Tutorial#reference-cursors |
| 05:49 | hellofunk | I'm using 0.7.1 |
| 05:51 | hellofunk | the-kenny have you studied the techniques used in the undo feature of the ToDo demo? |
| 05:51 | the-kenny | hellofunk: I haven't used it in my projects yet, but I'm aware of the technique |
| 05:52 | hellofunk | i haven't studied it, but in a nutshell how is this done and is this what "time travel" refers to? |
| 05:53 | hellofunk | my guess is that you just make changes to the app state and conj them onto a vector of all past app states, each item in the vector has a minor change, then you can cycle through them if desired. but this may be totally wrong. |
| 05:53 | the-kenny | That's exactly how it is |
| 05:53 | hellofunk | oh wow |
| 05:54 | the-kenny | Om/React doesn't care how big the difference is - you can swap between two totally different application states without any issues |
| 05:54 | hellofunk | and it is because of the persistent data engineering that makes this efficient, even though it would appear that the vector is storing multiple copies, actually it is not under the hood |
| 05:54 | the-kenny | yup |
| 05:55 | hellofunk | in other words, if you have an app state A like {..bunch of stuff...} and then you have B which is (assoc A :new :stuff) then your overall app state of [A B] is actually not much larger than just [A] or for that matter [A B C...] |
| 05:55 | the-kenny | That's a property of the persistent data structures, yes. |
| 05:55 | hellofunk | Fascinating. The undo example just allows you to pop off items then from this app state vector? |
| 05:57 | the-kenny | hellofunk: In a nutshell: https://swannodette.github.io/2013/12/31/time-travel/ |
| 05:57 | hellofunk | this is a perfect example of what Om can bring to the React world that React does not do on its own |
| 06:01 | the-kenny | It's also harder to do in plain React as it encourages component-local state way more than om, right? (I have no experience with plain react) |
| 06:02 | hellofunk | i have little experience with JS directly. React uses more component-local state? that's interesting. |
| 06:02 | the-kenny | Someone else might know more - that was just my impression by skimming over it |
| 06:11 | pkkm | is there a variant of reduce in the standard library that always calls the reducing function with 2 arguments (`reduce' appears to initially call it with 0 arguments)? |
| 06:12 | jkj | pkkm: you can give reduce the initial form |
| 06:12 | jkj | pkkm: thus it doesn't have to determine it by 0-arg call |
| 06:12 | pkkm | thanks jkj |
| 06:14 | hellofunk | jkj pkkm: whether you give it an initial form or not, isn't it always calling with 2 args? |
| 06:15 | pkkm | hellofunk: it appears to call with 0 args if I don't give the initial form. |
| 06:15 | hellofunk | pkkm example? |
| 06:15 | hellofunk | if you don't give it an initial form, it uses the first 2 items in your collection as args |
| 06:15 | hellofunk | if you *do* give it an initial form, it uses that form and the first item as its 2 args |
| 06:15 | hellofunk | 2 args either way, right? |
| 06:16 | jkj | oh it does that |
| 06:16 | hellofunk | there are no zero arg calls for the reduce fn |
| 06:17 | pkkm | then it must be a weird error in my code, sorry for the confusion. |
| 06:17 | hellofunk | pkkm feel free to share your code if you want more specific help |
| 06:20 | pkkm | thanks, I will if I won't be able to figure this out |
| 06:22 | SagiCZ1 | yesterday i was in a programming competition and couldnt get one problem to work.. i had no idea what was wrong with it.. after a long time a realized java arrays are mutable.. what an evil thing.. i was passing an array and not its copy :X .. thats what i get for getting used to clojure |
| 06:22 | hellofunk | true dat |
| 06:23 | SagiCZ1 | immutability now just seems so natural i cant believe i could code without it |
| 06:24 | the-kenny | Yup, that's a bad effect of Clojure: You stop thinking about side effects |
| 06:26 | jkj | SagiCZ1: many hit that even without first spoiling them with immutability. in some contexts it requires being extra careful to always think about moving pointers around |
| 06:41 | hellofunk | the-kenny I suppose a key reason why channels are used in Om click handlers is that the native om/update! and transact! don't work in an onClick since that is outside the render phase, right? Therefore, using channels communicates these clicks to a place that watches and then acts using update! or transact! |
| 06:41 | the-kenny | hellofunk: no! transact! and update! work fine |
| 06:42 | hellofunk | the-kenny you often get errors like "cannot manipulate a cursor outside render phase" or something like that when you use om/update! in an onClick |
| 06:42 | the-kenny | It's only accessing the cursor as a *value* that's forbidden outside of a render-phase (as there is no 'consistent' view of the state in that situation) |
| 06:42 | the-kenny | hellofunk: you need to deref cursors outside of render phases |
| 06:42 | the-kenny | While rendering, cursors behave like values. Outside of render phases, they behave like atoms |
| 06:42 | hellofunk | so you are saying that om/update! can be used on a @app-state deref inside an :onClick? |
| 06:43 | the-kenny | No, @app-state will give you the value. You need to call update! or transact! on the cursor itself |
| 06:43 | the-kenny | Forbidden: (do (println my-cursor) (update! my-cursor ...)), ok: (do (println @my-cursor) (update! my-cursor ...)) |
| 06:43 | hellofunk | it seems that often causes an error to direclty use om/update! app-state in an :onClick |
| 06:44 | the-kenny | Maybe when doing (update! (:foo my-cursor) ...)? |
| 06:45 | the-kenny | you need to use update-in or assoc-in in that case, as :foo counts as 'accessing' too |
| 06:45 | hellofunk | i see, so the (:foo cursor) is requiring a read of the cursor's value |
| 06:46 | the-kenny | yup |
| 06:46 | hellofunk | but if i used update-in i would need to de-ref first, right? |
| 06:46 | the-kenny | no! |
| 06:46 | hellofunk | but doesn't update-in return the value of the cursor? |
| 06:46 | the-kenny | update! or transact! always work on cursors. Deref will get you the value the cursor points to |
| 06:47 | the-kenny | (om/transact! cursor (fn [v] (assoc-in v [:foo] 42))) is how you would do it |
| 06:47 | hellofunk | interesting, i shall try. |
| 06:48 | the-kenny | You need to think of cursors outside of render phases just like atoms. |
| 06:48 | hellofunk | i didn't realize that you could manipulate a cursor outside render phase as long as you weren't reading it also. |
| 06:48 | the-kenny | ,(swap! @(atom 42) inc) |
| 06:48 | clojurebot | #<ClassCastException java.lang.ClassCastException: java.lang.Long cannot be cast to clojure.lang.Atom> |
| 06:48 | the-kenny | (swap! (atom 42) inc) |
| 06:48 | the-kenny | ,(swap! (atom 42) inc) |
| 06:48 | clojurebot | 43 |
| 06:48 | hellofunk | in other words, think of update! and transact! as operating on atoms like swap! or reset! |
| 06:49 | the-kenny | yes |
| 06:50 | hellofunk | that's a big help |
| 06:50 | hellofunk | (inc the-kenny) |
| 06:50 | lazybot | ⇒ 2 |
| 06:50 | hellofunk | (inc the-kenny) |
| 06:50 | lazybot | ⇒ 3 |
| 06:50 | hellofunk | hee hee |
| 06:50 | the-kenny | haha |
| 06:50 | the-kenny | hey, you're cheating |
| 06:51 | the-kenny | (dec the-kenny) |
| 06:51 | lazybot | You can't adjust your own karma. |
| 06:51 | the-kenny | not even down?! |
| 06:51 | hellofunk | you answered 2 questions, so you were aptly rewarded |
| 06:51 | the-kenny | ok :) |
| 06:52 | dysfun_ | what's the easiest way to repeat a character n times? |
| 06:52 | hellofunk | the-kenny: I suppose it is acceptable to pass korks outside render phase though also? |
| 06:53 | dysfun_ | and get back a string, i mean |
| 06:53 | hellofunk | dysfun_ (take 5 (cycle "a")) |
| 06:53 | hellofunk | ,(take 5 (cycle "a")) |
| 06:53 | clojurebot | (\a \a \a \a \a) |
| 06:53 | hellofunk | ,(apply str (take 5 (cycle "a")) |
| 06:53 | clojurebot | #<RuntimeException java.lang.RuntimeException: EOF while reading> |
| 06:54 | hellofunk | ,(apply str (take 5 (cycle "a"))) |
| 06:54 | clojurebot | "aaaaa" |
| 06:54 | dysfun_ | aha, apply, that's what i was missing |
| 06:54 | dysfun_ | thanks |
| 06:54 | hellofunk | np |
| 06:55 | the-kenny | there's also StringUtils.repeat - might be more performant for bigger strings |
| 06:55 | dysfun_ | that's not liable to be an issue here |
| 06:56 | the-kenny | Yup, just mentioning it |
| 06:56 | dysfun_ | :) |
| 07:08 | the-kenny | hellofunk: Sorry, missed your questions. I'm not sure what you're meaning by korks though. |
| 07:08 | the-kenny | hellofunk: ohh to transact! and update!. Yes! That's totally ok - and I totally forgot about that |
| 07:08 | the-kenny | hellofunk: (om/transact! cursor :foo inc) is totally fine |
| 07:10 | hellofunk | the-kenny this line: (om/update! omstate/data :popup popup) is giving me this error: "No protocol method ITransact.-transact! defined for type cljs.core/Atom" when I use this in an onClick |
| 07:11 | schmee | anyone here using Vinyasa? |
| 07:11 | the-kenny | hellofunk: omstate/data isn't a cursor. |
| 07:11 | hellofunk | the-kenny well, it's the atom that holds the app state |
| 07:11 | the-kenny | Yup, that's not a cursor ;) Are you updating that from inside a component or from a totally different part of the application? |
| 07:11 | the-kenny | (inside a component, maybe via some other function) |
| 07:12 | hellofunk | that line above is running as a fn inside an :onClick that is in a component |
| 07:12 | hellofunk | so a "cursor" is only something inside the atom, not the atom itself? components often have the parameter "app" (along with "owner") that is the entire atom |
| 07:12 | the-kenny | hellofunk: Then you need to access it via the cursor passed to the component. Or, if you need a root-cursor, via `om/root-cursor' from om-0.8.0-alpha1 |
| 07:13 | hellofunk | ahh, i see. i'm directly accessing the atom itself rather than the cursor that points to the whole atom |
| 07:13 | the-kenny | A cursor is its own data type. You pass the atom to `om/root' and it will build a cursor around it. |
| 07:13 | hellofunk | got it. i shall try momentarily. |
| 07:13 | the-kenny | s/its own/a different/ |
| 07:14 | the-kenny | hellofunk: In general, a component can only access data from the cursor it was passed and downward. If you pass (:foo app) to om/build, the component built can't access app itself. |
| 07:14 | the-kenny | (true before 0.8.0) |
| 07:17 | hellofunk | the-kenny beautiful man, got that working by passing down the cursor. awesome. |
| 07:17 | the-kenny | hellofunk: it's in general good style to pass "just" the data a component needs. The less it knows the better. In terms of code-simplicity and performance. |
| 07:17 | hellofunk | all year i have been relying on channels only because i didn't realize that onClick handlers could do this outside render phase |
| 07:19 | noncom | is anyone here using quil recently ? |
| 07:30 | engblom | Is anyone aware of any minimal tutorial teaching a subset of clojure? I am looking for something ready made rather than writing myself one. I will have some clojure workshops with elementary school kids. The total time I will have (including exercises) is 10 weeks with 2x45 minutes each week. |
| 07:45 | luxbock | engblom: I don't know about tutorial but you could ask @thattommyhall, I think he mentioned having taught kids with Clojure in his EuroClojure talk |
| 07:45 | luxbock | his talk was about DSL's |
| 07:46 | luxbock | http://vimeo.com/100425264 |
| 07:46 | luxbock | this is the talk |
| 08:00 | schmee | gaaah, can someone please help me with this? |
| 08:00 | Bronsa | schmee: with what? |
| 08:01 | jal | testing.core=> (let [{:as orig} (range 20)] orig) |
| 08:01 | jal | {0 1, 4 5, 6 7, 12 13, 2 3, 14 15, 16 17, 10 11, 18 19, 8 9} |
| 08:01 | jal | why is there no 1 key in there? |
| 08:01 | schmee | I want two functions automatically available in a new REPL: `pp`, to alias `clojure.pprint/pprint`, and `p` to alias `println` |
| 08:01 | schmee | it seems easy enough, but I can't get it to work |
| 08:01 | Bronsa | schmee: you can use :injections in your user lein profile |
| 08:02 | schmee | I've been mucking around with Vinyasa, Lein injections but there seems to be some conflict cause clojure.pprint is loaded in to the repl by default |
| 08:02 | Bronsa | jal: you're destructuring a seq as a map, that'll turn '(1 2 3 4) into {1 2, 3 4} |
| 08:02 | schmee | and `pp` is already defined in clojure.pprint |
| 08:02 | Bronsa | schmee: use ns-unmap |
| 08:02 | jal | ah |
| 08:03 | schmee | Bronsa: in lein :injections? |
| 08:04 | Bronsa | schmee: yeah put something like [(ns-unmap *ns* 'pp) (def pp c.p/pprint) (def p println)] |
| 08:07 | schmee | Bronsa: here's my user.clj and what happens when I try your suggestion: https://gist.github.com/schmee/662a1444754141b721d1 |
| 08:07 | schmee | seems very close, but no cigar |
| 08:10 | Bronsa | schmee: I'm out of my league here, you'll have to wait for some lein wizards |
| 08:11 | schmee | Bronsa: haha, I feel the same way :P Thanks for your help! |
| 08:41 | arnaudsj | does anybody know what type of pattern to use to build a lazy seq based on back-end api calls? |
| 08:44 | luxbock | schmee: you have to require vinyasa as well and then use vinyasa.inject/in add whatever you wish to have available in clojure.core |
| 08:47 | luxbock | schmee: see https://gist.github.com/luxbock/59f0abf4217ee54932c3 |
| 08:48 | luxbock | I think you need to leiningen dependency in there as well, at least for something, I forgot which |
| 08:52 | schmee | luxbock: thanks for the code example! How can I rename a function when importing it with Vinyasa? In particular, can I rename `pprint` to `pp` without causing trouble (since it is already defined)? |
| 08:52 | luxbock | yes, see the thing I do with the macroexpands |
| 08:52 | luxbock | use a vector |
| 08:53 | luxbock | [namespace [old-name new-name]] |
| 08:56 | schmee | luxbock: hmm... that's what I tried at first. But it doesn't work for me at least, see here: https://gist.github.com/schmee/12af069cdfd8b6204e7a |
| 08:59 | luxbock | schmee: maybe just use a different alias so they won't get overwritten |
| 09:00 | luxbock | clojure.pprint/pp pretty prints the last thing that was output so it's pretty convenient as well |
| 09:01 | schmee | luxbock: yeah, I should probably just do that, I hate the feeling of being defeated by my own tools though... I'm sure it's possible, I'm just to stupid to figure it out |
| 09:02 | luxbock | are you requiring clojure.pprint with :refer :all at any point? |
| 09:07 | schmee | luxbock: no, but I think it gets loaded in the user namespace by default in the REPL |
| 09:15 | pkkm | could you help me a bit with debugging? I've written a simple calculator with a recursive descent parser, <https://gist.github.com/pkkm/3a61ff7061803bf7020a>, in which there are 2 mutually recursive functions (lines 139, 157): `factor' and `expression' (defined in that order with `def'). it works when `expression' calls `factor', but not the other way around, despite `expression' being forward-declared. the |
| 09:15 | pkkm | error is: "Attempting to call unbound fn: #'modulo-calculator.core/expression". |
| 09:21 | squeedee | pkkm you can use declare |
| 09:21 | squeedee | dunno how to use this bot |
| 09:21 | squeedee | ,declare |
| 09:21 | clojurebot | #<CompilerException java.lang.RuntimeException: Can't take value of a macro: #'clojure.core/declare, compiling:(NO_SOURCE_PATH:0:0)> |
| 09:22 | squeedee | its not that |
| 09:22 | the-kenny | it is declared. |
| 09:22 | squeedee | (doc declare) |
| 09:22 | clojurebot | "([& names]); defs the supplied var names with no bindings, useful for making forward declarations." |
| 09:22 | squeedee | oh |
| 09:22 | pkkm | (the error can be triggered by launching the calculator, inputting any intereger >= 2, and when the ">>> " prompt appears, and then inputting some expression with parens, for example "2+(3*1)".) |
| 09:23 | squeedee | i missed that completely |
| 09:34 | pkkm | I found a hack that makes it work: (declare expression) (defn expression-caller [& args] (apply expression args)) and replace `expression' with `expression-caller' in the body of `factor'. |
| 09:34 | squeedee | pkkm: the issue occurs higher up in parser_concat, so i thought maybe you needed to declare expression even earlier |
| 09:35 | squeedee | hah |
| 09:36 | pkkm | moving `declare' to the top doesn't work unfortunately. |
| 09:37 | pkkm | do you have any idea why this `expression-caller' hack works? |
| 09:39 | pkkm | (replacing `expression' with (fn [& args] (apply expression args)) works too.) |
| 09:39 | squeedee | no |
| 09:40 | squeedee | But i think its worth producing a cut down replication and sharing it with the group |
| 09:40 | pkkm | which group? I'm new, this is my first clojure program. |
| 09:41 | squeedee | clojure goolge group |
| 09:41 | squeedee | |
| 09:41 | pkkm | ah, ok. |
| 09:41 | squeedee | im really green too. but this looks like a bug, possibly because of a non-idiomatic approach? |
| 09:42 | squeedee | either way, you might get some insight |
| 09:43 | squeedee | i woulda stayed in school if my homework was this interesting |
| 09:43 | jonh | hehe |
| 09:43 | squeedee | I'm feeling a little green about some code i wrote: https://github.com/squeedee/mapper/blob/master/src/mapper/core.clj#L20 |
| 09:44 | squeedee | I have a 'Map' that carries with it a higher order function which, when asked for the content of a cell, returns it. The map is also bound. So when i treat it as a seq, i get a flat seq of the entire map. |
| 09:45 | Bronsa | squeedee: a minor unrelated, code style complain. in a ns decl usually we put :refer-clojure, :require, :import in this order |
| 09:45 | squeedee | What feels wrong here, is i assume that idiomatically, someone would expect the seq to return something representing the fields [x y fn] |
| 09:45 | squeedee | Bronsa: ta, I'm still very confused about my (ns) |
| 09:45 | r4vi | if I want a function that when called returns the next integer how should I go about it? return a function from a closure with an atom for the value? (defn make-incr ...[] (let [count (atom )] (fn [] (swap! count inc)) |
| 09:46 | squeedee | Bronsa the import was placed there by cursive-clojure auto-import! tch |
| 09:47 | Bronsa | squeedee: also, you can replace (.map-fn this) with map-fn |
| 09:47 | squeedee | oh neat |
| 09:47 | squeedee | this is lexically scoped? |
| 09:47 | Bronsa | yes |
| 09:48 | Bronsa | deftypes inject their fields in the lexical scope of the inline methods decls |
| 09:48 | hellofunk | r4vi you are creating a new atom every time the fn is called in your example |
| 09:48 | hellofunk | put the let above the defn as one alternative |
| 09:48 | Bronsa | (defrecords too) |
| 09:48 | Bronsa | squeedee: so you can replace (:width this) with width too |
| 09:48 | hellofunk | unless you are calling the make-incr only once, r4vi |
| 09:48 | squeedee | line 26 shows that i knew this |
| 09:49 | squeedee | even if it was subconcious |
| 09:49 | r4vi | hellofunk: yep calling make-incr once to get the anon function, then keep calling that |
| 09:49 | r4vi | is there a better way |
| 09:49 | r4vi | without the closure |
| 09:50 | hellofunk | well, you are talking about some form of stateful persistence so I would expect an atom to be in there somewhere. |
| 09:50 | squeedee | Bronsa, what you think about making the sequable interface return something other than the fields |
| 09:51 | hellofunk | r4vi you could also do something without an atom by using core.async channels. but that would be overkill in your case. |
| 09:51 | Bronsa | squeedee: I don't see a problem with that |
| 09:51 | r4vi | hellofunk: yes bingo |
| 09:51 | r4vi | hellofunk: I like that |
| 09:51 | hellofunk | r4vi just put a list of integers onto a channel. every time you pull from the channel, you get the next integer |
| 09:51 | Bronsa | squeedee: a Range seq would do that too, for example |
| 09:51 | squeedee | true. |
| 09:51 | r4vi | r4vi: well I've trivialised the case here but in my actual case a core async channel would be cool |
| 09:52 | r4vi | just put (range) on one side of the channel then consume one every time |
| 09:52 | squeedee | Bronsa because i had to change it from a defrecord to deftype to do what i needed, i wondered if that was some kind of smell |
| 09:52 | myguidingstar | weavejester, codox can't find metadata for protocols in a Clojurescript project of mine |
| 09:53 | hellofunk | r4vi you could also just add a new integer to the channel only when you have first pulled an integer, and then just add the inc of the integer that was pulled. start with only the number 1 on the chan and you're done |
| 09:53 | myguidingstar | so I tried codox.example in codox source, and it failed to generate doc for protocols, too |
| 09:53 | weavejester | myguidingstar: ClojureScript is missing metadata for a few things. I think protocols are one of them. |
| 09:53 | myguidingstar | okay |
| 09:54 | myguidingstar | I just wanted to know if there's a previous version of codox/clojurescript that worked |
| 10:48 | abx_freenode | what is discussed? |
| 10:49 | borkdude | I filed an issue in jira of a project I was working on this week at my company. I'm starting to realize what I reported may be is just the way people program OO: a class for every kind of thing. It felt so wrong to me. |
| 10:52 | wink | bonus points if they do something like class Thing extends Object |
| 10:53 | wink | it's like customising the generic object to your domain ;) |
| 11:06 | borkdude | wink why would you extend Object? that happens automatically? |
| 11:07 | wink | speaking of java, yes. was more meant in a universal sense |
| 11:10 | gfredericks | borkdude: an issue for what? |
| 11:10 | borkdude | gfredericks using a class for every new thing (a thing being something that needed to be converted from json and persisted to database with an aweful intransparent ORM framework) |
| 11:11 | gfredericks | "thing" == "domain object"? |
| 11:12 | borkdude | gfredericks well, an enumeration of options with certain questions etc |
| 11:12 | borkdude | gfredericks and their translations... a new class for every ThingTranslation of course |
| 11:12 | gfredericks | ["Mother's maiden name" "Childhood pet's name" "Favorite pants"] |
| 11:17 | borkdude | just found a song that expresses my feelings with this subject https://www.youtube.com/watch?v=fCLQEkpZy1A |
| 11:20 | myguidingstar | ,(defprotocol MyProtocol "a docstring") |
| 11:20 | clojurebot | MyProtocol |
| 11:20 | myguidingstar | ,(meta MyProtocol) |
| 11:20 | clojurebot | nil |
| 11:20 | sveri | Hi, I usually construct my maps like this (let [a b c d...] {:a a :c c} Now, I wonder if what the idiomatic way is to put something into a map only if a predicate is true, something like (some? d)? I know there is merge, but that looks somewhat ugly to have several merge statements |
| 11:20 | myguidingstar | ,(:doc MyProtocol) |
| 11:20 | clojurebot | "a docstring" |
| 11:20 | gfredericks | ,(meta #'MyProtocol) |
| 11:20 | clojurebot | {:doc "a docstring", :ns #<Namespace sandbox>, :name MyProtocol, :file "NO_SOURCE_PATH", :column 0, ...} |
| 11:21 | myguidingstar | oh, thanks gfredericks |
| 11:21 | gfredericks | sveri: you want to add the key/val only if the val is truthy? |
| 11:22 | sveri | gfredericks: No, not only, an empty string "" is truthy too, but then the key/val should not be part of the map |
| 11:22 | myguidingstar | hmm, I saw people type `(inc some-irc-nick)` here. what does that mean? |
| 11:22 | gfredericks | sveri: okay, I'd use cond-> I suppose |
| 11:22 | sveri | gfredericks: cond->? with maps? Hm, haven't seen that, do you have an example please? |
| 11:23 | gfredericks | myguidingstar: lazybot tracks karma; it's a slightly more measurable way of saying thanks |
| 11:23 | myguidingstar | awesome |
| 11:23 | gfredericks | ,(let [a "yep" b ""] (cond-> {} (seq a) (assoc :a a) (seq b) (assoc :b b))) |
| 11:23 | clojurebot | {:a "yep"} |
| 11:23 | myguidingstar | (inc gfredericks) |
| 11:23 | lazybot | ⇒ 94 |
| 11:23 | gfredericks | sveri: ^ |
| 11:24 | gfredericks | sveri: I like it as it seems to be the most succinct way of maybe-modifying something |
| 11:24 | sveri | gfredericks: I see, looks nice too, a more intentional way then merge I think, thank you :-) |
| 11:24 | gfredericks | np |
| 11:25 | sveri | ,(inc gfredericks) |
| 11:25 | clojurebot | #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: gfredericks in this context, compiling:(NO_SOURCE_PATH:0:0)> |
| 11:25 | sveri | (inc gfredericks) |
| 11:25 | lazybot | ⇒ 95 |
| 11:25 | sveri | ah :-) |
| 11:28 | myguidingstar | @gfredericks |
| 11:29 | gfredericks | yes? |
| 11:29 | myguidingstar | is there anyway to check someone's karma? |
| 11:29 | myguidingstar | I tried to `deref` yours ;) |
| 11:30 | ustunozgur | for those of you who switch bt. emacs and intellij during work, this could be helpful: https://github.com/ustun/emacs-friends |
| 11:30 | borkdude | anyone here uses sente? I want to see the uid of the event that the client sent |
| 11:30 | borkdude | currently I see :client-uuid 5-75035d91, but I only need 5 |
| 11:30 | gfredericks | $karma gfredericks |
| 11:30 | lazybot | gfredericks has karma 95. |
| 11:30 | gfredericks | myguidingstar: ^ |
| 11:30 | myguidingstar | got it |
| 11:31 | myguidingstar | (inc gfredericks) |
| 11:31 | lazybot | ⇒ 96 |
| 11:31 | gfredericks | $juxt |
| 11:31 | gfredericks | $karma juxt |
| 11:31 | lazybot | juxt has karma 14. |
| 11:31 | myguidingstar | hmm, it's not very lispy to do so |
| 11:33 | justin_smith | borkdude: that's a weird value for a uuid |
| 11:33 | borkdude | justin_smith it's not even a uuid, but I use incremental values for the clients |
| 11:33 | justin_smith | ,(java.util.UUID/randomUUID) |
| 11:33 | clojurebot | #uuid "665601a3-5e78-4e68-a2fa-c510fac771d4" |
| 11:33 | borkdude | justin_smith sente appends something though |
| 11:33 | justin_smith | oh, I saw uuid in the name and was confused |
| 11:34 | borkdude | justin_smith yeh, sente appends something uuid-ish |
| 11:34 | gfredericks | NVUID |
| 11:35 | justin_smith | PUID - Potentially Unique IDentifier |
| 11:35 | gfredericks | the uniqueness of this ID cannot be ruled out on purely logical grounds |
| 11:36 | borkdude | unique enough for me |
| 11:36 | justin_smith | there exists at least one timeline in which this ID will be unique |
| 11:36 | pyrtsa | "Randomly unique identifier" |
| 11:37 | myguidingstar | how do I lookup metadata of a protocol in Clojurescript? |
| 11:37 | borkdude | justin_smith but does there exist a unique such a timeline? |
| 11:38 | squeedee | wow im having a hard time with protocols. I have a 'Map' type which carries three fields, width, height and a fn(x y) to obtain the value at a location |
| 11:39 | gfredericks | fun fact: you can efficiently tell if a positive integer is a nontrivial power (e.g. p^k for k>1) |
| 11:39 | squeedee | then Map.seq returns a seq of fn(x y) for all of widths in all of heights. |
| 11:40 | squeedee | Im thinking that my sequencing function doesnt need to be forced to using the Map type. |
| 11:41 | gfredericks | squeedee: I for one cannot yet tell what exactly the trouble you're having is |
| 11:41 | squeedee | i could alternatively just have map-seq which accepts different args |
| 11:41 | squeedee | or leave it smple (defn map-seq [width height fn[) |
| 11:41 | justin_smith | squeedee: sounds very OO |
| 11:42 | squeedee | which seems less painful |
| 11:42 | squeedee | i know right? |
| 11:42 | justin_smith | why can't this just be a map? |
| 11:43 | justin_smith | or a defrecord (that you can use as you would a map) |
| 11:43 | bbloom | and a function that uses a for comprehension |
| 11:44 | squeedee | i dont want a map |
| 11:44 | bbloom | ,(let [m {:width 3 :height 2 :f vector}] (for [y (range (:height m)) x (range (:width y))] (f x y))) |
| 11:44 | clojurebot | #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: f in this context, compiling:(NO_SOURCE_PATH:0:0)> |
| 11:44 | squeedee | i want composable functions that lazily describe a map |
| 11:45 | bbloom | ,(let [m {:width 3 :height 2 :f vector}] (for [y (range (:height m)) x (range (:width y))] ((:f m) x y))); i was so close |
| 11:45 | clojurebot | #<NullPointerException java.lang.NullPointerException> |
| 11:45 | bbloom | blah |
| 11:45 | squeedee | justin_smith: but you confirmed my feelings about my tactic being 'OO" |
| 11:46 | bbloom | ,(let [m {:width 3 :height 2 :f vector}] (for [y (range (:height m)) x (range (:width m))] ((:f m) x y))); irc coding never works |
| 11:46 | clojurebot | ([0 0] [1 0] [2 0] [0 1] [1 1] ...) |
| 11:53 | pgmcgee | is there an equality function that will return true for two atoms holding the same content? ex: (= (atom 1) (atom 1)) => true |
| 11:53 | pyrtsa | That sounds very data-racy. |
| 11:53 | pgmcgee | i suppose i could write (= @(atom 1) @(atom 1)) |
| 11:54 | pgmcgee | but i'm looking for something recursive... perhaps i have to write it myself |
| 11:54 | bbloom | pgmcgee: yeah, it's easy to do, but pyrtsa is right: that looks like a data race |
| 11:54 | pyrtsa | Yes. And you should note that there's no guarantee that anyone else would see the same equality hold. |
| 11:54 | justin_smith | and that says "there was one moment in time where these values {were,were-not} equal" |
| 11:54 | pgmcgee | this is for writing a test |
| 11:54 | bbloom | pgmcgee: unless you know you're single threaded |
| 11:54 | pyrtsa | justin_smith: There might even be a thread for which they never were equal at the same time. |
| 11:54 | justin_smith | pgmcgee: if you are confident they are not changing, why not a promise or delay? |
| 11:55 | bbloom | pgmcgee: you have recursive atoms? ie atoms within atoms that you want checked for equality? |
| 11:55 | justin_smith | pyrtsa: note the were-not option |
| 11:55 | justin_smith | pyrtsa: it makes one of those claims |
| 11:55 | pyrtsa | Haha, gotcha. :) |
| 11:55 | bbloom | pgmcgee: there is *definitely* not any prebaked predicate for that b/c it's definitely a design problem |
| 11:55 | pyrtsa | That. |
| 11:55 | pgmcgee | justin_smith: i'm not familiar with promises or delays, perhaps this is my problem |
| 11:56 | bbloom | (doc future) |
| 11:56 | clojurebot | "([& body]); Takes a body of expressions and yields a future object that will invoke the body in another thread, and will cache the result and return it on all subsequent calls to deref/@. If the computation has not yet finished, calls to deref/@ will block, unless the variant of deref with timeout is used. See also - realized?." |
| 11:56 | bbloom | (doc delay) |
| 11:56 | clojurebot | "([& body]); Takes a body of expressions and yields a Delay object that will invoke the body only the first time it is forced (with force or deref/@), and will cache the result and return it on all subsequent force calls. See also - realized?" |
| 11:56 | pgmcgee | bbloom: yeah, i'm writing a tree structure for maps that i want to be able to update just certain nodes without locking |
| 11:56 | bbloom | pgmcgee: now you're familiar with them :-) |
| 11:56 | bbloom | pgmcgee: swap! on the root won't lock, it will spin compare and swap |
| 11:56 | justin_smith | pgmcgee: short version: a promise is created but does not have a value yet, anyone can fulfill the value, a delay is initialized with some function that is not called until the value is asked for |
| 11:57 | bbloom | pgmcgee: how many threads are accessing your atom? what operations are they doing to it? |
| 11:57 | bbloom | if the number of threads if not huge or the cost of atomic operations given to swap is cheap, then it's a good idea to just use swap plus update-in |
| 11:58 | bbloom | if you're not sure, you should still just use swap! & update-in, then profile your application to see if contention is hurting you |
| 11:58 | bbloom | and only then figure out how to optimize it |
| 11:58 | pgmcgee | bbloom: basic structure looks like (atom {:a (atom {:b nil :c (atom {:d nil})}) :e nil}) |
| 11:58 | pgmcgee | bbloom: good advice |
| 11:59 | pgmcgee | justin_smith: thanks for the advice to check out promise and future |
| 11:59 | bbloom | homogenous use of atoms basically always requires justification |
| 11:59 | bbloom | you shouldn't have N atoms where N varies at runtime, you should have M where M varies with architecture |
| 12:00 | bbloom | obviously that's not always true, but it's a reasonable starting principal |
| 12:01 | pgmcgee | bbloom: time to go rework the algo a bit, thanks |
| 12:10 | justin_smith | pgmcgee: I suggested delay and promise on the off chance you were not using the atoms for arbitrary mutation, but since you are, - the base case is to use a map with keys pointing to all your atomic values (this simplifies things, and works for most people), if performance is hurt because of parallel modifications within that structure, don't jump to multiple atoms, use refs - this is the exact (and rare) use case they are designed f |
| 12:10 | bbloom | justin_smith: pgmcgee: but before you use refs, come back here and explain to us your architecture so we can explain to you how to do it even simpler and faster w/o refs :-) |
| 12:10 | justin_smith | heh :) |
| 12:11 | pgmcgee | :) |
| 12:11 | pgmcgee | basically, i'm practicing my clojure by implementing suffix trees |
| 12:12 | pgmcgee | trying to wrap my head around all this stuff in a real-ish world use case |
| 12:12 | justin_smith | if you are not heavily mutating the tree in parallels, a single atom holding a hash-map should suffice |
| 12:12 | pgmcgee | i think i was thinking atom-in-atom, because when i think recursive i think "update in place" which you need an atom for |
| 12:13 | pgmcgee | but, that's not very clojure-ish i'm guessing |
| 12:13 | justin_smith | right, but you don't need an atom inside an atom for update in place |
| 12:13 | bbloom | ,(let [a (atom {:x {:y {:z 1}}})] (swap! a update-in [:x :y :z] inc)) |
| 12:13 | clojurebot | {:x {:y {:z 2}}} |
| 12:14 | bbloom | pgmcgee: ^^ |
| 12:14 | justin_smith | ,(swap! {:a {:b {:c []}}} update-in [:a :b :c] conj 0) |
| 12:14 | clojurebot | #<ClassCastException java.lang.ClassCastException: clojure.lang.PersistentArrayMap cannot be cast to clojure.lang.Atom> |
| 12:14 | justin_smith | ,(swap! (atom {:a {:b {:c []}}}) update-in [:a :b :c] conj 0) |
| 12:14 | clojurebot | {:a {:b {:c [0]}}} |
| 12:14 | justin_smith | bbloom beat me to it anyway |
| 12:14 | pgmcgee | seems like rather than calling my function recursively with (f (:keyword node) new-value) i should be calling (f node (conj loc :keyword) new-value) and then using update-in, yeah? |
| 12:14 | justin_smith | yeah |
| 12:15 | pgmcgee | different recursive pattern to get used to when using trees |
| 12:47 | quickezed | I'm using sqlkorma but am struggling with the syntax for a query which adds two columns together. |
| 12:47 | quickezed | I can't figure out the correct what to use the + operator. |
| 12:48 | quickezed | Anyone familiar with this? |
| 12:53 | bbloom | quickezed: may i suggest https://github.com/krisajenkins/yesql ? |
| 12:56 | quickezed | bbloom: you certainly can :) |
| 12:56 | quickezed | bbloom: this looks like my preferred route, thanks for the suggestion. |
| 12:57 | bbloom | quickezed: yeah, korma is just more of the same old bad ideas |
| 12:57 | bbloom | i can't speak for ibdknox but i wouldn't be surprised if he'd agree with that statement :-) |
| 12:57 | bbloom | (now, at least) |
| 12:58 | quickezed | bbloom: hehe, yeh, i'm used to writing sql. i've always struggled with orm and dsl type layers. |
| 12:58 | bbloom | quickezed: that struggle should be a hint, but apparently nobody can take a hint |
| 12:59 | quickezed | bbloom: i've tried to broach the topic at work but people think i'm mad haha |
| 12:59 | quickezed | I can tell you now we'll be struggling to optimise queries in the future. |
| 12:59 | bbloom | quickezed: clojure can undo brains of poison |
| 12:59 | quickezed | hahahaha |
| 13:00 | quickezed | bbloom: i'll have to stick with it then! |
| 13:00 | bbloom | i meant "years of brain poison" but i like the way it came out too heh |
| 13:04 | quickezed | bbloom: what would you recommend for database migrations? I'm currently using ragtime. |
| 13:05 | bbloom | quickezed: i don't know about any of the tools out there for clojure, I usually avoid complex migration systems |
| 13:05 | gfredericks | clojurebot: clojure |can undo| brains of poison |
| 13:05 | clojurebot | Roger. |
| 13:05 | bbloom | i have some faith in weavejester, so that lib may be good |
| 13:06 | bbloom | actually, looking at it now |
| 13:06 | bbloom | it seems like it *is* good |
| 13:06 | bbloom | migrations as sql files? yes, please. |
| 13:07 | quickezed | bbloom: hehe yeh, that's exactly why I decided to give it a shot. |
| 13:07 | quickezed | bbloom: I'm actually authoring the migrations in sql. It just handles the migrate and rollback. |
| 13:08 | bbloom | looking at it, it looks like the stuff i usually hack up with bash |
| 13:08 | bbloom | +1 |
| 13:10 | bbloom | (inc bash) ; while i'm at it |
| 13:10 | lazybot | ⇒ 1 |
| 13:13 | sveri | Anyone knows a ring middleware that trims all params? |
| 13:15 | justin_smith | sveri: as in remove leading and trailing whitespace? |
| 13:17 | gfredericks | (defn wrap-trimmings [handler] #(-> % (update :params (partial map-vals clojure.string/trim)) (handler))) |
| 13:18 | gfredericks | or so |
| 13:19 | justin_smith | gfredericks: would need a walk for json params I guess |
| 13:19 | gfredericks | yeah the requirements are a bit ambiguous so far :) |
| 13:21 | sveri | justin_smith: exactly |
| 13:23 | martinklepsch | can anyone point me to a library that provides compojure/ring routes? I want to write one but I'm uncertain how to design the API. Some ring handler you could just plug in at a certain route sounds good to me |
| 13:25 | sveri | gfredericks: justin_smith well, I guess before some json / transit / edn middleware converts them they exist just as plain params, so it would be nice to trim these params before they get converted, which might be easy by placing the middleware before the other middlewares |
| 13:25 | mr- | Does anyone know some good learning material for somebody who doesn't speak any lisp dialect but is fine with e.g. Haskell? |
| 13:27 | justin_smith | sveri: so trim the json string before it gets parsed? or trim the values in the json before passing them on? |
| 13:29 | sveri | justin_smith: trimming them before they are passed on |
| 13:32 | justin_smith | sveri: yeah, clojure.walk/post-walk with somethig like #(if (string? %) (string/trim %) %) |
| 13:32 | justin_smith | to get all the nested stuff |
| 13:32 | sveri | justin_smith: ah, postwalk, that looks good, :-) thank you |
| 13:34 | martinklepsch | asking again: whats the best way to provide a route/handler to be used in someone's ring app via a library? examples would be perfect! :) |
| 13:37 | kenrestivo | why does lein have to go out on the network and complain if an artifact isn't in clojars or maven central, when it's already installed in ~/.m2/repository ? |
| 13:37 | kenrestivo | i'd expect it'd check the net only iff it didn't find the artifact locally. |
| 13:38 | kenrestivo | ah, nevermind. it does exactly that. |
| 13:39 | justin_smith | martinklepsch: a handler is a function, for bonus points you can provide a "factory" that takes some configuration parameters and returns a handler function |
| 13:52 | corecode | hi |
| 13:53 | corecode | how would i use split-with while also limiting the maximum elements i take? |
| 13:54 | justin_smith | (doc take) |
| 13:54 | clojurebot | "([n] [n coll]); Returns a lazy sequence of the first n items in coll, or all items if there are fewer than n. Returns a stateful transducer when no collection is provided." |
| 13:54 | justin_smith | either (take n (split-with ...)) or (map #(take n %) (split-with ...)) |
| 13:57 | corecode | well, i'm trying to take a maximum of 2 digits, while not holding on to the head, but retaining the rest |
| 13:58 | quickezed | bbloom: I'm giving yesql a shot and am trying to run a query which has no parameters and I get the following error: "clojure.lang.ArityException Wrong number of args (1) passed to: query/test-query" |
| 13:58 | corecode | justin_smith: so take alone won't work |
| 13:58 | quickezed | bbloom: Any ideas? I'm hoping this is very obvious. |
| 13:59 | bbloom | quickezed: are you using defquery? |
| 13:59 | bbloom | or defqueries? |
| 13:59 | quickezed | bbloom: yeh |
| 13:59 | quickezed | defquery |
| 13:59 | bbloom | did you try (clojure.repl/doc test-query) like the readme shows? |
| 14:00 | bbloom | what does it say your parameters are? |
| 14:00 | corecode | maybe something like (let [digits (take 2 (take-while is-digit seq)) rest (drop (count digits) seq)] ...)? |
| 14:00 | quickezed | bbloom: I've just got into the repl now. I'll let you know. Thanks. |
| 14:00 | corecode | but that is extremely ugly |
| 14:03 | quickezed | bbloom: I see what's happening. I have some hardcoded timestamps in my where clause in the sql and due to the colons in the timestamp yesql thinks they are params. |
| 14:03 | quickezed | bbloom: at least i think that's what's happening. |
| 14:04 | bbloom | quickezed: yeash. i'd say that seems like a yesql bug |
| 14:04 | quickezed | xfd.query/test ... ([db 00 59]) ... A test query |
| 14:04 | quickezed | The dots are new lines |
| 14:04 | bbloom | haha yeah that's what that looks like |
| 14:04 | bbloom | anyway, seems like a harmless bug at least |
| 14:05 | bbloom | might want to report that issue though, not sure how much of the parsing business yesql wants to be in |
| 14:05 | quickezed | bbloom: Yeh, I am going to parameterise these timestamps anyway, I just hardcoded them for now because I thought it'd be quicker to test. |
| 14:40 | csd_ | How can I execute a statement in the REPL and have it return to me a thread ID so that I can terminate the thread if it's nonresponsive? |
| 14:40 | justin_smith | csd_: you can explicitly create a thread |
| 14:41 | justin_smith | ,(Thread.) |
| 14:41 | clojurebot | #<SecurityException java.lang.SecurityException: no threads please> |
| 14:41 | justin_smith | then tell it to run your function |
| 14:41 | justin_smith | or, use a future, you can use that handle |
| 14:41 | csd_ | will that cause a problem if the statement is itself spawning threads using pmap? |
| 14:41 | justin_smith | csd_: pmap is usually useless |
| 14:41 | justin_smith | btw |
| 14:41 | csd_ | how so |
| 14:42 | justin_smith | ~pmap |
| 14:42 | clojurebot | pmap is not what you want |
| 14:42 | csd_ | lol |
| 14:42 | justin_smith | thanks clojurebot |
| 14:42 | justin_smith | I thought there was a better factoid... |
| 14:42 | justin_smith | ~pmap |
| 14:42 | clojurebot | pmap is not what you want |
| 14:44 | csd_ | can i bind to future using let |
| 14:45 | justin_smith | csd_: if you are afraid of pmap getting lost in a worthless calculation, you should embed a signal of some sort that tells the function to exit, that the function explicitly checks. For example a promise, and you bail out if the promise has been realized (this is nice because a promise can only be fulfilled once and isn't an arbitrary mutable thing) |
| 14:45 | justin_smith | csd_: you can bind the return value of a future, yes |
| 14:46 | justin_smith | but future-cancel is not so clean as it seems - unless your function checks (.isInterrupted (Thread/currentThread)) it doesn't do much |
| 14:46 | justin_smith | (checks it and acts on it that is) |
| 14:46 | csd_ | i want a function to scrape data from n pages and return a list of the results.. in that case what datatype would you use? |
| 14:46 | csd_ | eval is stalling during the scraping and it's difficult to debug because the REPL hangs |
| 14:47 | corecode | if i am parsing a (string) sequence, would it be more idiomatic to use an atom to mutate the state (current position), or would it be better to carry the rest of the sequence around? |
| 14:48 | justin_smith | csd_: you could just put the whole scraping thing in its own future, that checks isCancelled (or a custom atom or promise or whatever) before each recursion |
| 14:48 | the-kenny | corecode: I strongly prefer carrying the rest of the sequence. Mutation is seldom the answer. |
| 14:49 | justin_smith | corecode: something like (lazy-seq (parse (firt-token input)) (recur (rest-tokens input))) |
| 14:49 | csd_ | justin_smith: right how i have a list of urls and fn scrape-from-url and pmap scrape fn across the urls. guessing that's the wrong way then |
| 14:49 | justin_smith | csd_: the issue with pmap is it does unexpected things with chunking, and is optimized for CPU bound taskes (scraping web pages is not CPU bound) |
| 14:50 | csd_ | is there a version of doseq that executes concurrently? |
| 14:52 | Raynes | Good morning folks |
| 14:52 | justin_smith | csd_: what about a queue on which you place URLs to scrape, and a pool of worker threads that each run (loop (when-not (should-bail?) (let [page (.take queue)] (process (slurp page))))) |
| 14:52 | corecode | justin_smith: i thought about that, but i'm trying to do a recursive descent parser |
| 14:53 | justin_smith | corecode: than instead of running parse on the tail, you map parse across the tail |
| 14:53 | justin_smith | lazy seqs can contain elements that are lazy seqs |
| 14:53 | corecode | sorry, beginner here, don't know how i could do that |
| 14:54 | justin_smith | csd_: where of course process would end up putting each URL it finds onto the queue etc. |
| 14:54 | justin_smith | corecode: yeah, it takes a little while to realize all the implications of our tools :) |
| 14:54 | csd_ | justin_smith: makes sense |
| 14:54 | justin_smith | it's less about know whether something is possible, and more about figuring out which ones in practice are effective :) |
| 14:55 | corecode | yea, that's why i'm asking |
| 14:56 | corecode | the problem is that depending on what i'm matching, i need to consume more or fewer characters |
| 14:56 | justin_smith | corecode: this can be solved by using a proper parsing lib maybe :) |
| 14:57 | corecode | i tried instaparse |
| 14:57 | corecode | takes 8s to parse 8000 lines |
| 14:57 | corecode | so i thought, maybe write a parser myself, can learn me some clojure at the same time |
| 14:58 | justin_smith | I think that there is a single root cause of parsing taking so long and the difficulty of writing the parser by hand - a complex / difficult / perhaps badly designed language |
| 14:58 | justin_smith | pure speculation |
| 14:58 | corecode | no |
| 14:58 | corecode | this is a data exchange format from the 60ies |
| 14:58 | arrdem | justin_smith: 8k lines indicates an existing dataset |
| 14:59 | corecode | you can parse it with almost no backtracking |
| 14:59 | justin_smith | arrdem: fair point |
| 14:59 | corecode | https://gist.github.com/corecode/58606f3178c4c301627a |
| 15:00 | corecode | that's my instaparse grammar |
| 15:00 | arrdem | corecode: did you try using sequenced choice? |
| 15:00 | corecode | yes |
| 15:00 | corecode | a bit slower |
| 15:00 | arrdem | interesting. |
| 15:01 | arrdem | maybe try throwing this at fnparse or one of the other parser libraries for Clojure? |
| 15:01 | arrdem | there's no reason that you should invent a parser engine for such an obvious grammar |
| 15:01 | corecode | yes |
| 15:02 | arrdem | cgrand has a couple... I have two... |
| 15:02 | corecode | but then i thought, maybe try to write a simple recursive parser, as an excercise |
| 15:02 | arrdem | sure |
| 15:02 | corecode | exercise* |
| 15:08 | Raynes | TEttinger3: Yo. |
| 15:11 | corecode | basically i need a way to consume a variable amount of characters while mapping over a string |
| 15:16 | rads | dnolen_: is there a short answer for why the transducers js library has transducers that operate on "transforms" rather than reducing functions? |
| 15:16 | rads | from what I've seen in the clojure implementation, transducers operate on regular functions, not objects |
| 15:16 | arrdem | rads: afaik dnolen_ is on a plane to Germany rn |
| 15:17 | rads | oh, good to know |
| 15:17 | rads | maybe I'll figure it out by the time he gets off the plane ;) |
| 15:17 | arrdem | :P |
| 15:17 | borkdude | arrdem he just tweeted |
| 15:18 | schmee | on the topic of transducers, what's the story of transducers vs reducers? |
| 15:18 | schmee | are reducers completely superceded by transducers? |
| 15:18 | Raynes | borkdude discovers in-flight wifi |
| 15:19 | rads | schmee: it seems like transducers are replacing reducers |
| 15:19 | arrdem | schmee: yes, transducers are a more general structure than reducers |
| 15:19 | arrdem | schmee: not sure whether clojure.core.reducers will be removed or not however |
| 15:19 | borkdude | Raynes we're still dealing with getting wifi to work properly on trains here in NL |
| 15:20 | Raynes | Well, we're still dealing with getting wifi to work properly in apartments in Los Angeles, so it's cool. |
| 15:20 | schmee | arrdem: it makes sense to remove them I think, just like the core.async map et al. got deprecated after transducers came about |
| 15:20 | borkdude | hehe |
| 15:20 | arrdem | yeah here in Texas Time Warner has no damn idea how to keep a DCHP server up so.. |
| 15:21 | arrdem | schmee: yeah. we'll see. deprecation notices in 1.7 and removal in 1.8 would be nice but I'm not holding my breath |
| 15:23 | borkdude | it's kind of funny how they have all sorts of luxuries in planes that aren't properly available on the ground sometimes, I once had good espresso on a plane for example |
| 16:00 | SagiCZ1 | borkdude: while many people consider flights necessary evil, i enjoy the luxury of the transatlantic flights even in the economy class.. :) |
| 16:01 | justin_smith | corecode: another random thought - being able to split something into groups of arbitrary size is a pattern mapcat is well suited for |
| 16:24 | sveri | (inc justin_smith) |
| 16:24 | lazybot | ⇒ 96 |
| 16:25 | Raynes | (inc sveri) |
| 16:25 | lazybot | ⇒ 1 |
| 16:26 | justin_smith | sveri: was that because the post-walk string trim thing worked? |
| 16:28 | sveri | justin_smith: I did not try it yet, evening time here, but you helped often already and I learned about the feature today, so I thought it was appropriate |
| 16:29 | sveri | *you helped me often |
| 16:29 | squeedee | good point |
| 16:29 | squeedee | (inc justin_smith) |
| 16:29 | lazybot | ⇒ 97 |
| 16:30 | Raynes | (inc squeedee) |
| 16:30 | lazybot | ⇒ 1 |
| 16:35 | justin_smith | (inc karma) |
| 16:35 | lazybot | ⇒ 1 |
| 16:41 | SagiCZ1 | how would i extend defrecord? lets say it has fields a b c, and i want a record with those field plus another 'd' field? |
| 16:41 | bbloom | ,(defrecord NoFields []) |
| 16:41 | clojurebot | sandbox.NoFields |
| 16:41 | bbloom | ,(assoc (NoFields.) :a-field 123) |
| 16:41 | clojurebot | #sandbox.NoFields{:a-field 123} |
| 16:41 | bbloom | SagiCZ1: ^^ they are already extensible |
| 16:43 | justin_smith | SagiCZ1: use protocols or multimethods, not inheritence |
| 16:43 | SagiCZ1 | bbloom: not sure if thats good for me |
| 16:43 | the-kenny | SagiCZ1: You likely want to move the common stuff to a protocol - or rethink your use of records |
| 16:43 | SagiCZ1 | justin_smith: but both of these deal with functions, not fields |
| 16:44 | justin_smith | SagiCZ1: a function can be a field accessor |
| 16:44 | SagiCZ1 | i read about both protocols and records in Clojure Programming, but now when I might need them I am not sure when to use what |
| 16:45 | Bronsa | SagiCZ1: is there a reason why you can't use a plain map? |
| 16:47 | SagiCZ1 | i am remaking this application written in Common Lisp from a book... they use defclass to define some type hierarchy which they later use..while using simple inheritence to inherit some core fields which the whole family of types uses.. i thought i would replace that by records. |
| 16:48 | bbloom | SagiCZ1: just use maps |
| 16:48 | bbloom | SagiCZ1: skip the inheritence, put a :type key in the map, use multimethods that dispatch by :type |
| 16:48 | SagiCZ1 | sounds simple |
| 16:49 | Bronsa | SagiCZ1: and if you really need inheritance, use a ns qualified keyword for :type and use derive to build the hierarchy |
| 16:50 | SagiCZ1 | its just kinda scary.. what if i need two instances of one "type" .. if they are both simple maps, who is enforcing, that they both have the same fields? |
| 16:50 | bbloom | SagiCZ1: you are, with the help of immutability |
| 16:50 | bbloom | SagiCZ1: just make a factory function just like you would have made a constructor in the past |
| 16:50 | SagiCZ1 | factory function! |
| 16:50 | SagiCZ1 | of course |
| 16:50 | SagiCZ1 | thanks, let me try that |
| 17:03 | zand` | newbie question for you guys: |
| 17:03 | zand` | how would one convert: ([false (1 3)] [true (6 8)]) |
| 17:03 | zand` | into: |
| 17:04 | zand` | {false [1 3], true [6 8]} |
| 17:04 | Bronsa | ,(into {} '([false (1 3)] [true (6 8)])) |
| 17:04 | clojurebot | {false (1 3), true (6 8)} |
| 17:04 | Bronsa | you can convert the lists into vectors before or after, if you care |
| 17:05 | justin_smith | zand`: depending where that came from ##(group-by even? (range 1 8)) |
| 17:05 | lazybot | ⇒ {false [1 3 5 7], true [2 4 6]} |
| 17:05 | zand` | cool thanks - I'm sure I tried that already... i'm not sure why that didn't work for me the first time. |
| 17:06 | justin_smith | zand`: maybe you mapped over it after group-by |
| 17:06 | zand` | it's a 4clojure question (#63) and it's comes from a for loop |
| 17:06 | zand` | the restriction is to not use "group-by" |
| 17:07 | justin_smith | aha |
| 17:07 | justin_smith | :) |
| 17:20 | SagiCZ1 | bbloom: so if i have a map of fields, one of the fields could be function, and i could call it like this ((:method-name my-object) arguments), right? if i had extended some protocol, i could call it like this (method-name my-object arguments) .. is that correct? |
| 17:22 | Bronsa | SagiCZ1: you can still call (method-name obj args) if you make method-name a multimethod dispatching on :type/:op/whatever |
| 17:23 | Bronsa | SagiCZ1: silly example: (defn make-foo [x] {:op :foo :x x}) (defmulti method :op) (defmethod method :foo [_] 1) (method (make-foo :foo)) |
| 17:23 | SagiCZ1 | Bronsa: I see, so in that case i wouldnt have mutliple functions in the map, just one field called :type, and the functions would move to one multimethod where i would implement methods of all types i wanted |
| 17:24 | qbg | SagiCZ1: If you wanted to do something like ((:method-name my-object) arguments), you would probably want to do ((:method-name my-object) my-object arguments) instead |
| 17:24 | Bronsa | SagiCZ1: yes, keeping the data and and the functions manipulating the data separate |
| 17:25 | SagiCZ1 | Bronsa: interesting.. i was taught to keep the data and the functions manipulating them together |
| 17:25 | SagiCZ1 | qbg: yeah thanks, that would probably be the right way |
| 17:26 | justin_smith | SagiCZ1: this is one of the most important differences between fp and oo |
| 17:26 | justin_smith | regarding keeping functions and data tied or independent |
| 17:27 | SagiCZ1 | justin_smith: i guess i should embrace that then |
| 17:27 | SagiCZ1 | my idea was that maybe my factory function could make an instance via reify, but it cant hold any data |
| 17:27 | qbg | In OO you want to keep the functions with the data because the data is mutable |
| 17:27 | qbg | With FP, that is less important |
| 17:27 | justin_smith | SagiCZ1: you shouldn't need to be reifying anything here... |
| 17:28 | Bronsa | SagiCZ1: even when using a deftype w/ a protocol, the protocol fn are not tied to the type (if not for performance reasons that you should ignore now) |
| 17:29 | SagiCZ1 | okay |
| 17:29 | SagiCZ1 | thanks for pointing me in the right direction |
| 17:29 | lodin | qbg: You still need to assure that you don't break any conditions on the data though. |
| 17:30 | Bronsa | lodin: you can use prismatic's schema for that |
| 17:30 | SagiCZ1 | lodin: i guess when you are implementing one of the methods in the mutlimethod u know exactly what data you can work with, dont you? |
| 17:30 | qbg | lodin: True, but it is harder to "accidently" break the invariants when the objects are immutable |
| 17:33 | SagiCZ1 | one more question to the multimethods.. they group together the methods, but not the classes themselves, so if i wanted to add another class, i need to go through all the multimethods and add the methods there, right? i know i am not using the exact terms here but i hope you can catch my drift |
| 17:34 | Bronsa | SagiCZ1: yes you have to extend the multimethods to whatever new dispatch value you're adding |
| 17:35 | Bronsa | but it's an open system so there's no problem doing that. you can (defmethod my-method :new-dispatch-value ..) at anytime |
| 17:35 | SagiCZ1 | Bronsa: yes it does sound very flexible |
| 17:36 | SagiCZ1 | Bronsa: its just something completely different from what i was used to work with |
| 17:36 | zand` | justin_smith: I'm running into another hurdle that I can't seem to figure out -> can you tell me why this results in an error? : (flatten ( ( true (6 8) ) (false (1 3)) ) ) |
| 17:36 | qbg | zand`: You need to quote the list |
| 17:37 | qbg | Otherwise it'll try to evaluate it as code |
| 17:37 | zand` | well, there ya go! thanks :-) |
| 17:45 | lodin | qbg: Depends on the invariant I guess. If you have a structure holding two maps, one being the inverse of the other, then that's an invariant that immutability doesn't help you with (especially if you use e.g. assoc-in). |
| 17:48 | qbg | The structure can't change behind your back though, so you just have to ensure that you preserve the invariants that you care about |
| 17:50 | lodin | qbg: Ah, ok. Yes, I took that part for granted. :-) |
| 17:59 | SagiCZ1 | does backwards partial exist? |
| 18:00 | gfredericks | just in utility libs |
| 18:00 | SagiCZ1 | #(foo % arg1 arg2 arg3) |
| 18:01 | gfredericks | though that there is more of a "skip-the-first-arg-partial" |
| 18:01 | gfredericks | which I think would be nice sometimes |
| 18:02 | SagiCZ1 | i guess i can write a macro |
| 18:02 | SagiCZ1 | except that i cant |
| 18:02 | qbg | SagiCZ1: A function would do here |
| 18:02 | SagiCZ1 | true |
| 18:02 | SagiCZ1 | one should resort to macros only if a function cant do, right? |
| 18:02 | qbg | correct |
| 18:04 | gfredericks | and only after reconsidering whether you really need the thing or not |
| 18:04 | qbg | (inc gfredericks) |
| 18:04 | lazybot | ⇒ 97 |
| 18:06 | johnwalker | why doesn't contains? work for transients? |
| 18:06 | the-kenny | ,(let [x (transient {:foo 42})] (contains? x :foo)) |
| 18:06 | clojurebot | #<IllegalArgumentException java.lang.IllegalArgumentException: contains? not supported on type: clojure.lang.PersistentArrayMap$TransientArrayMap> |
| 18:07 | gfredericks | transients tend to be a bit primitive |
| 18:07 | the-kenny | Works in ClojureScript |
| 18:07 | johnwalker | oddly enough, .contains works for sets |
| 18:08 | johnwalker | but not maps |
| 18:08 | gfredericks | ,(.contains (transient {}) 42) |
| 18:08 | clojurebot | #<IllegalArgumentException java.lang.IllegalArgumentException: No matching method found: contains for class clojure.lang.PersistentArrayMap$TransientArrayMap> |
| 18:08 | gfredericks | ,(.contains (transient #{}) 42) |
| 18:08 | clojurebot | false |
| 18:08 | johnwalker | and furthermore, contains? works in clojurescript for sets |
| 18:09 | johnwalker | but not in clojure |
| 18:09 | the-kenny | and maps too |
| 18:09 | johnwalker | browsing the source. yeah, it looks like you're right the-kenny |
| 18:09 | gfredericks | I'm having trouble figuring that one out |
| 18:10 | SagiCZ1 | ,(repeat 5 (rand)) |
| 18:10 | clojurebot | (0.5837106342374121 0.5837106342374121 0.5837106342374121 0.5837106342374121 0.5837106342374121) |
| 18:10 | SagiCZ1 | i thought it would call the function 5 times? |
| 18:10 | justin_smith | ,(repeatedly 5 rand) |
| 18:10 | the-kenny | You want repeatedly |
| 18:10 | clojurebot | (0.3072787760975273 0.44169036150361773 0.29816617155704184 0.3742460514682746 0.6341255615995526) |
| 18:10 | the-kenny | SagiCZ1: repeat is a function. It gets passed two values: 5, and the result of (rand) |
| 18:11 | SagiCZ1 | but repeatedly takes a function of no args |
| 18:11 | the-kenny | yes |
| 18:11 | SagiCZ1 | what if i want to repeatedly call a function with some args? |
| 18:11 | gfredericks | the same args? |
| 18:12 | the-kenny | Same args: Use #(rand ...), different: Use `map' |
| 18:12 | justin_smith | ,(repeatedly 5 #(rand-int 5)) |
| 18:12 | clojurebot | (1 2 4 2 1) |
| 18:12 | SagiCZ1 | thank you |
| 18:12 | gfredericks | ,(pr-str (repeatedly 20 #(rand-nth '(boom waka waka)))) |
| 18:12 | clojurebot | "(waka waka waka boom boom ...)" |
| 18:12 | SagiCZ1 | :> |
| 18:12 | justin_smith | hiphop generator |
| 18:13 | gfredericks | ,(clojure.string/join " " (repeatedly 20 #(rand-nth '(boom waka waka)))) |
| 18:13 | clojurebot | "waka boom waka waka waka waka boom waka waka waka waka boom waka waka boom waka waka waka boom waka" |
| 18:13 | justin_smith | (inc gfredericks) |
| 18:13 | lazybot | ⇒ 98 |
| 18:15 | gfredericks | what on earth is a TransactionalHashMap |
| 18:15 | gfredericks | is that for the refs? |
| 18:16 | bbloom | gfredericks: i think it's effectively dead code |
| 18:16 | gfredericks | I had just come to that conclusion |
| 18:18 | kenrestivo | ,(pr-str (repeatedly 20 (constantly "OONTZ"))) ;; techno generator |
| 18:18 | clojurebot | "(\"OONTZ\" \"OONTZ\" \"OONTZ\" \"OONTZ\" \"OONTZ\" ...)" |
| 18:18 | bbloom | (doc repeat) ; kenrestivo |
| 18:18 | clojurebot | "([x] [n x]); Returns a lazy (infinite!, or length n if supplied) sequence of xs." |
| 18:19 | the-kenny | Classic (for ClojureScript): (str (clojure.string/join "" (repeat 10 (- "wat" 1))) " Batman!") |
| 18:19 | johnwalker | haha nice |
| 18:22 | kenrestivo | bbloom: indeed, that's more efficient, but the uglier version contains the adjectives "repeatedly" and "constantly" which are kind of appropriate for that variety of music |
| 18:23 | gfredericks | effectively using clojure.core function names to disparage music genres for dummies |
| 18:27 | johnwalker | ok, it's a bug. transients are broken |
| 18:27 | johnwalker | http://dev.clojure.org/jira/browse/CLJ-700 |
| 18:28 | arrdem | I need a meme for jira hell... |
| 18:29 | johnwalker | well, can't really blame jira |
| 18:29 | the-kenny | http://www.quickmeme.com/img/d6/d6d1b31fed4c49fdc2ac502b9c68a0092f37f92590630b03a235025a5cfe0e8d.jpg |
| 18:30 | arrdem | MFW: Obvious bug fix vetted, two years old |
| 19:01 | bbloom | arrdem: it's even fixed by a alex redington at relevance |
| 19:09 | johnwalker | bbloom: puredanger suggested that it was an incomplete fix |
| 19:09 | arrdem | I suspect but am too tired to prove that bbloom was joking |
| 19:09 | gfredericks | I tried to fix a different transient issue once with a similar assessment |
| 19:10 | gfredericks | it was more of "aw man this class hierarchy is all borked; what are we gonna do." |
| 19:10 | bbloom | argh. |
| 19:10 | johnwalker | welp |
| 19:12 | gfredericks | it was wrt ##(subvec (transient [1 2 3]) 1 2) I think |
| 19:12 | lazybot | java.lang.ClassCastException: clojure.lang.PersistentVector$TransientVector cannot be cast to clojure.lang.IPersistentVector |
| 19:12 | gfredericks | no the other way around |
| 19:12 | gfredericks | &(transient (subvec [1 2 3] 1 2)) |
| 19:12 | lazybot | java.lang.ClassCastException: clojure.lang.APersistentVector$SubVector cannot be cast to clojure.lang.IEditableCollection |
| 19:12 | johnwalker | yes, i recently voted on that issue |
| 19:23 | arrdem | &'#(+ x %1) |
| 19:23 | lazybot | ⇒ (fn* [p1__11656#] (+ x p1__11656#)) |
| 19:28 | johnwalker | so why is a raven like a writing desk ? |
| 19:30 | justin_smith | johnwalker: one is a pest for wrens, the other is a rest for pens |
| 19:32 | johnwalker | lol http://www.quora.com/Why-is-a-raven-like-a-writing-desk |
| 19:33 | gfredericks | "Because there's a b in both, and because there's an n in neither." |
| 19:39 | arrdem | justin_smith: http://stackoverflow.com/questions/26456524/clojure-using-map-to-store-results-and-parameters easy pickings |
| 19:41 | justin_smith | arrdem: there's a few doses of wat in that question to be sure, but yes, very easy to answer |
| 19:42 | johnwalker | ,((juxt #(apply min %) identity) [1 2 3]) |
| 19:42 | clojurebot | [1 [1 2 3]] |
| 19:42 | johnwalker | actually nevermind. i'm not sure what he's asking |
| 19:43 | johnwalker | oh he wants additive inverses |
| 19:44 | johnwalker | ,(map (juxt identity -) [1 2 3]) |
| 19:44 | clojurebot | ([1 -1] [2 -2] [3 -3]) |
| 19:44 | gfredericks | huh speaking of which |
| 19:44 | gfredericks | ,(+ Double/POSITIVE_INFINITY Double/NEGATIVE_INFINITY) |
| 19:44 | clojurebot | NaN |
| 19:44 | johnwalker | ahahahhaha |
| 19:44 | arrdem | which makes perfect sense |
| 19:44 | gfredericks | I guess that's the best you can do |
| 19:45 | johnwalker | is there a destroy all software talk coming up for clojure ? |
| 19:46 | gfredericks | is that a confusion of me with gary bernhardt? |
| 19:47 | johnwalker | no, but i bet you could get away with it |
| 19:48 | gfredericks | ,(* Double/NEGATIVE_INFINITY -1e-10) |
| 19:48 | clojurebot | Infinity |
| 19:52 | johnwalker | how long has he been joining clojure and promptly quitting? |
| 19:57 | arrdem | johnwalker: dude just ignore joins and parts. seriously. #emacs et all are unlurkable otherwise. |
| 20:01 | johnwalker | "/ignore -channels #emacs,#clojure * JOINS PARTS QUITS NICKS" |
| 20:01 | arrdem | :+1: |
| 20:02 | gfredericks | I still get nicks; it is 99% noise and 1% clears up an otherwise confusing mention |
| 20:03 | justin_smith | it would be nice to have that data togglable - like with a switch it would disappear entirely (default) or appear, in chronological contex (when turned on to resolve some ambiguity) |
| 20:03 | gfredericks | ah yeah |
| 20:03 | johnwalker | or take a spam filter approach |
| 20:03 | gfredericks | it's at least pretty low noise |
| 20:13 | johnwalker | ,(count (transient {})) |
| 20:13 | clojurebot | 0 |
| 20:13 | johnwalker | ,(empty? (transient {})) |
| 20:13 | clojurebot | #<IllegalArgumentException java.lang.IllegalArgumentException: Don't know how to create ISeq from: clojure.lang.PersistentArrayMap$TransientArrayMap> |
| 20:13 | johnwalker | ,(transient (hash-map)) |
| 20:13 | clojurebot | #<TransientArrayMap clojure.lang.PersistentArrayMap$TransientArrayMap@7a1e34> |
| 21:06 | papachan | hello |
| 21:07 | papachan | if i want to test my project in suite test my project use ring, i must lein run first and lein specs |
| 21:14 | justin_smith | papachan: you could also decompose the logic of your code into pure functions, and test those without booting up ring |
| 21:15 | justin_smith | papachan: but anyway, you can start up ring without lein run |
| 21:15 | papachan | thanks |
| 21:15 | papachan | oh yeah certainly |
| 21:15 | justin_smith | maybe I didn't understand what you were saying |
| 21:16 | justin_smith | oh, you are running the lein spec plugin |
| 21:17 | papachan | yeah i was trying with speclj first |
| 21:17 | justin_smith | anyway, there are a few options, you can manually run your specs from inside a repl / lein run, or you can start up the server from within the testing code, or, as I mentioned, move all the logic into a pure function, such that you can test its return value for the known input(s) without the server running |
| 21:18 | justin_smith | functional code + immutible values can simplify testing quite a bit |
| 21:19 | papachan | i had take a look at kerodon, pretty good project |
| 21:24 | squeedee | unit testing at whatever level under the skin is important, but so too is acceptance testing. Side effects are going to happen because there are places for mutable state, such as the db, and external services. |
| 21:24 | justin_smith | squeedee: sure, integration tests |
| 21:24 | justin_smith | but if it touches the db it isn't strictly a unit test |
| 21:24 | squeedee | thats not what i was saying |
| 21:25 | justin_smith | OK |
| 21:25 | squeedee | Just that I don't think you can safely do without either |
| 21:26 | squeedee | how is everyone tonight? |
| 21:26 | squeedee | I took a break from second guessing myself about how i code clojure, reminded myself that I dont have to learn everything in one go, so now I'm going to make my autogenerated maps work dangit. |
| 21:39 | squeedee | Hmm any way to get compiler warnings about locals shadowing? |
| 21:42 | squeedee | Or a lint anyone recommends? |
| 21:44 | oskarkv | squeedee https://github.com/jonase/eastwood is the only one I've heard about. |
| 21:46 | justin_smith | there's lein-bikeshed and lein-kibit |
| 21:46 | squeedee | sorry i typed in "giving it a whirl now" but it went into my browser search bar by mistake :P |
| 21:46 | ddellacosta | I'd like to hear other folks' opinions on this: https://github.com/ddellacosta/friend-oauth2/issues/27 |
| 21:47 | squeedee | yes, there are those two. I remembered looking at options last week and thinking i should ask in here for opinions |
| 21:47 | ddellacosta | would love to know how others would respond |
| 21:48 | squeedee | same guy wrote kibit so i guess they are very much compimentary |
| 21:49 | squeedee | ddellacosta: thats totally reasonable |
| 21:49 | ddellacosta | squeedee: what is? |
| 21:49 | squeedee | support for 'quirks' is also a reasonable thought |
| 21:49 | squeedee | your position |
| 21:50 | mdeboard | In the core.async doc, it lists several functions map<, filter<., etc as being deprecated and to use transformers instead. What's meant by this? |
| 21:50 | ddellacosta | squeedee: yeah, I guess I should clarify--I don't even want to add an option that my lessen security, especially if it's just because some providers don't follow the spec. Is that unreasonable? |
| 21:50 | ddellacosta | *that may lessen |
| 21:51 | squeedee | does setting 'assume-state' cause a potential security flaw? |
| 21:51 | squeedee | I think it might be a little unreasonable |
| 21:52 | squeedee | providing an option thats clearly dangerous means you've done your bit, but not made life maddening for the consumer. |
| 21:52 | squeedee | they could always maintain a fork, but that too becomes madenning |
| 21:52 | squeedee | that said, I still understand where you're coming from |
| 21:53 | ddellacosta | squeedee: hmm. Again, why should we be adding features to a library to circumvent security because providers have not properly followed the RFC? I still feel like the "circumventing security by default" part is more important here than "making things more inconvenient for the consumer." I'm trying to see if there's a good counter-argument. |
| 21:53 | squeedee | if it were { :quirks { :dangerous { :assume-state "suckitup" }}} ? |
| 21:54 | ddellacosta | ...or maybe just don't use a service that isn't secure? |
| 21:54 | ddellacosta | or rather, fork it if you really need to. I dunno, I'm really not sure on this one. |
| 21:55 | ddellacosta | if it were some other non-security-related thing I think I'd be more open |
| 21:55 | ddellacosta | but it's not like OAuth2's security is that great to begin with |
| 21:56 | ddellacosta | well, thanks squeedee for your feedback, I'll give it a bit more thought. Maybe I'm overthinking it |
| 21:56 | SqueeD | sorry, hospital wifi is tragic |
| 21:56 | ddellacosta | ah, hahaha |
| 21:57 | SqueeD | so.. you cant make business domain decisions for your consumers |
| 21:57 | SqueeD | you can help them heaps |
| 21:57 | SqueeD | and in helping them heaps, your product gains favour |
| 21:57 | SqueeD | thats my 2cents |
| 21:58 | SqueeD | i may use crippled oauth to a service simply because: 1. I must, i am not in a position to change the dictatorial attitude of some PM or the company as a whole |
| 21:58 | SqueeD | 2. It's a good stop gap to keep development moving |
| 21:59 | SqueeD | 3. I honestly dont care, I just want the convenience oauth provides to let my users enter their details quicker. |
| 21:59 | SqueeD | Im arguing here, for your sake. Im not worried how you take it :D |
| 22:01 | ddellacosta | squeedee: no, this is what I wanted to hear, definitely |
| 22:01 | ddellacosta | squeedee: thanks, I'll think about it. I tend to go all out on the security side, and I realize that it's a balanced between convenience and security, and maybe I'm going to far here. Will think on it further--thanks a lot! |
| 22:01 | squeedee | I'm just pleased its not a clojure question, so i can actually offer something :P |
| 22:01 | ddellacosta | ah, haha |
| 22:01 | squeedee | welcome |
| 22:02 | ddellacosta | edits: *it's a balance , *going too far ...typing too fast. :-/ |
| 22:02 | squeedee | Meh, it's IRC |
| 22:03 | squeedee | I find it funny that people get annoyed at sloppy written communications in IRC. |
| 22:03 | squeedee | How well do they fare when chatting with people at meetups who use broken english or slang |
| 22:04 | squeedee | hello rubygeek :D |
| 22:05 | squeedee | Can anyone tell I'm desperate for company? |
| 22:07 | ddellacosta | squeedee: haha. Yeah, I like to try to write well in every medium, if I can. |
| 22:07 | ddellacosta | personal point of pride is all, I don't actually care that much how other people write, mostly. |
| 22:08 | squeedee | Thats cool :D |
| 22:09 | squeedee | I was a tech writer for years |
| 22:09 | squeedee | and when i was chilling in IRC in the evenings, i got murderous when people brought me up on my grammar and typos. |
| 22:10 | arrdem | hehe yeah nothing like someone pointing out a typo you missed in that shiney new post :P |
| 22:10 | squeedee | Admittedly i was younger, back when i got murderous about really deranged things. |
| 22:11 | squeedee | I don't mind that so much if it's done politely. But a post is not conversational. |
| 22:11 | squeedee | in chat i'm more interested in conveying my thoughts than perfecting my written craft. If you're actually confused by something i said in chat, you can just say 'wait.. i didnt understand that' |
| 22:12 | squeedee | context is everything |
| 22:12 | squeedee | or a huge amount thereof |
| 22:12 | ddellacosta | yeah, agreed. |
| 22:16 | squeedee | ddellacosta are you producing clojure web apps professionally yourself? |
| 22:16 | ddellacosta | squeedee: well, as part of a team |
| 22:16 | squeedee | where at? |
| 22:16 | ddellacosta | squeedee: https://diligenceengine.com |
| 22:17 | squeedee | new york? |
| 22:20 | squeedee | ddellacosta: hah says tokyo on your github account. is that where you're at? |
| 22:22 | andrewhr | mdeboard: you question got unaswered or a miss something? anyway.. that doc means that you should use 1.7’s tranducers |
| 22:22 | andrewhr | that’s the new way to go |
| 22:23 | ddellacosta | squeedee: yep! |
| 22:23 | ddellacosta | squeedee: but working remotely |
| 22:30 | squeedee | ddellacosta: i work at pivotal labs in NY, (remotely from virginia) |
| 22:31 | ddellacosta | squeedee: really! I wonder if you know my buddy Jon there |
| 22:31 | squeedee | ddellacosta: i wish we would do some clojure projects |
| 22:31 | squeedee | berger? |
| 22:31 | ddellacosta | squeedee: yeah, Jon Berger |
| 22:31 | squeedee | sure do |
| 22:31 | ddellacosta | squeedee: yeah, I thought you guys were doing some ClojureScript |
| 22:31 | squeedee | That guy gets around |
| 22:31 | squeedee | none that i've seen |
| 22:31 | squeedee | not in NY anyway. |
| 22:32 | squeedee | I'll be moving to the Cloud Foundry organisational arm of Pivotal soon, so probably even less chance. |
| 22:32 | ddellacosta | whoops |
| 22:32 | squeedee | Tho I'm going to try and subsume one of the community clojure buildpacks and champion that |
| 22:45 | andrewhr | squeedee: nice! |
| 22:46 | squeedee | andrew do you ever deploy CLJ to heroku/cf ? |
| 22:48 | andrewhr | unfornutally, no. I still trying to squeeze some clj on my daily work (consultacy, primary ruby) |
| 22:49 | squeedee | i feel ya |
| 22:49 | andrewhr | my current project I’m using clojurescript, but that’s because they leaved me alone with all the toys |
| 22:49 | andrewhr | :P |
| 22:50 | andrewhr | anyway, will be nice to add support to clojure on CF since it’s another-platform-to-deploy |
| 22:52 | squeedee | It's big sell is you can get your clients to use it behind the firewall, makes them feel safe :P |
| 22:52 | squeedee | I personally love CF, or i wouldnt have asked to transfer there from Labs. |
| 22:56 | andrewhr | CF works like a run-on-your-machine-paas? I’m not so familiar with it |
| 23:05 | squeedee | andrewhr CF is a run-your-own paas. you can run it on your own machine in a vm but thats not exactly prod ready |
| 23:06 | squeedee | normally you pick your IaaS. the current onprem solution most people use is vsphere |
| 23:06 | squeedee | theres openstack support too |
| 23:06 | squeedee | theres an abstraction layer designed to make it run on any IaaS |
| 23:13 | andrewhr | sorry squeedee, I’m accidentally disconnected :/ |
| 23:13 | andrewhr | but thank you for the explanation :) |
| 23:14 | andrewhr | oh, freenode logs save the day |
| 23:15 | andrewhr | thank you guys, but need to go. bedtime. Seeya! |
| 23:49 | rritoch | Hi, does anyone know how to alter a root binding at runtime? I have a dynamic variable (def ^:dynamic *somevar*) that I need to set the root of at runtime so every thread defaults to an assigned root binding. |