2014-12-26
| 00:46 | ryancole | as a newbie to clojure, what editor should i be using on windows? is light table the way to go, or should i try something like emacs? |
| 00:46 | ryancole | like in the long run, which would benefit me the most |
| 00:47 | justin_smith | ryancole: as a newcomer, I would start by using (require 'my.ns :reload) after saving a new version of the namespace file |
| 00:47 | justin_smith | save the editor integration for later, when you realize it isn't magic |
| 00:48 | ryancole | i think that was over my head. are you saying to just use repl? |
| 00:48 | justin_smith | I like emacs as a long term user, but cider gets broken a lot with new releases, so it can be frustrating. I have been using inferior lisp lately instead. |
| 00:48 | justin_smith | ryancole: yes, you can reload code in the repl with require, after saving it. The editor integration just maps that to a keypress (and has shortcuts for things like docs of course) |
| 00:49 | justin_smith | ryancole: also, the most featureful editor integration for clojure is intellij idea, with the cursive plugin |
| 00:50 | justin_smith | ryancole: afaik the only sane way to do step debugging of clojure code right now |
| 00:50 | justin_smith | (but I still use emacs because I have used emacs for over a decade and IDEs bug me) |
| 00:52 | ryancole | ok, perhaps clojure's repl is powerful enough to fully support editing code in files and such, without the need for an extra text editor? |
| 00:52 | ryancole | im familiar with repl for like python where it wasnt commonly used as also the "editor" |
| 00:52 | justin_smith | not quite. Do the editing in whatever editor you like best (at first), and the repl can reload after you update the code. |
| 00:52 | ryancole | more so used for like one-off testing, or running files, etc |
| 00:52 | ryancole | ah ok i see |
| 00:53 | namra | ryancole: you might also look at this http://thinkrelevance.com/blog/2013/06/04/clojure-workflow-reloaded |
| 00:53 | justin_smith | clojure's repl is interesting in that you can leave it running as you update code, and it can reload all your new definitions etc. without needing a restart |
| 00:53 | justin_smith | though there are a few constructs that don't play as nicely with that, they are only a few |
| 00:59 | ryancole | cool, im going to go hop in bed and read that workflow blog post. thanks! :) |
| 00:59 | justin_smith | namra: ryancole: the reloaded workflow is great, but not really the best way to *start* using clojure |
| 00:59 | justin_smith | imho |
| 01:00 | justin_smith | eventually, you'll love it, but better to just do the repl basics first I think |
| 01:00 | namra | true |
| 01:00 | namra | but it give a nice overview what is possible with the repl, and that one is not really required to use a specific editor that has plugins to interact with a repl. |
| 01:01 | namra | of course using such editor with a plugin comes also in handy ^^ |
| 01:01 | justin_smith | that's an excellent point, yes |
| 01:08 | namra | ryancole: have you worked with anything like emacs or vim before? |
| 01:09 | namra | such editors are nice when you like to tinker and customize stuff, and don't want a large IDE to get into your way |
| 01:10 | namra | and currently it looks like that there are both for vim and emacs good plugins available to write programms in clojure |
| 01:10 | ryancole | namra, vim - not emacs |
| 01:10 | justin_smith | fireplace.vim is good |
| 01:10 | namra | yep |
| 01:11 | justin_smith | but I still think starting without the editor integration helps |
| 01:11 | namra | justin_smith: i agree with you |
| 01:12 | namra | ryancole: then i'd go with vim or vim-like, so you don't need to dive into emacs, if time is scarce. but there's still evil-mode ^^, to make a transition to emacs a little bit easier. |
| 01:13 | ryancole | haha, vi for emacs |
| 01:13 | ryancole | nice |
| 01:13 | namra | a nice looking and simple ide that comes with integrated leiningen and repl: https://nightcode.info/ |
| 01:14 | justin_smith | ryancole: I use it because I like the features of emacs (eg. especially org-mode and gpg integration), and I like the extension language being a real language I can tolerating coding in, but I hate the default keybindings, they are sadistic |
| 01:14 | namra | :D |
| 01:15 | ryancole | so ive heard :P |
| 01:15 | namra | never tried emacs, but the elisp now looks very appealing. easier than the cryptic vim-syntax ^^ |
| 01:16 | ryancole | im just aiming for the most minimal, basic route into a simple edit code -> run code learning process |
| 01:17 | ryancole | and as i get familiar with the tools, add in more feature packed editors |
| 01:18 | namra | then what justin_smith said seems a good way, take an editor your familiar with, edit you code within it and use the repl to reload the files and test your stuff within the repl |
| 01:24 | ryancole | sweet, sounds good to me :) |
| 01:24 | ryancole | ok guys gotta hop off. ill be reading up on stuff and swing back by later, im sure. |
| 01:24 | ryancole | thanks |
| 02:34 | santaClaws_ | hey |
| 02:36 | santaClaws_ | can I do those haskell (f.g) x = f (g x) stuff in clojure? |
| 02:38 | andyf | (comp f g) is Clojure's (f . g) |
| 02:47 | santaClaws_ | ok cool thing. I have just started, The chapter on maps nad list is uite long . at iloveponies.github.io |
| 02:47 | santaClaws_ | *and |
| 02:53 | santaClaws_ | I wanted to know about functional programming , I chose clojure, although my codes have an awful lot of parenthesis. |
| 03:03 | rksm | Hello, any fipp users here? Is there an easy way to keep comments when pretty printing with fipp.clojure/pprint? |
| 03:15 | rksm | Or for that matter, is there a recommended other way to pretty print clj code? |
| 03:27 | korpse | How do people use joplin or ragtime in production or from an uberjar? |
| 04:17 | piranha | I'm having exact trouble like here: http://stackoverflow.com/questions/23489106/cljx-starter-project-browser-repl-issue - any ideas how to solve? |
| 04:17 | piranha | I've connected to my browser and can't require anything |
| 04:18 | augustl | does mori (cljs data structures in JS) have any serialization built in? |
| 04:19 | piranha | augustl: you convert it to JS structures and then JSON.stringify, if that's your question |
| 04:21 | octe | what better way is there to get the shortest collection then this: (reduce (fn [x y] (if (> (count x) (count y)) y x)) coll) |
| 04:22 | hyPiRion | octe: (apply min-key count colls) |
| 04:22 | si14 | is there anything similar to Prismatic's Graph, but for "decision graphs" like this one https://github.com/for-GET/http-decision-diagram ? |
| 04:23 | octe | thanks |
| 04:23 | si14 | there is Liberator, but I'm interested in more general "engine" |
| 04:24 | si14 | of course it's possible to use just a big bunch of nested if-s, but it quickly becomes uncomfortable |
| 04:27 | augustl | piranha: I see, was hoping there was a way to avoid the conversion to JS structures :) |
| 04:28 | piranha | augustl: well, I guess with transit-js you could write handlers to do that :) |
| 04:55 | octe | i'm writing a function to find the shortest path between two nodes in a graph, it seems to work but is quite slow and i'm not sure how to do it in a faster way without having some kind of mutable state |
| 04:55 | octe | http://pastebin.com/X7HxwpyU |
| 04:58 | si14 | octe: you may be interested in Dijkstra algorithm. Google gives a lot of relevant posts on "dijkstra clojure" request |
| 05:01 | si14 | octe: generally speaking, you have quite a lot of overhead in your algorithm. e.g., this (filter #(not (lazy-contains? (flatten path) %1)) (get-neighbours current)) piece will have quadratic complexity because you are flattening and scanning for each of neighbours |
| 05:02 | octe | yeah, i know |
| 05:02 | octe | i'm just not sure how to do it in a better way :) |
| 05:03 | octe | i'm reading up on dijkstras algoorithm |
| 05:16 | si14 | octe: it's a bit nontrivial to translate it to Clojure properly from typical "mutable" description, but it's a worthy exercise :) |
| 05:17 | octe | yeah |
| 05:17 | octe | it's an interesting task :) |
| 05:22 | mearnsh | justin_smith: "nothing in the code you pasted uses atom" - that's why i'm stumped... |
| 05:25 | mearnsh | (and yeah I know my use of atom? is confounding but it makes sense here) |
| 05:27 | andyf | are you aware of the data.priority-map library for maintaining maps with items sorted by their values? Very useful for Dijkstra's algorithm |
| 05:57 | dysfun | is there a macro for doing the inverse of {:keys [foo bar]}, i.e. i have vars foo and bar and i want a shorthand for doing {:foo foo :bar bar} |
| 05:58 | dysfun | it seems like a common case |
| 05:58 | SagiCZ1 | wait what |
| 05:59 | SagiCZ1 | you cant use values to get keys, can you?.. they are not uniqe |
| 05:59 | dysfun | you *could*, potentially expecting multiple results |
| 05:59 | dysfun | but it would be slow and daft |
| 06:00 | SagiCZ1 | i guess.. |
| 06:00 | dysfun | if you want this functionality, there's a function that inverts a map (with those limitations), let me look up the name |
| 06:01 | sm0ke | is there some representation for int in clojure like for bigdec and bigint? |
| 06:01 | SagiCZ1 | cool i didnt know that.. well what you ask for is not a macro but a destructuring functionality i think |
| 06:01 | sm0ke | ,(class 1M) |
| 06:01 | clojurebot | #<AccessControlException java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "accessDeclaredMembers")> |
| 06:01 | sm0ke | hurmm |
| 06:01 | SagiCZ1 | ,(type 4) |
| 06:01 | clojurebot | #<AccessControlException java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "accessDeclaredMembers")> |
| 06:02 | dysfun | SagiCZ1: well in this case, that's a destructuring bind taken care of by the reader, yes. this is just shorthand to allow me to be lazy. I can see how it would be a trivial macro. but we're assuming i'm going to pass in a fixed set of items anyway and since the names are calculable trivially, i'm not concerned with the ramifications of potentially duplicating things etc. |
| 06:06 | sm0ke | edn should ideally differentate between a int and a long |
| 06:06 | sm0ke | is my point |
| 06:07 | SagiCZ1 | sm0ke: why do you need to? |
| 06:08 | dysfun | SagiCZ1: https://www.refheap.com/95417 |
| 06:09 | SagiCZ1 | oh.. i see.. i didnt realize that the value and key is the same in the pair |
| 06:13 | dysfun | if they weren't, it wouldn't be the inverse of the destructuring bind :) |
| 06:15 | Bronsa | dysfun: fyi there's no such thing as "destructuring bind taken care of by the reader" |
| 06:15 | Bronsa | dysfun: the destructuring functionality is just macrology |
| 06:24 | dysfun | hrm, howso? |
| 06:26 | Bronsa | $source destructure |
| 06:26 | lazybot | destructure is http://is.gd/R9QO9F |
| 06:27 | Bronsa | dysfun: destructure is just a regular function, it's used inside a bunch of macros like let and fn |
| 06:31 | dysfun | oh right, cool |
| 06:33 | SagiCZ1 | can i avoid calling rand twice here and get the same result? |
| 06:33 | SagiCZ1 | ,(repeatedly 5 #(vector (rand) (rand))) |
| 06:33 | clojurebot | #<AccessControlException java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "accessDeclaredMembers")> |
| 06:33 | SagiCZ1 | who broke clojurebot? |
| 07:49 | Frozenlock | dysfun: is this what you were looking for? https://www.refheap.com/11818 |
| 07:49 | mearnsh | justin_smith: uh sorry, i'm a fool, ignore |
| 08:00 | dysfun | Frozenlock: no, i already refheap'd a quickly thrown together one: https://www.refheap.com/95417 |
| 08:02 | dysfun | actually, sorry, i misread your example. yes, that also works |
| 08:02 | Frozenlock | Ah sorry. Your's more general. I guess the one I pasted was filtering nil values for some reason. |
| 08:04 | dysfun | *shrug* it was the first thing i came up with |
| 08:04 | dysfun | i figure there's not a great deal that can go wrong |
| 08:04 | Frozenlock | inb4 the planet explodes!!!! |
| 08:06 | dysfun | hrm, that's odd |
| 08:06 | dysfun | ,(keyword 'nil) |
| 08:06 | clojurebot | #<AccessControlException java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "accessDeclaredMembers")> |
| 08:06 | jonathanj | i don't understand how to deploy lein-ring applications to production using an uberjar, ring options have to be in a :ring key in the project so how do i override/set these in production? |
| 08:07 | dysfun | jonathanj: it's possible you've outgrown lein-ring, it's really just a small wrapper that'll provide a main() |
| 08:08 | dysfun | it uses jetty under the hood. you can write your own main function and provide :main in the project.clj |
| 08:08 | dysfun | ring-server is very easy to use, just a single function call |
| 08:08 | Frozenlock | jonathanj: as dysfun said, you might want to use jetty in your -main. ----> (jetty/run-jetty #'app {:port some-port :join? false}) |
| 08:09 | dysfun | (as is jetty. well, if you're not using it as a container, that is...) |
| 08:10 | jonathanj | dysfun, Frozenlock: thank you :) |
| 08:33 | godd2 | would you say that [1 2 3] is merely syntactic sugar for (vector 1 2 3) ? |
| 08:40 | AimHere | Yes |
| 08:40 | AimHere | Though I'd dispute the phrase 'merely syntactic sugar' |
| 08:40 | AimHere | Unless you're at the level of wiring up your NAND gates yourself, all computer programming is just syntactic sugar |
| 08:42 | dysfun | heh |
| 08:42 | dysfun | nice way of looking at it |
| 08:43 | dysfun | does anyone know why (keyword 'nil) returns nil? surely at that point it's the symbol nil? |
| 08:44 | Bronsa | ,(keyword nil) |
| 08:44 | clojurebot | #<AccessControlException java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "accessDeclaredMembers")> |
| 08:44 | Bronsa | &(keyword nil) |
| 08:44 | lazybot | ⇒ nil |
| 08:44 | Bronsa | &(keyword 2) |
| 08:44 | lazybot | ⇒ nil |
| 08:44 | Bronsa | &(keyword (Object.)) |
| 08:44 | lazybot | ⇒ nil |
| 08:44 | Bronsa | dysfun: keyword returns nil if you hand it a nonsensical arg |
| 08:44 | AimHere | (keyword '2) |
| 08:44 | godd2 | &(keyword 'nil) |
| 08:44 | lazybot | ⇒ nil |
| 08:45 | AimHere | ,(keyword '2) |
| 08:45 | clojurebot | #<AccessControlException java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "accessDeclaredMembers")> |
| 08:45 | Bronsa | dysfun: also 'nil is the same as nil |
| 08:45 | dysfun | why is a symbol nonsensical? |
| 08:45 | Bronsa | dysfun: nil is not a symbol |
| 08:45 | Bronsa | &(symbol? nil) |
| 08:45 | lazybot | ⇒ false |
| 08:45 | Bronsa | &(symbol? 'nil) |
| 08:45 | lazybot | ⇒ false |
| 08:45 | dysfun | so nil can't be quoted? |
| 08:45 | Bronsa | &(= nil 'nil) |
| 08:45 | lazybot | ⇒ true |
| 08:45 | Bronsa | dysfun: it can be quoted, it's just not a symbol |
| 08:45 | Bronsa | dysfun: like true and false |
| 08:45 | Bronsa | quoting nil, true and false returns nil true and false |
| 08:45 | Bronsa | they are self-evaluating |
| 08:46 | Bronsa | just like quoting a keyword returns that keyword |
| 08:46 | Bronsa | ,':foo |
| 08:46 | clojurebot | #<AccessControlException java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "accessDeclaredMembers")> |
| 08:46 | Bronsa | &':foo |
| 08:46 | lazybot | ⇒ :foo |
| 08:46 | dysfun | so in order to store the symbol nil, i would have to cast to symbol first? |
| 08:46 | Bronsa | yeah.. you can only obtain it via ##(symbol "nil") |
| 08:46 | lazybot | ⇒ nil |
| 08:46 | dysfun | hrm. i'm not sure how i feel about that |
| 08:47 | Bronsa | about what? |
| 08:47 | dysfun | nil being self-evaluating |
| 08:48 | Bronsa | dysfun: it is documented that nil is not a symbol btw |
| 08:48 | dysfun | i'm sure it is |
| 08:48 | Bronsa | "Strings, numbers, characters, true, false, nil and keywords evaluate to themselves." |
| 08:48 | luxbock | ##(nil? (symbol "nil")) |
| 08:48 | lazybot | ⇒ false |
| 08:48 | Bronsa | and also, "nil is not a Symbol" |
| 08:49 | dysfun | i'm trying to figure out in my head if that's more or less confusing than the alternative |
| 08:49 | Bronsa | dysfun: imgagine how confusing it would be if every time something returned "nil" you had to figure out if it was the symbol nil or the "value" nil |
| 08:50 | AimHere | I thought nil can be a value of any data type |
| 08:50 | Bronsa | dysfun: not even talking about the fact that (symbol "nil") evaluates to a truthy value |
| 08:50 | dysfun | well not really. most programs don't use symbols outside of macros |
| 08:51 | dysfun | i think if you've quoted nil, it's quite clear you meant the symbol |
| 08:52 | dysfun | but it's not a common case, so i don't think it's a big deal |
| 08:52 | Bronsa | dysfun: sure but think about (defn foo [some-map] (get some-map some-key)), and you get back "nil" at the repl |
| 08:52 | Bronsa | dysfun: now you have no way to know if that's a symbol or the nil "value", looking at it |
| 08:53 | dysfun | well, my repl has pretty-printing that works. and your code will know, since strings are truthy |
| 08:55 | dysfun | i guess it comes down to whether you think having the symbol 'nil around is a good thing |
| 08:56 | dysfun | and i think in the general case, probably not |
| 09:24 | SagiCZ1 | say you have an application with gui and there is a way to start some long running tasks.. there should always be an option to interrupt that task and stop it.. say it runs in a thread in future, how would i go about interrupting it? |
| 09:28 | jonathanj | i'm trying to define a name (used in several places) that is passed in from the command-line |
| 09:28 | jonathanj | (a database uri in this case) |
| 09:28 | jonathanj | usually i'd just pass the value around but in this case it seems like using a ^:dynamic var might be easier? |
| 09:29 | jonathanj | i've defined it as (def ^:dynamic foo) and in my main function i do (defonce foo ...) |
| 09:29 | Bronsa | SagiCZ1: future-cancel |
| 09:29 | jonathanj | this gives me a warning though: Warning: *database-uri* not declared dynamic and thus is not dynamically rebindable, but its name suggests otherwise. Please either indicate ^:dynamic *database-uri* or change the name. |
| 09:30 | dysfun | jonathanj: you want (binding [name val]) |
| 09:30 | SagiCZ1 | (doc future-cancel) |
| 09:30 | clojurebot | #<AccessControlException java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "accessDeclaredMembers")> |
| 09:32 | jonathanj | dysfun: *database-uri* is used from several functions (called from various places probably from other threads if i understand how jetty works) so how do i used binding in this case? |
| 09:32 | jonathanj | (binding [...] (run-jetty ...) ? |
| 09:32 | si14 | (sorry, that /me was erroneous) |
| 09:33 | SagiCZ1 | si14: do you find it unreadable? |
| 09:34 | si14 | SagiCZ1: I wonder if it can be done better. One of the low handing fruits is if-not-let macro, of course |
| 09:34 | dysfun | jonathan: should be fine |
| 09:35 | SagiCZ1 | si14: this written in java would be three times as long |
| 09:36 | si14 | SagiCZ1: you are right, of course :) I believe it can be improved though |
| 09:36 | SagiCZ1 | si14: yeah i would love to hear some improvements myself.. |
| 09:38 | SagiCZ1 | Bronsa: thank you for future-cancel |
| 10:08 | kl | Hi |
| 10:08 | kl | Looking into core.async |
| 10:08 | jonathanj | how can i conditionally thread some things? something like (-> X foo bar (if some-cond? (-> quux baz)) quaz)? |
| 10:08 | kl | When you use a go macro in clojure/core.async - is it a thread of its own? |
| 10:08 | SagiCZ1 | go macro does not create a thread |
| 10:09 | kl | SagiCZ1: what is it? I'm looking to compare that to an actual golang Goroutine |
| 10:09 | SagiCZ1 | it is just a block of code that gets executed via callback.. the callback mechanism is hidden.. but no new threads are spawned.. cant really compare it to golang |
| 10:10 | kl | SagiCZ1: so every go macro executes, on the main thread? |
| 10:11 | SagiCZ1 | yse |
| 10:11 | SagiCZ1 | yes |
| 10:11 | SagiCZ1 | u can have thread if you use thread blocks |
| 10:11 | SagiCZ1 | (thread ...) |
| 10:11 | SagiCZ1 | and then use >!! and <!! |
| 10:11 | dysfun | huh? aren't go blocks thread-local as opposed to specifically on the main thread? |
| 10:12 | kl | something doesn't sound right about this |
| 10:12 | SagiCZ1 | i might be wrong |
| 10:12 | SagiCZ1 | the doc say: Asynchronously executes the body, returning immediately to the calling thread. |
| 10:12 | SagiCZ1 | and: ...by 'parking' the calling thread rather than tying up an OS thread |
| 10:13 | SagiCZ1 | me too actually, dont take my word on it.. |
| 10:14 | SagiCZ1 | i thought that go blocks and >! <! dont use new threads |
| 10:16 | dysfun | okay, it uses a thread pool |
| 10:20 | kl | dysfun: so it basically uses a thread (with a maximum number of threads i.e. pool) |
| 10:20 | kl | This is what I thought |
| 10:26 | octe | i have a map where each key is a parent and the value is the child and i want to from one key create a list of the relations |
| 10:26 | octe | bad explanation i think |
| 10:26 | octe | but in a mutable/imperative way i'd do something like while ((current = map.get(current)) != null) { resultList.add(current) } |
| 10:27 | SagiCZ1 | that would always leave you with one element in the list |
| 10:29 | octe | not really? |
| 10:29 | SagiCZ1 | current is still the same thing? |
| 10:29 | octe | it would change for each iteration |
| 10:29 | SagiCZ1 | yeah i dont see that in the example |
| 10:29 | octe | = map.get(current) |
| 10:30 | octe | http://pastebin.com/N5FCKS0C clojure implementation |
| 10:30 | octe | showing what i mean |
| 10:32 | octe | but obviously not implemented in a very good way.. |
| 10:32 | octe | but it works |
| 10:32 | SagiCZ1 | yeah |
| 10:32 | SagiCZ1 | you can use nil? btw |
| 10:32 | SagiCZ1 | instead of not (= nil .. ) |
| 10:32 | octe | true |
| 10:33 | SagiCZ1 | i think you could build this list using reduce |
| 10:34 | SagiCZ1 | so you have a map like this {:parent "child" :child "grandchild" ..} ? |
| 10:34 | octe | yes |
| 10:34 | octe | ending where the key maps to nil |
| 10:35 | SagiCZ1 | and you want a path from root to the last children? |
| 10:35 | octe | from one of the keys to the root, i guess |
| 10:35 | SagiCZ1 | i see |
| 10:35 | octe | '(:parent :child :grandchild) |
| 10:36 | SagiCZ1 | the maps in clojure are not really meant to used this way i think.. but you can have a look at tree-seq and clojure.walk which should solve this issue |
| 10:37 | kl | are there any must-reads after Joy of Clojure? |
| 10:37 | octe | what would be a better way to represent it? |
| 10:38 | SagiCZ1 | clojure.zip is for working with nodes, children, branches etc |
| 10:38 | SagiCZ1 | http://clojure.github.io/clojure/clojure.zip-api.html |
| 10:52 | octe | SagiCZ1, http://pastebin.com/fVJ6RvCS that seems to work with reduce |
| 10:53 | octe | if you were curious :) |
| 10:54 | nuwanda_ | https://www.youtube.com/watch?v=YgvJqWiyMRY Brandon Bloom talking about representing data in trees with clojure |
| 11:00 | justin_smith | octe: sounds like you may want the adjacency list representation for graphs |
| 11:00 | justin_smith | http://en.wikipedia.org/wiki/Adjacency_list |
| 11:01 | justin_smith | the nice thing about an adjacency list, is it can represent a fully general graph (including potentially cycles) without using a mutable or cyclic datastructure |
| 11:02 | bbloom | kl: a goroutine is a proper green thread with it's own stack |
| 11:03 | bbloom | kl: go blocks in core.async have their own per-block state, but it's a finite state machine, not a full stack |
| 11:03 | justin_smith | SagiCZ1: and they use their own pool of threads on the jvm version |
| 11:03 | bbloom | dysfun: go block code may run on the original thread depending on readiness of channels and other implementation details |
| 11:03 | bbloom | there is a thread pool pre-allocated for go blocks |
| 11:03 | bbloom | which is similar to how golang multiplexes go routines on to threads |
| 11:04 | bbloom | on cljs, there are no threads |
| 11:04 | bbloom | so go blocks execute via setTimeout (or similar) when there is idle time |
| 11:04 | bbloom | on the jvm, there is a thread pool for go block execution |
| 11:04 | bbloom | but where the go block code runs is never a promise |
| 11:04 | bbloom | i should say "is undefined" |
| 11:04 | bbloom | yeah, but like i said: sometimes go block code can run on the original thread |
| 11:05 | bbloom | go block bodies should never block the thread w/o using channel operations |
| 11:07 | octe | justin_smith, that sounds fitting |
| 11:08 | justin_smith | bbloom: I think you were (are?) lagging again |
| 11:08 | justin_smith | maybe not |
| 11:09 | bbloom | justin_smith: argh. thanks |
| 11:09 | bbloom | i have no way of debugging it |
| 11:10 | justin_smith | erc had a "lag" section of its status bar |
| 11:10 | justin_smith | I don't know if other clients have this... |
| 11:10 | bbloom | i have a /lagcheck command |
| 11:10 | bbloom | but i have to execute it manually |
| 11:10 | justin_smith | yeah, seems like it would be a nice thing to have periodically run and displayed in a status bar automatically |
| 11:12 | octe | i think i've created an implementation of dijkstras algorithm |
| 11:12 | octe | http://pastebin.com/QcQU3n30 how does it look? |
| 11:14 | octe | it still kind of slow for longer paths |
| 11:14 | justin_smith | octe: there are also graph libs, that implement various path finding algorithms (and books full of various graph algorithms you could implement...) |
| 11:15 | octe | yup, i wanted to try myself though :) |
| 11:15 | justin_smith | http://www.textbooks.com/BooksDescription.php?BKN=951029&SBC=ME8&kpid=9780262033848N&kpid=9780262033848N&kenshu=02dbe049-1491-fa29-ea40-0000115ff57c&mcid=XKS-7565-39-186-GoogleShopping-PRIDREPLACE-291&gclid=CK_tzqyN5MICFVSSfgodjXgA7g lots of great graph algorithms in this book |
| 11:16 | justin_smith | it's a commonly used textbook, so not super hard to find used |
| 11:18 | fm75 | justin_smith: studied on it long time ago, and re-bought it recently for my library :) |
| 11:19 | justin_smith | fm75: it's a good book, I have learned a lot from it |
| 11:20 | fm75 | justin_smith: I didn't like too much the fact that arrays are 1-based in the pseudocode - sometimes it was painful |
| 11:21 | justin_smith | yeah, it's not perfect |
| 11:34 | Hamled | Is it non-idiomatic or otherwise a bad idea to do something like (let [sentinel (gensym) foo (get coll key sentinel)] (if (= foo sentinel) ...)) |
| 11:34 | justin_smith | Hamled: (contains? coll key) |
| 11:34 | Hamled | does that work for indexed sequences like vectors |
| 11:34 | justin_smith | same way get does |
| 11:35 | Hamled | okay thanks |
| 11:35 | justin_smith | by checking if the index is there |
| 11:35 | justin_smith | &(contains? [:a :b :c] 1) |
| 11:35 | lazybot | ⇒ true |
| 11:36 | dnolen_ | Hamled: it's more common to use a namespaced keyword or (Object.) |
| 11:36 | bbloom | Hamled: it's not super idiomatic, but it's not a bad idea either. in addition to contains?, which justin_smith mentioned, there's also ##(doc find) |
| 11:36 | lazybot | ⇒ "([map key]); Returns the map entry for key, or nil if key not present." |
| 11:36 | justin_smith | oh yeah, I keep forgetting about find |
| 11:37 | Hamled | ah yeah I had been thinking about find and I think my experience with other languages made me figure it wouldn't work with vectors |
| 11:37 | Hamled | thanks :) |
| 11:37 | justin_smith | &(find [:a :b :c] 1) |
| 11:37 | lazybot | ⇒ [1 :b] |
| 11:37 | justin_smith | I would not have guessed |
| 11:37 | justin_smith | but that is nifty |
| 11:38 | luxbock | had no idea about `find` but I could've used it many times before, nice |
| 11:39 | luxbock | I should try to find a way to use it with what I'm working now so I don't forget about it |
| 11:40 | justin_smith | also, find should be on the clojure cheatsheet |
| 11:40 | justin_smith | ahh, it's in grimoire, of course |
| 11:40 | Hamled | oh I'll have to bookmark that |
| 11:43 | SagiCZ1 | thanks to all who reacted to something i wrote, i was out for a second. |
| 11:43 | SagiCZ1 | on the topic of trees.. i am trying to write an algorithm that divides data into a non-balanced binary tree and i need to be able to easily traverse the leaves of this tree.. what would be the best data representation? i am not sure if a simple map can cut it |
| 11:44 | SagiCZ1 | watching Brandon's video atm |
| 11:45 | justin_smith | SagiCZ1: for a simple non-balanced tree I would use (deftype tree [left right]) and a protocol for inserting / removing |
| 11:45 | justin_smith | err [value left right] of course |
| 11:45 | SagiCZ1 | that would be a first time when i would really need to implement a protocol in clojure.. maybe its about time i learn about that |
| 11:46 | justin_smith | SagiCZ1: I think IAssociative would be the right one to implement (maybe?) |
| 11:47 | luxbock | SagiCZ1: I'm working on a project that uses zippers to represent game trees, and when I started out I was just learning about protocols, so I made all my nodes records and then created some protocols to use them with, but now I just finished re-writing all of that to just use regular maps |
| 11:47 | octe | e |
| 11:47 | octe | heh |
| 11:47 | SagiCZ1 | luxbock: cool.. so how does that work? |
| 11:48 | octe | turns out most of the time was being spent on getting the children in my function, which was actually a database query |
| 11:48 | justin_smith | woah, zippers? |
| 11:48 | justin_smith | octe: heh, that would do it |
| 11:49 | luxbock | SagiCZ1: I have three different kinds of nodes, so I had a TreeNode protocol with branch?, children and make-node defined |
| 11:49 | luxbock | but I switched to just using :type key inside a map instead |
| 11:49 | octe | yup, a path with 17 nodes went from 1s to 130ms when i memoized the db-query function |
| 11:49 | octe | :P |
| 11:50 | SagiCZ1 | luxbock: so how does the protocol work now? it gets dispatched acording to the :type? |
| 11:50 | luxbock | now branch?, children and make-node are just functions, and yeah they do stuff based on the :type key |
| 11:51 | SagiCZ1 | luxbock: i really like how you simplified the problem.. i dont think you needed a protocol there necessarily... in my problem the creation of tree is just a necessary structure for the algo to work so i am reluctant to build a library around it |
| 11:52 | luxbock | SagiCZ1: yeah, I just used them because I was learning about them at the time, and in a way I'm glad I did because now I understand them better |
| 11:52 | luxbock | but I think this simpler approach is better in the end. It wasn't use the nodes that I rewrote. I had over-engineered a bunch of other stuff as well while learning about new things :) |
| 11:54 | SagiCZ1 | luxbock: its really hard at first when you dont know what is available... to correctly design |
| 11:54 | luxbock | yeah indeed |
| 11:58 | luxbock | I'm just now racking my brain trying to figure out a function to translate the existing tree structures I have to expand them by inserting new branches in the middle of the tree |
| 11:58 | luxbock | zippers are fun |
| 11:58 | justin_smith | I've never found a good use for them. Maybe my brain is wired wrong for zipper usage. |
| 11:58 | SagiCZ1 | i always feel like just thinking and almost never typing in clojure.. then i look at my work from the past 10 hours and its just couple lines of code.. i feel stupid |
| 12:00 | luxbock | I like to sketch by planning top-down |
| 12:01 | OscarZ- | theres "bean" function to turn java beans to maps, but is there something to do it the other way ? given a map and java class, it would return instance of the class filled with properties from the map ? |
| 12:02 | OscarZ- | oh.. just found this: https://github.com/clojure/java.data |
| 12:03 | OscarZ- | it was in the comments for "bean", didnt notice it first |
| 12:16 | OscarZ- | is it possible to require a namespace and with same command switch to that namespace? |
| 12:21 | ddima | you don't need to require, as by switching to a new ns all symbols will be resolved to that ns |
| 12:21 | SagiCZ1 | ddima: and will the file get loaded |
| 12:23 | OscarZ- | im working in a repl and id like to load my namespace which itself does stuff like (:require [clojure.java.data :refer all]) |
| 12:24 | ddima | SagiCZ1: that I'm not sure of, something which I'd need to try out |
| 12:24 | OscarZ- | i'd just want to be able to refer to functions from clojure.java.data in my repl without qualifying them |
| 12:27 | OscarZ- | hmm.. it works when i require my namespace (myrepl) and then do (ns myrepl) |
| 12:30 | ddima | yeah, it doesnt load it, just checked. I dont think there is something like this per default, just wrap it yourself a la (do (require foo) (in-ns foo)) |
| 12:30 | ddima | (you can use in-ns if you dont need any of the ns-macro magic) |
| 12:30 | OscarZ- | ok, its not too much work :) |
| 12:30 | SagiCZ1 | in my editor i always do load and then switch manually |
| 12:30 | ddima | you could of course override in-ns or something ;) |
| 12:31 | justin_smith | (doto 'foo require in-ns) |
| 12:31 | OscarZ- | i still dont fully understand how the namespaces work.. in my repl, im first at namespace user, in my file myrepl.clj im defining (ns myrepl)) and some functions |
| 12:31 | ddima | or the more concise version from justin ;) |
| 12:32 | OscarZ- | in one of the function in myrepl namespace i put (println *ns*), im surprised that it prints out "user" when i call it from user namespace |
| 12:32 | justin_smith | OscarZ-: *ns* is the namespace you are calling from, not the one where the thing was defined |
| 12:32 | OscarZ- | how come it finds the stuff from myrepl as im referring to them in my function? |
| 12:33 | justin_smith | that's compile time |
| 12:33 | OscarZ- | ok |
| 12:33 | justin_smith | at compile time, it is in that ns, and it sees all the mappings defined in that ns |
| 12:33 | justin_smith | at runtime, in the repl, when you call the compiled code, *ns* will refer to the namespace you are in when you call the function |
| 12:34 | OscarZ- | i see, ok |
| 12:34 | justin_smith | on the other hand, you can use *ns* in a macro, and cause it to be captured at compile time |
| 12:34 | justin_smith | if you really need such a thing |
| 12:36 | tomjack | is there a story you can tell where *ns* is just a normal dynamic var, which correctly explains the semantics of *ns* if not the facts? |
| 12:37 | gfredericks | um |
| 12:37 | justin_smith | tomjack: that's the story. It's a dynamic var. It's looked up at runtime, like any other uncaptured var. |
| 12:37 | gfredericks | well the story should probably talk about compile-time and runtime though |
| 12:37 | ddima | cool story :D |
| 12:37 | gfredericks | in chapter 2 |
| 12:38 | tomjack | my vague memory is that both clj and cljs compilers have magic inside for *ns* |
| 12:38 | gfredericks | not to mention repls |
| 12:38 | gfredericks | well who else is going to set it? |
| 12:38 | justin_smith | tomjack: magic, beyond the fact that it is a dynamic var that is used by def/defn to decide where something gets interned? |
| 12:39 | tomjack | I don't remember what the magic was at all -- but if the magic doesn't change the story at all, then great :) |
| 12:39 | gfredericks | tomjack: I think the normal confusion point is that (let [n *ns] (defn f [] n)) does something different from (defn f [] *ns*) |
| 12:40 | gfredericks | even further confused by the fact that I think those are the same (at a glance) at any normal repl |
| 12:40 | justin_smith | gfredericks: which is why I was careful to say "like any other uncaptured var" :) |
| 12:41 | OscarZ- | if i have a namespace and define functions "foo" and "bar" with defn, and bar is calling foo, how is the foo reference realized in function bar? is foo compiled as the var that name "foo" pointed at compile-time ? |
| 12:41 | gfredericks | justin_smith: more confusing in this case though because most uses of *ns* are at compile-time |
| 12:42 | gfredericks | true of other compiler vars I guess, but *ns* is more tempting to use for other dynamic purposes |
| 12:42 | justin_smith | OscarZ-: yeah, everything is fully resolved at compile time |
| 12:43 | OscarZ- | ok.. and if i put (def foo something-else) in the end, it doesnt have any effect anymore on function bar as it was already compiled? |
| 12:43 | justin_smith | OscarZ-: that's where capture comes in - are you resolving the var, or have you stored the value it pointed to at a prior time |
| 12:44 | tomjack | I guess the only magic in clojure is resolving '*ns* to the var set up in RT |
| 12:44 | justin_smith | by default, vars are looked up on each call |
| 12:44 | tomjack | and I see no trace of magic in cljs |
| 12:44 | justin_smith | but you can circumvent that with let capture |
| 12:45 | justin_smith | OscarZ-: this is an optimization trick actually - you can improve performance in a tight loop by capturing vars, so they don't get looked up repeatedly |
| 12:46 | OscarZ- | what you mean by "capture" exactly ? |
| 12:46 | justin_smith | OscarZ-: resolve it once, and store that value |
| 12:46 | justin_smith | like in gfredericks example above |
| 12:47 | justin_smith | (let [ns *ns*] (defn f [] ns)) |
| 12:47 | justin_smith | that captures *ns* value at compile time |
| 12:48 | OscarZ- | ok |
| 12:48 | OscarZ- | so *ns* is a bit like function call |
| 12:48 | justin_smith | OscarZ-: usage of any var is a bit like a function call |
| 12:48 | justin_smith | *ns* is not special in its behavior (it just gets used in special ways) |
| 12:49 | Bronsa | 18:47:25 <justin_smith> that captures *ns* value at compile time |
| 12:49 | OscarZ- | but if i have (defn foo [] (println ("ho ho ho!)) (defn bar [] foo) |
| 12:49 | Bronsa | at the risk of being overly pedantic, that's not true :P |
| 12:49 | justin_smith | Bronsa: oh, please explain |
| 12:49 | Bronsa | justin_smith: I mean, it's true if you meant "compile time" as in "while loading the namespace" |
| 12:49 | gfredericks | it compiles to code that looks it up in init? |
| 12:49 | OscarZ- | is that foo function forever locked to be the one that is called from bar ? even if i do (def foo [] (print "ha ha ha")) afterwards |
| 12:50 | justin_smith | OscarZ-: it's easy enough to test |
| 12:50 | OscarZ- | true :) |
| 12:51 | justin_smith | OscarZ-: https://www.refheap.com/95426 |
| 12:52 | justin_smith | (I changed it slightly - in a way that makes it more clear I hope) |
| 12:52 | justin_smith | Bronsa: OK, yeah, I keep using that "compile time" term a little too loosely I think, thanks |
| 12:53 | OscarZ- | justin_smith, damn it did change :D i thought it wouldnt |
| 12:53 | justin_smith | OscarZ-: vars are mutable |
| 12:53 | justin_smith | and var lookup is not finalized at compilation |
| 12:53 | justin_smith | OscarZ-: thus what I said about capturing vars for performance reasons, etc. etc. |
| 12:54 | OscarZ- | oh.. i see.. |
| 12:54 | justin_smith | OscarZ-: this is useful, because it means we can redefine our code in the repl or by reloading our namespaces and things stay consistent / updated |
| 12:54 | OscarZ- | so what gets compiled in, is just the name "foo".. |
| 12:55 | gfredericks | are there any examples of leiningen projects that are setup to run tests on different versions of java? |
| 12:56 | justin_smith | OscarZ-: well, not just the name "foo" but the fully resolved symbol iirc. or is it the var? Bronsa would know. |
| 12:56 | gfredericks | this feels awkward to me because I know how to set up the java-cmd in a leiningen profile, but the value thereof seems machine-sensitive, so putting in in the project seems bad |
| 12:57 | Bronsa | OscarZ-: justin_smith it resolves the var at compile time & stores that. at runtime it just derefs it |
| 12:57 | justin_smith | Bronsa: aha, so if someone cleared the var and recreated a var with the same name something might break? |
| 12:58 | justin_smith | ie. ns-unmap |
| 12:58 | OscarZ- | ah right.. the var stays but it can be mutated to point at some new function |
| 12:58 | gfredericks | justin_smith: probably depends on what they were assuming that would do |
| 12:58 | OscarZ- | you guys explained about vars earlier |
| 12:59 | mbac | yay holiday break |
| 12:59 | Bronsa | justin_smith: yep |
| 12:59 | Bronsa | justin_smith: http://sprunge.us/ATBb?clj |
| 13:00 | mbac | time to start and make impressive progress on personal coding projects then starve them from lack of love when the holidays are over and i'm back to working fulltime |
| 13:00 | mbac | the cycle never really ends : / |
| 13:00 | justin_smith | just tried it, updated my refheap... interesting https://www.refheap.com/95426 |
| 13:01 | justin_smith | Bronsa: so here, it is still referring to the old, now unmapped, var |
| 13:01 | OscarZ- | justin_smith, does that mean that the actual var gets baked in? |
| 13:02 | justin_smith | OscarZ-: yeah, I think so. It resolves the var, but derefs the value on each call (since it could have changed) |
| 13:02 | OscarZ- | so there is no lookup ? |
| 13:02 | Bronsa | justin_smith: right, (def x y) when x is already defined just replaces the var root. if it's not mapped, you get a new var |
| 13:02 | OscarZ- | right ok :) |
| 13:02 | justin_smith | OscarZ-: no lookup, just deref |
| 13:02 | OscarZ- | i think i finally get it |
| 13:03 | OscarZ- | i also tried to redefine foo in user namespace, then call myrepl/bar, it doesnt change even though *ns* is user during the bar call |
| 13:03 | OscarZ- | as bar is referring to the var myrepl/foo |
| 13:03 | justin_smith | OscarZ-: right, because it already looked up the var |
| 13:04 | OscarZ- | yes, ok.. |
| 13:09 | OscarZ- | what are the reasons for having keywords like :a :b, in some places you can use strings and keywords interchangeably, but i guess there are good reasons to have keywords as their own things? |
| 13:09 | SagiCZ1 | keywords are faster |
| 13:09 | justin_smith | keywords do O(1) comparison, yeah |
| 13:10 | justin_smith | and they act as the "get" function when applied to a map or set |
| 13:10 | OscarZ- | are they turned into integers or something under the hood? |
| 13:10 | justin_smith | they are interned, so when you compare them you are effectively comparing two integers |
| 13:10 | OscarZ- | ok |
| 13:11 | justin_smith | all that said, people are often over-enthusiastic about replacing strings with keywords |
| 13:12 | justin_smith | if you take a json map from some API, transform it, then return json again, it's silly to turn the keys into keywords, that can only make things more complex |
| 13:13 | OscarZ- | what kind of trouble can you get into? |
| 13:13 | justin_smith | not trouble |
| 13:13 | justin_smith | it's just silly |
| 13:13 | OscarZ- | :) |
| 13:13 | bbloom | no, you can get in to lots of trouble |
| 13:13 | justin_smith | oh? |
| 13:13 | bbloom | for example, invalid keywords constructed at runtime |
| 13:14 | bbloom | eg keywords shouldn't start with digits, or contain spaces |
| 13:14 | bbloom | or contain a slash |
| 13:14 | justin_smith | aha, so if you tried to serialize to edn, you'd get a broken mess |
| 13:14 | bbloom | automatic keywordization is just a bad idea |
| 13:15 | bbloom | seriously, everybody stop doing it |
| 13:15 | tolstoy | What if you control both sides of the message? |
| 13:15 | bbloom | tolstoy: the day will come when you only have yourself to blame |
| 13:15 | justin_smith | tolstoy: then what do you gain by keywordizing? |
| 13:15 | tolstoy | Heh. |
| 13:15 | tolstoy | If only! |
| 13:16 | bbloom | for example, you want a map with URLs as keys |
| 13:16 | tolstoy | Makes the code more readable. |
| 13:16 | bbloom | {"http://omg.com" "127.0.0.1"} |
| 13:16 | bbloom | whoops: ##(keyword "http://omg.com") |
| 13:16 | lazybot | ⇒ :http://omg.com |
| 13:16 | bbloom | that's no good. |
| 13:17 | Bronsa | ,:http://omg.com |
| 13:17 | clojurebot | #<AccessControlException java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "accessDeclaredMembers")> |
| 13:17 | tolstoy | That's why I mentioned controlling both sides, like from a one-page app to an underlying host service. |
| 13:17 | Bronsa | &:http://omg.com |
| 13:17 | lazybot | ⇒ :http://omg.com |
| 13:17 | Bronsa | :P |
| 13:17 | bbloom | now you need to go retrofit all your old code that assumed global keywordization to be parameterized by a schema, so that you can prevent keywordization in one special case |
| 13:17 | bbloom | ,(name :http://omg.com) ; Bronsa |
| 13:17 | clojurebot | #<AccessControlException java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "accessDeclaredMembers")> |
| 13:17 | OscarZ- | I ran into EDN data format somewhere... what are the biggest benefits for using that instead of JSON ? |
| 13:17 | bbloom | &(name :http://omg.com) ; Bronsa |
| 13:17 | lazybot | ⇒ "/omg.com" |
| 13:17 | Bronsa | bbloom: I know I know, I was just joking :) |
| 13:17 | bbloom | Bronsa: ok but for other ppl who don't know you know every single edge case ;-) |
| 13:18 | tolstoy | That said, I did have a nice hour wondering what the hell was going on before I discovered that ClojureScript allows keywords starting with numbers, and Clojure doesn't. |
| 13:18 | Bronsa | also hiredman should stop christmas partying and fix clojurebot |
| 13:19 | Bronsa | tolstoy: sadly, it actually does ##:9000 |
| 13:19 | Bronsa | lazybot: ? |
| 13:19 | Bronsa | &:9000 |
| 13:19 | lazybot | ⇒ :9000 |
| 13:20 | justin_smith | Bronsa: with ##(do :9000) notation, you need parens |
| 13:20 | lazybot | ⇒ :9000 |
| 13:20 | [blake| | Why is that sad? |
| 13:20 | Bronsa | [blake|: because it's allowed but the docs forbid it, and support is also inconsistent |
| 13:20 | Bronsa | &:a/9 |
| 13:20 | lazybot | java.lang.RuntimeException: Invalid token: :a/9 |
| 13:20 | Bronsa | &::9 |
| 13:20 | lazybot | ⇒ :clojure.core/9 |
| 13:21 | Manaphy91 | Anyone can explain me why I obtain an empty string with this http://pastebin.com/Jueh8Fcr code? |
| 13:21 | justin_smith | Manaphy91: for is lazy |
| 13:21 | justin_smith | put a (dorun) around it |
| 13:21 | tolstoy | I was using UUIDs as keys, which is where bbloom's prediction came true. |
| 13:22 | bbloom | tolstoy: that's another good one |
| 13:22 | Bronsa | what's wrong with using uuids as keys? |
| 13:22 | justin_smith | Bronsa: auto-keywordizing UUID |
| 13:22 | [blake| | Bronsa: I was gonna say it's not an issue in Smalltalk, but then I checked and it's also inconsistent. =P |
| 13:22 | Bronsa | ah ok |
| 13:23 | justin_smith | which would lead to issues, I bet |
| 13:23 | tolstoy | I was using the string (not the #uuid thing). Some lead with zeros. |
| 13:24 | tolstoy | It would have been okay if that had broken everywhere (clj vs cljs) but it didn't, so, lots of argh. ;) |
| 13:25 | Manaphy91 | @justin_smith with `dorun` is the same thing... |
| 13:25 | bbloom | clojurebot: keywordization |is| just say no |
| 13:25 | justin_smith | &(with-out-str (dorun (for [e [1 2 3]] (println e))) |
| 13:25 | lazybot | java.lang.RuntimeException: EOF while reading, starting at line 1 |
| 13:25 | clojurebot | Ack. Ack. |
| 13:25 | justin_smith | &(with-out-str (dorun (for [e [1 2 3]] (println e)))) |
| 13:25 | lazybot | java.lang.SecurityException: You tripped the alarm! push-thread-bindings is bad! |
| 13:25 | justin_smith | Manaphy91: it shouldn't be |
| 13:25 | justin_smith | (dorun (for ...)) |
| 13:25 | justin_smith | the problem is that for does nothing if you don't force the value |
| 13:25 | justin_smith | even better, replace (for ...) with (doseq ...) |
| 13:26 | Manaphy91 | @justin_smith perfect!! Thaks a lot!! |
| 13:27 | zilti | I'm working with a transient map, and it seems I can only conj! 8 MapEntry instances to it, afterwards it ignores them. How can I work around that? |
| 13:28 | justin_smith | zilti: you need to use the return value of conj! |
| 13:28 | justin_smith | it is not guaranteed to mutate the argument, it is merely *allowed* to |
| 13:28 | justin_smith | and with more than 8 mapentries, it replaces rather than mutating |
| 13:28 | zilti | hmm |
| 13:29 | justin_smith | (doc conj!) |
| 13:29 | clojurebot | #<AccessControlException java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "accessDeclaredMembers")> |
| 13:29 | justin_smith | &(doc conj!) |
| 13:29 | lazybot | ⇒ "([] [coll] [coll x]); Adds x to the transient collection, and return coll. The 'addition' may happen at different 'places' depending on the concrete type." |
| 13:29 | zilti | This is going to be somewhat of a headache inside a transducer... I found this out because I'm calling "step" multiple times |
| 13:29 | justin_smith | zilti: restructure your code to use the result of conj!, the same way you would if you were using conj in a loop |
| 13:31 | zilti | justin_smith: Well, this fixed it :) Thanks! |
| 13:31 | justin_smith | np |
| 13:31 | Bronsa | there's obviously no guarantee that the replacing will happen every 8 args |
| 13:31 | justin_smith | right, that was just a "for example" of course |
| 13:31 | zilti | It's nonetheless a weird behaviour, and I don't understand why it gets exposed to the "users" |
| 13:31 | Bronsa | it's usually after 32 IIRC |
| 13:32 | Bronsa | 8 is just because of the arraymap -> hashmap promotion |
| 13:32 | justin_smith | zilti: it's the way conj! is meant to behave. The weird part is that ignoring the return value ever works. |
| 13:32 | Bronsa | zilti: transients are just a performance construct. it's well specified that you *have* to use the return value or bad things will happen |
| 13:32 | zilti | justin_smith: Yes, that's what I mean - that it actually works sometimes |
| 13:33 | justin_smith | Bronsa: I was surprised not to see a more explicit reference / warning in the doc string for conj! actually |
| 13:33 | zilti | Still, I currently have an atom to store the return value of conj! ... Meh. Really have to refactor this piece now |
| 13:34 | Bronsa | justin_smith: it would be better to have it in the docstring of `transient` i think. but yeah, agreed that having it only mentioned in clojure.org might cause confusion |
| 13:35 | justin_smith | maybe I'll make a doc string PR |
| 13:37 | Manaphy91 | &(time (with-out-str (dorun (for [[k v] mark] (println k "->" v))))) |
| 13:37 | lazybot | java.lang.SecurityException: You tripped the alarm! push-thread-bindings is bad! |
| 13:37 | justin_smith | Manaphy91: that would have failed because mark is unbound, anyway |
| 14:30 | profil | I am writing a small validation function for form params from ring. But I find my function very ugly, how could I improve it? make it more idiomatic? https://www.refheap.com/95427 |
| 14:31 | profil | I thought about using monads, but I dont want to pull in such a big dependency just for this small function |
| 14:54 | bzf | Any tips for reading 4 bytes from a FileInputStream as an integer? |
| 15:05 | justin_smith | bzf: you could read it into a byte-array, then make a ByteBuffer from that, and read an int from the ByteBuffer |
| 15:08 | bzf | justin_smith: Figured out I could just instatiate a DataInputStream from the FileInputStream :) |
| 15:09 | justin_smith | bzf: I am not as familiar with that (and am suspicious of the marshalling stuff), but that looks like it would work. |
| 15:12 | justin_smith | though DataInputStream is an interface |
| 15:13 | justin_smith | so that sounds a bit more complicated than a ByteBuffer / getInt |
| 15:14 | justin_smith | &*java-version* |
| 15:14 | lazybot | java.lang.RuntimeException: Unable to resolve symbol: *java-version* in this context |
| 15:15 | justin_smith | &(.getInt (java.nio.ByteBuffer/wrap (byte-array [1 2 3 4]))) |
| 15:15 | lazybot | ⇒ 16909060 |
| 15:15 | justin_smith | ^^ I think that's simpler than anything that would give you a DataInputStream would be |
| 15:15 | justin_smith | unless you have a class implementing it handy already |
| 15:17 | justin_smith | bzf: oh wait I was looking at the wrong "DataInputStream" - the one in java.io looks exactly right, yeah |
| 15:18 | justin_smith | bzf: but if you find yourself dealing with things like endianness, ByteBuffer makes that simple to fix |
| 15:19 | bzf | justin_smith: Alright, thanks :) |
| 15:23 | SagiCZ1 | is vector a sequence? |
| 15:23 | justin_smith | ,(sequential? []) |
| 15:23 | clojurebot | #<AccessControlException java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "accessDeclaredMembers")> |
| 15:23 | justin_smith | &(sequential? []) |
| 15:23 | lazybot | ⇒ true |
| 15:24 | SagiCZ1 | shouldnt this return more than one node? whats wrong with it.. |
| 15:24 | SagiCZ1 | &(count (tree-seq :x :x [{:x [{:x {:potato 6}} {:x {:o 3}}]}])) |
| 15:24 | lazybot | ⇒ 1 |
| 15:25 | justin_smith | &(:x []) |
| 15:25 | lazybot | ⇒ nil |
| 15:25 | justin_smith | that's why |
| 15:25 | justin_smith | maybe you want sequential? instead of one of those :x |
| 15:25 | justin_smith | &(doc tree-seq) |
| 15:25 | lazybot | ⇒ "([branch? children root]); Returns a lazy sequence of the nodes in a tree, via a depth-first walk. branch? must be a fn of one arg that returns true if passed a node that can have children (but may not). children must be a fn of one arg that returns a sequence of th... https://www.refheap.com/95432 |
| 15:26 | SagiCZ1 | i dont understand that example you gave |
| 15:26 | SagiCZ1 | where do i do that? |
| 15:26 | justin_smith | [] has no :x key |
| 15:26 | SagiCZ1 | there is no empty vector |
| 15:27 | justin_smith | [{:x ...}] has no :x key |
| 15:27 | justin_smith | the emptiness isn't importatn, the vectorness is |
| 15:27 | SagiCZ1 | &(count (tree-seq :x :x {:x [{:x {:potato 6}} {:x {:o 3}}]})) |
| 15:27 | lazybot | ⇒ 5 |
| 15:27 | SagiCZ1 | i think this is what i want |
| 15:27 | justin_smith | that does look more like what you would want, yes |
| 15:28 | SagiCZ1 | thanks :) |
| 15:28 | justin_smith | np |
| 15:33 | SagiCZ1 | so i have this tree.. i want to find a particular node and add children to it.. how can i do that? |
| 15:33 | SagiCZ1 | in imperative code i would have a function that returns a reference to the node, and mutate it, which would update it in the tree as well |
| 15:33 | SagiCZ1 | in simple map, i would use assoc |
| 15:33 | justin_smith | assoc-in |
| 15:33 | justin_smith | or update-in |
| 15:33 | SagiCZ1 | i would need to know the full path to the node though |
| 15:34 | justin_smith | ,(assoc-in {} [:a :b :c] 42) |
| 15:34 | clojurebot | #<AccessControlException java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "accessDeclaredMembers")> |
| 15:34 | justin_smith | &(assoc-in {} [:a :b :c] 42) |
| 15:34 | lazybot | ⇒ {:a {:b {:c 42}}} |
| 15:34 | justin_smith | indeed, you would need to know that |
| 15:34 | SagiCZ1 | hmm tree-seq doesnt give me the path.. |
| 15:34 | justin_smith | in order to mutate the node, you would also need to find that path, though you may not have stored it in a single place |
| 15:35 | justin_smith | yeah, tree-seq isn't so good for making a new tree |
| 15:35 | justin_smith | perhaps you want clojure.walk/postwalk |
| 15:35 | SagiCZ1 | i could add a uuid to each node and find it later by that.. thats seems like an overkill though |
| 15:35 | SagiCZ1 | or maybe tree of atoms? |
| 15:36 | justin_smith | if you want to walk a tree, and update certain branches, use clojure.walk/post-walk |
| 15:36 | SagiCZ1 | ok |
| 15:36 | SagiCZ1 | i will have a look at that |
| 15:42 | munderwo | Hey all. So I have this data structure https://www.refheap.com/95433 … and I want to collapse it so its one map with each value being the combined list of values. How would one go about doing that? is there a higher order function that does this? Im using a for loop to generate it, which might be the wrong way to go about it…. |
| 15:45 | justin_smith | munderwo: I hope you realize you have a bunch of illegal keywords in there |
| 15:45 | munderwo | oh? what makes a keyword illegal? |
| 15:46 | justin_smith | multiple / for example in this case |
| 15:47 | SagiCZ1 | or starting with a number |
| 15:47 | munderwo | I’d guessed that the multiple / might do it. but starting with a number? |
| 15:48 | justin_smith | munderwo: anyway (apply merge-with into ...) |
| 15:48 | justin_smith | that will merge all the maps, using into to combine the vectors |
| 15:49 | tomjack | neither of those uses look suited to keywords |
| 15:49 | justin_smith | though you may also want to do some merging inside those vectors? |
| 15:49 | justin_smith | no, actually not, the merge-with into suffices for that data at least |
| 15:49 | SagiCZ1 | i dont see how clojure.walk helps me.. it doesnt even let me specify how to walk the datastructure like tree-seq |
| 15:50 | justin_smith | SagiCZ1: it already knows how to walk all the clojure data structures |
| 15:50 | justin_smith | and you can conditionally output an altered child at each branch |
| 15:50 | munderwo | magic! thanks justin_smith ! |
| 15:50 | SagiCZ1 | i have a tree where each node is map with :name and :children .. it doesnt walk it right |
| 15:51 | justin_smith | what does "doesn't walk it right" mean? it should hit every single nested value in the tree, the trick is only acting on the apropriate branches (and returning the original otherwise) |
| 15:52 | justin_smith | &(require '[clojure.walk :as walk]) |
| 15:52 | lazybot | ⇒ nil |
| 15:52 | Raynes | Everybody ends up with a tree where each node is a map of :name and :children. |
| 15:52 | Raynes | Eventually. |
| 15:52 | SagiCZ1 | &(walk/walk #(println %) identity {:x [{:x [1 2]} 3]}) |
| 15:52 | lazybot | ⇒ [:x [{:x [1 2]} 3]] {} |
| 15:52 | dysfun | is there a reasonable library for generating DDL? |
| 15:52 | Raynes | I use our DBA for that |
| 15:53 | dysfun | ah, well my dba is too lazy |
| 15:53 | SagiCZ1 | i feel like my problem really cant be solved in a functional language.. so weird |
| 15:53 | dysfun | i only need postgres support, but since this is open source i'd like to support other engines too |
| 15:53 | justin_smith | &(walk/post-walk (fn [x] (if (contains? x :children) (assoc % :naughty true) x)) {:children {:a 0} :naughty false}) |
| 15:53 | lazybot | java.lang.RuntimeException: No such var: walk/post-walk |
| 15:54 | justin_smith | &(walk/postwalk (fn [x] (if (contains? x :children) (assoc % :naughty true) x)) {:children {:a 0} :naughty false}) |
| 15:54 | lazybot | java.lang.RuntimeException: Unable to resolve symbol: % in this context |
| 15:55 | justin_smith | &(walk/postwalk (fn [x] (if (and (map? x) (contains? x :children)) (assoc x :naughty true) x)) {:children {:a 0 :b {:children nil}} :naughty false}) |
| 15:55 | lazybot | ⇒ {:children {:b {:naughty true, :children nil}, :a 0}, :naughty true} |
| 15:56 | justin_smith | ^^ SagiCZ1 that's how to do it |
| 15:56 | SagiCZ1 | let me process that with my slow brain |
| 15:56 | justin_smith | SagiCZ1: you could run it in your own repl, adding a (println x) if that helps |
| 15:57 | justin_smith | x will end up being every possible branch of the nested data structure, and your function decides what is returned in its place |
| 15:57 | SagiCZ1 | i see that you are associng based on whether its a map and has children.. but what if i want to access only on a node that has some minimal value out of all the leave nodes.. i would have to walk with some state there |
| 15:58 | SagiCZ1 | *assoc , leaf |
| 15:59 | justin_smith | in that case you could use tree-seq to find the minimal values, and post-walk to act on said minimal values in context |
| 15:59 | SagiCZ1 | so how would i find the minimal value with the postwalk? |
| 15:59 | SagiCZ1 | treeseq tells me its 7 so i go look for 7? |
| 16:00 | justin_smith | you test whether it is a leaf, and if so whether it is in your set of minimal values, yes |
| 16:00 | justin_smith | you use the tree-seq to generate the set of minimal values |
| 16:00 | SagiCZ1 | okay |
| 16:01 | SagiCZ1 | and why the post walk goes twice into some nodes? like this: |
| 16:01 | SagiCZ1 | [:children nil] |
| 16:01 | SagiCZ1 | {:children nil} |
| 16:01 | justin_smith | the first is an entry |
| 16:01 | justin_smith | the second is the entire map |
| 16:02 | justin_smith | if you had {:a 0 :b 1} you would see [:a 0] [:b 1] {:a 0 :b 1} |
| 16:02 | SagiCZ1 | oh i see.. its because its post.... walk |
| 16:02 | SagiCZ1 | so first it travels deep.. and then it backs up |
| 16:02 | justin_smith | right, there is also prewalk |
| 16:02 | justin_smith | but in practice postwalk is often what you want |
| 16:02 | SagiCZ1 | we learned this at the university, but it confuses me now |
| 16:03 | justin_smith | also, your walk/walk example (which does both pre and post walk) replaces the whole data structure with nil |
| 16:03 | justin_smith | as a result of the println :) |
| 16:03 | SagiCZ1 | ok i dont think i need both post and pre |
| 16:04 | justin_smith | SagiCZ1: well, the point of walk is it takes two functions, the first is applied in pre, the second in post |
| 16:04 | justin_smith | so your datastructure is replaced by the return value of println |
| 16:04 | justin_smith | which is nil |
| 16:04 | SagiCZ1 | so it changes the tree as it walks through it? |
| 16:04 | justin_smith | and this happens before the rest of it can be processed |
| 16:05 | justin_smith | that's the point of these walk functions, yes :) |
| 16:05 | justin_smith | well, it makes a modified copy |
| 16:05 | justin_smith | that's what you wanted, right? |
| 16:05 | SagiCZ1 | yes |
| 16:05 | SagiCZ1 | it feels like killing a butterfly with a tank, but yes, this i can use |
| 16:05 | nuwanda_ | couldn't you use pre to compute the minimal values and post to act on them? |
| 16:05 | SagiCZ1 | seems very powerful |
| 16:05 | justin_smith | nuwanda_: that's an excellent point |
| 16:06 | SagiCZ1 | but i would have to accumulate the minimal value somewhere |
| 16:06 | justin_smith | nuwanda_: thought of course you would likely need a mutable accumulator to store it (tree-seq avoids the mutation aspect) |
| 16:06 | nuwanda_ | in the tree itself maybe, then remove them in post |
| 16:07 | justin_smith | nuwanda_: I think updating an atom would be simpler, but also I think finding your min keys via tree-seq is simplest |
| 16:07 | justin_smith | though it means two steps instead of one |
| 16:07 | SagiCZ1 | i dont know.. finding the min keys before feels dirty for some reason |
| 16:08 | SagiCZ1 | because then they become a node identifier |
| 16:08 | SagiCZ1 | which in imperative language would be just a simple pointer to the particular node |
| 16:08 | SagiCZ1 | what if there are too nodes with the same minimal value.. i need to split only one of them |
| 16:08 | SagiCZ1 | *two |
| 16:08 | justin_smith | you could use a mutable deftype and mutate pointers if you really want that kind of thing |
| 16:10 | SagiCZ1 | justin_smith: that wouldnt feel clojury |
| 16:11 | hellofunk | i should probably study the various tree APIs before i ask this, but is it possible for each child to get a sequence of all its parents back to root? |
| 16:13 | justin_smith | hellofunk: you would need some stateful accumulator closed over by the function arg (likely something shard by the two function args to walk/walk, the pre would append to it, the post would pop elements from the end) |
| 16:13 | justin_smith | *shared |
| 16:13 | hellofunk | i feel you |
| 16:14 | hellofunk | i guess it's not a common need |
| 16:23 | craigglennie | I have an existing list of values that I want to add to a channel one at a time - what’s the best way to do this? Recursion? Seems like it would be common enough for there to be a shortcut |
| 16:23 | craigglennie | or maybe with “map” ? |
| 16:27 | SagiCZ1 | i would use doseq |
| 16:27 | SagiCZ1 | (doseq [e list-of-e] (put-to-channel chan e)) |
| 16:29 | craigglennie | SagiCZ1: Cool, thanks. The docs for doseq says “Repeatedly executes body (presumably for side-effects)” - is putting a value in a channel considered a side effect? |
| 16:29 | SagiCZ1 | it is |
| 16:30 | SagiCZ1 | is it core.async channel? |
| 16:33 | craigglennie | SagiCZ1: yes, core.async |
| 16:34 | SagiCZ1 | yes i think that would be a side effect.. putting something without sideeffect into doseq makes no sense, since it doesnt collect any results |
| 16:34 | SagiCZ1 | &(doseq [e (range 10)] (+ e 2)]) |
| 16:34 | lazybot | java.lang.RuntimeException: Unmatched delimiter: ] |
| 16:35 | SagiCZ1 | &(doseq [e (range 10)] (+ e 2)) |
| 16:35 | lazybot | ⇒ nil |
| 16:35 | hellofunk | craigglennie: you could use map as you suggested but since you are not concerned with the results of the process, then no point constructing a sequence with map |
| 16:35 | SagiCZ1 | note that if you use map, it creates lazy sequence that does not get realized unless you take some elements or call (dorun .. ) |
| 16:35 | hellofunk | that is true |
| 16:36 | craigglennie | ok, doseq makes more than map then |
| 16:36 | SagiCZ1 | it fits better to your use |
| 16:36 | craigglennie | both because I don’t care about the result, and because map is lazy |
| 16:39 | SagiCZ1 | if i am not mistaken (dorun (map .... )) does the same as (doseq ... ) only with different syntax |
| 16:41 | hellofunk | of course that only applies if you are working with a single sequence. they become more different as soon as you add a second set of bindings to doseq or more than 2 args to map |
| 16:42 | justin_smith | doseq and (dorun (for ...)) on the other hand... |
| 16:51 | hex6 | No method in multimethod 'process-input' for dispatch value: null, Does it have to have some default dispatch? |
| 17:00 | justin_smith | hex6: where is process-input defined? |
| 17:01 | justin_smith | you can do (defmethod :process-input :default ...) |
| 17:01 | justin_smith | err make that (defmethod process-input :default ...) |
| 17:05 | hex6 | justin_smith: found my problem, I had failed to supply one of the arguments in the correct form, so it was as it said; it tried to dispatch null |
| 17:05 | hex6 | thanks though |
| 17:05 | justin_smith | oh, I had thought based on your question that you wanted dispatching on null to work |
| 17:06 | justin_smith | and adding :default would do that |
| 17:08 | hex6 | yeah, I should probably add that though |
| 17:09 | craigglennie | core.async channels are unordered? I can’t find any docs that say one way or the other |
| 17:11 | SagiCZ1 | craigglennie: do you mean the order in which they process input/output? |
| 17:11 | SagiCZ1 | i would think it should be FIFO |
| 17:11 | craigglennie | SagiCZ1: I would have thought FIFO too, but it doesn’t seem to be |
| 17:17 | SagiCZ1 | craigglennie: try some more tests.. if you have one consumer and one producer, the order should be kept |
| 17:17 | SagiCZ1 | (imho) |
| 17:21 | craigglennie | SagiCZ1: This is what I did in the REPL, it pretty reliably returns out-of-order: https://www.refheap.com/95436 |
| 17:21 | justin_smith | craigglennie: the default channel is effectively fifo, but has no buffer - which means that it will block if it is unread, but the order that waiting puts go onto it would be indeterminate |
| 17:21 | justin_smith | it only holds one value at a time |
| 17:21 | justin_smith | oh, and your (go) blocks run in indeterminate order |
| 17:22 | justin_smith | they all return immediately to the doseq |
| 17:22 | justin_smith | and the order that they run is unspecified |
| 17:24 | justin_smith | if you did (def c (chan 10)) and (go (doseq [i [1 2 3 4 5 6]] (>! c i))) you would get the results back in order |
| 17:24 | justin_smith | but as it is, you have two factors (no buffering, go blocks not running in order) that scramble order |
| 17:25 | tomjack | no need for buffering? |
| 17:26 | justin_smith | tomjack: the default chan is not buffered, it blocks until read, and can only hold one value at a time |
| 17:26 | tomjack | yes, but the producer won't proceed until each value goes in (and comes out) |
| 17:27 | justin_smith | tomjack: but the producers are launched in parallel in a loop, and the order that each of them gets its go isn't deterministic |
| 17:27 | tomjack | oh, yes, I mean in your example with doseq inside go |
| 17:27 | tomjack | it can just be (def c (chan)) |
| 17:28 | justin_smith | right, either of my changes would likely suffice on its own |
| 17:28 | justin_smith | (if ordering was desired) |
| 17:29 | tomjack | craigglennie: also, see onto-chan |
| 17:29 | craigglennie | tomjack: Oh, thanks, that looks useful |
| 17:29 | tomjack | and I guess into as well: (<!! (a/into [] (doto (chan) (a/onto-chan [1 2 3 4 5 6])))) |
| 17:35 | bzf | If I do (bit-clear 6516 64), just to see if I'm too tired to be continuing, the number can't be greater than 64? |
| 17:36 | SagiCZ1 | how would i take-while one more? |
| 17:36 | SagiCZ1 | (take-while odd? [3 3 3 9 7 8 4 6 3]) ---> (3 3 3 9 7 8) |
| 17:37 | bzf | SagiCZ1: Doesn't happen to me :) |
| 17:37 | hellofunk | SagiCZ1: well i suppose you could inc the count of the take-while and then take that from the original |
| 17:38 | justin_smith | bzf: ##(= (bit-clear Long/MAX_VALUE 65) Long/MAX_VALUE) |
| 17:38 | lazybot | ⇒ false |
| 17:38 | justin_smith | oh, wait... |
| 17:39 | hellofunk | &(take (inc (count (take-while odd? [3 3 3 9 7 8 4]))) [3 3 3 9 7 8 4]) |
| 17:39 | lazybot | ⇒ (3 3 3 9 7 8) |
| 17:39 | justin_smith | (= (bit-clear Long/MAX_VALUE 65) (bit-clear Long/MAX_VALUE 1)) |
| 17:39 | justin_smith | &(= (bit-clear Long/MAX_VALUE 65) (bit-clear Long/MAX_VALUE 1)) |
| 17:39 | lazybot | ⇒ true |
| 17:39 | justin_smith | bzf: ^^ it wraps after 64 |
| 17:40 | justin_smith | bzf: likely the jvm impl only looks at the lowest 6 bits of the arg |
| 17:41 | bzf | justin_smith: Oh, so it doesn't compare against the full integer? |
| 17:41 | justin_smith | no integers are involved there |
| 17:41 | justin_smith | it's two longs |
| 17:41 | bzf | %s/integer/number/ :) |
| 17:41 | justin_smith | but it only uses the lowest 6 bits of the second long (or so it seems) |
| 17:46 | bzf | Shouldn't (bit-and x (bit-not y)) be the same as (bit-clear x y)? |
| 17:49 | [blake| | Not directly Clojure related (except I'm doing it in a Clojure program) but I want to save part of a web page for reviewing either. Thought about HTML, but there's no formatting info. Thought about a JPG but that seems excessive. Any ideas? |
| 17:49 | [blake| | For reviewing later. Not either. |
| 17:52 | craigglennie | [blake|: What kind of review do you want to do? |
| 17:52 | craigglennie | [blake|: If you’re extracting content you should probably save the HTML, if you just want to visually inspect it then capturing a JPG seems like a good approach |
| 17:53 | [blake| | It's a single page form, users put in inputs on left, output show up on right. Just want to look at (and maybe print) the form. |
| 17:53 | [blake| | craigglennie: Yeah...It rankles but it might be the simplest and not too piggy. |
| 17:54 | craigglennie | [blake|: Since you’re using clojure, taxi has a get-screenshot function |
| 17:54 | SagiCZ1 | how could i rewrite this using clojure's looping constructs? https://www.refheap.com/95438 |
| 17:54 | Raynes | For the 5 people on the planet using laser, notice of deprecation: https://github.com/Raynes/laser#deprecated-laser |
| 17:56 | [blake| | craigglennie: Interesting. Thanks! |
| 17:56 | [blake| | (inc craigglennie) |
| 17:56 | lazybot | ⇒ 1 |
| 17:57 | [blake| | Not sure how this works with a client browser, tho'. |
| 17:58 | hellofunk | SagiCZ1: you are just generating a seq of :a's is that right? |
| 17:59 | SagiCZ1 | hellofunk: no dont simplify it that much |
| 17:59 | SagiCZ1 | lets say i am updating acc in some way |
| 17:59 | SagiCZ1 | not necesarily conj |
| 17:59 | hellofunk | well, in any case, reduce is probably your friend in most cases where an accumulator is produced from a sequence |
| 18:00 | SagiCZ1 | maybe reduce, but i need to stop after n iterations |
| 18:00 | hellofunk | i guess you'd need to provide a more meaningful example of what you want to achieve because yours is as simple as (repeat 5 :a) |
| 18:01 | hellofunk | with reduce, if you only want to deal with n iterations, then just take n from your initial coll |
| 18:02 | SagiCZ1 | this should work https://www.refheap.com/95439 |
| 18:04 | hellofunk | SagiCZ1: take a look at iterate |
| 18:04 | craigglennie | So I tried to add too much (I guess) stuff to my channel, and got an assertion error: “No more than 1024 pending puts are allowed on a single channel. Consider using a windowed buffer.” |
| 18:04 | hellofunk | &(doc iterate) |
| 18:04 | lazybot | ⇒ "([f x]); Returns a lazy sequence of x, (f x), (f (f x)) etc. f must be free of side-effects" |
| 18:04 | craigglennie | Is that referring to sliding-buffer? I don’t want to lose any of my items |
| 18:04 | craigglennie | Or should I just create a channel with a huge buffer? That feels like a bit of a hack |
| 18:05 | hellofunk | craigglennie: yes. you can use either depending on how important it is that all items on teh channel are eventually processed. |
| 18:05 | hellofunk | craigglennie: it's not a hack, that's how it works. up to you to decide what is more important. |
| 18:06 | craigglennie | hellofunk: How would you handle the case of an infinite / unknown number of items that need to be processed, and the requirement that none be dropped? |
| 18:07 | craigglennie | Can I have a buffered channel that, when empty, would call a function to get some more data? |
| 18:07 | hellofunk | craigglennie: well if your items continue to come in, you just need to make sure the buffer is large enough to hold as many as you think you will have before your taking logic does its deed. you can have 1 million items on the channel but have a buffer of 10K if your taking is fast enough to ensure you'll never get more than 10K piled up |
| 18:08 | craigglennie | hellofunk: Pity, I was hoping I wouldn’t have to think about that kind of thing |
| 18:08 | craigglennie | hellofunk: I’d like something like a generator in Python. It could keep track of the number of items in the channel and add more when it was empty or running low |
| 18:09 | craigglennie | It seems like lazy-seq maybe would do that? |
| 18:09 | hellofunk | craigglennie: a channel and a sequence are two very different things. |
| 18:11 | craigglennie | I guess I can just create a channel with a huge buffer. I do have some idea of how much could be in the channel |
| 18:12 | hellofunk | craigglennie: don't know your specifics but you could throttle your put!s or combined values into a single put! instead of many put!s if that applies to you. |
| 18:16 | craigglennie | hellofunk: Yes, that could work |
| 18:17 | craigglennie | I’m not sure core.async is the right framework for what I’m trying to do: I want to have a queue/channel of URLs, and a fixed number of consumers that process the URL (scraping using taxi, in this case) |
| 18:18 | SagiCZ1 | i dont see why you couldnt use core.async |
| 18:18 | craigglennie | In Python I’d use a queue and a number of threads or processors reading from the queue |
| 18:18 | craigglennie | SagiCZ1: Is it the best choice, or just a choice? |
| 18:19 | craigglennie | It seems like it should work... |
| 18:19 | SagiCZ1 | you could use something like pmap maybe.. or maually manage the futures.. but this should work and look nicer |
| 18:19 | craigglennie | s/processors/processes |
| 18:19 | justin_smith | craigglennie: there's no reason you can't use a queue and threads reading from the queue in Clojure, but people like core.async as an abstraction over queue usage |
| 18:20 | justin_smith | SagiCZ1: with a scraper, each scraped page is going to result in more links to follow, so pmap wouldn't suffice |
| 18:20 | craigglennie | justin_smith: Ok, that was my understanding, too. I’m familiar with threads and queues, but I’m trying to learn clojure, so I should probably use core.async |
| 18:21 | SagiCZ1 | justin_smith: i see.. scratch that then |
| 18:21 | SagiCZ1 | craigglennie: if you don't have any experience with clojure, maybe this is a little too hard to start with.. |
| 18:22 | SagiCZ1 | i am learning clojure for months, and core.async didnt see easy to me when i tried to use it couple days ago |
| 18:22 | justin_smith | craigglennie: core.async is just one way to use queues in Clojure, there is also clojure.lang.PersistentQueue and the various queues offered by java.util.concurrent |
| 18:22 | TEttinger | 4clojure to the rescue! |
| 18:22 | SagiCZ1 | TEttinger: are there any core.async exercises? |
| 18:22 | TEttinger | I don't think so, but if you're just starting out, it's probably a good place to start |
| 18:24 | SagiCZ1 | i second that |
| 18:25 | ben_vulpes | i'm having a bit of a wacky problem with cider/emacs. when i run my irclj-bot at a terminal repl, when it catches messages it prints them right to the console. what in cider would be trapping these messages? |
| 18:26 | justin_smith | ben_vulpes: *out* is a dynamic binding that is not always propagated to new threads |
| 18:26 | justin_smith | ben_vulpes: look for a buffer with a name like *nrepl server* |
| 18:27 | justin_smith | that will be the failover when the output to the cider buffer is not propagated |
| 18:27 | ben_vulpes | config.el shows special buffers hidden...fixing... |
| 18:29 | ben_vulpes | awesome, justin_smith. what do I want to bind *out* to, and what's the best way to get that wired in regularly? |
| 18:29 | justin_smith | ben_vulpes: create threads using future and it is handled automatically |
| 18:29 | justin_smith | or you can pass in *out* to the function the thread runs, and bind it dynamically there |
| 18:29 | justin_smith | (binding [*out* captured-out-value] ...) |
| 18:31 | justin_smith | OOPS I parted by mistake |
| 18:31 | Bronsa | justin_smith: we all laughed at you while you weren't looking |
| 18:31 | justin_smith | porkys is spamming |
| 18:32 | justin_smith | (I was trying to part from the pm channel and parted here instead, mid conversation) |
| 18:34 | ben_vulpes | justin_smith: i think that i'm still confused as to why the *out* binding would be passed correctly when using the irclj library from my terminal, but not getting passed correctly when invoked from cider. |
| 18:34 | justin_smith | ben_vulpes: it's not passed properly, so it gets the root binding, which is your terminal |
| 18:35 | Dynasty | does clojure allow variable shadowing? |
| 18:35 | justin_smith | in emacs, it's not passed properly, so it gets the root binding, which is that weird *nrepl server* buffer that most people don't even know exist |
| 18:35 | ben_vulpes | hm, so this https://github.com/Raynes/irclj/blob/master/src/irclj/core.clj#L143 thread call might be the culprit then? |
| 18:35 | justin_smith | ben_vulpes: basically, shitty design in cider |
| 18:35 | ben_vulpes | boo. |
| 18:36 | justin_smith | ben_vulpes: I bet if you replaced that thread call with a call to future, that would propagate *out* properly |
| 18:36 | justin_smith | or you could store a binding to the *out* stream in the cider repl, and use it explicitly when printing |
| 18:37 | justin_smith | Dynasty: vars cannot be shadowed, but bindings can (via function arguments, or let) |
| 18:37 | Dynasty | okay thanks |
| 18:37 | justin_smith | and vars can be defined to have thread-local bindings (leading to odd behavior like I am discussing with ben_vulpes here) |
| 18:37 | ben_vulpes | downright kooky. |
| 18:38 | ben_vulpes | justin_smith: now for the million dollar question - what is the right value for *out*? |
| 18:38 | ben_vulpes | on a fresh cider repl i get #<PrintWriter java.io.PrintWriter@47ee14d4> |
| 18:39 | justin_smith | ben_vulpes: the value it has when you are in the repl buffer, obviously |
| 18:39 | ben_vulpes | because that's what's not getting passed into the thread |
| 18:39 | justin_smith | so you need to capture it, and bind it somewhere that your thread can find it when printing |
| 18:39 | justin_smith | right |
| 18:40 | ben_vulpes | well that's bloody irksome. |
| 18:40 | justin_smith | if cider attached the process to the repl buffer, *out* would fall back to that buffer, and things would be much more sensible |
| 18:40 | justin_smith | but they attach the process to a weird hidden buffer that they don't expect anyone to ever look at, which is weird |
| 18:43 | ben_vulpes | man i am now strongly tempted to just watch the repl-server buffer instead of getting printing properly in my emacs buffer |
| 18:43 | ben_vulpes | :( |
| 19:12 | supersym | https://wiki.theory.org/YourLanguageSucks#Clojure_sucks_because |
| 19:12 | supersym | aw.. only 1 reason with clojure, lol |
| 19:12 | supersym | dumb one too "Lisp syntax provides no way of seeing what's a function etc. - No visual distinction" |
| 19:13 | justin_smith | man, I could come up with 20 good reasons clojure sucks, and that wouldn't even make the fucking list |
| 19:13 | justin_smith | and I am a huge fan of clojure |
| 19:14 | supersym | right ^^ |
| 19:15 | TEttinger | ,(str (map inc [1 2 3])) |
| 19:15 | clojurebot | #<AccessControlException java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "accessDeclaredMembers")> |
| 19:15 | TEttinger | lol |
| 19:16 | justin_smith | TEttinger: great example of something that sucks though ##(str (map inc [1 2 3])) |
| 19:16 | lazybot | ⇒ "clojure.lang.LazySeq@7c42" |
| 19:16 | TEttinger | that should not be an accesscontrolexception, hiredman! |
| 19:16 | TEttinger | I just fixed a bug related to that |
| 19:17 | TEttinger | ...while furthur codegolfing my cthulhutext generator |
| 19:17 | TEttinger | ,(let[a #(apply str(flatten %))r repeatedly p partition N rand-nth n #(a(N(concat(repeat %"")(mapcat p[1 2 3]%&))))v #(n 0"aioeu""iaai")w(fn[](let[b(n 6"!.""""...")s[(n 0"STKNYPKLG""GlThShNyFt""ZvrCth")(r(N[1 2])#(do[(v)(n 9(map str"'-"(r 2 v)))(n 0(concat"lpstnkgx"[(N["h""gl""gr""nd"])(v)])"rlthggghtsltrkkhshng")]))]][b(if(seq b)[" "s][(n 3",")" "(.(a s)toLowerCase)])]))](re-find #"[A-Z].+"(a[(r 500 w)"."]))) |
| 19:17 | clojurebot | #<AccessControlException java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "accessDeclaredMembers")> |
| 19:17 | TEttinger | &(let[a #(apply str(flatten %))r repeatedly p partition N rand-nth n #(a(N(concat(repeat %"")(mapcat p[1 2 3]%&))))v #(n 0"aioeu""iaai")w(fn[](let[b(n 6"!.""""...")s[(n 0"STKNYPKLG""GlThShNyFt""ZvrCth")(r(N[1 2])#(do[(v)(n 9(map str"'-"(r 2 v)))(n 0(concat"lpstnkgx"[(N["h""gl""gr""nd"])(v)])"rlthggghtsltrkkhshng")]))]][b(if(seq b)[" "s][(n 3",")" "(.(a s)toLowerCase)])]))](re-find #"[A-Z].+"(a[(r 500 w)"."]))) |
| 19:17 | lazybot | ⇒ "Shiap. Thainosh thiash nex fte-ugg... Glutialt, glothets, situg. Lugr nyuggang! Nyikith satsegg yaix zvraltol shets... Cthaikh, pol... Nokh tes paits sigith shughe'elt ke'iax! Saishats, thelt... Ketogl yaingaish... Yiaghig sorkiat nyorlu-ugl puk kiarlot shatsi-ugh! ... https://www.refheap.com/95445 |
| 19:17 | TEttinger | ah, error somewhere in there |
| 19:18 | justin_smith | ? looked OK to me |
| 19:19 | TEttinger | there's just a logic bug, it allowed gr as an ending consonant |
| 19:19 | justin_smith | "Sax!" - scariest otherworldly creature ever |
| 19:19 | TEttinger | &(let[a #(apply str(flatten %))r repeatedly p partition N rand-nth n #(a(N(concat(repeat %"")(mapcat p[1 2 3]%&))))v #(n 0"aioeu""iaai")w(fn[](let[b(n 7"!.""""...")s[(n 0"STKNYPKLG""GlThShNyFt""ZvrCth")(r(N[1 2])#(do[(v)(n 9(map str"'-"(r 2 v)))(n 0(concat"lpstnkgx"[[(N["h""gl""gr""nd"])(v)]])"rlthggghtsltrkkhshng")]))]][b(if(seq b)[" "s][(n 3",")" "(.(a s)toLowerCase)])]))](re-find #"[A-Z].+"(a[(r 500 w)"."]))) |
| 19:19 | lazybot | ⇒ "Yai-ongush, cthaiglaeg, les liag shuts. Piarl! Le'ugh ge'iashiark giatuth piggia-aig, yosiakh. Zvro-aighaho nyath ka-irl, kogh gaigg cthep ftail zvret... Thai'erkikh... Ta'il cthag, kaik. Yep, tox paggogg tanerl... Pagh, ftotsaha, kerk! Shukh gul gai-aino-is, kiathi... https://www.refheap.com/95447 |
| 19:20 | TEttinger | well, I'm pretty pleased, it packs more features in shorter code now |
| 19:20 | [blake| | Can anyone explain why Hastur just showed up in my cubicle? |
| 19:21 | Mikke | bryanzera: i mean, move the <script> reference to angular.js |
| 19:21 | TEttinger | rich is trying to figure out state and identity so he swapped his brain through time with a Yith |
| 19:21 | justin_smith | [blake|: serves you right for making siri read IRC out loud to you |
| 19:22 | [blake| | justin_smith: There are drawbacks. (Related: Anyone know where I can get a very, very tiny pair of gloves and hat?) |
| 19:24 | Mikke | vonnegut, http://plnkr.co/edit/Q6lBcquZc2329FjTFHEI?p=preview <-- seems to work okay can you show what's different in yours? |
| 19:25 | justin_smith | Mikke: maybe you meant that for a different channel? |
| 19:26 | Mikke | joules: what's your point? |
| 19:27 | justin_smith | Mikke: joules, vonnegut, and bryanzera are not in this channel, this is #clojure |
| 19:29 | Mikke | (RaeCarruth) OnlyOne: can I have some nudes with my pringles? * SammoSideKick sword in the hand. |
| 19:31 | Mikke | ride* |
| 19:31 | Mikke | aw thx RaeCarruth |
| 19:34 | Mikke | We started a massive fight in gawminers |
| 19:37 | Mikke | ahahah |
| 19:50 | windobu | technomancy? |
| 19:50 | clojurebot | technomancy is <jweiss> oh man this sucks, why didn't anyone warn me about protocols |
| 19:50 | windobu | oh |
| 19:55 | windobu | welcomne. |
| 20:02 | justin_smith | windobu: hello |
| 20:03 | justin_smith | are you looking for technomancy? I think he moved recently and may be less active in IRC for a bit |
| 20:18 | tom39291 | (-> "foo" (fn [x] x)) fails, but I expect it to return "foo" |
| 20:19 | justin_smith | tom39291: ##(macroexpand '(-> "foo" (fn [x] x))) |
| 20:19 | lazybot | java.lang.IllegalArgumentException: Parameter declaration foo should be a vector |
| 20:19 | justin_smith | tom39291: anyway, it becomes (fn "foo" [x] x) |
| 20:19 | justin_smith | which causes the above error |
| 20:19 | justin_smith | tom39291: ##(macroexpand-1 '(-> "foo" (fn [x] x))) |
| 20:19 | lazybot | ⇒ (fn "foo" [x] x) |
| 20:19 | justin_smith | there we go, nice |
| 20:20 | justin_smith | tom39291: ##(macroexpand-1 '(-> "foo" ((fn [x] x)))) |
| 20:20 | lazybot | ⇒ ((fn [x] x) "foo") |
| 20:21 | justin_smith | tom39291: ##(-> "foo" ((fn [x] x))) |
| 20:21 | lazybot | ⇒ "foo" |
| 20:21 | tom39291 | justin_smith: Thanks. Will have a think why that is correct. |
| 20:22 | justin_smith | tom39291: this may be another hint: ##((-> [x] (fn x) "foo") |
| 20:22 | justin_smith | did I nest my parens bad? I think I did |
| 20:22 | justin_smith | &((-> [x] (fn x)) "foo") |
| 20:22 | lazybot | ⇒ "foo" |
| 20:23 | justin_smith | fn isn' |
| 20:23 | justin_smith | t "special", it's first arg is a vector |
| 20:23 | TEttinger | or a symbol |
| 20:23 | justin_smith | true |
| 20:26 | justin_smith | anyway, never use code like (-> [x] (fn x)) that's terrible and evil and only serves to demonstrate what -> does |
| 20:42 | ambrosebs | ,(-> -> ()) |
| 20:42 | clojurebot | #<AccessControlException java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "accessDeclaredMembers")> |
| 20:42 | justin_smith | ambrosebs: clojurebot is acting up ##(-> -> ()) |
| 20:42 | ambrosebs | &(-> ->) |
| 20:42 | lazybot | java.lang.IllegalArgumentException: Can't call nil |
| 20:42 | lazybot | java.lang.RuntimeException: Can't take value of a macro: #'clojure.core/-> |
| 20:43 | ambrosebs | ##(-> -> ((fn [->] 1))) |
| 20:43 | lazybot | java.lang.RuntimeException: Can't take value of a macro: #'clojure.core/-> |
| 20:43 | ambrosebs | well that was fun |
| 20:44 | ambrosebs | porkys just spammed me |
| 20:44 | justin_smith | yeah, he got me too, the mods have forsaken us for the holidays |
| 20:46 | ambrosebs | cool |
| 20:46 | ambrosebs | ##(-> ((fn [->])) ->) |
| 20:46 | lazybot | clojure.lang.ArityException: Wrong number of args (0) passed to: sandbox11388/eval17526/fn--17527 |
| 20:47 | justin_smith | oh, wow |
| 20:47 | justin_smith | that's getting close to something truly terrible |
| 20:47 | ambrosebs | ##((-> (fn [->]) ->)) |
| 20:47 | lazybot | clojure.lang.ArityException: Wrong number of args (0) passed to: sandbox11388/eval17537/fn--17538 |
| 20:47 | ambrosebs | ##((->> (fn [->]) ->)) |
| 20:47 | lazybot | clojure.lang.ArityException: Wrong number of args (0) passed to: sandbox11388/eval17548/fn--17549 |
| 20:48 | ambrosebs | ##((->> -> (fn [->]) )) |
| 20:48 | lazybot | clojure.lang.ArityException: Wrong number of args (0) passed to: sandbox11388/eval17559/fn--17560 |
| 20:48 | ambrosebs | :) |
| 20:50 | ambrosebs | ##(->> ->> (fn [->>] ->>)) |
| 20:50 | lazybot | ⇒ #<sandbox11388$eval17570$fn__17571 sandbox11388$eval17570$fn__17571@6d102211> |
| 20:50 | ambrosebs | ##(->> (->> ->> (fn [->>] ->>)) '->>) |
| 20:50 | lazybot | ⇒ ->> |
| 20:50 | justin_smith | reminds me of salmon season |
| 20:53 | ambrosebs | ##(-> [x 1] (let x)) |
| 20:53 | lazybot | ⇒ 1 |
| 20:55 | ambrosebs | ##(-> 1 `(let 1)) |
| 20:55 | lazybot | clojure.lang.ArityException: Wrong number of args (2) passed to: core/seq |
| 20:55 | ambrosebs | ##(macroexpand `(let 1)) |
| 20:55 | lazybot | java.lang.IllegalArgumentException: clojure.core/let requires a vector for its binding in sandbox11388: |
| 20:56 | justin_smith | &(macroexpand-1 `(let 1)) |
| 20:56 | lazybot | java.lang.IllegalArgumentException: clojure.core/let requires a vector for its binding in sandbox11388: |
| 20:56 | justin_smith | hmm |
| 20:56 | ambrosebs | &(macroexpand-1 ``(let 1)) |
| 20:56 | lazybot | ⇒ (clojure.core/seq (clojure.core/concat (clojure.core/list (quote clojure.core/let)) (clojure.core/list 1))) |
| 20:57 | ambrosebs | &(macroexpand-1 '`(let 1)) |
| 20:57 | justin_smith | I think the leading space threw it off |
| 20:57 | ambrosebs | &(macroexpand-1 '`(let 1)) |
| 20:57 | lazybot | ⇒ (clojure.core/seq (clojure.core/concat (clojure.core/list (quote clojure.core/let)) (clojure.core/list 1))) |
| 20:58 | ambrosebs | &(= ``(let 1) '`(let 1)) |
| 20:58 | lazybot | ⇒ true |
| 21:00 | ambrosebs | &((fn clojure.core/fn [a] (if a (clojure.core/fn nil) 2)) 1) |
| 21:00 | lazybot | java.lang.IllegalArgumentException: Parameter declaration should be a vector |
| 21:00 | hbccbh | (doc doc) |
| 21:00 | clojurebot | #<AccessControlException java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "accessDeclaredMembers")> |
| 21:02 | ambrosebs | &((fn fn [a] (if a (fn nil) 2)) 1) |
| 21:02 | lazybot | java.lang.IllegalArgumentException: Parameter declaration should be a vector |
| 21:21 | nub | Hi! I'm trying to display a chart with incanter, but it just spits this out in my repl instead of dislpaying a chart: #<ChartFrame org.jfree.chart.ChartFrame[frame2,0,23,500x400,layout=java.awt.BorderLayout,title=Incanter Plot,resizable,normal,defaultCloseOperation=DISPOSE_ON_CLOSE,rootPane=javax.swing.JRootPane[,0,22,500x378,layout=javax.swing.JRootPane$RootLayout,alignmentX=0.0,alignmentY=0.0,border=,flags=16777673,maximumSize=,minim |
| 21:21 | nub | Does anyone know what might be going on? |
| 21:24 | nub | Actually it works if I run lein-repl from the terminal. But with my Emacs nREPL it doesn't display the chart. |
| 21:25 | justin_smith | nub: emacs in an X window or emacs in a terminal? |
| 21:26 | nub | emacs gui on OSX |
| 21:28 | nub | justin_smith: actually it did display, but it popped up behind my emacs window |
| 21:28 | nub | justin_smith: do you know if there's a way to make the graphs appear in the foreground? |
| 21:29 | justin_smith | nub: no I don't, I am sure that is OS specific |
| 21:29 | nub | justin_smith: oh ok, thanks! |
| 21:29 | justin_smith | there may be a jframe method for popping to the foreground that you could invoke on the chartframe? |
| 21:29 | justin_smith | I assume the chartframe is a subclass of a jframe |
| 21:32 | justin_smith | nub: looks like java.awt.Window has .toFront |
| 21:32 | justin_smith | if you have a handle to the top level window object (or if that ChartFrame inherits from Window) |
| 21:33 | justin_smith | http://www.jfree.org/jfreechart/api/javadoc/org/jfree/chart/ChartFrame.html yeah, ChartFrame inherits from java.awt.Window, so it has the .toFront method |
| 21:33 | justin_smith | so that should just work |
| 21:34 | nub | justin_smith: oh cool, thanks! |
| 22:47 | windobu | 4chan is down :/ |
| 23:51 | Dynasty | is there a function to conduct a pre-walk on a tree with an accumulator? |
| 23:53 | Dynasty | nvm I can probably make it work with zippers |