2016-01-21
| 00:00 | luxbock | felixn_: I don't know Python that well but I think the big difference between transducers and generators is that transducers are source agnostic |
| 00:00 | luxbock | i.e. you can re-use the same code with sequences and channels |
| 00:01 | luxbock | and any other source that might come up in the future |
| 00:02 | baritonehands | so defprotocol for CRUD by id semantics, where one implementation is in memory ref, future implementation is some DB? |
| 00:02 | justin_smith | right |
| 00:02 | justin_smith | and then you could even have general game-logic code that calls the methods of that protocol |
| 00:03 | justin_smith | and if you do it right, that game-logic code can be completely stateless / functional |
| 00:03 | felixn_ | luxbock: if python had channels, I imagine it could work with that. generators seem to support the same API as transducers, so my thinking is just that they're built with HoF... which makes me "get it", unless what I'm saying is wrong, than I still don't get it XD |
| 00:03 | justin_smith | a bunch of functions that take a game, and return the next round of the game |
| 00:04 | baritonehands | justin_smith: not too much game logic, just state transitions mostly, and validation |
| 00:04 | baritonehands | waiting -> playing -> done |
| 00:04 | justin_smith | felixn_: for all X in clojure, X is higher order functions |
| 00:04 | justin_smith | baritonehands: your state transitions are what I called logic |
| 00:07 | baritonehands | justin_smith: so for actual file organization, what would you recommend? |
| 00:07 | baritonehands | where would by protocol and its implementations go, etc. |
| 00:08 | justin_smith | state management protocol gets its own namespace, each implementation of that protocol gets its own namespace, all validation and transition functions use the protocol methods but the protocol is the only code shared between any of these |
| 00:09 | justin_smith | so validate.clj requires state.clj and calls its methods, sql.clj requires state.clj and implements its methods, ref.clj requires state.clj and implements its methods, state.clj is very small, just defines the protocol. Then a namespace that brings the pieces together and starts all the code. |
| 00:10 | baritonehands | justin_smith: does my RESTful api fit into all of this? |
| 00:11 | justin_smith | it would be an implementation detail of that last namespace that it serves an API |
| 00:11 | felixn_ | baritonehands: if you're building an API, is there a need to build turtles all the way down? you could just keep the API code flat and straight forward |
| 00:12 | baritonehands | felixn_: The api code is also very generic. If I could reuse CRUD semantics there as well it would help |
| 00:13 | baritonehands | felixn_: Current api - https://github.com/baritonehands/avalon/blob/master/src/clj/avalon/api/games.clj |
| 00:13 | felixn_ | baritonehands: seems like a function that just builds endpoints would be sufficient |
| 00:13 | felixn_ | you'll drastically cut down on lines of code |
| 00:14 | baritonehands | felixn_: defresource is a macro, so I think it would have to use a macro to generate |
| 00:16 | justin_smith | baritonehands: my one bit of feedback on that api namespace is that there is code in that namespace that relies of the fact that the game state is in a ref |
| 00:16 | justin_smith | otherwise it's an api :) |
| 00:17 | baritonehands | justin_smith: I don't think it relies on games being a ref. I only ever call functions in the games namespace. Never reference games ref directly. |
| 00:18 | justin_smith | baritonehands: dosync |
| 00:18 | baritonehands | ah, yeah, games and people need to be updated in the same transaction |
| 00:18 | justin_smith | for sql this would be some transaction holding function instead |
| 00:18 | justin_smith | point is, it's a leaked detail |
| 00:19 | baritonehands | justin_smith: Yeah, hmm |
| 00:20 | justin_smith | if you want the implementation to be abstracted, and for it to handle state with methods owned by the data state, then I'd do the protocol as I mentioned before, and let the protocol methods handle the transaction logic as needed |
| 00:21 | baritonehands | justin_smith: so that means the protocol needs a method to create and relate two different references/db entities |
| 00:21 | justin_smith | probably, yes |
| 00:28 | justin_smith | in fact you could simply not expose the data objects themselves, and just expose unique ids, then you don't need to expose any transaction function at all, the implementation could use transactions as apropriate, implicitly |
| 00:35 | neoncontrails | Is there a better way to do this? |
| 00:36 | neoncontrails | ,(read-string ((comp str str/lower-case) (reduce into #{} '[(:FOO :BAR :BAZ)]))) |
| 00:36 | clojurebot | #error {\n :cause "No such namespace: str"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.RuntimeException: No such namespace: str, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyze "Compiler.java" 6688]}\n {:type java.lang.RuntimeException\n :message "No such namespace: str"\n :at [clojure.lang.Util runtimeException "Util.java" 221]}]\n ... |
| 00:36 | neoncontrails | ,(read-string ((comp clojure.string clojure.string/lower-case) (reduce into #{} '[(:FOO :BAR :BAZ)]))) |
| 00:36 | clojurebot | #error {\n :cause "clojure.string"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.ClassNotFoundException: clojure.string, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyze "Compiler.java" 6688]}\n {:type java.lang.ClassNotFoundException\n :message "clojure.string"\n :at [java.net.URLClassLoader$1 run "URLClassLoader.java" 366]}]\n :trace\... |
| 00:38 | neoncontrails | Hmmm. Not sure how to fix without importing clojure.string. But the expected output is #{:baz :bar :foo} |
| 00:51 | baritonehands | justin_smith: How do I reference the memdb implementation where I need it, but only reference the crud protocol? |
| 00:52 | baritonehands | (defprotocol CRUD |
| 00:52 | baritonehands | (create [entity]) |
| 00:52 | baritonehands | (get [id]) |
| 00:53 | baritonehands | (save [id updates]) |
| 00:53 | baritonehands | (delete [id])) |
| 00:53 | baritonehands | ,(defn create-db [] |
| 00:53 | baritonehands | (let [db (ref {})] |
| 00:53 | clojurebot | #<RuntimeException java.lang.RuntimeException: EOF while reading> |
| 00:53 | baritonehands | (reify CRUD |
| 00:53 | baritonehands | (create [entity] |
| 00:53 | baritonehands | (let [id (str (java.util.UUID/randomUUID))] |
| 00:53 | baritonehands | (dosync (alter db assoc id (assoc entity :id id))) |
| 00:54 | baritonehands | entity)) |
| 00:54 | baritonehands | (get [id] |
| 00:54 | baritonehands | (@db id)) |
| 00:54 | baritonehands | (save [id updates] |
| 00:54 | baritonehands | (dosync (alter db update-in [id] merge updates))) |
| 00:54 | baritonehands | (delete [id] |
| 00:54 | baritonehands | (dosync (dissoc db id)))))) |
| 00:54 | amalloy | baritonehands: long pastes to a pastebin, please, such as gist.github.com |
| 00:56 | baritonehands | justin_smith: https://gist.github.com/baritonehands/b75dc69242948308ff3d |
| 01:02 | nys- | where does the nrepl-port file go |
| 02:55 | autogen_ | hey guys |
| 03:02 | alex`` | hey there |
| 03:43 | devangshah | alexyakushev: i have completed the incremental build project and have it approved... |
| 03:44 | devangshah | https://github.com/celeritas9/lein-droid/tree/inc-build |
| 03:44 | devangshah | shall i create the PR? |
| 03:45 | devangshah | what would you suggest…? I want to have it merged.. :-) |
| 03:59 | jonathanj | what's the quickest dirtiest way to get the current system timestamp as a string? |
| 03:59 | jonathanj | apparently System/currentTimeMillis doesn't exist, despite javadocs telling me it does, am I missing something? |
| 04:00 | jonathanj | java.lang.RuntimeException: Unable to find static field: currentTimeMillis in class java.lang.System |
| 04:04 | ridcully_ | ,(System/currentTimeMillis) |
| 04:04 | clojurebot | 1453367011585 |
| 04:09 | TEttinger | jonathanj: were you doing: |
| 04:09 | TEttinger | ,System/currentTimeMillis |
| 04:09 | clojurebot | #error {\n :cause "Unable to find static field: currentTimeMillis in class java.lang.System"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.RuntimeException: Unable to find static field: currentTimeMillis in class java.lang.System, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyze "Compiler.java" 6688]}\n {:type java.lang.RuntimeException\n ... |
| 04:09 | TEttinger | it is a static method |
| 04:10 | TEttinger | I can see it could have been either way though, |
| 04:10 | TEttinger | it makes sense as a field and method |
| 04:29 | Wojciech_K | Why unquote and syntax-quote are in diffrent namespaces? |
| 04:50 | neoncontrails | Wojciech_K: hehehe. They're very different in scope. If you're not sure which one you want, use quote |
| 04:51 | Wojciech_K | neoncontrails, I use syntax-quote with conjuction with unquote, the stange thing is |
| 04:51 | Wojciech_K | unquote and quote are in clojure.core |
| 04:52 | Wojciech_K | while syntax-quote is in clojure.tools.reader |
| 04:52 | Wojciech_K | syntax-quote and quote are more similar to each other than to unquote |
| 04:58 | neoncontrails | syntax-quote resolves symbols to their values in the namespace it gets called by. Between consenting adults, it's fine, but it's possible to do horrible things to other namespaces if used wrong |
| 05:00 | Wojciech_K | right, thanks |
| 05:07 | jonathanj | TEttinger: oh, you're probably right, I forgot to call it |
| 05:07 | jonathanj | how can i create a List from Clojure? |
| 05:07 | jonathanj | a List<String> to be precise |
| 05:07 | neoncontrails | ,'() |
| 05:07 | clojurebot | () |
| 05:07 | jonathanj | neoncontrails: not a list, a java.util.List |
| 05:09 | jonathanj | i have a function whose signature is List<String> can i just pass ["" ...] to that? |
| 05:09 | noncom | clojure seqs implement List ? i dont' remember for sure |
| 05:10 | TEttinger | ,(java.util.ArrayList. [1 2 3]) |
| 05:10 | clojurebot | [1 2 3] |
| 05:10 | TEttinger | ,(java.util.ArrayList. '(1 2 3)) |
| 05:10 | clojurebot | [1 2 3] |
| 05:10 | noncom | looks like they do |
| 05:11 | TEttinger | not sure if vector or seq implement List. ArrayList takes a Collection IIRC, so more general |
| 05:11 | TEttinger | ,(java.util.ArrayList. #{1 2 3}) |
| 05:11 | clojurebot | [1 3 2] |
| 05:11 | noncom | ,(instance? java.util.List []) |
| 05:11 | clojurebot | true |
| 05:11 | noncom | ,(instance? java.util.List '()) |
| 05:11 | clojurebot | true |
| 05:11 | TEttinger | ah good then |
| 05:12 | TEttinger | ,(instance? java.util.List [1]) |
| 05:12 | clojurebot | true |
| 05:12 | TEttinger | ,(instance? java.util.List (range)) |
| 05:12 | clojurebot | true |
| 05:12 | TEttinger | whaaaaat |
| 05:12 | noncom | cool. lists are rather widespread! |
| 05:12 | noncom | well, can't a lazy seq implement a list ? :) |
| 05:12 | TEttinger | ,(class (range)) |
| 05:12 | clojurebot | clojure.lang.Iterate |
| 05:13 | noncom | (.add (range) 1) |
| 05:13 | noncom | ,(.add (range) 1) |
| 05:13 | clojurebot | #error {\n :cause nil\n :via\n [{:type java.lang.UnsupportedOperationException\n :message nil\n :at [clojure.lang.ASeq add "ASeq.java" 151]}]\n :trace\n [[clojure.lang.ASeq add "ASeq.java" 151]\n [sun.reflect.NativeMethodAccessorImpl invoke0 "NativeMethodAccessorImpl.java" -2]\n [sun.reflect.NativeMethodAccessorImpl invoke "NativeMethodAccessorImpl.java" 57]\n [sun.reflect.DelegatingMethodA... |
| 05:13 | noncom | hehe |
| 05:13 | jonathanj | what is a java.util.List<String> vs a java.util.List? |
| 05:13 | noncom | unsup op, what i expected |
| 05:13 | noncom | jonathanj: same |
| 05:13 | jonathanj | eh? |
| 05:13 | TEttinger | jonathanj: generics like <String> only apply in java source, they're erased in bytecode |
| 05:13 | jonathanj | what is a java.util.List<String> vs a java.util.List<Turnip> then? |
| 05:13 | noncom | same |
| 05:13 | jonathanj | oh okay |
| 05:14 | jonathanj | sorry, i don't JVM |
| 05:14 | TEttinger | it's weird in any language, the generic erasure |
| 05:14 | noncom | jonathanj: so just be aware that something may brake in runtime if the types are not friends |
| 05:14 | TEttinger | there's a reason for it, I assume, but it's still weird |
| 05:14 | noncom | the reason is always performance |
| 05:16 | TEttinger | hence why java.util.Random is at least 5x slower than a non-thread-safe linear congruential pseudo-random generator? |
| 05:16 | TEttinger | the reason there is thread safety |
| 05:17 | noncom | hmm |
| 05:17 | TEttinger | LCGs are supposed to be among the fastest RNG types, which sorta helps make up for their lousy quality |
| 05:17 | noncom | oh maybe, i don't know this matter for sure |
| 05:18 | TEttinger | I've been in RNG land recently. I had a dream last night about an RNG truncating instead of casting to int, so all the numbers it made were usually "about a billion" |
| 05:19 | noncom | :D |
| 05:19 | TEttinger | the number it returned was that text |
| 05:19 | TEttinger | good ol' dream code |
| 05:19 | noncom | omg lol :D |
| 07:26 | neoncontrails | Are tail calls acceptable if the stack depth is bounded? Say, if the function is guaranteed to terminate in 3 recursions or less |
| 07:29 | gfredericks | neoncontrails: you're wondering about the function calling itself by name instead of using recur? |
| 07:31 | neoncontrails | gfredericks: yup. Discouraged or actually risky? |
| 07:35 | neoncontrails | My recursive case-analysis works great for almost all inputs... but with an interesting exception. It fails whenever a string contains a single quotation mark , e.g. "didn't" |
| 07:37 | neoncontrails | I wonder if it might be related. The individual functions I'm passing the inputs to all work, so I wonder if it's the tail call... |
| 08:01 | oracle123 | what's CLOJURE_HOME ? I am using CLOJURE_HOME ,and let set it? but in the document for socket REPL, it gives some code to run under CLOJURE_HOME, but how to set it? |
| 08:19 | ridcully_ | oracle123: CLOJURE_HOME is most likely an environment variable? could you please post the link, what "document" is meant? |
| 08:20 | neoncontrails | Figured out the issue I was having earlier. Strings with single quotes (e.g. "didn't") break the SQL query, which makes sense. Is there a clever way to transliterate the single quote so I can recover the original string pretty easily when I need the literal value? |
| 08:24 | ToxicFrog | neoncontrails: use stored procedures instead, stop caring about escaping your inputs to be to SQL-safe? |
| 08:28 | neoncontrails | ToxicFrog: I think I'm on the right track then. The ` character doesn't appear to break SQL, is it safe to translate ' -> `? |
| 08:28 | ToxicFrog | neoncontrails: what? That's the complete opposite of what I suggested. |
| 08:28 | neoncontrails | I know ` is special in Clojure, but I don't think that should matter in the string |
| 08:29 | neoncontrails | ToxicFrog: sorry could you clarify what you meant then? "Stored procedures" could mean almost anything |
| 08:29 | ToxicFrog | Also, how will you handle strings that naturally include ` in them? |
| 08:29 | ToxicFrog | SQL stored procedures. |
| 08:30 | neoncontrails | Ooh I see. This is my first db app, I didn't know SQL had such things |
| 08:30 | ToxicFrog | Aka prepared statements or parameterized queries. |
| 08:30 | ToxicFrog | You write the query in SQL as a function, then call it from clojure passing in the parameters needed. |
| 08:31 | ToxicFrog | No escaping is needed, the parameters are treated as raw data even if they contain characters that would normally be special to SQL. |
| 08:33 | ToxicFrog | It requires a bit more setup up front, but it protects against SQL injection attacks, frees you from worrying about correctly escaping your stuff even if injection isn't a concern, and if you're worried about qps, it's also faster than assembling the query ex nihilo each time. |
| 08:33 | neoncontrails | Oh cool that sounds a lot more sane than what I'm currently doing. Thanks for the suggestion |
| 08:36 | ToxicFrog | Ok, it's been a while; parameterized queries and stored procedures are related but are not the same thing. |
| 08:36 | ToxicFrog | Stored procedures are written up front and stored in the DB. |
| 08:36 | ToxicFrog | Parameterized queries can be created on the fly, and might look something like this (details depend on implementation): |
| 08:37 | ToxicFrog | (sql-query-with-params "SELECT ? FROM users WHERE name == ?" field-name user-name) |
| 08:37 | ToxicFrog | field-name and user-name shouldn't be escaped and are correctly spliced into the command where the ?s appear. |
| 08:37 | ToxicFrog | neoncontrails: ^ |
| 08:38 | ToxicFrog | neoncontrails: if you're using JDBC, it looks something like this: http://rosettacode.org/wiki/Parametrized_SQL_statement#Clojure |
| 08:40 | neoncontrails | ToxicFrog: awesome, I was just about to ask about jdbc. Thanks for the examples, this is really helpful |
| 08:48 | neoncontrails | ToxicFrog: Success! |
| 08:48 | neoncontrails | Thanks again, I had no idea this was a thing. |
| 08:51 | jsabeaudry | What's the status with incanter? |
| 08:52 | oracle123 | about the clojure home, sorry it's not mean CLOJURE_HOME, but just clojure home, the doc says |
| 08:52 | oracle123 | The simplest way to launch a Clojure repl is to use the following command line from within Clojure’s home directory: |
| 08:52 | oracle123 | |
| 08:52 | oracle123 | java -cp clojure.jar clojure.main |
| 08:53 | oracle123 | the doc is here http://clojure.org/reference/repl_and_main#_launching_a_socket_server |
| 08:53 | oracle123 | but I am using lein, so where should I run the java -cp clojure.jar clojure.main? |
| 09:04 | jsabeaudry | oracle123, if you use lein you dont need to run that |
| 09:10 | oracle123 | I want to start up a socket REPL in clojure 1.8, there is no doc about how to start it in lein. only show how to start it up in java. |
| 09:11 | wink | that's because 1.8 is like 2 days old |
| 09:12 | wink | I'm still trying to find out what this new socket REPL's benefits are |
| 09:14 | oracle123 | I could telnet and send command to it. Maybe we could also do the same in Nrepl. |
| 09:15 | oracle123 | if I start an clojure app which tightly loop doing something, if I connect to it using repl, how will it repsonse? since it's busy working in a tight loop, will it kicks off a service thread accept request and reply? |
| 09:16 | ToxicFrog | neoncontrails: you're welcome! |
| 09:16 | pbx | is there a 'lein version' equivalent that tells me the installed clojure version? |
| 09:17 | oracle123 | lein version won't tell the version of clojure, and in the project.clj, we could define different version of clojure |
| 09:18 | oracle123 | so it's depends on the proejct.clj, it can't give a fixed version. |
| 09:19 | hyPiRion | pbx: `clojure -e '(clojure-version)'` or `lein run -m clojure.main -e '(clojure-version)'` |
| 09:19 | wink | `lein version` would also be ambigous depends on whether it is called inside a project dir or not |
| 09:19 | wink | i.e. would you want your project clojure version, or the one lein uses? |
| 09:25 | hyPiRion | oracle123: You can change the lein repl version to 1.8.0 via https://github.com/technomancy/leiningen/blob/master/doc/PROFILES.md#replacing-default-repl-dependencies and then run something like `JVM_OPTS='-Dclojure.server.repl={:port 5555 :accept clojure.core.server/repl}' lein repl` |
| 09:25 | hyPiRion | This should start a socket which you can connect over via `telnet 127.0.0.1 5555` |
| 09:28 | neoncontrails | ToxicFrog: I think this should be possible, but just to make sure... any reason I couldn't just use the (sql/execute! ... ) method to insert the name, and use update! to populate the fields? |
| 09:32 | ToxicFrog | neoncontrails: I'm not sure what you mean by "use sql/execute! to insert the name |
| 09:33 | ToxicFrog | neoncontrails: that said, I have a suspicion that the example in (doc sql/update!) or https://github.com/clojure/java.jdbc/blob/master/src/main/clojure/clojure/java/jdbc.clj#L1042 will answer your question |
| 09:37 | oracle123 | hi hyPiRion, what I am trying to do is, run a clojure app using lein run with remote repl enabled at home, then I could control its run time behaviou from outside, such as define as var using "def", and connect from another computer, modify the var value to change how the app runs. |
| 09:37 | oracle123 | but using your approach, it starts a lein repl, it doesn't run my code. |
| 09:38 | oracle123 | normally I am running using "lein run" |
| 09:40 | beaky | hello |
| 09:40 | neoncontrails | ToxicFrog: I'm wondering if I can compose those calls to avoid restructuring my map as an ordered seq. This works just fine: "(sql/execute! spec ["UPDATE mydb SET name = ?" "it's"]) Can I then populate it with (sql/update! spec :mydb {:name "it's"} ["fieldA = ?" 0]), or do the fields need to be declared in execute? |
| 09:40 | beaky | is clojure enterprise ready |
| 09:41 | ToxicFrog | neoncontrails: yes, and that's pretty much exactly the example given in (doc sql/update!) |
| 09:42 | ToxicFrog | In fact, that update! call of yours basically turns into: (sql/execute! spec ["UPDATE mydb SET name = ? WHERE fieldA = ?" "it's" 0]) |
| 09:42 | powered | JVM is good enough for enterprises, and clojure uses JVM so I'd say yes beaky |
| 09:57 | pseudonymous | So I'm trying to retrofit my project with tests. Is there any way to mock/monkeypatch calls ? I'd like not to actively call the database. I looked into bindings but those only apply to vars (not imports?) which must be declared dynamic beforehand |
| 09:58 | tdammers | mocking databases is hilariously cumbersome |
| 09:58 | tdammers | if you want simulation tests, I suggest just running them against a real database (but not one that you care about); clear it out and fill it with whatever fixture you want before running the test, and then just point your application to it |
| 09:58 | tdammers | for unit tests, things are trickier |
| 09:59 | pseudonymous | tdammers: would not be surprised. I've given up testing many times because pretty much all my projects use databases heavily... |
| 10:00 | tdammers | I think a reasonable way to go about it is to wrap your database in a low-level-ish data access layer, and mock *that* |
| 10:00 | tdammers | and then use simulation tests against a test database to cover you bases |
| 10:01 | tdammers | then the only problem you might have is that your data access layer might break in ways that you cannot easily detect using your unit tests |
| 10:01 | tdammers | so the trick is to keep that layer small and simple |
| 10:16 | alex`` | guys, what's the proper way of evaluating a vector passed to a macro? i'm getting the annoying "can't create ISeq from symbol" error while trying to map through the vector |
| 10:17 | justin_smith | alex``: macros can only use data that is present at compile time |
| 10:18 | justin_smith | you have to write the macro such that the data is only mapped over by the resulting code, and not accessed by the code generation |
| 10:20 | justin_smith | simple example (defmacro m [f coll] (map f coll)) won't work because coll is accessed by map at compile time, (defmacro m [f coll] (list 'map f coll)) will work, because map is not called on coll until runtime, and coll is not accessed by the macro itself |
| 10:21 | alex`` | understand |
| 10:21 | alex`` | but i need to map the data to generate code |
| 10:21 | justin_smith | alex``: then the data needs to be present at compile time |
| 10:22 | alex`` | if i write (defmacro [& args]) it works, but saying (defmacro [args]) doesn't |
| 10:22 | jonathanj | java.lang.IllegalArgumentException: No matching method: asList |
| 10:22 | jonathanj | trying to do (java.util.Arrays/asList ...) |
| 10:22 | jonathanj | it would be useful if this error told me what it tried to match |
| 10:23 | justin_smith | ,(java.util.Arrays/asList (into-array [1 2 3])) |
| 10:23 | clojurebot | [1 2 3] |
| 10:23 | justin_smith | ,(type (java.util.Arrays/asList (into-array [1 2 3]))) |
| 10:23 | clojurebot | java.util.Arrays$ArrayList |
| 10:23 | jonathanj | oh, is there something i should know about Java varargs functions? |
| 10:24 | justin_smith | jonathanj: varargs methods really take all the extra args as an array |
| 10:24 | jonathanj | okay, good to know |
| 10:24 | justin_smith | being picky about method / function here because they are different things in this world |
| 10:24 | jonathanj | except that didn't help me debug this stupid problem *cry* |
| 10:25 | jonathanj | (clojure.java.io/copy) doesn't do any encoding translation, does it? it's just straight bytes from a to b? |
| 10:25 | justin_smith | you can give an :encoding arg if you want it to convert |
| 10:26 | justin_smith | it depends on if you are going byte->byte byte->char, char->byte, char->char, iirc only the middle two need the encoding |
| 10:26 | jonathanj | i'm trying to figure out why trying to mimic <https://github.com/apache/pdfbox/blob/2.0.0-RC2/tools/src/main/java/org/apache/pdfbox/tools/ExtractImages.java#L301> is filling my file with weird junk that definitely isn't image data |
| 10:26 | jonathanj | justin_smith: it's a copy from InputStream to File |
| 10:26 | justin_smith | but it defaults to utf-8 which should usually be correct on sane systems |
| 10:26 | jonathanj | it's binary data, i definitely don't want any decoding/encoding to happen |
| 10:26 | justin_smith | jonathanj: inputstream to file is byte->byte so you are fine |
| 10:27 | justin_smith | right, you don't have chars on either side, so no worries |
| 10:27 | jonathanj | i was hoping to hear "you're a moron, you are supposed to do X" and then i'd be done debugging this |
| 10:27 | justin_smith | copy just hase the :encoding option because it can handle chars too |
| 10:27 | justin_smith | haha |
| 10:28 | justin_smith | jonathanj: I'll look out for reasons to call you a moron then |
| 10:28 | jonathanj | thanks, you're a true friend |
| 10:28 | jonathanj | dump-1: DOS executable (device driver) |
| 10:28 | jonathanj | *argh* |
| 10:29 | jonathanj | i've been fighting with pdfbox and java for a whole day trying to debug this nonsense |
| 10:29 | justin_smith | so the headers aren't coming out right? |
| 10:29 | justin_smith | have you tried checking cmp to see where the first differing byte is? |
| 10:29 | jonathanj | the data seems to be complete garbage |
| 10:30 | jonathanj | it seems like 99% of the file is \377 |
| 10:30 | jonathanj | whatever that is, probably 0xff? |
| 10:31 | justin_smith | oh, weird |
| 10:31 | jonathanj | justin_smith: i'm trying to extract the images from a PDF, i'm just basing my code on that pdfbox code but i'm not getting anything even remotely correct |
| 10:31 | ToxicFrog | \377 is 0xFF in octal, yeah |
| 10:31 | humanbsd | Sorry for the off-topic: Anyone of you people are playing sauerbraten? |
| 10:31 | ToxicFrog | Not-entirely-joking suggestion: shell out to pdfimages(1) |
| 10:32 | justin_smith | jonathanj: so I assume you have a setup where you have a pdf generated with a known image etc. |
| 10:33 | jonathanj | justin_smith: it's such a long sad story, i'm trying to recompress the image in the PDF but i want the original image data so i can do something like estimate the JPEG quality (based on the qtables) |
| 10:33 | jonathanj | if i didn't need the original stream, i'd just use the method that gives me a BufferedImage |
| 10:34 | justin_smith | jonathanj: right, I was just thinking if I were trying to do this, I would start with a known image, and a pdf I made with that image in it, so I could look at differences between what is extracted and the original |
| 10:34 | jonathanj | i think at this point, it's probably as much work to calculate the quality than to just always resave the image and throw it away if it's bigger |
| 10:35 | jonathanj | justin_smith: that might help if the data resembled something other than garbage |
| 10:35 | justin_smith | jonathanj: well, when you have something correct to compare it too, that can only add information right? |
| 10:35 | jonathanj | justin_smith: i dunno, something weird is happening, guess i'll bash my head against it |
| 10:35 | jonathanj | justin_smith: i dunno, can it? |
| 10:36 | jonathanj | justin_smith: for some reason this data is all exactly the same size (for all different images) but `pdfimages -list` shows them as definitely not the same size |
| 10:36 | justin_smith | jonathanj: the extra 0xff makes me think that somewhere something is taking bytes and making them 16 bit characters (what the vm uses internally) and then you are outputting bytes derived from those, so it would be twice as much output, and every other byte would be 0xff |
| 10:36 | justin_smith | that's just a wild guess though |
| 10:37 | jonathanj | i thought that might be the case too but then i wouldn't expect the files to all be the same size |
| 10:37 | justin_smith | well, every other byte would be 0xff or 0x00 (sign extension...) |
| 10:37 | justin_smith | jonathanj: could be more than one thing is wrong here :) |
| 10:38 | jonathanj | justin_smith: yes, i think that may well be a possibility |
| 10:39 | justin_smith | jonathanj: how about, for debugging purposes, make an "image" that's just 0xdeadbeef over and over, and another that is just 0xfeedcafe over and over, then try extracting the two - if the output has any relation to the input at least those would be recognizable even mangled |
| 10:39 | justin_smith | well, packing them into a pdf, and then extracting them, of course |
| 10:52 | jonathanj | oh well i fixed it |
| 10:52 | justin_smith | "oh well" haha |
| 10:53 | jonathanj | apparently PDXObject.createInputStream creates an input stream containing the data for the entire XObject as it appears in the PDF |
| 10:53 | jonathanj | whereas PDFObject.getStream.createInputStream creates an input stream for only the embedded object data |
| 10:53 | justin_smith | oh, nice |
| 10:53 | justin_smith | and also weird |
| 10:54 | jonathanj | yeah, i didn't even expect that to work and the docs don't really seem to explain this |
| 10:54 | jonathanj | thanks, justin_smith |
| 11:00 | tos9 | is there some atriviality to apply'ing interop-ed things |
| 11:00 | tos9 | e.g. (apply (.log js/console) whatever) or (apply .someJavaThing ... |
| 11:04 | justin_smith | tos9: methods are not functions, apply is for applying function args |
| 11:05 | tos9 | justin_smith: Hm, OK -- is there another thing that means that? |
| 11:05 | justin_smith | among other issues, apply takes a collection as argument, and the argument count and types will indicate different methods (unlike a function call where you might get a different arity but it is still the same function) |
| 11:05 | justin_smith | tos9: no |
| 11:06 | tos9 | oh, right, multimethods... that's annoying. |
| 11:06 | beaky | hello |
| 11:06 | beaky | how do i dockerize a clojure app |
| 11:06 | justin_smith | well, multimethods are something different - but method overloading is the issue here, yes |
| 11:06 | tos9 | justin_smith: So given some arguments, there's no generic way to call an interop callable thing with them? |
| 11:07 | justin_smith | beaky: make a docker image that has a jvm in it and a script that starts up your jar? |
| 11:07 | justin_smith | not that I know of |
| 11:07 | ystael | beaky: well, the simplest thing you can do is "java -jar uberjar.jar" as your CMD |
| 11:07 | ystael | there is a "clojure:1.8" image in hub |
| 11:07 | justin_smith | right, you hardly even need docker for that |
| 11:08 | tos9 | justin_smith: Interesting. Thank you. |
| 11:08 | justin_smith | tos9: wait, you mentioned js/console above - I have been talking about jvm clojure |
| 11:08 | tos9 | justin_smith: Yeah -- which doesn't ahve overloading, so this should be simpler there? |
| 11:08 | justin_smith | tos9: with js clojure, there are js methods that call a js function with a coll as args |
| 11:08 | tos9 | justin_smith: (But I somewhat intentionally asked it generically) |
| 11:08 | justin_smith | forget how it works, but it is a thing |
| 11:08 | justin_smith | right, not generically a thing, won't work on the jvm, but js has a way to do it |
| 11:08 | tos9 | Yeah I can probably use like .apply from JS land |
| 11:09 | tos9 | OK, cool |
| 11:13 | beaky | ah |
| 11:16 | tos9 | How to I tell lein to put ~/.lein someplace else |
| 11:16 | tos9 | man lein is not a thing :/ |
| 11:17 | justin_smith | tos9: lein help |
| 11:18 | tos9 | justin_smith: it just prints usage info, and lein readme just prints.. the readme. I don't see anything explaining any environment variables lein respects, or config info, etc. etc. |
| 11:21 | justin_smith | tos9: config info is partially in lein help profiles, but what you want is in the sample project.clj (and yes it should also be in regular docs) https://github.com/technomancy/leiningen/blob/master/sample.project.clj#L489 |
| 11:21 | tos9 | Ah, awesome. |
| 11:21 | tos9 | justin_smith: Thank you! |
| 11:22 | justin_smith | tos9: see also "lein help sample | grep HOME" |
| 11:24 | justin_smith | "lein help sample" is full of amazing info (though it might be more convenient to just go to that github page) |
| 11:25 | tos9 | yeah I read it a few times yesterday but was too overwhelmed at the time by all the settings to play with :) |
| 11:25 | tos9 | I'll have to read it again when I shed some noobiness. |
| 11:25 | justin_smith | heh, and of course the env vars are at the bottom |
| 11:25 | justin_smith | tos9: it's a reference document, I've never read it start to finish |
| 11:25 | justin_smith | just like most man pages in fact |
| 11:28 | jonathanj | i really wish i could map (.foo) without a lambda/anonymous function |
| 11:29 | justin_smith | jonathanj: blame java for methods not being first class data, and needing some Object to carry them |
| 11:30 | justin_smith | on a bytecode level a method isn't something you can pass as an arg |
| 11:32 | justin_smith | jonathanj: the obvious rejoinder there is that clojure could wrap it for convenience reasons, but in general clj likes to stay "close to the metal" in terms of how it uses the vm, and not use implicit abstractions for interop |
| 11:34 | jonathanj | actually, now that you say that, istr some kind of function to turn a method into a clojure function, but i can't remember the name (or exactly what it does) |
| 11:34 | beaky | i love the cloud |
| 11:34 | gfredericks | #method .foo |
| 11:34 | beaky | oops wrong channel |
| 11:34 | gfredericks | ,(doc memfn) |
| 11:34 | clojurebot | "([name & args]); Expands into code that creates a fn that expects to be passed an object and any args and calls the named instance method on the object passing the args. Use when you want to treat a Java method as a first-class fn. name may be type-hinted with the method receiver's type in order to avoid reflective calls." |
| 11:34 | jonathanj | that's the one |
| 11:34 | justin_smith | memfn is depricated though |
| 11:34 | justin_smith | it's better to just use #(.foo %) |
| 11:35 | gfredericks | because of default-reflection? |
| 11:35 | gfredericks | well that's no different from #(.foo %) I guess |
| 11:35 | gfredericks | I'd never heard that it was deprecated |
| 11:35 | justin_smith | somehow #(.foo %) can be optimized where memfn isn't, I forget the details it's been ages since I learned about this... |
| 11:36 | gfredericks | surely you could implement memfn with #() |
| 11:36 | justin_smith | gfredericks: now I'm wondering if it was "deprecated" or just "there's no case where using it is better than just using a lambda" |
| 11:37 | gfredericks | that sounds a lot more likely |
| 11:37 | gfredericks | it makes you feel clever |
| 12:51 | cap10morgan_ | Is clojurebot's source code on GitHub somewhere? |
| 12:51 | justin_smith | yes |
| 12:51 | justin_smith | https://github.com/hiredman/clojurebot |
| 12:51 | cap10morgan | justin_smith: cool, was just going to ask if that was the one. thanks! |
| 14:14 | elvis4526 | Is there an alternative to this: (alter-var-root #'get-all-users (fn [of] (fn [request] "poo"))) |
| 14:14 | elvis4526 | |
| 14:14 | elvis4526 | Im the repl and i want to redefine a var assigned to a function inside a namespace |
| 14:15 | elvis4526 | (or perhaps its the function that is assigned to the var) |
| 14:16 | justin_smith | elvis4526: (intern 'some-ns 'some-symbol value) |
| 14:17 | justin_smith | and you can also do (in-ns 'random-ns) (def ...) (in-ns 'other-ns) |
| 14:18 | justin_smith | ,(intern 'some-ns 'some-var 42) |
| 14:18 | clojurebot | #error {\n :cause "No namespace: some-ns found"\n :via\n [{:type java.lang.Exception\n :message "No namespace: some-ns found"\n :at [clojure.core$the_ns invokeStatic "core.clj" 4032]}]\n :trace\n [[clojure.core$the_ns invokeStatic "core.clj" 4032]\n [clojure.core$intern invokeStatic "core.clj" 6071]\n [clojure.core$intern invoke "core.clj" 6071]\n [sandbox$eval25 invokeStatic "NO_SOURCE_FIL... |
| 14:18 | justin_smith | oops! |
| 14:18 | justin_smith | ,(create-ns 'some-ns) |
| 14:18 | clojurebot | #object[clojure.lang.Namespace 0x1b74fd63 "some-ns"] |
| 14:18 | justin_smith | ,(intern 'some-ns 'some-var 42) |
| 14:18 | clojurebot | #'some-ns/some-var |
| 14:19 | justin_smith | ,some-ns/some-var |
| 14:19 | clojurebot | 42 |
| 14:34 | elvis4526 | Ha I didn't know changing it with def was allowed when you were in the same namespace |
| 14:35 | elvis4526 | its working perfectly thanks |
| 14:35 | justin_smith | cool |
| 14:35 | justin_smith | elvis4526: yeah, that's why the repl is so useful, being able to redefine in a running system just by running the new code |
| 14:54 | justin_smith | playing with this new socket server thing in 1.8, it's pretty cool, especially being able to run a repl just based on a command line arg with no code added to the codebase |
| 15:00 | wht_rbt | probably a newb question here -- does clojure have a way to prompt a user for a password on the console, so that the user's input does not echo? |
| 15:03 | Shayanjm | wht_rbt: not sure about Clojure specifically, but Java has java.io.Console.readPassword |
| 15:03 | domokato | line-seq makes a lazy sequence - does that mean it reads from a file when the elements are gotten from the resulting seq? |
| 15:04 | amalloy | domokato: yes |
| 15:04 | domokato | amalloy: th |
| 15:04 | domokato | amalloy: thx |
| 15:08 | wht_rbt | Chayanjm: thnx - I went down that rabbit hole, but ended up getting strange results |
| 15:08 | wht_rbt | similar to this: https://groups.google.com/forum/#!topic/clojure/hlv2m00hhgU |
| 15:08 | wht_rbt | System.console was coming back null for me |
| 15:24 | tos9 | I have 4 channels which contain 1 value each. I want to join the 4 values -- what's the easiest way to do that? |
| 15:24 | tos9 | I see async/merge for one way? |
| 15:24 | tos9 | join the 4 values as 1 str |
| 15:33 | optikalmouse | does clojure have the same Environment stuff as Common Lisp? like trace/untrace, dribble, etc.? |
| 15:33 | elvis4526 | tos9: i'd use async/merge yes |
| 15:33 | optikalmouse | or actually man I would love to have APROPOS |
| 15:34 | jonathanj | ,(doc apropos) |
| 15:34 | clojurebot | "([str-or-pattern]); Given a regular expression or stringable thing, return a seq of all public definitions in all currently-loaded namespaces that match the str-or-pattern." |
| 15:34 | tos9 | elvis4526: I must be doing that wrong I think, because (go (let [strs (<! (async/map str (async/merge comments)))] (println strs))) gives me Error: [object Object] is not ISeqable |
| 15:35 | elvis4526 | tos9: is comments a list of channels ? |
| 15:36 | tos9 | elvis4526: yes (although let me print it to be sure) |
| 15:37 | tos9 | it's: (#object[cljs.core.async.impl.channels.ManyToManyChannel] #object[cljs.core.async.impl.channels.ManyToManyChannel]) |
| 15:37 | jonathanj | merge returns one channel |
| 15:37 | jonathanj | map expects a seq |
| 15:37 | tos9 | a ha |
| 15:37 | elvis4526 | thats what i was about to say |
| 15:37 | elvis4526 | Usage: (map f chs) |
| 15:37 | elvis4526 | |
| 15:39 | tos9 | does that mean that I want (reduce str "" (async/merge comments)) then? Or does it mean I'm highly confused (Which I probably am). |
| 15:39 | jonathanj | so comments is a bunch of channels that each return one comment? more than one comment? |
| 15:39 | tos9 | jonathanj: they're a bunch of channels, each has 1 comment in it, yeah. |
| 15:39 | jonathanj | tos9: merge returns a channel, clojure.core/reduce doesn't know how to reduce a channel, does it? |
| 15:40 | tos9 | jonathanj: no, but along with like a <! |
| 15:40 | tos9 | oh hm no |
| 15:40 | tos9 | yeah that doesn't work. |
| 15:40 | jonathanj | so what are you trying to do? |
| 15:40 | tos9 | jonathanj: I have those 4 channels which contain 1 comment each which are strs. I want 1 str which is the concat of those 4 strs. |
| 15:40 | tos9 | (I'll want to interleave some other HTML, but first I want to see ^) |
| 15:41 | jonathanj | i think a transducer might make building that processing chain easier |
| 15:41 | tos9 | Yeah so it seeeems likely that that's true, and also it seems like cljs-http can *take* a channel rather than returning one, in which case I could probably get it to put my responses all on the same channel |
| 15:41 | beaky | helllo |
| 15:41 | beaky | is om production ready |
| 15:42 | elvis4526 | tos9: You could loop over the output channel with go-loop, collect each string and concat them for each iterations |
| 15:42 | tos9 | But I'm trying not to change my approach in a way that complicates it, I'm only like 3 hours into clojure programming :P |
| 15:42 | jonathanj | tos9: sorry i barely know anything about core.async so i can't really suggest a concrete solution |
| 15:42 | domokato | map-indexed should perform better than dotimes + nth, right? |
| 15:42 | tos9 | elvis4526: The merged one? Cool that sounds like a thing I might be able to do. Will give it a shot. |
| 15:42 | tos9 | jonathanj: Have you seen the evil thing I'm working on? |
| 15:42 | elvis4526 | tos9: yes the merged one |
| 15:43 | jonathanj | tos9: no, sorry i just started reading IRC |
| 15:43 | tos9 | jonathanj: Well you will soon, it's complete techcrap :) |
| 15:54 | mistnim | hi, what is clojure commonly used for? web development? anything else? |
| 15:55 | tos9 | what's wrong with my syntax here: https://github.com/Julian/sphinxcontrib-githubcomments/blob/master/src-cljs/githubcomments/core.cljs#L10-L14 |
| 15:55 | tos9 | clojure is telling me I'm not allowed to recur there |
| 15:56 | optikalmouse | jonathanj: thx! |
| 15:58 | jonathanj | tos9: i don't think you (recur) in a (go-loop) |
| 15:58 | hiredman | of course you can |
| 15:59 | tos9 | jonathanj: I'm copying the example at https://clojuredocs.org/clojure.core.async/go-loop |
| 15:59 | tos9 | or at least I think I am |
| 15:59 | jonathanj | oh you do, sorry, the docs are just really sparse |
| 16:00 | hiredman | tos9: replace go-loop with (go (loop [ ...] ...)) and then ask yourself what is wrong |
| 16:00 | tos9 | hiredman: I did, and then got "wrong number of arguments to recur |
| 16:00 | hiredman | tos9: do you know how loop/recur works? |
| 16:00 | tos9 | hiredman: I do not! |
| 16:00 | tos9 | I'm reading the docs on loop now |
| 16:00 | hiredman | tos9: good |
| 16:01 | tos9 | Oh I see. |
| 16:01 | tos9 | I need to pass the 2 new values. |
| 16:06 | elvis4526 | tos9: there is probably a better way to do it, but this is what I had in mind https://gist.github.com/j-allard/1efb23c2e13af35ed490 |
| 16:09 | justin_smith | jonathanj: regarding "map expects a seq" - the two argument version of map doesn't need a seq, and can be applied as a transducer on a channel |
| 16:15 | justin_smith | ,(sequence (map inc) (range 10)) |
| 16:15 | clojurebot | (1 2 3 4 5 ...) |
| 16:15 | justin_smith | and can also use a seq |
| 16:16 | jonathanj | justin_smith: i meant (clojure.core.async/map) which was the function in question, i was just lazy |
| 16:16 | justin_smith | jonathanj: clojure.core.async/map is depricated |
| 16:16 | justin_smith | it's just map now |
| 16:16 | jonathanj | mmm, the docs don't say it's deprecated |
| 16:16 | jonathanj | so how do you apply a transducer to a channel? |
| 16:17 | justin_smith | jonathanj: sorry, it's map> and map< that are depricated, map is still legit |
| 16:18 | justin_smith | jonathanj: you can provide a transducer as an optional arg to a channel |
| 16:18 | jonathanj | hmm, that seems kind of inconvenient, like if you merge, how do you apply a transducer to a channel you didn't create? |
| 16:20 | justin_smith | jonathanj: by piping onto a channel you did create, which has the transforms you want |
| 16:20 | justin_smith | or using pipeline |
| 16:21 | justin_smith | this is how we replace all the "Depricated - this function will be removed. Use transducer instead" functions |
| 16:27 | amalloy | justin_smith: replace them with "Deprecated"? |
| 16:46 | rcassidy | been using vim&fireplace with clojure and it's been awesome, but i'm missing one feature |
| 16:49 | rcassidy | jumping to definition of a symbol is easy -- any way to find usage of a symbol across files? something like ctags does in vim for :ts ? |
| 16:55 | justin_smith | rcassidy: sad but true, I usually just reply on grep -Rn ... |
| 16:56 | justin_smith | *rely |
| 16:56 | justin_smith | emacs has a mode where it lists the hits and there's a keyboard shortcut to visit the next hit etc. |
| 16:56 | justin_smith | I'm sure vim has some sort of grep / silver searcher plugin |
| 16:57 | rcassidy | justin_smith: thanks, that's what I'm doing too re: grep |
| 16:57 | rcassidy | ctags was nice for c++ in vim, can easily find all occurrences of a symbol and hop around based on the tag... sad there's not a similar thing that fits into fireplace |
| 17:01 | justin_smith | rcassidy: I've never seen tags for lisps like for algol family languages, I don't know if that's coincidence or some property of lispy languages that makes tags less useful or what |
| 17:02 | rcassidy | i saw some ctags syntax regexes to add support for tags, but doing c-style tags on top of fireplace just for one feature feels like overkill |
| 17:02 | rcassidy | and I don't feel like setting up my tagfile right now at work :p |
| 17:02 | rcassidy | s/support for tags/support for clojure tags/ |
| 17:04 | justin_smith | rcassidy: oh look, you can generate a tags file for clojure with etags http://stackoverflow.com/questions/1481842/clojure-emacs-etags |
| 17:05 | justin_smith | rcassidy: more relevant https://gist.github.com/vladh/1e1e7bc5eb274235e0b9 |
| 17:05 | rcassidy | found those :) |
| 17:05 | rcassidy | like I said, I could just straight use ctags, but that's a lot of cruft just to avoid grepping |
| 17:06 | rcassidy | maybe i'll give in eventually |
| 17:06 | justin_smith | true that |
| 17:06 | justin_smith | eventually CPU / disk speed improvement beats the old clever caching maybe |
| 17:13 | tos9 | elvis4526: Sorry - I jumped into a meeting -- thanks I think that's really helpful |
| 17:14 | tos9 | I still can't get go-loop to work, and probably I don't understand scoping 100% yet |
| 17:14 | tos9 | But I've just tried https://github.com/Julian/sphinxcontrib-githubcomments/blob/master/src-cljs/githubcomments/core.cljs#L10-L14 which appears to do *something*, although it also pegs a CPU, so maybe my channels aren't closing after the value pops out |
| 17:15 | justin_smith | tos9: why do you have an infinite loop inside your set! call? |
| 17:16 | justin_smith | the loop never returns, so set! never gets called |
| 17:16 | tos9 | a ha -- OK, so I guess I need to figure out how <! tells me that there's nothing left to read then? |
| 17:16 | justin_smith | it will return nil if the channel is closed |
| 17:17 | tos9 | Ah cool! OK, /me tries. |
| 17:17 | justin_smith | then you can conditionally recur only if hte channel is open |
| 17:17 | justin_smith | and then close the channel on the writing end |
| 17:19 | tos9 | I wish I knew the paredit things already, it'd make editing not be completely tedious :P |
| 17:22 | tos9 | ! Amazing :) it works. |
| 17:22 | justin_smith | nice |
| 17:26 | tos9 | justin_smith: http://platform-guild.readthedocs.org/en/latest/code-review.html |
| 17:27 | tos9 | the result of my evil handiwork (so far, still needs lots of work) |
| 17:27 | tos9 | but that bottom text box (the gray one) is what I just spent 2 evil days on -- bringing github comments onto a source doc at the client side, so thanks, appreciated |
| 17:27 | justin_smith | very cool |
| 17:27 | tos9 | Now I just need to work on styling and some other nonsense. |
| 17:28 | tos9 | And also on figuring out why apparently these AJAX requests aren't automatically cached by browsers :/ |
| 17:29 | tos9 | Are there any general tips for making https://github.com/Julian/sphinxcontrib-githubcomments/blob/master/src-cljs/githubcomments/core.cljs look more idiomatic overall? |
| 17:32 | justin_smith | tos9: why are you calling apply on line 31 instead of just calling the function? |
| 17:33 | tos9 | because it started off as dorun and as a thing with side effects (to print), fixing now :) |
| 18:30 | justin_smith | tos9: I think your loop could be (reduce str "" comments) |
| 18:30 | justin_smith | async/reduce that is |
| 18:34 | justin_smith | tos9: https://gist.github.com/noisesmith/4fb0b6fec934128d89e1 |
| 18:35 | justin_smith | totally works as a async/reduce call, which is cool |
| 18:35 | justin_smith | reduce doesn't even need to be in a go block, which makes sense |
| 18:57 | nuttynutnut | hi |
| 18:59 | nuttynutnut | is there a simple way to find the longest end subsequence of a number? like for 32541 it would be 541 |
| 18:59 | nuttynutnut | for 1428531 it would be 8531, for 61256 it would just be 6 |
| 18:59 | nuttynutnut | i came up with one solution but i was wondering if there was a better way.. one sec lemme code it up |
| 19:06 | tos9 | justin_smith: Ah awesome! That does work -- I tried it before but I didn't realize async/reduce returns a channel |
| 19:08 | tos9 | justin_smith: it doesn't look like cljs.core.async has <!! so I think I do need to keep the go blcok though? |
| 19:09 | justin_smith | tos9: oh, I only used <!! and >!! so that I could use the repl interactively |
| 19:09 | justin_smith | tos9: in the real code do all the puts and takes in go blocks |
| 19:10 | tos9 | justin_smith: Ah, OK, good. |
| 19:13 | nuttynutnut | ok back |
| 19:13 | nuttynutnut | that took longer than expected |
| 19:13 | nuttynutnut | so i came up with something like this but there must be a more elegant way, right? (distinct (flatten (take-while (fn [[l r]] (> (int r) (int l))) (partition 2 1 (reverse (str 32541)))))) |
| 19:15 | justin_smith | I think you'd want something like (map first ...) or (map second ...) rather than (distinct (flatten ...)) |
| 19:15 | nuttynutnut | that doesnt work |
| 19:16 | nuttynutnut | it only gives 14 and not 145 |
| 19:16 | nuttynutnut | oh and yeah it needs to be 541 so then i need to reverse |
| 19:17 | nuttynutnut | so it'd be .. (reverse (distinct (flatten (take-while (fn [[l r]] (> (int r) (int l))) (partition 2 1 (reverse (str 32541))))))) |
| 19:17 | nuttynutnut | gross |
| 19:17 | justin_smith | and that's still giving chars and not numbers |
| 19:18 | nuttynutnut | yeah |
| 19:19 | justin_smith | ,(defn rev-digits [n] (->> n (iterate #(quot % 10)) (take-while (complement zero?)) (map #(rem % 10)))) |
| 19:19 | clojurebot | #'sandbox/rev-digits |
| 19:19 | justin_smith | ,(let [digits (rev-digits 52741)] (reduce (fn [digs d] (if (< d (first digs)) digs (conj digs d))) (take 1 digits) (rest digits))) |
| 19:19 | clojurebot | (7 4 1) |
| 19:20 | justin_smith | oops! |
| 19:20 | justin_smith | ,(let [digits (rev-digits 52741)] (reduce (fn [digs d] (if (<= d (first digs)) (reduced digs) (conj digs d))) (take 1 digits) (rest digits))) |
| 19:20 | clojurebot | (7 4 1) |
| 19:21 | justin_smith | bonus: real math instead of string hacks |
| 19:22 | justin_smith | nuttynutnut: also, that version finds the sequence starting at the end, which is guaranteed to do the minimum amount of checks |
| 19:23 | nuttynutnut | yeah pretty cool |
| 19:23 | nuttynutnut | clojure is missing a function |
| 19:23 | nuttynutnut | there should be something in the core that lets you compare two elements at a time |
| 19:23 | nuttynutnut | there's so many times in a lot of these 4clojure problems that i have to compare the current item and the next item |
| 19:24 | nuttynutnut | have to end up doing some weird partition hack and then extracting the result from the vector later |
| 19:24 | justin_smith | or a reduce |
| 19:24 | nuttynutnut | yeah but that's ugly too |
| 19:24 | ystael | nuttynutnut: reduce is love, reduce is life |
| 19:24 | nuttynutnut | anything can be done with reduce |
| 19:24 | nuttynutnut | reduce is just like doing a for loop in imperative |
| 19:24 | justin_smith | (inc ystael) |
| 19:24 | nuttynutnut | higher abstractions are better |
| 19:25 | justin_smith | nuttynutnut: it's like a list comprehension that iterates over elements of one sequence and can optionally exit early |
| 19:25 | justin_smith | it's no for loop |
| 19:25 | justin_smith | or even clojure's for for that matter |
| 19:26 | nuttynutnut | it's just a loop with an accumulator |
| 19:26 | justin_smith | no it's not, because it is guaranteed to only run as many cycles as the number of elements in your input |
| 19:26 | justin_smith | it's not an arbitrary loop |
| 19:26 | justin_smith | we have "loop" for that |
| 19:27 | ystael | nuttynutnut: possibly not coincidentally, a computer is a loop (device for performing repetitive computation) with an accumulator (memory) |
| 19:27 | nuttynutnut | like.. something like this would be cool (taking-peak #(< %1 %2) [1 2 5 4 3]) |
| 19:27 | nuttynutnut | actually even better |
| 19:27 | nuttynutnut | an overload for take, filter, etc. that take 2 parameters instead of one |
| 19:27 | justin_smith | nuttynutnut: (reduce max 1 2 3 4 5) |
| 19:27 | nuttynutnut | so you could optionally look at the next item |
| 19:28 | nuttynutnut | ? |
| 19:28 | nuttynutnut | that doesnt run |
| 19:28 | justin_smith | nuttynutnut: (reduce max [1 2 3 4 5]) |
| 19:28 | justin_smith | which is the same as apply max, of course |
| 19:28 | justin_smith | unless that's not what you mean by "taking-peak" |
| 19:28 | nuttynutnut | taking-peak is just like take-while |
| 19:29 | justin_smith | oh, yeah mean peek |
| 19:29 | nuttynutnut | is it possible to add an overload to functions like take-while so their function takes 2 arguments instead of one? |
| 19:29 | nuttynutnut | so you could optionally use the take-while that just looks at the current value |
| 19:29 | nuttynutnut | or the one that looks at both |
| 19:30 | nuttynutnut | i think that'd be pretty cool |
| 19:30 | nuttynutnut | so often with these functions i need to look at the next or previous items in the sequence as well |
| 19:30 | nuttynutnut | and you can't so you have to use some hacky reduce |
| 19:30 | nuttynutnut | could be added to filter, reduce, map, etc. |
| 19:30 | TEttinger | or defined in a lib |
| 19:30 | ystael | nuttynutnut: it would be more coherent to mimic the behavior of map, which treats all its arguments after the function as successive arguments to the function |
| 19:31 | TEttinger | ,(map + [1 2 3] [20 40 60]) |
| 19:31 | clojurebot | (21 42 63) |
| 19:31 | nuttynutnut | yeah that could be a problem |
| 19:31 | TEttinger | one way you could do it is with... |
| 19:32 | TEttinger | ,(defn map-ahead [f coll] (map f coll (rest coll))) |
| 19:32 | clojurebot | #'sandbox/map-ahead |
| 19:32 | amalloy | nuttynutnut: don't do it with special overloads to all sequence functions, just use partitino |
| 19:32 | TEttinger | where the second argument to f is the next element in the collection, and the last element isn't used |
| 19:32 | amalloy | ,(partition 2 1 (range 5)) |
| 19:32 | nuttynutnut | it's messy though |
| 19:33 | clojurebot | ((0 1) (1 2) (2 3) (3 4)) |
| 19:33 | nuttynutnut | because you have to extract the values later |
| 19:34 | justin_smith | sounds like a job for a monad |
| 19:34 | nuttynutnut | i showed the code above that was required to get 541 from 32541 |
| 19:34 | nuttynutnut | (reverse (distinct (flatten (take-while (fn [[l r]] (> (int r) (int l))) (partition 2 1 (reverse (str 32541))))))) |
| 19:34 | nuttynutnut | with this it could instead be something like.. |
| 19:34 | TEttinger | ,(defn map-ahead [f coll] (map f coll (rest (cycle coll)))) |
| 19:34 | clojurebot | #'sandbox/map-ahead |
| 19:34 | justin_smith | nuttynutnut: flatten is 100x as hacky as the worst reduce |
| 19:34 | nuttynutnut | (take-while #(< %1 %2) (reverse (str 32541))) |
| 19:34 | nuttynutnut | or something like that |
| 19:35 | nuttynutnut | well yeah flatten is bad too |
| 19:35 | nuttynutnut | im saying there's no good solution |
| 19:35 | nuttynutnut | that's concise |
| 19:35 | amalloy | justin_smith: probably a comonad actually, right? like that's what zippers are for |
| 19:35 | nuttynutnut | or if there is i'd like to be made aware of it |
| 19:35 | justin_smith | amalloy: that's over my head still, but sure, sounds legit |
| 19:35 | amalloy | haha |
| 19:36 | TEttinger | what does that function even do, nuttynutnut? finds an increasing section of a sequence starting from the back? |
| 19:36 | nuttynutnut | yeah |
| 19:36 | nuttynutnut | the reason im trying to make it: |
| 19:36 | amalloy | well mine too, mostly. but as i understand zippers, a zipper on a list is a "pointer" to one specific element in the overall list, with a (get) function to read the current element, and functions (left) and (right) to give you a new zipper with a new focus |
| 19:36 | justin_smith | TEttinger: digits of a number actually |
| 19:37 | nuttynutnut | http://stackoverflow.com/questions/352203/generating-permutations-lazily control+f for "Find the longest "tail" that is ordered in decreasing order. (The "541" part.)" |
| 19:37 | justin_smith | amalloy: oh yeah, nuttynutnut could totally be using a zipper |
| 19:37 | nuttynutnut | trying to code that first step concisely |
| 19:37 | nuttynutnut | zippers huh? |
| 19:37 | nuttynutnut | ive heard of them but no idea what they do |
| 19:37 | nuttynutnut | is that a good solution to this? |
| 19:37 | justin_smith | nuttynutnut: yeah, check the api - from a given position you can look at the values to the left and right etc. |
| 19:37 | nuttynutnut | o |
| 19:37 | nuttynutnut | thats perfect |
| 19:38 | justin_smith | or even up and down in a tree |
| 19:38 | nuttynutnut | ok ill look in to those |
| 19:39 | TEttinger | ,(reductions #(or (< %1 %2) (reduced %1)) (reverse "32541")) |
| 19:39 | clojurebot | #<ClassCastException java.lang.ClassCastException: java.lang.Character cannot be cast to java.lang.Number> |
| 19:40 | justin_smith | I was just playing with the new clojure 1.8 socket repl, accidentally printed an infinite lazy seq, and Control-C just locked up the terminal until I shut down the socket server |
| 19:40 | TEttinger | ,(reductions #(or (< %1 %2) (reduced %1)) (map int (reverse "32541"))) |
| 19:40 | clojurebot | #<ClassCastException java.lang.ClassCastException: java.lang.Boolean cannot be cast to java.lang.Number> |
| 19:40 | TEttinger | gah |
| 19:40 | TEttinger | ,(reductions #(if (< %1 %2) %1 (reduced %1)) (map int (reverse "32541"))) |
| 19:40 | clojurebot | (49 49 49 49 49) |
| 19:40 | TEttinger | right. |
| 19:40 | irctc | Is there a function like map, but where I can discard some elements? A kind of combined remove+map where I would remove elements I don't need, and transform the ones I do at the same time? |
| 19:40 | nuttynutnut | yeah that was messing with me earlier too |
| 19:40 | nuttynutnut | lol |
| 19:40 | nuttynutnut | filter? |
| 19:40 | clojurebot | filter is not map |
| 19:40 | justin_smith | irctc: mapcat |
| 19:41 | justin_smith | irctc: or keep |
| 19:41 | justin_smith | (doc keep) |
| 19:41 | irctc | hum, I'll have a look at all of these |
| 19:41 | clojurebot | "([f] [f coll]); Returns a lazy sequence of the non-nil results of (f item). Note, this means false return values will be included. f must be free of side-effects. Returns a transducer when no collection is provided." |
| 19:41 | justin_smith | keep if you never want a nil element |
| 19:42 | justin_smith | mapcat is more general and allows nil elements and also removing elements |
| 19:42 | justin_smith | (but it's a little clumsier) |
| 19:42 | irctc | Keep is exactly what I want thanks |
| 19:43 | justin_smith | ,(mapcat #(cond (even? %) [%] (> 10 %) [nil] :true nil) [2 3 4 12 13 14]) |
| 19:43 | clojurebot | (2 nil 4 12 14) |
| 19:44 | justin_smith | keep couldn't do that because it eats all nils (but clearly keep works for your case) |
| 19:44 | didibus | Ya, I won't have nils |
| 19:44 | didibus | But it's good to know mapcat is there if I ever need it |
| 19:45 | justin_smith | usually people only think of mapcat as combining multiple results per item, but really it's the options for "0 or more results per item" |
| 19:48 | didibus | Ya, I'm still slowly learning about all the core functions, there's just so many awesome jewel |
| 19:52 | TEttinger | ,(reduce #(if (< (or (first %1) -1) %2) (apply vector %2 %1) (reduced %1)) [] (map #(Character/digit % 10) (reverse "32541"))) |
| 19:52 | TEttinger | seems too long |
| 19:52 | clojurebot | [5 4 1] |
| 19:54 | nuttynutnut | yeah still pretty long |
| 20:02 | amalloy | mapcat is a primitive operation powerful enough to implement map, filter, keep, and a whole bunch of other stuff in terms of |
| 20:02 | justin_smith | yupyup |
| 20:12 | neoncontrails | Speaking of core functions. I'm working on something that requires taking a lot of set intersections, lots of set membership queries. I need persistent collections, rather than the lazy ones I keep creating with map |
| 20:13 | justin_smith | ,(into #{} (map #(* % %)) [1 2 3 4]) ; like this? |
| 20:13 | clojurebot | #{1 4 9 16} |
| 20:13 | neoncontrails | Is there an eager alternative? A better core function to use when you generally need to build the structure in memory? |
| 20:14 | justin_smith | neoncontrails: that's what the map transducer used with into is for, yes |
| 20:14 | justin_smith | the above builds a set with the help of the transducing function generated by the single arity version of map |
| 20:14 | justin_smith | *single arg arity of map |
| 20:15 | neoncontrails | justin_smith: interesting. I didn't know into had that property, that's useful |
| 20:16 | justin_smith | neoncontrails: yeah, the idea with the whole transducers thing is not needing to generate a lazy seq if you know you already need a different data structure, and into is one of the most straightforward ways to use a transducer |
| 20:18 | neoncontrails | Maybe today is the day I'll learn what transducers are. I read up on them a few months ago, and there was lots of head whooshing |
| 20:27 | justin_smith | neoncontrails: it should be straightforward to parse out what into does with a single transducer arg (like (map f) or (filter f)) with trial and error |
| 20:28 | justin_smith | after that comes composing transducers, etc. |
| 20:37 | neoncontrails | It is with consistent practice, yeah. There's an interesting variety of types in Clojure that makes the patterns a little harder to see than in Scheme |
| 20:38 | neoncontrails | But it's a nice variety. I dig it |
| 22:36 | rhg135 | any idea why a put! to a manifold stream would immediatly return false if it's not closed |
| 23:26 | bja | any idea why the .setBounds in this snippet seems to be underestimating the height of my images consistently? https://gist.github.com/555c96a26dab2483c671 |
| 23:26 | bja | this is probably just a swing 101 question, not precisely a clojure question, although it is in clojure |
| 23:38 | John[Lisbeth] | where is the bin for ghci located in ubuntu? |
| 23:39 | John[Lisbeth] | oops |
| 23:51 | rhg135 | https://www.refheap.com/113945 this is really perplexing, it was working before and I don't recall changing the relevant code |