2015-07-30
| 02:22 | ddellacosta | so, finally giving Stuart Sierra's component a shot, and I'm having trouble replicating the basic functionality in the repl |
| 02:23 | ddellacosta | I suspect it's actually a referring-to-records problem vs. a problem with how I'm using component, but it seems like none of the behavior I've added to the record is actually getting performed--for example, just doing a basic assoc with 'this' similarly to how he does it in the README doesn't work |
| 02:24 | ddellacosta | I just get the record back as it was |
| 02:24 | ddellacosta | and printlns don't do anything either |
| 02:24 | ddellacosta | which makes it seem like there is a no-op running vs. my actual protocol implementation |
| 02:24 | ddellacosta | anyone seen this kind of behavior using component (or types/records in general) in the repl? |
| 02:31 | ddellacosta | this gist shows what I'm trying to do, and how it's failing: https://gist.github.com/ddellacosta/07be4db31425f4827f1a |
| 02:32 | noidi | ddellacosta, try running lein clean before you start the repl |
| 02:32 | ddellacosta | noidi: I've restarted the repl and run lein clean a few times, don't believe that's it |
| 02:33 | ddellacosta | will try it again once more to make sure though |
| 02:36 | ddellacosta | yep, no luck with that (again). It's also suspicious because I've never implemented my record with no-ops--I've always had it at least printing. So I would assume that if there is some old instance of my record in memory it would be using that--but it's clearly just doing nothing. |
| 02:57 | crocket | How do I specify datetime in edn? |
| 03:00 | crocket | Oh, there is https://github.com/edn-format/edn#inst-rfc-3339-format |
| 03:01 | crocket | edn is good as a wire format. |
| 03:01 | crocket | Although it could be slower than other wire formats. |
| 03:02 | crocket | Do you use edn as your wire format? |
| 03:18 | seangrove | Is there any way to check if a value is a core.async channel? |
| 03:20 | seangrove | Nooooooope http://dev.clojure.org/jira/browse/ASYNC-74 |
| 03:34 | arrdem | crocket: no, don't do that, use parquet or avro or protobuffs or transit or something else |
| 03:34 | crocket | arrdem, Why? |
| 03:34 | crocket | performance? |
| 03:35 | clojurebot | http://clojure.org/java_interop#toc46 |
| 03:35 | arrdem | it is possible to use edn as a wire protocol, as it is possible to use json, it's just encoding inefficient |
| 03:35 | arrdem | arguably gzip streams get around some of this, but it's still a thing |
| 03:36 | arrdem | at work we've reaped a huge performance win from using parquet to store lots and lots of what were previously EDN records on disk / move em over wire |
| 03:38 | arrdem | But maybe you don't care, try em and see |
| 03:38 | arrdem | Only You Can Profile Your Code |
| 03:39 | crocket | How do you document your wire format? |
| 03:39 | crocket | Did you document your API interface independent of wire format and wire protocol? |
| 03:40 | arrdem | Short answer is we don't, we're using parquet to move a lot of data which fits a single uniform schema and use a (could be thinner) Java layer to interact with it from Clojure |
| 03:41 | arrdem | so this may not be a great datapoint for you if you're interested in a message protocol of some sort |
| 03:41 | crocket | hmm... |
| 03:41 | crocket | Probably, it is not a public API. |
| 03:41 | crocket | It's ok to not document at all if it is an internal thing. |
| 03:42 | arrdem | I mean it is documented in so much as parquet is a versioned, schema based compiled encoding and ther exist docs for the Java classes that wrap parquet encoded "objects". |
| 03:43 | arrdem | but being internal and an implementation detail such docs are languishing |
| 03:44 | arrdem | I thin a reasonable approach would be to design your procol first and prototype it with an EDN encoding, get that working, and then rework it to use some tighter format for performance once you have documentation and desired behavior. |
| 03:44 | arrdem | but that's also Brooks' plan to throw one away which you may not be game for |
| 03:48 | ddellacosta | hmm, is it possible component isn't working for me as advertised because of Clojure 1.7? |
| 03:48 | crocket | arrdem, Is parquet for storage or wire? |
| 03:48 | ddellacosta | I just realized he says he's only tested with 1.6 and below |
| 03:48 | arrdem | crocket: it's just a data encoding you can do both with it. |
| 03:48 | arrdem | socket.write(parquet.getBytes())... |
| 03:49 | arrdem | crocket: we're using it for on disk (HDFS) data storage |
| 03:51 | crocket | Do you send parquet on the wire, too? |
| 03:51 | arrdem | no, that I can't speak directly to |
| 03:52 | arrdem | I mean we do in so much as HDFS does it magically for us |
| 03:52 | arrdem | but I'm not piping parquet data over sockets if that's the goal |
| 03:57 | crocket | What goes over the wire? |
| 04:36 | tgoossens | I have to do doseq over a possible large array (millions). Is there an easy way to parallelize this? |
| 05:05 | arrdem | Grimoire 0.4.23 live now with 1.7 special forms (issue 213/214) not broken and a minor fix or two. |
| 05:05 | arrdem | sleep now |
| 05:31 | dabd | I have small app that writes some files to the filesystem. I packaged it with lein uberjar. If I call -main from the REPL it works fine, however if I run it from the cmd line it won't write anything. Anything I am missing? |
| 05:34 | Kneiva | dabd: how do you run it from command line? |
| 05:34 | dabd | with java -jar <standalone jar> arg1 arg2 ... |
| 05:36 | dabd | I think I found the problem. The side effects were being called inside a 'map' which is lazy and probably the repl forces the evaluation which won't happen when I call it from the cmd line. I switched the map to run! and now it works |
| 05:36 | Kneiva | great |
| 05:36 | dabd | does this make sense? |
| 05:36 | Kneiva | yes |
| 05:37 | dabd | supposing I wanted to use map how do I force the evaluation? |
| 05:38 | MasseR | dabd: haven't written clojure for a while, but wasn't there something like doseq which forces evaluation? |
| 05:38 | MasseR | Use map for pure computations and doseq for side-effects |
| 05:40 | dabd | yes makes sense |
| 05:58 | cfleming | Somewhat OT: I just know enough IRC to get connected and then not touch anything. Recently for some reason I started receiving private messages from *status every time I connect to my ZNC instance. Does anyone know how to disable that? I'm using Textual on OSX. |
| 07:07 | perplexa | gfredericks: didn't you put up some black magic 'timestamps' created only with the java math lib? can you gimme a link pls? |
| 07:20 | Cka3 | Hello, can someone help me? I need to figure out how to get from two collections e.g. [2 8 6] [8 5 1] one collection of collections like this ([2 8 6][3 7 5][4 6 4][5 5 3][6 5 2][7 5 1][8 5 1]) ? |
| 07:21 | alexyakushev | Cka3: Where are the other elements coming from? |
| 07:21 | zphds | Cka3: you could flatten the source coll and use permutations |
| 07:21 | zphds | http://clojure.github.io/math.combinatorics/ |
| 07:22 | alexyakushev | zphds: It doesn't look lke permutations, more like reducing the last number and increasing the first one, but still unclear |
| 07:22 | Cka3 | here is my first step |
| 07:22 | zphds | alexyakushev: yes, you're right |
| 07:22 | snowell | Looks like it's showing intermediate steps to transform the first one into the second one |
| 07:22 | snowell | Using inc and dec |
| 07:22 | Cka3 | (let [from-color [2 8 6] |
| 07:22 | Cka3 | to-color [8 5 1] |
| 07:22 | Cka3 | step 1 |
| 07:22 | Cka3 | direction (fn [a b] (map #(if (> %1 %2) - +) a b)) |
| 07:22 | Cka3 | crange (fn [a b c] (conj (vec (range a b (c step))) b)) |
| 07:22 | Cka3 | ] |
| 07:22 | Cka3 | (map crange from-color to-color (direction from-color to-color))) |
| 07:23 | Cka3 | => ([2 3 4 5 6 7 8] [8 7 6 5] [6 5 4 3 2 1]) |
| 07:23 | Cka3 | I'm very new to programming) |
| 07:24 | Cka3 | ([2 8 6][3 7 5][4 6 4][5 5 3][6 5 2][7 5 1][8 5 1]) |
| 07:24 | Cka3 | this what I need to get) |
| 07:28 | Cka3 | Any ideas? )) |
| 07:29 | Cka3 | Rich? ) |
| 07:29 | justin_smith | Cka3: don't do multiple line pastes, please. Use a site like refheap.com for that |
| 07:30 | Cka3 | Sorry |
| 07:31 | justin_smith | Cka3: your "c" argument to crange needs to be a function you can call, and direction does not return a function |
| 07:32 | justin_smith | actually to be correct, direction would have to return a sequence of functions |
| 07:32 | justin_smith | or you would have to do something with c other than calling it |
| 07:33 | Cka3 | it returns collection of functions + or - |
| 07:33 | justin_smith | oh, wait, never mind, it does return a sequence of functions |
| 07:33 | justin_smith | right |
| 07:33 | Cka3 | but I having problem with the next steps |
| 07:34 | Cka3 | how I can go from this ([2 3 4 5 6 7 8] [8 7 6 5] [6 5 4 3 2 1]) to this ([2 8 6][3 7 5][4 6 4][5 5 3][6 5 2][7 5 1][8 5 1]) |
| 07:34 | justin_smith | Cka3: (apply mapv vector) will give you your answer |
| 07:35 | justin_smith | ,(apply mapv vector '([2 3 4 5 6 7 8] [8 7 6 5] [6 5 4 3 2 1])) |
| 07:35 | clojurebot | [[2 8 6] [3 7 5] [4 6 4] [5 5 3]] |
| 07:35 | justin_smith | except one of your sequences is too short, you need to fix that |
| 07:35 | Cka3 | no I don't) |
| 07:35 | justin_smith | OK, then don't use the simple solution |
| 07:35 | justin_smith | and fix it some other way |
| 07:37 | justin_smith | Cka3: the straightforward solution would be to fill the short inputs by repeating the last element until they are equal in length to the longest |
| 07:37 | justin_smith | followed by mapv vector |
| 07:37 | Cka3 | so I need to check which collection is longest and then for other two collections fill missing items with last element of themselves? |
| 07:38 | justin_smith | or you could use a loop |
| 07:43 | justin_smith | the loop version is a lot uglier |
| 07:48 | justin_smith | Cka3: this gives the right answer, but it is ugly I think https://www.refheap.com/107264 |
| 07:56 | justin_smith | Cka3: I updated the paste above, maybe the second version is a bit better |
| 08:02 | Cka3 | thank you! |
| 08:04 | gfredericks | perplexa: I think what you're remembering was just some tweets, and I can't search twitter effectively enough to find them; but this is related https://gist.github.com/gfredericks/96e284ce2d52b91d481e |
| 08:05 | gfredericks | oh just kidding, searching for "Math/cbrt" worked: https://twitter.com/gfredericks_/status/517622176821043200 |
| 08:06 | justin_smith | gfredericks: OH, I remember when we were mucking with that stuff! |
| 08:07 | justin_smith | making arbitrary doubles using only java.lang.Math and no literals |
| 08:11 | perplexa | gfredericks: thanks |
| 08:13 | gfredericks | justin_smith: I don't think I succeeded in getting arbitrary doubles; I got pretty close though |
| 08:13 | gfredericks | I think arbitrary integers for sure |
| 08:14 | gfredericks | though I guess in the 2^53 range that's about the same problem |
| 09:06 | jonathanj | user=> "\003" |
| 09:06 | jonathanj | "" |
| 09:07 | jonathanj | i'm assuming that the \003 is elided from the REPL output there because it's not printable, but how can i actually be sure? |
| 09:14 | opqdonut | jonathanj: try (seq "\003") to look at the characters in the string |
| 09:15 | opqdonut | ,(seq "\012\141") -- like this |
| 09:15 | clojurebot | (\newline \a) |
| 09:15 | opqdonut | ,(seq "x\003x") |
| 09:15 | clojurebot | (\x \ \x) |
| 09:16 | opqdonut | well that looks weird |
| 09:17 | justin_smith | ,(first "\003") |
| 09:17 | clojurebot | \ |
| 09:17 | justin_smith | haha |
| 09:17 | opqdonut | ,(seq (.getBytes "\003")) |
| 09:17 | clojurebot | (3) |
| 09:17 | opqdonut | so it really is there |
| 09:18 | opqdonut | ,\o003 |
| 09:18 | clojurebot | \ |
| 09:18 | opqdonut | ,\o004 |
| 09:18 | clojurebot | \ |
| 09:18 | opqdonut | hrmph |
| 09:19 | opqdonut | ,[\o010 \o016] |
| 09:19 | clojurebot | [\backspace \] |
| 09:19 | opqdonut | right, clojure probably just prints \<the character> when you don't hit one of the \tab \newline etc. special cases |
| 09:19 | opqdonut | or rather, tries to print |
| 09:20 | justin_smith | ,(apply str [\a \backspace \b]) |
| 09:20 | clojurebot | "a\bb" |
| 09:20 | justin_smith | hrmph |
| 09:20 | justin_smith | ,(print (apply str [\a \backspace \b])) |
| 09:20 | clojurebot | ab |
| 09:41 | tgoossens | given a map m , how can i update the values of m (for all keys) given a transform fn |
| 09:41 | justin_smith | ,(into {} (map (fn [[k v]] [k (inc v)]) {:a 0 :b 1 :c 2})) |
| 09:41 | clojurebot | {:a 1, :b 2, :c 3} |
| 09:42 | tgoossens | <3 destructuring, justin_smith thanks! |
| 09:42 | justin_smith | or ##(reduce-kv (fn [m k v] (assoc m k (inc v))) {} {:a 0 :b 1 :c 2}) |
| 09:42 | lazybot | ⇒ {:a 1, :b 2, :c 3} |
| 09:44 | snowell | Is using `for` more/less efficient than map/reduce? |
| 09:44 | snowell | Ah, he did say "given a transform fn" |
| 09:45 | snowell | Turns out the best way for me to read something is to hastily reply to it :/ |
| 09:45 | justin_smith | snowell: for should be pretty much equivalent to map |
| 09:45 | i-blis | snowell, I think the difference might come from into vs .kvreduce |
| 09:46 | i-blis | into uses transients (and I guess reduce doesn't use mutation) |
| 09:47 | justin_smith | the reduce-kv version could easily be updated to use transients, of course |
| 09:48 | justin_smith | (persistent! (reduce-kv (fn [m k v] (assoc! m k (inc v))) (tansient {}) {:a 0 :b 1 :c 2}) |
| 09:48 | justin_smith | ,(persistent! (reduce-kv (fn [m k v] (assoc! m k (inc v))) (tansient {}) {:a 0 :b 1 :c 2}) |
| 09:48 | clojurebot | #<RuntimeException java.lang.RuntimeException: EOF while reading> |
| 09:48 | justin_smith | err |
| 09:48 | i-blis | yeap, one could wrap it in persistent! |
| 09:48 | justin_smith | ,(persistent! (reduce-kv (fn [m k v] (assoc! m k (inc v))) (tansient {}) {:a 0 :b 1 :c 2})) |
| 09:48 | clojurebot | #error {\n :cause "Unable to resolve symbol: tansient in this context"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.RuntimeException: Unable to resolve symbol: tansient in this context, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyze "Compiler.java" 6611]}\n {:type java.lang.RuntimeException\n :message "Unable to resolve symbol: tansien... |
| 09:48 | justin_smith | hmm |
| 09:48 | justin_smith | ,(persistent! (reduce-kv (fn [m k v] (assoc! m k (inc v))) (transient {}) {:a 0 :b 1 :c 2})) |
| 09:48 | clojurebot | {:a 1, :b 2, :c 3} |
| 10:23 | csd_ | Is it possible to have `lein repl`, when run inside a project dir, *not* execute the project's top level forms? |
| 10:24 | justin_smith | csd_: you can not specify a :main, you can use lein run -m clojure.main to launch a vanilla repl that does not load your project |
| 10:24 | justin_smith | but that's not going to be an nrepl, of course |
| 10:24 | csd_ | justin_smith: would that still allow access to the project deps as needed? |
| 10:24 | justin_smith | csd_: via require, yes |
| 10:25 | csd_ | cool thank you |
| 10:26 | justin_smith | csd_: lein is hella convenient, but I think there's something to be said for knowing how to set things up by hand too |
| 10:26 | csd_ | another unrelated question-- my coworkers are telling me that an uberjar can only package up clojure deps, and not java deps. so instead we're using an eclipse package that does this but its really clunky. do you know of any alternatives? |
| 10:27 | justin_smith | csd_: :provided in project.clj should prevent the dep from being packed into an uberjar |
| 10:27 | csd_ | no we want to have an uberjar that has every dependency in it, whether clojure or java based |
| 10:28 | justin_smith | csd_: oh, they are claiming a clojure uberjar is unable to contain java deps? that's patently false |
| 10:28 | justin_smith | just add the java dep to your dependencies, it just works |
| 10:28 | justin_smith | I thought they were saying those deps should be excluded |
| 10:28 | csd_ | hrm i don't know then |
| 10:29 | clgv | csd_: uberjar it is then ;) |
| 10:30 | justin_smith | csd_: well anyway, if your uberjar was including a thing erroneously, you can use the :provided {:dependencies [things you want but not in uberjar]} thing, and for java deps you do want in an uberjar, you just convert the maven coordinates to lein notation, which is easy, and put them under :dependencies |
| 10:30 | TimMc | csd_: Every uberjar I've ever made disagrees with their claim. |
| 10:30 | csd_ | i see |
| 10:30 | csd_ | would this still work for java dependencies that are accessed locally and which arent hosted on maven/etc? |
| 10:31 | justin_smith | csd_: you would need to at least run lein install, or put them in resources/ or something |
| 10:31 | justin_smith | (or mvn install or whatever) |
| 10:31 | justin_smith | it's really not hard to make a maven accessible jar of something |
| 10:31 | clgv | justin_smith: putting them in resources requires some serious weight lifting to load them afterwards ;) |
| 10:32 | justin_smith | csd_: like adding resources/foo.jar to your classpath? |
| 10:32 | justin_smith | err, that was for clgv |
| 10:32 | csd_ | ok well idk what they're talking about then |
| 10:32 | clgv | justin_smith: would work from leiningen but not from the uberjar afaik |
| 10:33 | justin_smith | clgv: but yeah, the better solution is to put the jar into a maven repo |
| 10:33 | justin_smith | clgv: resources end up in your uberjar |
| 10:33 | clgv | csd_: for repeatable builds from different dev machines you should host those dependencies anyway |
| 10:33 | csd_ | yeah |
| 10:33 | clgv | justin_smith: that's true but there is no eays way to add a jar within a jar to the classpath |
| 10:33 | csd_ | just a lot of other things need doing too :-P |
| 10:33 | justin_smith | yeah, we use s3-wagon-private, but I think we should upgrade to a regular private maven server |
| 10:34 | clgv | csd_: but broadcasting new deps is annoying as well, isnt it? |
| 10:34 | csd_ | it really only applies to two things, and one of them is fairly stable |
| 10:34 | clgv | csd_: not to mention potential inconsistencies |
| 10:35 | csd_ | we have a hacked version of one serialization library, and the other is our java platform code which we export some of into a jar |
| 10:35 | csd_ | the serialization library has been fairly stable |
| 10:35 | clgv | setting up a repository is not that hard |
| 10:37 | csd_ | do you know of a good guide? |
| 10:38 | clgv | csd_: those repository tools usually have their guide. I checked archiva and nexus where that is the case |
| 10:38 | justin_smith | csd_: iirc nexus has a good walkthrough |
| 10:42 | clojure | help me ? "Cannot cast clojure.lang.PersistentVector to [Ljava.lang.Class;" my code: (def ctor (-> clazz (.getDeclaredConstructor [String, String, int]))) |
| 10:43 | clojure | help me ? i got a exception: "Cannot cast clojure.lang.PersistentVector to [Ljava.lang.Class;" here is my code: (def ctor (-> clazz (.getDeclaredConstructor [String, String, int]))) |
| 10:43 | csd_ | How do I refer to a Java compiled class (Foo.class) in clojure? I'm getting a class not found error. Specifically this is to mimic something like Guice's Key.get(Thingie.class, annotation) syntax |
| 10:46 | clgv | clojure: read that blog post (or tutorial) more carefully |
| 10:48 | noncom|3 | speaking of idiomatic clojure.. if you have some program or a script, big enough to be spread over several namespaces, and which conducts some process, do you prefer to pass the state among all the functions in the program or do you reside to storing it in an atom? |
| 10:49 | noncom|3 | i find storage in atom far more convenient in most occasions, however, i wonder what others think.. |
| 10:49 | TimMc | clojure: Do you need help understanding the exception? |
| 10:49 | TimMc | Or what? |
| 10:51 | noncom|3 | clojure: i think you need (into-array [String, String, int]) ... ? |
| 10:51 | noncom|3 | coz [] is not [Ljava.lang.* |
| 10:52 | noncom|3 | csd_: even better - push you library to clojars and enjoy the eternal benifits of repeatability right away! |
| 10:54 | clgv | csd_: use only the class name itself |
| 11:00 | jonathanj | so there was no real consensus as to how i get \003 to usefully display in a REPL? |
| 11:01 | jonathanj | it would be nice if non-printables were just printed in their escaped octal form |
| 11:03 | opqdonut | jonathanj: indeed it would |
| 11:03 | jonathanj | can i file a bug somewhere? |
| 11:03 | noncom|3 | in jira? |
| 11:04 | opqdonut | jonathanj: you could just use StringEscapeUtils to get the escaped string back, but yeah, file a bug |
| 11:04 | noncom|3 | or maybe in the issue tracker of the particular repl you're using... |
| 11:05 | jonathanj | does the REPL itself construct the representation? |
| 11:22 | noncom|3 | jonathanj: not sure what you mean... repl is the one who presents you the data |
| 11:22 | noncom|3 | i think that you can sorta change this data before it presents it to you |
| 11:23 | noncom|3 | other details depend on the particular repl you use |
| 11:23 | clgv | jonathan: prn |
| 11:23 | clgv | ,(prn \003) |
| 11:23 | clojurebot | #<RuntimeException java.lang.RuntimeException: Unsupported character: \003> |
| 11:23 | tmtwd | Are there any libraries for putting in html and spitting out hiccup? |
| 11:24 | clgv | huh? |
| 11:24 | clgv | ,(prn (char 3)) |
| 11:24 | clojurebot | \\n |
| 11:26 | jonathanj | i'm not sure how it works with Clojure, but with Python presenting a representation of data is generally up to the data type via the repr() API |
| 11:26 | clgv | jonathan: clojure has the print-method multi method |
| 11:27 | jonathanj | can i determine whether there is a method defined for a particular type? |
| 11:28 | jonathanj | anyway, is it truly solely up to the REPL to determine how best to display the result of every value? |
| 11:29 | clgv | jonathan: as I said, that is the task of the print-method |
| 11:30 | jonathanj | okay, so filing the bug against the REPL i'm using is probably not the right course of action |
| 11:30 | clgv | jonathanj: indeed. |
| 11:31 | clgv | jonathanj: you can look up the types via ##(keys (.getMethodTable print-method)) |
| 11:31 | lazybot | ⇒ (nil java.lang.Boolean clojure.lang.Var java.lang.Character clojail.testers.ClojailWrapper clojure.core.Iteration java.util.Date java.lang.Class java.util.RandomAccess java.util.regex.Pattern java.util.UUID :default clojure.lang.ISeq java.sql.Timestamp clojure.lang.... https://www.refheap.com/107273 |
| 11:33 | clgv | jonathanj: you can override as follows: (defmethod print-method Character [x, w] (.write w (format "char: %s" (long x)))) |
| 11:34 | clgv | jonathanj: though that only handles single characters |
| 11:41 | tmtwd | I meant if there are any libraries that let you input raw html and outputs hiccup-html |
| 11:41 | tmtwd | that way I can paste templates from bootstrap and use hiccup instantly |
| 12:20 | csd_ | is there any other magic i need to do to get slamhound.el working other than jacking in with cider? It looks like it's having trouble talking to the nrepl |
| 13:08 | dabd | anyone has an idea what the function parse-opts from tools.cli expects as first argument? (parse-opts ["-h"] ["-h" "--help"]) |
| 13:08 | dabd | throws an exception |
| 13:09 | dabd | I meant (parse-opts ["-h"] [["-h" "--help"]]) |
| 13:32 | TimMc | lgtm |
| 13:46 | slester | Is there accepted style for using (cond->)? Do I just use a space after each condition or do I line up conditions and functions? |
| 14:07 | kwladyka | I am so confuse... i have my own algorithm in Clojure and i have not my algorithm in Scala. This one in Scala run in 1 sec, but my don't stop after 30 minuts. As i see they do exactly the same.... somebody is able to help me understand why is that? |
| 14:08 | bja | are you sure they are the same? |
| 14:08 | bja | (i.e. not using mutable ops in scala) |
| 14:08 | kwladyka | if i see good they do the same |
| 14:09 | bja | do you have an example somewhere (maybe a gist)? |
| 14:09 | kwladyka | https://github.com/VlachJosef/scalac-chess-problem/tree/master/src/main/scala/vlach/josef <- scala super fast |
| 14:10 | kwladyka | my, the most important part https://www.refheap.com/76772dd5a7946a727450d76bb |
| 14:10 | kwladyka | scala use bfs and my use dfs but as i know there is no difference |
| 14:11 | kwladyka | *no difference in complexity |
| 14:11 | justin_smith | I wonder why clojure-mode wants to highlight "handle" as if it were special... |
| 14:12 | kwladyka | i have maybe a little mess in code because i was changing it so many times and still looking right one |
| 14:12 | kwladyka | justin_smith, can i please you to look on my question? i am fighting with this so long |
| 14:13 | kwladyka | do you see any mistake in my code which can make it slow? |
| 14:13 | kwladyka | or why scala code is so fast? |
| 14:13 | kwladyka | it doesn't make sense |
| 14:15 | justin_smith | kwladyka: for starters your recursive-solutions is not tail-recursive, unlike the scala version |
| 14:16 | justin_smith | the only way to do tail-recursion in clojure is recur, though you could also use loop or trampoline to the same effect |
| 14:17 | kwladyka | justin_smith, but is it changing anything if i will use recur instead of name of function? |
| 14:17 | kwladyka | in performance |
| 14:17 | kwladyka | but ok, i can change the name to recur, it should works without changing anything else |
| 14:18 | kwladyka | but still it is slow |
| 14:18 | justin_smith | kwladyka: no, "changing the name to recur" doesn't do it |
| 14:18 | kwladyka | ok, i can't change it so easy |
| 14:19 | justin_smith | and yeah, you can't just swap out the self call - you have to change how the stack is being managed |
| 14:19 | kwladyka | before i was using recur with loops and it was also slow |
| 14:19 | justin_smith | also, eventually you would want something other than doseq anyway, because otherwise your function will always return nil |
| 14:19 | justin_smith | ,(doseq [i (range 10)] i) |
| 14:20 | clojurebot | nil |
| 14:20 | kwladyka | justin_smith, because the solutions is only on the end of tree i am using ref variable |
| 14:20 | kwladyka | and change it only if i am on the end of tree |
| 14:21 | kwladyka | so i dont have to return anything |
| 14:21 | justin_smith | OK |
| 14:21 | kwladyka | so... am i using something what is slow? |
| 14:21 | justin_smith | btw, a ref-set that uses the existing value should be replaced with alter (see line 10) |
| 14:22 | justin_smith | kwladyka: yes, primitive recursion is slower than a loop or tail recursion via recur. Using a ref is slower than passing a value along to hold results |
| 14:23 | kwladyka | justin_smith, ref is not exaclty a problem, there is only 92 call this in example what i am trying do faster |
| 14:24 | kwladyka | justin_smith, hmm but loop and recur is not lazy? |
| 14:24 | justin_smith | no, it is not |
| 14:24 | justin_smith | nor is self call |
| 14:24 | justin_smith | which is what you do now |
| 14:24 | justin_smith | neither is lazy |
| 14:25 | justin_smith | the only thing that is lazy is lazy-seq (or one of our many helpful functions that use lazy-seq) |
| 14:25 | justin_smith | kwladyka: that doseq on line 64 is not lazy, it will call the function again for every result, eagerly |
| 14:25 | kwladyka | justin_smith, so do you think if i will rewrite it with loop and recur it will change it from 40 minuts to 1 second? ;) |
| 14:26 | justin_smith | kwladyka: I have no idea, but I suspect that you are wasting CPU cycles in that eager doseq with self calls on line 64 |
| 14:26 | justin_smith | because that is driving your algorithm, and it is not in any way lazy |
| 14:26 | justin_smith | nor is it fast - you want one or the other at least |
| 14:27 | kwladyka | what else can i check? |
| 14:28 | justin_smith | kwladyka: I have no idea, I've got other stuff I need to attend to at work, sorry |
| 14:28 | kwladyka | justin_smith, ok, thank you for help |
| 14:28 | kwladyka | just.... i cant live with this problem, i am spending hours on that why it is so slow.. |
| 14:29 | kwladyka | everyday |
| 14:29 | kwladyka | :) |
| 14:29 | justin_smith | kwladyka: I suspect the solution will involve replacing the doseq with something lazy |
| 14:31 | kwladyka | i was trying do this in so many ways... but i will try again, each time i am clever :) |
| 14:31 | justin_smith | also the concat on line 22, you'd get a faster result by replacing all those filters with one group-by followed by some key lookups |
| 14:32 | justin_smith | wait, no, just use frequencies |
| 14:32 | justin_smith | ,(frequencies [:queen :queen :rook :rook :rook :bishop :knight :bishop :knight :king]) |
| 14:33 | clojurebot | {:queen 2, :rook 3, :bishop 2, :knight 2, :king 1} |
| 14:34 | justin_smith | if you really need that format ##(sort-by (zip-map [:queen :rook :bishop :king :knight] (range)) [:queen :queen :rook :rook :rook :bishop :knight :bishop :knight :king]) |
| 14:34 | lazybot | java.lang.RuntimeException: Unable to resolve symbol: zip-map in this context |
| 14:34 | justin_smith | ,(sort-by (zipmap [:queen :rook :bishop :king :knight] (range)) [:queen :queen :rook :rook :rook :bishop :knight :bishop :knight :king]) |
| 14:34 | clojurebot | (:queen :queen :rook :rook :rook ...) |
| 14:34 | justin_smith | much faster than 5 filters and a concat |
| 14:38 | slester | justin_smith, my game is coming along slowly. Still trying to parse/determine what you were saying about passing along snapshots of the game state as a lazyseq |
| 14:39 | TEttinger | slester: ah! |
| 14:40 | TEttinger | I had an idea for that |
| 14:40 | TEttinger | https://github.com/tommyettinger/infinite-raid/blob/master/src/infinite_raid/state.clj |
| 14:40 | TEttinger | pretty simple state tracking, it needs an RNG with a highly visible state, so you can get and reseed the RNG to earlier states |
| 14:42 | justin_smith | slester: in a functional language, you can replace any global state with a sequence of values, which each value is a snapshot in time |
| 14:43 | justin_smith | TEttinger: what's the reasoning for repeated swap! calls on the same atom? why not one assoc with multiple keys and vals? |
| 14:44 | justin_smith | TEttinger: the order is guaranteed ##(assoc {} :a (doto 1 pr) :b (doto 2 pr) :c (doto 3 pr)) |
| 14:44 | lazybot | ⇒ 123{:c 3, :b 2, :a 1} |
| 14:44 | TEttinger | justin_smith: http://i110.photobucket.com/albums/n86/MCRfreek92/i-have-no-idea-what-im-doing-dog.jpg |
| 14:45 | justin_smith | haha |
| 14:45 | kwladyka | thx |
| 14:45 | kwladyka | justin_smith, thx |
| 14:45 | justin_smith | TEttinger: the reason I ask, is atoms have a relatively high overhead for modification, so if you reduce the number of swap! calls you'll usually see a benefit |
| 14:45 | hellofunk | justin_smith: doesn't that replacement of values kinda depend on persistent data structures? not all functional languages actually implement their data in the way Clojure does |
| 14:45 | TEttinger | yah, I haven't touched that code in a while |
| 14:46 | justin_smith | hellofunk: you could do a full tree copy in a language that doesn't have immutable values |
| 14:47 | justin_smith | hellofunk: the only difference is that it's up to the programmer to be disciplined and not touch the history (rather than enforced fairly strongly by the language itself) |
| 14:47 | hellofunk | that's one of the things that really bugs me about Swift. they have all these seductive functional idioms everywhere, but the data is fully copied when you actually "change" anything |
| 14:47 | TEttinger | I was wondering about using in-memory file serialization to mimic clojure in lua |
| 14:48 | justin_smith | yeah, and what's worse, they lead naive users to think that functional programming implies that kind of slow deep copying everywhere |
| 14:48 | hellofunk | it's awful. |
| 14:48 | justin_smith | so they try fp in swift and are like "never mind, fp is too slow" |
| 14:48 | hellofunk | i'm saddened that apple didn't do more under the hood. but that's probably why they are open sourcing the language, they want the community to fix it |
| 14:48 | TEttinger | https://github.com/torch/torch7/blob/master/doc/file.md#serialization-methods |
| 14:54 | slester | TEttinger, thanks, I'll look at it! I'm still a newbie to clojure/functional programming so it's taking me a while to process things. |
| 14:56 | gfredericks | hello |
| 14:56 | kwladyka | justin_smith, can you recommend me something to watch / read about how to write algorithm with good performance. I mean for example to use recur instead of primitive recur and use lazy instead of eager, but with explanation why and what is happening inside? to better understand how to write fast code? |
| 15:00 | justin_smith | slester: what I had in mind was somthing much simpler - imagine a game where :a and :b repeatedly flip a coin and keep a tally ##(iterate #(update % (if (> 0.5 (rand)) :a :b) inc) {:a 0 :b 0}) |
| 15:00 | lazybot | java.lang.RuntimeException: Unable to resolve symbol: update in this context |
| 15:00 | justin_smith | ,(iterate #(update % (if (> 0.5 (rand)) :a :b) inc) {:a 0 :b 0}) |
| 15:00 | clojurebot | ({:a 0, :b 0} {:a 1, :b 0} {:a 2, :b 0} {:a 2, :b 1} {:a 2, :b 2} ...) |
| 15:01 | justin_smith | an immutable lazy seq containing every state the game reaches, in order |
| 15:01 | justin_smith | ,(iterate #(update % (if (> 0.5 (rand)) :a :b) inc) {:a 0 :b 0}) |
| 15:01 | clojurebot | ({:a 0, :b 0} {:a 0, :b 1} {:a 1, :b 1} {:a 2, :b 1} {:a 3, :b 1} ...) |
| 15:03 | slester | justin_smith, ah! I'm kind of going to be doing that in a way. I have state, and I just recur until the state's "over" flag is set to true |
| 15:04 | justin_smith | slester: right, you could even use take-while with iterate if you wanted the full history instead of just the final state |
| 15:04 | slester | I'm hesitant to show code because it's probably awful |
| 15:04 | slester | ah, nice idea |
| 15:04 | justin_smith | heh, remember it's a great way to learn if your ego can handle the bruising |
| 15:04 | slester | it can, I just don't want to waste people's time |
| 15:06 | justin_smith | kwladyka: sorry about the delay - that is a huge subject and I can't think of something simple off the top of my head - it's likely covered in a functional way in SICP? https://mitpress.mit.edu/sicp/full-text/book/book.html which is a great textbook, available for free online, in a language very similar to clojure |
| 15:07 | justin_smith | hmm maybe that doesn't cover run time complexity actually... |
| 15:09 | justin_smith | kwladyka: you could check out using clojure.tools.trace to see how much each of your functions is getting called |
| 15:10 | slester|lunch | justin_smith, https://github.com/slester/amiss is the code if you're interested. I'll be back after lunch! |
| 15:10 | slester|lunch | maybe PM would be best? |
| 15:10 | slester|lunch | appreciated if you do have time |
| 15:12 | justin_smith | slester|lunch: on line 66, you don't need partial ##(apply + 1 [2 3]) |
| 15:12 | lazybot | ⇒ 6 |
| 15:13 | justin_smith | ,(map (comp {-1 false 0 nil 1 true} compare) [1 2 3 4 5] [5 4 3 2 1]) |
| 15:13 | clojurebot | (false false nil true true) |
| 15:14 | justin_smith | slester|lunch: ^ suggestion for compare-cards |
| 15:15 | justin_smith | slester|lunch: on line 106 the two assoc-in calls could be replaced with a single assoc |
| 15:17 | justin_smith | ,(< 1 2 5) ; slester|lunch - suggestion for line 168 |
| 15:17 | clojurebot | true |
| 15:28 | amalloy | Bronsa: re clj-1460 it may be helpful to know that clojure.core/case macroexpands to something involving a sorted-map |
| 15:30 | amalloy | or maybe an array-map? i forget. at any rate if you macroexpand a case statement yourself and then eval it, and that case has "too many" clauses, stuff breaks because the cases are no longer in the right order |
| 15:31 | Bronsa | amalloy: yeah that's how I discovered that bug actually |
| 15:31 | amalloy | i wonder if you heard about it from me complaining about that issue in here, ages ago |
| 15:32 | Bronsa | amalloy: i wish i had. I remember spending hours trying to figure out why t.e.jvm was bugged. |
| 15:33 | amalloy | ah. for me, it came up trying to use c.t.macro/macrolet |
| 15:33 | amalloy | where i wound up let'ing a macro that involved a 10-clause case |
| 15:33 | Bronsa | fun times debugging that stuff I bet |
| 15:35 | amalloy | i've been bitten by macrolet like 5 different times in 5 different ways, and yet the siren song of macrolet always calls me back |
| 15:38 | sdegutis | My intuition about partition-by at some recent point became no longer in sync with reality. |
| 15:39 | sdegutis | I assumed (partition-by (partial = :z) [:a :b :z :c :d :z :e]) would give '((:a :b) (:c :d) (:e)) but it's actually giving '((:a :b) (:z) (:c :d) (:z) (:e)) |
| 15:48 | justin_smith | sdegutis: so you were imagining it to behave like string/split does |
| 15:48 | sdegutis | I suppose yes. |
| 15:49 | sdegutis | In fact the first function I Dash'd was split-with. |
| 15:49 | sdegutis | Then I realized I probably wanted something more like partition-by. |
| 15:49 | sdegutis | (Since I wanted it to happen multiple times, not just once.) |
| 15:51 | sdegutis | Right now I'm just combining that `partition-by` with (remove (partial = [:z]) ...) |
| 15:51 | sdegutis | Seems to work, but feels sloppy and careless. |
| 15:51 | tear | ------------------------------------------------- |
| 15:56 | wasamasa | smooth |
| 16:05 | Bronsa | amalloy: looks like it is documented that (eval (sorted-map 1 1)) is allowed to return a PAM :/ |
| 16:10 | slester | justin_smith, thanks, looking at those now |
| 16:12 | sdegutis | wasamasa: I don't get it. |
| 16:13 | slester | ,(compare 1 5) |
| 16:13 | clojurebot | -1 |
| 16:13 | slester | justin_smith, I think I was under the impression that it returned like, -4 |
| 16:14 | wasamasa | sdegutis: I guess you didn't see that /quit |
| 16:15 | sdegutis | wasamasa: I have them hidden. Much quieter this way: https://www.dropbox.com/s/8qh22b5vn6x5e6f/quieterirc.png?dl=0 |
| 16:15 | wasamasa | sdegutis: smart filter ftw |
| 16:16 | sdegutis | wasamasa: what was it? |
| 16:16 | wasamasa | sdegutis: tear got immediately k-lined after posting |
| 16:17 | sdegutis | Ha. |
| 16:24 | sdegutis | How do you get the current year. Thanks. |
| 16:25 | justin_smith | ,(.getYear (java.util.Date.)) |
| 16:25 | clojurebot | 115 |
| 16:25 | justin_smith | you probably want to add 1900 |
| 16:25 | justin_smith | ,(+ 1900 (.getYear (java.util.Date.))) |
| 16:25 | clojurebot | 2015 |
| 16:26 | Bronsa | sdegutis: you keep asking questions not related to clojure that you could answer yourself with 20 seconds of google, could you try doing that next time before asking? |
| 16:27 | sdegutis | Thanks, I used the Clojure library chee.datetime. |
| 16:27 | sdegutis | ,(do (require '[chee.datetime :as dt]) (str (dt/year (dt/now)))) |
| 16:27 | clojurebot | #error {\n :cause "Could not locate chee/datetime__init.class or chee/datetime.clj on classpath."\n :via\n [{:type java.io.FileNotFoundException\n :message "Could not locate chee/datetime__init.class or chee/datetime.clj on classpath."\n :at [clojure.lang.RT load "RT.java" 456]}]\n :trace\n [[clojure.lang.RT load "RT.java" 456]\n [clojure.lang.RT load "RT.java" 419]\n [clojure.core$load$fn__... |
| 16:29 | justin_smith | sdegutis: lol top google hit for chee.datetime https://github.com/slagyr/joodo/issues/27 |
| 16:31 | jsabeaudry | Is there a csv library for clojurescript ? |
| 16:31 | sdegutis | Most likely. |
| 16:32 | Bronsa | jsabeaudry: https://cljsjs.github.io/ looks like there are a few |
| 16:33 | Bronsa | ah nevermind, those are js libraries |
| 16:33 | Bronsa | https://github.com/testdouble/clojurescript.csv this seems what you need otoh |
| 16:33 | sdegutis | justin_smith: how is that lol? |
| 16:34 | jsabeaudry | Bronsa, thanks for the first link |
| 16:34 | jsabeaudry | Bronsa, that second one cannot read csvs haha |
| 16:34 | sdegutis | Bronsa: Sometimes #clojure surprises me with very excellent pure-Clojure answers that aren't in the top Google results. |
| 16:35 | Bronsa | sdegutis: "how to get the current year" is hardly a question you'd expect to get such an answer |
| 16:35 | sdegutis | Bronsa: You never know! |
| 16:35 | sdegutis | :) |
| 16:52 | slester | it's why I try to google and understand things before I ask here, and why I'm afraid to actually post code snippets until I've tried to vet them myself heh |
| 17:01 | phyzome | slester: As long as it's clear you're putting in some effort of your own it's fine to ask questions and link to snippets! |
| 17:09 | jsabeaudry | Somehow the cljsjs does not get compiled when I run my project? Is there anything I need to do when a lein project has boot dependencies? |
| 17:17 | justin_smith | Bronsa: in fact, people fear, mistrust, and commonly misuse java.util.Date, and will go through all kinds of silliness to avoid the simplest answer if the simplest answer is to use Date |
| 17:19 | justin_smith | like a wrapper library that makes a calender out of a data and pulls the year out of the calendar |
| 17:27 | oddcully | and because Date is so awesome, there is a new api in each major java version |
| 17:35 | numberten | is there a place you can add let variables in a prop/for-all with test.check? |
| 17:35 | numberten | instead of recomputing a constant for every test |
| 17:36 | sdegutis | justin_smith: on the other hand, an API that is easy to misuse is poorly designed |
| 17:48 | TimMc | I've certainly never heard someone claim that Date was well-designed. :-) |
| 17:54 | sdegutis | Is there a way that I can make (require 'foo.bar) look in "src/foo/bar/[something].clj" instead of "src/foo/bar.clj" ? |
| 18:04 | sdegutis | Thanks. |
| 18:09 | numberten | is there something like clojure.test's 'thrown?' that you can use in test.check? |
| 18:16 | sdegutis | Why isn't this true? &&(= {:a 2} {:a 2 :b nil}) |
| 18:16 | sdegutis | Oops I forgot the bot notation. |
| 18:17 | Cr8 | ,[(:b {:b nil} :missing) (:b {} :missing)] |
| 18:17 | clojurebot | [nil :missing] |
| 18:17 | sdegutis | Oh. |
| 18:17 | sdegutis | Still, it seems that in the general case, nil and absent should be equivalent. |
| 18:18 | Cr8 | ,(mapv seq [{} {:b nil}]) |
| 18:18 | clojurebot | [nil ([:b nil])] |
| 18:19 | Cr8 | ,(map (partial contains? :b) [{} {:b nil}]) |
| 18:19 | clojurebot | #<IllegalArgumentException java.lang.IllegalArgumentException: contains? not supported on type: clojure.lang.Keyword> |
| 18:19 | Cr8 | ok i got something wrong there but you get the idea |
| 18:19 | Cr8 | lots of respects in which containing a k-nil pair is different than not having an entry for k |
| 18:20 | Cr8 | you couldn't even roundtrip JSON through if that were the case |
| 18:21 | sdegutis | I assumed for maps that (= m1 m2) would be equivalent to (every? #(= (% m1) (% m2)) (distinct (concat (keys m1) (keys m2)))) |
| 18:21 | sdegutis | That seems like the most common-sense meaning of = for maps. |
| 18:22 | Bronsa | equality on maps uses contains?, not get |
| 18:22 | Bronsa | which is the reasonable thing to do |
| 18:22 | justin_smith | ,(= {Double/NaN Double/NaN} {Double/NaN Double/NaN}) |
| 18:22 | clojurebot | false |
| 18:22 | Cr8 | https://github.com/clojure/clojure/blob/b926222fbdbd866806d441fa362e3ac0cf0afafa/src/jvm/clojure/lang/APersistentMap.java#L52-L71 |
| 18:23 | Bronsa | sdegutis: would you have two maps be equal when their `count` differs? |
| 18:23 | Cr8 | checks pair count is the same, checks contains for each key, then checks get equivalence |
| 18:23 | Bronsa | ,[(count {:b 1 :a nil}) (count {:b 1})] |
| 18:23 | clojurebot | [2 1] |
| 18:23 | sdegutis | Bronsa: because (= (get m1 :b) (get m2 :b)) |
| 18:23 | Bronsa | so what? |
| 18:23 | Bronsa | (not= (contains? m1 :b) (contains? m2 :b)) |
| 18:23 | Bronsa | what's your point? |
| 18:24 | sdegutis | Bronsa: so it seems intuitive to me that they're equal when (get) for all keys produce equal results |
| 18:24 | justin_smith | sdegutis: so (= {:a 0} {:a 0 :b 1 :c 2}) by that argument |
| 18:24 | Cr8 | if (get) was the only thing on the map interface that would make sense |
| 18:24 | Cr8 | it's not |
| 18:24 | Bronsa | sdegutis: and contains? does not. |
| 18:24 | Bronsa | nor does count on the map |
| 18:24 | sdegutis | justin_smith: No, that would be false. |
| 18:24 | Bronsa | a nil key is not a non-present key |
| 18:24 | Cr8 | plus also there's get of other arities that isn't the same |
| 18:24 | sdegutis | justin_smith: either you're completely misunderstanding what I said, or I completely butchered saying it. |
| 18:25 | Cr8 | ,[(get {:b nil} :b :missing) (get {} :b :missing)] |
| 18:25 | clojurebot | [nil :missing] |
| 18:25 | Cr8 | or: |
| 18:25 | Cr8 | nil doesn't mean "not present", it's just the default default value |
| 18:26 | justin_smith | ,((juxt = list) (hash-map Double/NaN Double/NaN) (hash-map Double/NaN Double/NaN Double/NaN Double/NaN)) |
| 18:26 | clojurebot | [false ({NaN NaN} {NaN NaN, NaN NaN})] |
| 18:26 | sdegutis | The fact that the /default/ for get on a map with an absent key is nil seems to suggest that the :missing key is an exception for special circumstances, and that in the general case, you shouldn't care whether the key pointed to a literal nil or missing. |
| 18:26 | sdegutis | And = should assume the general case, not the exception. |
| 18:27 | Bronsa | that's not how equality works. |
| 18:27 | sdegutis | Bronsa: Honestly I think you just want to defend whatever Clojure currently does without regard to what it ought to do. |
| 18:27 | Bronsa | sdegutis: lol. |
| 18:29 | justin_smith | ,(iterate #(assoc % Double/NaN Double/NaN) {}) |
| 18:29 | clojurebot | ({} {NaN NaN} {NaN NaN, NaN NaN} {NaN NaN, NaN NaN, NaN NaN} {NaN NaN, NaN NaN, NaN NaN, NaN NaN} ...) |
| 18:29 | Cr8 | :missing isnt special |
| 18:29 | Cr8 | ,[(get {:b nil} :b :bob) (get {} :b :bob)] |
| 18:29 | Bronsa | sdegutis: I've given you at least two reasons why `=` behaves correctly with regards to nil values |
| 18:29 | clojurebot | [nil :bob] |
| 18:29 | Bronsa | which you seem to have ignored |
| 18:31 | sdegutis | Bronsa: Were your reasons about contains? and :missing? |
| 18:31 | Bronsa | read the backlog |
| 18:31 | sdegutis | Because I responded to both of those. |
| 18:31 | Cr8 | ,(doc get) |
| 18:31 | clojurebot | "([map key] [map key not-found]); Returns the value mapped to key, not-found or nil if key not present." |
| 18:32 | bmay_ | in Ring, how do i get the file content from a file submitted with enctype multipart/form-data |
| 18:34 | sdegutis | This is how = should be defined for maps `ms`: (every? (fn [k] (apply = (map #(get % k) ms))) (distinct (mapcat keys ms))) |
| 18:34 | sdegutis | Bronsa: reading now |
| 18:34 | Cr8 | that would make it impossible to represent nil as a value of a kv pair in a map |
| 18:34 | Cr8 | why is that better |
| 18:34 | sdegutis | Cr8: how so? |
| 18:35 | Cr8 | if {:b nil} and {} are equivalent then you can't safely truck {:b nil} around |
| 18:35 | sdegutis | Cr8: It makes {:a 1} indistinguishable from {:a 1, :b nil}, but for the general case that doesn't matter. |
| 18:35 | Cr8 | yeah and it breaks *every case where it does* |
| 18:35 | sdegutis | Cr8: in what situation? |
| 18:35 | Cr8 | say you're sticking those in a cache |
| 18:35 | Cr8 | you put in {:b nil} and you get back {} when you ask for it back |
| 18:35 | Cr8 | that's a problem |
| 18:35 | Bronsa | sdegutis: you seem to think that your general case is everybody's general case |
| 18:36 | sdegutis | A cache sounds like a highly specific problem where nil values probably have a special meaning. |
| 18:36 | sdegutis | Bronsa: Yep. Pretty darn sure it is. |
| 18:36 | Bronsa | good. implement your own = and use that then |
| 18:37 | sdegutis | Bronsa: I'm pretty sure you have just as little code to back up your assertion that it's not as much as you think I have to support that it is. |
| 18:37 | Cr8 | thing is {:b nil} and {} are -different data-, and if = considered them the same I couldn't use huge parts of the stdlib |
| 18:37 | Cr8 | if i cared about it |
| 18:37 | Bronsa | i'd rather have my maps be not= when `keys` or `count` than for them to be = |
| 18:37 | Cr8 | and i might not *know* if I don't care about it, i might be a library author |
| 18:37 | justin_smith | (apply merge (repeat 9 {Double/NaN Double/NaN})) |
| 18:37 | Bronsa | when `keys` or `count` are not= |
| 18:37 | justin_smith | ,(apply merge (repeat 9 {Double/NaN Double/NaN})) |
| 18:37 | clojurebot | {NaN NaN, NaN NaN, NaN NaN, NaN NaN, NaN NaN, ...} |
| 18:37 | justin_smith | ,(apply merge (repeat 10 {Double/NaN Double/NaN})) |
| 18:37 | clojurebot | {NaN NaN} |
| 18:38 | sdegutis | Cr8: I fundamentally disagree, considering almost every single time you use a map is with (get) or some variation that uses (get). |
| 18:38 | hiredman | huh |
| 18:38 | Bronsa | justin_smith: is spamming NaN your subtle way to stop a flame? :) |
| 18:38 | justin_smith | Bronsa: I found the difference between the 9 map and 10 map result amusing |
| 18:38 | Bronsa | oh wait |
| 18:38 | Bronsa | I didn't even notice that |
| 18:39 | Cr8 | example: passing a param map to something than generates a url query string |
| 18:39 | Cr8 | example: serializing json to pass to some api that expects a key to be present and null |
| 18:39 | Bronsa | justin_smith: one is a PAM and the other is a PHM, but I have no idea how they can compare equal :| |
| 18:40 | Cr8 | really anything that consumes an entire map, or might care about the presence of a key |
| 18:40 | Bronsa | sdegutis: I couldn't undertand your last sentence. |
| 18:40 | justin_smith | clearly they are hashing or comparing differently - probably no differences that actually matter to code that is not insane |
| 18:42 | sdegutis | Bronsa: The highest priority driving forces of a data structure is how you use it, not how it's implemented. And even then, it's how they're most often used, not the few niche situations. |
| 18:42 | sdegutis | Bronsa: So the most important driving features of maps are assoc, merge, and get. |
| 18:42 | Cr8 | how is it useful to make it not workable to put nil in your collection |
| 18:42 | Bronsa | justin_smith: ah, it is possible that PAM doesn't use pointer identity checks while the PHM does, I guess |
| 18:43 | sdegutis | Bronsa: contains? is lower priority than these, since you usually just want to know the value of a key, not whether it's there or not. |
| 18:43 | Bronsa | sdegutis: and they are more important because you decided so? |
| 18:43 | Bronsa | sdegutis: what about count, keys, vals? |
| 18:43 | justin_smith | find even |
| 18:43 | Cr8 | or even (seq) |
| 18:43 | sdegutis | Bronsa: Because in my 4 years of experience writing Clojure full-time professionally, this is what I have encountered in my own code, the code of my colleagues, and code I have seen written in third party libs. |
| 18:44 | Cr8 | a map is a collection of kv pairs, why would you throw some out because you don't like what the .val portion is |
| 18:44 | sdegutis | Bronsa: I've rarely if ever seen count or contains? used, but sometimes keys and vals used by programmer-centric libraries. |
| 18:44 | sdegutis | (like a testing framework) |
| 18:44 | Bronsa | sdegutis: functions must return the *right* value not some opinionated result based on what is more generally used in your experience |
| 18:45 | Bronsa | sdegutis: and in your 4 years of experience writing clojure full-time professionally it just now occurs to you that (not= {:a 1} {:a 1 :b nil})? I'm sorry but if that's the case you might have some serious misunderstanding of the philosophy behind some design clojure design choices |
| 18:46 | Cr8 | if you are going to argue that (= {:b nil} {}) you need to argue {:b nil} shouldn't compile |
| 18:46 | Cr8 | otherwise the whole type would by maddeningly inconsistent |
| 18:47 | Bronsa | justin_smith: gah now you got me curious to see if there's actually a PAM/PHM bug hidden in there |
| 18:50 | sdegutis | Bronsa: Actually no, it came up years ago, resulting in me writing a special equality function for maps for our own use. |
| 18:51 | sdegutis | Bronsa: But I fully agree with you, it should do /the right thing/, not some opinionated thing. And I believe the right thing is the definition I provided, and that your suggestion of it being fine the way it is is just your incorrect opinion. |
| 18:51 | sobel | how can i make string/replace match case-insensitive? |
| 18:51 | justin_smith | sobel: with a case-insensitive regex? |
| 18:51 | sdegutis | Bronsa: Because you tend to agree with rhickey simply because he's rhickey rather than to think of how functions should work. |
| 18:51 | Bronsa | sdegutis: that's insulting and ignorant |
| 18:52 | sdegutis | contains? is a stupid function and works stupidly and is stupidly named. |
| 18:52 | justin_smith | sdegutis: I've seen Bronsa complain a lot about clojure internals |
| 18:52 | sobel | justin_smith: i'm sure it's obvious when you already know how to do it |
| 18:52 | sdegutis | justin_smith: but the public-facing API is another story |
| 18:52 | justin_smith | sobel: clojure regexes are java regexes, there is a ?i key |
| 18:52 | sdegutis | contains? should work completely differently, it should tell you whether a collection contains an element |
| 18:52 | Bronsa | sdegutis: I complain about the public API just aswell |
| 18:53 | justin_smith | ,(matches #"WORD" "word") |
| 18:53 | clojurebot | #error {\n :cause "Unable to resolve symbol: matches in this context"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.RuntimeException: Unable to resolve symbol: matches in this context, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyze "Compiler.java" 6611]}\n {:type java.lang.RuntimeException\n :message "Unable to resolve symbol: matches i... |
| 18:53 | justin_smith | ,(re-matches #"WORD" "word") |
| 18:53 | clojurebot | nil |
| 18:53 | sobel | justin_smith: thx, think i found the relevant doc bits now |
| 18:53 | justin_smith | ,(re-matches #"?iWORD" "word") |
| 18:53 | clojurebot | #<SecurityException java.lang.SecurityException: denied> |
| 18:54 | justin_smith | ,(re-matches #"(?i)WORD" "word") |
| 18:54 | clojurebot | "word" |
| 18:54 | justin_smith | finally |
| 18:54 | Bronsa | "Dangling meta character '?' near index 0" is an awesome error message |
| 18:55 | justin_smith | Bronsa: dangling off the front, heh |
| 18:59 | Bronsa | ,(let [a (hash-map Double/NaN 1)] [(assoc a Double/NaN 2) (assoc a (key (first a)) 2)]) |
| 18:59 | clojurebot | [{NaN 1, NaN 2} {NaN 2}] |
| 18:59 | Bronsa | wtf |
| 19:00 | justin_smith | wow |
| 19:00 | Bronsa | isn't that suppoosed to be impossible? I thought NaN returned false for pointer equality |
| 19:00 | hiredman | (hash Double/NAN) |
| 19:00 | hiredman | ,(hash Double/NAN) |
| 19:00 | clojurebot | #error {\n :cause "Unable to find static field: NAN in class java.lang.Double"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.RuntimeException: Unable to find static field: NAN in class java.lang.Double, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyze "Compiler.java" 6611]}\n {:type java.lang.RuntimeException\n :message "Unable to find st... |
| 19:01 | hiredman | ,(hash Double/NaN) |
| 19:01 | clojurebot | 2146959360 |
| 19:01 | hiredman | ,(hash Double/NaN) |
| 19:01 | clojurebot | 2146959360 |
| 19:01 | hiredman | hmmmm |
| 19:01 | Bronsa | hiredman: yeah but they still have to compare = |
| 19:01 | hiredman | Bronsa: doesn't matter |
| 19:01 | hiredman | for hash maps equality only kicks in after hashing |
| 19:02 | hiredman | ,(hash (Double. Double/NaN)) |
| 19:02 | clojurebot | 2146959360 |
| 19:03 | hiredman | but I guess I was wrong |
| 19:03 | hiredman | I assumed some kind of boxing thing created boxed NaN's with different hashes |
| 19:03 | Bronsa | uhmm |
| 19:03 | Bronsa | if my printlns are correct the value always gets assoc'd |
| 19:04 | hiredman | ,(let [a (hash-map (Object.) 1)] [(assoc a (Object.) 2) (assoc a (key (first a)) 2)]) |
| 19:04 | clojurebot | [{#object[java.lang.Object 0x17334611 "java.lang.Object@17334611"] 1, #object[java.lang.Object 0x273d11fd "java.lang.Object@273d11fd"] 2} {#object[java.lang.Object 0x17334611 "java.lang.Object@17334611"] 2}] |
| 19:04 | Bronsa | ,(let [a (hash-map Double/NaN 1)] (identical? (assoc a Double/NaN 2) a)) |
| 19:04 | clojurebot | false |
| 19:05 | hiredman | hard to see, but you get the same looking thing with objects that have identity |
| 19:05 | Bronsa | oh well obviously, the value is different mhh |
| 19:05 | Bronsa | uhm weird |
| 19:06 | Bronsa | no wait, not really? |
| 19:06 | Bronsa | hiredman: in the object case it's supposed to pass the pointer check |
| 19:06 | Bronsa | NaN is not |
| 19:06 | hiredman | sure, but in the second case it short circuits on the identity check |
| 19:06 | Bronsa | ,(let [a Double/NaN] (identical? a a)) |
| 19:06 | clojurebot | false |
| 19:07 | Bronsa | ,(let [a (Object.)] (identical? a a)) |
| 19:07 | clojurebot | true |
| 19:07 | hiredman | hmmm |
| 19:07 | Bronsa | like, it'd look like someplace in PHM it's using just the hashCode rather than doing equality checks |
| 19:08 | Bronsa | because there's no way for NaNs to compare equal or identical?, just the hash |
| 19:16 | Bronsa | what the |
| 19:16 | Bronsa | ,(let [a (hash-map Double/NaN 1)] (= (key (first a)) (key (first a)))) |
| 19:16 | clojurebot | true |
| 19:16 | Bronsa | ,(let [a Double/NaN] (= a a)) |
| 19:16 | clojurebot | false |
| 19:16 | hiredman | ah hah |
| 19:17 | hiredman | it has to be some kind of boxing issue |
| 19:18 | hiredman | ,(= (Double/valueOf Double/NaN) (Double/valueOf Double/NaN)) |
| 19:18 | clojurebot | false |
| 19:18 | hiredman | ,(let [a (hash-map Double/NaN 1)] (identical? (key (first a)) (key (first a)))) |
| 19:18 | clojurebot | true |
| 19:18 | Bronsa | is this some jvm weirdness I'm not aware of |
| 19:19 | hiredman | ,(let [a (hash-map Double/NaN 1)] (identical? (double (key (first a))) (double (key (first a))))) |
| 19:19 | clojurebot | false |
| 19:19 | hiredman | hah |
| 19:19 | justin_smith | ,(let [a [Double/NaN]] (= (first a) (first a))) |
| 19:19 | clojurebot | true |
| 19:19 | Bronsa | hiredman: how can you laugh, I'm having some serious identity crisis over here |
| 19:20 | hiredman | you have to laugh |
| 19:20 | hiredman | floating point |
| 19:20 | hiredman | ,(let [a (hash-map Double/NaN 1)] (identical? (double (key (first a))) (double (key (first a))))) |
| 19:20 | clojurebot | false |
| 19:21 | hiredman | ,(let [a (doto (java.util.HashMap.) (.add Double/NaN 1))] (= (key (first a)) (key (first a)))) |
| 19:21 | clojurebot | #error {\n :cause "No matching method found: add for class java.util.HashMap"\n :via\n [{:type java.lang.IllegalArgumentException\n :message "No matching method found: add for class java.util.HashMap"\n :at [clojure.lang.Reflector invokeMatchingMethod "Reflector.java" 53]}]\n :trace\n [[clojure.lang.Reflector invokeMatchingMethod "Reflector.java" 53]\n [clojure.lang.Reflector invokeInstanceMe... |
| 19:21 | hiredman | ,(let [a (doto (java.util.HashMap.) (.put Double/NaN 1))] (= (key (first a)) (key (first a)))) |
| 19:21 | clojurebot | true |
| 19:22 | Bronsa | here we go |
| 19:22 | Bronsa | ,(let [a (Double/valueOf Double/NaN)] (identical? a a)) |
| 19:22 | clojurebot | true |
| 19:22 | Bronsa | boxed NaNs compare identical |
| 19:23 | hiredman | ah, well, there you go |
| 19:25 | Bronsa | but now the question is why if they compare identical? PAM doesn't behave like PHM :P |
| 19:27 | Bronsa | ,(let [a (Double/valueOf Double/NaN)] (clojure.lang.Numbers/equal a a)) |
| 19:27 | clojurebot | false |
| 19:27 | Bronsa | and here's the answer |
| 19:31 | Bronsa | looks like Numbers/equal doesn't do pointer any pointer check but just unboxes the values and compares them |
| 19:31 | Bronsa | ,(let [a (Double/valueOf Double/NaN)] (identical? a a)) |
| 19:31 | clojurebot | true |
| 19:31 | Bronsa | ,(let [a (Double/valueOf Double/NaN)] (identical? (.doubleValue a) (.doubleValue a))) |
| 19:31 | clojurebot | false |
| 19:32 | hiredman | oh jvm |
| 19:32 | Bronsa | no idea why PAM uses Util.equivPred |
| 19:34 | Bronsa | well that was fun |
| 19:38 | Bronsa | ,(.equals Double/NaN Double/NaN) |
| 19:38 | clojurebot | true |
| 19:38 | Bronsa | TIL |
| 19:53 | elvis4526 | I have troubling understanding the difference between core.match and core.unify |
| 19:53 | hiredman | unification can be two way, pattern matching tends to be one way |
| 19:54 | elvis4526 | I have trouble seeing where matching the other way around could be useful |
| 19:54 | elvis4526 | Do you have an example ? |
| 19:54 | hiredman | it is useful for various tree searching things |
| 19:55 | hiredman | logic programming tends to be built on unification |
| 19:56 | hiredman | so core.logic's == |
| 19:56 | hiredman | it doesn't use unify, but it has its own unifier |
| 19:57 | hiredman | a unifier lets you say, I don't know what they two values are, but they are the same |
| 19:58 | elvis4526 | interesting its like algebra |
| 19:59 | hiredman | exactly |
| 19:59 | hiredman | some logic programming guys prefer to refer to it as relational programming |
| 20:00 | hiredman | because you specify relations between things (and then maybe search for a set of things with those relations) |
| 20:01 | hiredman | you often end up getting some like a unifier when implementing type inference, because you may not kow the types of terms in certain scopes, but you know how they relate |
| 20:01 | hiredman | something |
| 20:14 | numberten | can you add to prismatic schemas? for ex: take the json-coercion-matcher and add a datetime coercion rule to it? |
| 21:07 | gfredericks | numberten: there's no thrown?, you just have to catch things |
| 21:08 | numberten | gfredericks: that's what I ended up doing, thanks |
| 21:08 | numberten | figured I would check to see if there was an idiomatic nicer way :) |
| 21:08 | gfredericks | numberten: and you can write your own matchers with schema, you just have to study the code they used for json-coercion-matcher; it's a bit abstract/trippy |
| 21:08 | numberten | gfredericks: haha yeah.. I ended up just doing some manual coercion |
| 21:09 | numberten | if it becomes a pattern I'll see if I can abstract it out |
| 21:09 | gfredericks | numberten: I did a custom one to do keywordization and kebabization and UUIDization and DateTimeization and I love it |
| 21:10 | numberten | yeah it seems like it would be nifty |
| 21:11 | gfredericks | numberten: as for the let-bindings question, if it's constant why not put the let outside the for-all? |
| 21:11 | numberten | i wanted it out of local scope |
| 21:11 | numberten | something inbetween file-wide private and the for-all itself |
| 21:12 | gfredericks | (let [...] (prop/for-all [...] ...))? |
| 21:13 | numberten | I didn't realize you could do that |
| 21:13 | numberten | thanks :) |
| 21:14 | gfredericks | no problem, that's what I was trying to suggest at first |
| 21:15 | numberten | ah, I see |
| 21:48 | slester | Do most Clojurists seem to use OS X for development or Linux? I'm in the market for a new laptop... and yes, it's a weird question to ask, but just curious. I see a lot of MacBooks during talks on youtube. |
| 21:50 | TEttinger | slester: I think if you're doing JVM clojure dev, OS doesn't matter that much |
| 21:50 | TEttinger | JVM runs pretty much the same everywhere |
| 21:51 | TEttinger | clojurescript some tools may be better for server-y stuff if you are using an OS that has oriented itself for that, like Linux, but I don't know how much that matters. also linux drivers are, depending on brand, sometimes not good on laptops |
| 21:52 | TEttinger | generally smaller not-big-name parts are slower to get drivers |
| 21:53 | TEttinger | as in, if your hardware contains a name that has no english translations anywhere, expect english-speaking linux devs to be slower to release support for it, heh |
| 21:54 | slester | haha |
| 21:54 | slester | yeah, I know. I was just curious if there was a large leaning to OS X, or Windows, or *nix |
| 21:56 | TEttinger | however, if you're living in an island nation like new zealand, far away from major markets, your best bet for reasonable prices on laptops may be an online marketplace like, say, AliExpress, where many laptops are made in the same or similar factories as HP or Lenovo or whatnot but for whatever reason are unbranded with a major name |
| 21:57 | TEttinger | I've had surprisingly good experience buying tv sticks from AliExpress, the quality has been fine. one box came with a dead bug that had slipped in during transit, haha, but the device worked perfectly |
| 21:58 | TEttinger | for a long time that was the only place to buy them if they just came out |
| 21:58 | slester | I'm in the US, so that shouldn't be an issue, but ... yikes! |
| 21:58 | TEttinger | haha |
| 21:58 | TEttinger | yeah it was a silverfish, which seems like it slipped in on the american side |
| 21:59 | TEttinger | I don't know if they have the same kinds across the pacific |
| 21:59 | TEttinger | they eat paper and glue, bane of books |
| 22:00 | Jaood | slester: I would say most do dev in OS X and deploy to linux, they don't leave OS X because of the nice integration with hardware(macbooks) and a more polished desktop, some use linux VMs in OS X |
| 22:00 | slester | oh! silverfish aren't so bad, they're everywhere |
| 22:00 | Jaood | slester: depends on your preferences and what you are doing |
| 22:01 | TEttinger | also, reliable build quality from apple |
| 22:01 | TEttinger | and reliably higher prices |
| 22:01 | slester | I'm thinking just for sturdiness and dependability. My current laptop (3.5 years old now) was a 'gaming' one that feels pretty... flimsy? I don't know. It has a strange feel. |
| 22:01 | slester | macbooks and thinkpads have the kind of solid feel I like |
| 22:02 | Jaood | slester: If I recall well lein doesn't play nice in windows |
| 22:02 | slester | I'm on linux |
| 22:02 | slester | well I have windows 10 on a partition I only use if I need windows-specific apps |
| 22:03 | Jaood | slester: dell has some ubuntu certified laptops |
| 22:03 | TEttinger | I'm very very happy with the build quality on this MSI gaming laptop |
| 22:03 | slester | the thing I hate about my current linux setup is that switching languages/keyboards is awful |
| 22:03 | slester | I still haven't figured out how to get it to work |
| 22:03 | slester | OS X it's 3 clicks |
| 22:04 | atomi | slester, have you tried Cinnamon? |
| 22:04 | slester | atomi, nope, I haven't |
| 22:04 | slester | I'm on KDE5 |
| 22:04 | atomi | it's good imo |
| 22:04 | slester | I may look into it |
| 22:04 | TEttinger | I had a lenovo Y series that had just awful build quality, but once I 1) disabled the GPU by 2) installing windows server 2008 R2 as the OS, fresh install, and 2) disabled the windows audio driver because the sound card gets messed up on every lenovo it seems, it works fine. very long uptime, I use it as a server on a cooling pad. |
| 22:05 | TEttinger | http://www.techbargains.com/apple-macbook-pro-retina-deals#newsID441241 I have no idea if these are good deals for macs |
| 22:05 | TEttinger | considering there are 1/3 the price laptops elsewhere on there running win10 |
| 22:06 | slester | TEttinger, I'll check that out, but yeah, even a deeply discounted macbook is way expensive |
| 22:06 | TEttinger | http://www.techbargains.com/dell-inspiron-15-deals#newsID457636 |
| 22:06 | slester | plus I don't really like apple as a company |
| 22:06 | slester | but that's neither here nor there |
| 22:07 | slester | oh nice, they have 4k laptops :O |
| 22:07 | slester | clojuring in so many pixels!!! |
| 22:22 | slester | Andddd Linux just broke. Haha. |
| 23:02 | nicola | i have a list of actions to perform, each one being executed only on the success of the previous one (otherwise exit with some return message); is there an idiomatic way to write this in clojure without lots of nesting? i'm thinking something along the lines of the Maybe monad in haskell if it helps ... |
| 23:05 | johannbestowrous | you can do assertions at every action |
| 23:05 | johannbestowrous | and wrap the actions in a try catch |
| 23:06 | nicola | that would be very similar to what i'm doing right now |
| 23:06 | gfredericks | nicola: the maybe monad is a lot like some->; it's when you want the either monad that options get sparser |
| 23:07 | nicola | gfredericks: i'm not familiar with this, i'll look into it, thanks |
| 23:08 | nicola | (i mean i'm familiar with either monad in haskell, not sure about the clojure equivalent) |
| 23:18 | slester | any nice function to remove one matching value from a list? |
| 23:18 | slester | ,'(:a :a) |
| 23:18 | slester | for instance |
| 23:18 | clojurebot | (:a :a) |
| 23:18 | slester | to just remove one of those |
| 23:18 | johannbestowrous | you mean the first equality? |
| 23:19 | slester | Just one matching :a -- like disj but for a list, and just one element |
| 23:19 | slester | (= (some-fn '(:a :b) :a) '(b)) and also (= (some-fn '(:a :a) :a) '(:a)) |
| 23:21 | johannbestowrous | haha watch out some-fn is actually a core function just saw it today https://clojuredocs.org/clojure.core/some-fn |
| 23:21 | slester | ... whoops |
| 23:21 | slester | haha |
| 23:22 | slester | I meant generic function I am wanting :P |
| 23:23 | gfredericks | slester: it doesn't exist, probably because it would be inefficient for lists; e.g., should you be using a map instead? |
| 23:26 | TEttinger | ,(defn remove-first [coll] (let [sp (split-with (partial = :b) coll)] (concat (butlast (first sp)) (second sp)))) |
| 23:26 | clojurebot | #'sandbox/remove-first |
| 23:26 | TEttinger | ,(let [ls '(:a :b :a :b :a)] (remove-first ls)) |
| 23:26 | clojurebot | (:a :b :a :b :a) |
| 23:27 | TEttinger | damn |
| 23:27 | johannbestowrous | noice |
| 23:27 | TEttinger | not work |
| 23:27 | slester | I talk about getting a new laptop today, and then my computer crashes 3 times in a row. What'd I miss haha |
| 23:28 | TEttinger | ,(defn remove-first [coll item] (let [sp (split-with (partial not= item) coll)] (concat (butlast (first sp)) (second sp)))) |
| 23:28 | clojurebot | #'sandbox/remove-first |
| 23:28 | TEttinger | ,(let [ls '(:a :b :a :b :a)] (remove-first ls :b)) |
| 23:28 | clojurebot | (:b :a :b :a) |
| 23:28 | TEttinger | right. |
| 23:28 | TEttinger | ,(defn remove-first [coll item] (let [sp (split-with (partial not= item) coll)] (concat (first sp) (rest (second sp))))) |
| 23:28 | clojurebot | #'sandbox/remove-first |
| 23:28 | TEttinger | ,(let [ls '(:a :b :a :b :a)] (remove-first ls :b)) |
| 23:28 | clojurebot | (:a :a :b :a) |
| 23:29 | TEttinger | it's highly inefficient but if you need that behavior, sure |
| 23:29 | slester | oh awesome! here's my use case, maybe there's a better way |
| 23:29 | slester | in this game, we have a hand of 1-2 cards. cards can be duplicates. |
| 23:30 | slester | If I want to play a knight and the hand is '(:knight :knight), it doesn't matter which one I pick, and order doesn't matter either |
| 23:31 | TEttinger | (you may want to prefer vectors over quoted lists when using clojure for a few reasons, I'll get back to that later) |
| 23:31 | gfredericks | slester: you could keep a frequency map |
| 23:31 | gfredericks | ,(frequencies [:knight :knight]) |
| 23:31 | clojurebot | {:knight 2} |
| 23:31 | gfredericks | ^ that data structure |
| 23:31 | TEttinger | ,(frequencies [:knight :knight :dammit :gfredericks :ninja]) |
| 23:31 | clojurebot | {:knight 2, :dammit 1, :gfredericks 1, :ninja 1} |
| 23:32 | TEttinger | if using frequencies, this does become easier |
| 23:32 | TEttinger | ,(def hand {:knight 2 :king 1 :pawn 4}) |
| 23:32 | clojurebot | #'sandbox/hand |
| 23:33 | slester | how would I push a card into that? |
| 23:33 | gfredericks | (update m card-name inc) |
| 23:33 | gfredericks | ,(update hand :TEttinger (fnil inc 0)) |
| 23:33 | clojurebot | {:knight 2, :king 1, :pawn 4, :TEttinger 1} |
| 23:33 | TEttinger | god, 1.7 helps with that stuff a lot |
| 23:33 | gfredericks | forgot the fnil |
| 23:33 | slester | I thought I was being so good and choosing the right data type but I was so wrong |
| 23:34 | TEttinger | well it's interesting |
| 23:34 | TEttinger | quoted lists are really common in other lisps |
| 23:34 | TEttinger | along with using the behavior of quoting everything inside them |
| 23:34 | johannbestowrous | https://gist.github.com/jobez/27edc10dfe867deed82f here's a remove-first |
| 23:34 | TEttinger | ,'(I love pie) |
| 23:34 | clojurebot | (I love pie) |
| 23:35 | TEttinger | but they start having trouble with nesting and when you don't actually want to quote stuff |
| 23:35 | TEttinger | ,'(I love (+ 1 2)) |
| 23:35 | clojurebot | (I love (+ 1 2)) |
| 23:35 | gfredericks | slester: related vocabulary are "multiset" and "bag" |
| 23:36 | slester | gfredericks, as in 'things clojure doesn't have'? hehe |
| 23:36 | gfredericks | no things related to frequency maps |
| 23:37 | TEttinger | vectors work very well for data that needs random access, and are otherwise similar to seqs (IIRC if you call "(list 1 2 3)" it actually runs as its body "(seq 1 2 3)"). they conj at the end instead of at the beginning for seqs. |
| 23:39 | slester | TEttinger, seems reasonable |
| 23:39 | TEttinger | a multiset is, basically, a subcategory of associative maps |
| 23:39 | TEttinger | it has what would be the set's items as keys, so they are still unique, but has counts for values |
| 23:39 | slester | cool, I didn't make the connection until gfredericks made that comment |
| 23:39 | slester | :D |
| 23:40 | TEttinger | so if you have a non-strictly typed map implementation, you have multisets already, which is nice |
| 23:40 | TEttinger | (if you have a strictly typed one, you can do multisets for one kind of set entry) |
| 23:40 | gfredericks | you could imagine a multiset API similar to a set API instead of exposing it as a map |
| 23:41 | gfredericks | I'm sure there's a clojure library for this somewhere |
| 23:41 | TEttinger | flatland curates a number of useful libs, some for data structures. I love ordered collections myself, and I believe either flatland/ordered or amalloy/ordered is the most recent |
| 23:42 | TEttinger | I recently encountered a bizarre bug with a java demo I wrote for a gamedev lib to be used from clojure at some point |
| 23:42 | TEttinger | it generated the same dungeon layout in terms of walls, every time, with the same seed used every time |
| 23:43 | TEttinger | but on java 7, the water was in a different place than on java 8 |
| 23:43 | virmundi | hello |
| 23:43 | TEttinger | I couldn't figure it out... |
| 23:43 | TEttinger | hey virmundi |
| 23:43 | virmundi | does anyone know how to split a string on a hex value? I have a CSV style file where the split is 0x1F |
| 23:44 | TEttinger | virmundi: the string or the char? |
| 23:44 | virmundi | within the row. Rows are new line split |
| 23:44 | virmundi | the char |
| 23:44 | sdegutis | Why doesn't this work? (-> #(prn :hi) ()) |
| 23:44 | TEttinger | ,(clojure.string/split "\u001F" "hey\u001Fvirmundi\u001fhow is it going?") |
| 23:44 | clojurebot | #error {\n :cause "java.lang.String cannot be cast to java.util.regex.Pattern"\n :via\n [{:type java.lang.ClassCastException\n :message "java.lang.String cannot be cast to java.util.regex.Pattern"\n :at [clojure.string$split invoke "string.clj" 217]}]\n :trace\n [[clojure.string$split invoke "string.clj" 217]\n [sandbox$eval25 invoke "NO_SOURCE_FILE" 0]\n [clojure.lang.Compiler eval "Compile... |
| 23:45 | TEttinger | ,(doc clojure.string/split) |
| 23:45 | clojurebot | "([s re] [s re limit]); Splits string on a regular expression. Optional argument limit is the maximum number of splits. Not lazy. Returns vector of the splits." |
| 23:45 | sdegutis | ,(-> #(prn :hi) ()) |
| 23:45 | clojurebot | #error {\n :cause "Can't call nil"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.IllegalArgumentException: Can't call nil, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyzeSeq "Compiler.java" 6798]}\n {:type java.lang.IllegalArgumentException\n :message "Can't call nil"\n :at [clojure.lang.Compiler analyzeSeq "Compiler.java" 6783]}]\n :t... |
| 23:45 | virmundi | Thanks. I always forget about \u |
| 23:45 | gfredericks | ,(macroexpand-1 '(-> #(prn :hi) ()) |
| 23:45 | clojurebot | #<RuntimeException java.lang.RuntimeException: EOF while reading> |
| 23:45 | gfredericks | ,(macroexpand-1 '(-> #(prn :hi) ())) |
| 23:45 | clojurebot | (nil (fn* [] (prn :hi))) |
| 23:45 | TEttinger | ,(clojure.string/split "hey\u001Fvirmundi\u001fhow is it going?" #"\u001f") |
| 23:45 | clojurebot | ["hey" "virmundi" "how is it going?"] |
| 23:45 | gfredericks | sdegutis: ^ |
| 23:46 | gfredericks | I think the simple answer is the macro wasn't written to handle that case |
| 23:46 | gfredericks | I rewrote -> a couple years ago, am not sure if it did anything different before |
| 23:46 | TEttinger | ,() |
| 23:46 | clojurebot | () |
| 23:46 | sdegutis | gfredericks: oh ok |
| 23:47 | gfredericks | it's calling first on the empty list and getting nil and just going ahead with that |
| 23:47 | sdegutis | But it should in principle handle that case, right? |
| 23:47 | sdegutis | Like, it makes sense semantically as calling a function, right? |
| 23:47 | gfredericks | yeah you could certainly argue that |
| 23:47 | TEttinger | ,(-> #(prn :hi) (apply)) |
| 23:47 | clojurebot | #error {\n :cause "Wrong number of args (1) passed to: core/apply"\n :via\n [{:type clojure.lang.ArityException\n :message "Wrong number of args (1) passed to: core/apply"\n :at [clojure.lang.AFn throwArity "AFn.java" 429]}]\n :trace\n [[clojure.lang.AFn throwArity "AFn.java" 429]\n [clojure.lang.RestFn invoke "RestFn.java" 412]\n [sandbox$eval188 invoke "NO_SOURCE_FILE" 0]\n [clojure.lang.... |
| 23:47 | sdegutis | Okay. |
| 23:47 | gfredericks | I think deliver might work |
| 23:47 | TEttinger | ,(-> #(prn :hi) (apply ())) |
| 23:47 | clojurebot | :hi\n |
| 23:47 | gfredericks | ,(-> #(prn :hi) (deliver)) |
| 23:47 | clojurebot | #error {\n :cause "Wrong number of args (1) passed to: core/deliver"\n :via\n [{:type clojure.lang.ArityException\n :message "Wrong number of args (1) passed to: core/deliver"\n :at [clojure.lang.AFn throwArity "AFn.java" 429]}]\n :trace\n [[clojure.lang.AFn throwArity "AFn.java" 429]\n [clojure.lang.AFn invoke "AFn.java" 32]\n [sandbox$eval240 invoke "NO_SOURCE_FILE" 0]\n [clojure.lang.Com... |
| 23:48 | gfredericks | oh right |
| 23:48 | gfredericks | only for one-arg functions |
| 23:48 | TEttinger | TEttinger solved a weird thing! I'm happy |
| 23:48 | sdegutis | Although then again, the guiding purpose I have for wanting that probably doesn't extend very far beyond this one thing, and probably breaks more assumptions than it wins. |
| 23:48 | sdegutis | TEttinger: hahaha |
| 23:48 | TEttinger | and it works, which is kinda crazy. |
| 23:49 | virmundi | hanks |
| 23:49 | virmundi | thanks |
| 23:50 | gfredericks | consarnit I think I found another bug in goog.math.Integer |
| 23:50 | sdegutis | ,(-> #(prn :hi) (apply)) |
| 23:50 | clojurebot | #error {\n :cause "Wrong number of args (1) passed to: core/apply"\n :via\n [{:type clojure.lang.ArityException\n :message "Wrong number of args (1) passed to: core/apply"\n :at [clojure.lang.AFn throwArity "AFn.java" 429]}]\n :trace\n [[clojure.lang.AFn throwArity "AFn.java" 429]\n [clojure.lang.RestFn invoke "RestFn.java" 412]\n [sandbox$eval266 invoke "NO_SOURCE_FILE" 0]\n [clojure.lang.... |
| 23:51 | sdegutis | Clojure is closer to Common Lisp than Haskell. |
| 23:51 | sdegutis | :'( |
| 23:54 | scriptor | sdegutis: because it doesn't have function currying? |
| 23:55 | scriptor | that's because they chose to favor multi-arity function definitions |
| 23:55 | sdegutis | scriptor: sorry that's not what I meant |
| 23:56 | sdegutis | I meant, because Clojure favors exposing low-level implementation details as public APIs rather than high-level abstractions |
| 23:56 | sdegutis | Many functions in clojure.core are designed the way they are because efficiency and speed are considered more important than abstraction and purity to the Clojure team |
| 23:56 | sdegutis | By purity I don't mean in the FP sense, I meant in the cleanliness sense. |
| 23:57 | scriptor | can you give an example of low-level implementation leaking through the public API? |