#clojure log - Jan 21 2016

The Joy of Clojure
Main Clojure site
Google Group
List of all logged dates

0: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

0:00 i.e. you can re-use the same code with sequences and channels

0:01 and any other source that might come up in the future

0:02 baritonehands: so defprotocol for CRUD by id semantics, where one implementation is in memory ref, future implementation is some DB?

0:02 justin_smith: right

0:02 and then you could even have general game-logic code that calls the methods of that protocol

0:03 and if you do it right, that game-logic code can be completely stateless / functional

0: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

0:03 justin_smith: a bunch of functions that take a game, and return the next round of the game

0:04 baritonehands: justin_smith: not too much game logic, just state transitions mostly, and validation

0:04 waiting -> playing -> done

0:04 justin_smith: felixn_: for all X in clojure, X is higher order functions

0:04 baritonehands: your state transitions are what I called logic

0:07 baritonehands: justin_smith: so for actual file organization, what would you recommend?

0:07 where would by protocol and its implementations go, etc.

0: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

0:09 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.

0:10 baritonehands: justin_smith: does my RESTful api fit into all of this?

0:11 justin_smith: it would be an implementation detail of that last namespace that it serves an API

0: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

0:12 baritonehands: felixn_: The api code is also very generic. If I could reuse CRUD semantics there as well it would help

0:13 felixn_: Current api - https://github.com/baritonehands/avalon/blob/master/src/clj/avalon/api/games.clj

0:13 felixn_: baritonehands: seems like a function that just builds endpoints would be sufficient

0:13 you'll drastically cut down on lines of code

0:14 baritonehands: felixn_: defresource is a macro, so I think it would have to use a macro to generate

0: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

0:16 otherwise it's an api :)

0: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.

0:18 justin_smith: baritonehands: dosync

0:18 baritonehands: ah, yeah, games and people need to be updated in the same transaction

0:18 justin_smith: for sql this would be some transaction holding function instead

0:18 point is, it's a leaked detail

0:19 baritonehands: justin_smith: Yeah, hmm

0: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

0:21 baritonehands: justin_smith: so that means the protocol needs a method to create and relate two different references/db entities

0:21 justin_smith: probably, yes

0:28 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

0:35 neoncontrails: Is there a better way to do this?

0:36 ,(read-string ((comp str str/lower-case) (reduce into #{} '[(:FOO :BAR :BAZ)])))

0: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 ...

0:36 neoncontrails: ,(read-string ((comp clojure.string clojure.string/lower-case) (reduce into #{} '[(:FOO :BAR :BAZ)])))

0: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\...

0:38 neoncontrails: Hmmm. Not sure how to fix without importing clojure.string. But the expected output is #{:baz :bar :foo}

0:51 baritonehands: justin_smith: How do I reference the memdb implementation where I need it, but only reference the crud protocol?

0:52 (defprotocol CRUD

0:52 (create [entity])

0:52 (get [id])

0:53 (save [id updates])

0:53 (delete [id]))

0:53 ,(defn create-db []

0:53 (let [db (ref {})]

0:53 clojurebot: #<RuntimeException java.lang.RuntimeException: EOF while reading>

0:53 baritonehands: (reify CRUD

0:53 (create [entity]

0:53 (let [id (str (java.util.UUID/randomUUID))]

0:53 (dosync (alter db assoc id (assoc entity :id id)))

0:54 entity))

0:54 (get [id]

0:54 (@db id))

0:54 (save [id updates]

0:54 (dosync (alter db update-in [id] merge updates)))

0:54 (delete [id]

0:54 (dosync (dissoc db id))))))

0:54 amalloy: baritonehands: long pastes to a pastebin, please, such as gist.github.com

0:56 baritonehands: justin_smith: https://gist.github.com/baritonehands/b75dc69242948308ff3d

1:02 nys-: where does the nrepl-port file go

2:55 autogen_: hey guys

3:02 alex``: hey there

3:43 devangshah: alexyakushev: i have completed the incremental build project and have it approved...

3:44 https://github.com/celeritas9/lein-droid/tree/inc-build

3:44 shall i create the PR?

3:45 what would you suggest…? I want to have it merged.. :-)

3:59 jonathanj: what's the quickest dirtiest way to get the current system timestamp as a string?

3:59 apparently System/currentTimeMillis doesn't exist, despite javadocs telling me it does, am I missing something?

4:00 java.lang.RuntimeException: Unable to find static field: currentTimeMillis in class java.lang.System

4:04 ridcully_: ,(System/currentTimeMillis)

4:04 clojurebot: 1453367011585

4:09 TEttinger: jonathanj: were you doing:

4:09 ,System/currentTimeMillis

4: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 ...

4:09 TEttinger: it is a static method

4:10 I can see it could have been either way though,

4:10 it makes sense as a field and method

4:29 Wojciech_K: Why unquote and syntax-quote are in diffrent namespaces?

4:50 neoncontrails: Wojciech_K: hehehe. They're very different in scope. If you're not sure which one you want, use quote

4:51 Wojciech_K: neoncontrails, I use syntax-quote with conjuction with unquote, the stange thing is

4:51 unquote and quote are in clojure.core

4:52 while syntax-quote is in clojure.tools.reader

4:52 syntax-quote and quote are more similar to each other than to unquote

4: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

5:00 Wojciech_K: right, thanks

5:07 jonathanj: TEttinger: oh, you're probably right, I forgot to call it

5:07 how can i create a List from Clojure?

5:07 a List<String> to be precise

5:07 neoncontrails: ,'()

5:07 clojurebot: ()

5:07 jonathanj: neoncontrails: not a list, a java.util.List

5:09 i have a function whose signature is List<String> can i just pass ["" ...] to that?

5:09 noncom: clojure seqs implement List ? i dont' remember for sure

5:10 TEttinger: ,(java.util.ArrayList. [1 2 3])

5:10 clojurebot: [1 2 3]

5:10 TEttinger: ,(java.util.ArrayList. '(1 2 3))

5:10 clojurebot: [1 2 3]

5:10 noncom: looks like they do

5:11 TEttinger: not sure if vector or seq implement List. ArrayList takes a Collection IIRC, so more general

5:11 ,(java.util.ArrayList. #{1 2 3})

5:11 clojurebot: [1 3 2]

5:11 noncom: ,(instance? java.util.List [])

5:11 clojurebot: true

5:11 noncom: ,(instance? java.util.List '())

5:11 clojurebot: true

5:11 TEttinger: ah good then

5:12 ,(instance? java.util.List [1])

5:12 clojurebot: true

5:12 TEttinger: ,(instance? java.util.List (range))

5:12 clojurebot: true

5:12 TEttinger: whaaaaat

5:12 noncom: cool. lists are rather widespread!

5:12 well, can't a lazy seq implement a list ? :)

5:12 TEttinger: ,(class (range))

5:12 clojurebot: clojure.lang.Iterate

5:13 noncom: (.add (range) 1)

5:13 ,(.add (range) 1)

5: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...

5:13 noncom: hehe

5:13 jonathanj: what is a java.util.List<String> vs a java.util.List?

5:13 noncom: unsup op, what i expected

5:13 jonathanj: same

5:13 jonathanj: eh?

5:13 TEttinger: jonathanj: generics like <String> only apply in java source, they're erased in bytecode

5:13 jonathanj: what is a java.util.List<String> vs a java.util.List<Turnip> then?

5:13 noncom: same

5:13 jonathanj: oh okay

5:14 sorry, i don't JVM

5:14 TEttinger: it's weird in any language, the generic erasure

5:14 noncom: jonathanj: so just be aware that something may brake in runtime if the types are not friends

5:14 TEttinger: there's a reason for it, I assume, but it's still weird

5:14 noncom: the reason is always performance

5:16 TEttinger: hence why java.util.Random is at least 5x slower than a non-thread-safe linear congruential pseudo-random generator?

5:16 the reason there is thread safety

5:17 noncom: hmm

5:17 TEttinger: LCGs are supposed to be among the fastest RNG types, which sorta helps make up for their lousy quality

5:17 noncom: oh maybe, i don't know this matter for sure

5: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"

5:19 noncom: :D

5:19 TEttinger: the number it returned was that text

5:19 good ol' dream code

5:19 noncom: omg lol :D

7: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

7:29 gfredericks: neoncontrails: you're wondering about the function calling itself by name instead of using recur?

7:31 neoncontrails: gfredericks: yup. Discouraged or actually risky?

7:35 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"

7:37 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...

8: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?

8:19 ridcully_: oracle123: CLOJURE_HOME is most likely an environment variable? could you please post the link, what "document" is meant?

8: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?

8:24 ToxicFrog: neoncontrails: use stored procedures instead, stop caring about escaping your inputs to be to SQL-safe?

8: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 ' -> `?

8:28 ToxicFrog: neoncontrails: what? That's the complete opposite of what I suggested.

8:28 neoncontrails: I know ` is special in Clojure, but I don't think that should matter in the string

8:29 ToxicFrog: sorry could you clarify what you meant then? "Stored procedures" could mean almost anything

8:29 ToxicFrog: Also, how will you handle strings that naturally include ` in them?

8:29 SQL stored procedures.

8:30 neoncontrails: Ooh I see. This is my first db app, I didn't know SQL had such things

8:30 ToxicFrog: Aka prepared statements or parameterized queries.

8:30 You write the query in SQL as a function, then call it from clojure passing in the parameters needed.

8:31 No escaping is needed, the parameters are treated as raw data even if they contain characters that would normally be special to SQL.

8:33 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.

8:33 neoncontrails: Oh cool that sounds a lot more sane than what I'm currently doing. Thanks for the suggestion

8:35 * ToxicFrog refreshes his memory a bit

8:36 ToxicFrog: Ok, it's been a while; parameterized queries and stored procedures are related but are not the same thing.

8:36 Stored procedures are written up front and stored in the DB.

8:36 Parameterized queries can be created on the fly, and might look something like this (details depend on implementation):

8:37 (sql-query-with-params "SELECT ? FROM users WHERE name == ?" field-name user-name)

8:37 field-name and user-name shouldn't be escaped and are correctly spliced into the command where the ?s appear.

8:37 neoncontrails: ^

8:38 neoncontrails: if you're using JDBC, it looks something like this: http://rosettacode.org/wiki/Parametrized_SQL_statement#Clojure

8:40 neoncontrails: ToxicFrog: awesome, I was just about to ask about jdbc. Thanks for the examples, this is really helpful

8:48 ToxicFrog: Success!

8:48 Thanks again, I had no idea this was a thing.

8:51 jsabeaudry: What's the status with incanter?

8:52 oracle123: about the clojure home, sorry it's not mean CLOJURE_HOME, but just clojure home, the doc says

8:52 The simplest way to launch a Clojure repl is to use the following command line from within Clojure’s home directory:


8:52 java -cp clojure.jar clojure.main

8:53 the doc is here http://clojure.org/reference/repl_and_main#_launching_a_socket_server

8:53 but I am using lein, so where should I run the java -cp clojure.jar clojure.main?

9:04 jsabeaudry: oracle123, if you use lein you dont need to run that

9: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.

9:11 wink: that's because 1.8 is like 2 days old

9:12 I'm still trying to find out what this new socket REPL's benefits are

9:14 oracle123: I could telnet and send command to it. Maybe we could also do the same in Nrepl.

9:15 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?

9:16 ToxicFrog: neoncontrails: you're welcome!

9:16 pbx: is there a 'lein version' equivalent that tells me the installed clojure version?

9:17 oracle123: lein version won't tell the version of clojure, and in the project.clj, we could define different version of clojure

9:18 so it's depends on the proejct.clj, it can't give a fixed version.

9:19 hyPiRion: pbx: `clojure -e '(clojure-version)'` or `lein run -m clojure.main -e '(clojure-version)'`

9:19 wink: `lein version` would also be ambigous depends on whether it is called inside a project dir or not

9:19 i.e. would you want your project clojure version, or the one lein uses?

9: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`

9:25 This should start a socket which you can connect over via `telnet 5555`

9: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?

9:32 ToxicFrog: neoncontrails: I'm not sure what you mean by "use sql/execute! to insert the name

9:33 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

9: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.

9:37 but using your approach, it starts a lein repl, it doesn't run my code.

9:38 normally I am running using "lein run"

9:40 beaky: hello

9: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?

9:40 beaky: is clojure enterprise ready

9:41 ToxicFrog: neoncontrails: yes, and that's pretty much exactly the example given in (doc sql/update!)

9:42 In fact, that update! call of yours basically turns into: (sql/execute! spec ["UPDATE mydb SET name = ? WHERE fieldA = ?" "it's" 0])

9:42 powered: JVM is good enough for enterprises, and clojure uses JVM so I'd say yes beaky

9: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

9:58 tdammers: mocking databases is hilariously cumbersome

9:58 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

9:58 for unit tests, things are trickier

9: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 and then use simulation tests against a test database to cover you bases

10:01 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 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 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 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 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 trying to do (java.util.Arrays/asList ...)

10:22 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 (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 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 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 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 haha

10:28 jonathanj: I'll look out for reasons to call you a moron then

10:28 jonathanj: thanks, you're a true friend

10:28 dump-1: DOS executable (device driver)

10:28 *argh*

10:29 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 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 it seems like 99% of the file is \377

10:30 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 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 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 justin_smith: i dunno, can it?

10:36 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 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 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 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 whereas PDFObject.getStream.createInputStream creates an input stream for only the embedded object data

10:53 justin_smith: oh, nice

10:53 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 thanks, justin_smith

11:00 tos9: is there some atriviality to apply'ing interop-ed things

11:00 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 tos9: no

11:06 tos9: oh, right, multimethods... that's annoying.

11:06 beaky: hello

11:06 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 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 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 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 OK, cool

11:13 beaky: ah

11:16 tos9: How to I tell lein to put ~/.lein someplace else

11:16 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 justin_smith: Thank you!

11:22 justin_smith: tos9: see also "lein help sample | grep HOME"

11:23 * tos9 nods

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 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 tos9: it's a reference document, I've never read it start to finish

11:25 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 on a bytecode level a method isn't something you can pass as an arg

11:32 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 it's better to just use #(.foo %)

11:35 gfredericks: because of default-reflection?

11:35 well that's no different from #(.foo %) I guess

11:35 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 it makes you feel clever

12:51 cap10morgan_: Is clojurebot's source code on GitHub somewhere?

12:51 justin_smith: yes

12:51 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 Im the repl and i want to redefine a var assigned to a function inside a namespace

14:15 (or perhaps its the function that is assigned to the var)

14:16 justin_smith: elvis4526: (intern 'some-ns 'some-symbol value)

14:17 and you can also do (in-ns 'random-ns) (def ...) (in-ns 'other-ns)

14:18 ,(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 ,(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 its working perfectly thanks

14:35 justin_smith: cool

14:35 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 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 amalloy: thx

15:08 wht_rbt: Chayanjm: thnx - I went down that rabbit hole, but ended up getting strange results

15:08 similar to this: https://groups.google.com/forum/#!topic/clojure/hlv2m00hhgU

15:08 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 I see async/merge for one way?

15:24 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 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 map expects a seq

15:37 tos9: a ha

15:37 elvis4526: thats what i was about to say

15:37 Usage: (map f chs)


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 oh hm no

15:40 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 (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 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 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 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 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 I'm reading the docs on loop now

16:00 hiredman: tos9: good

16:01 tos9: Oh I see.

16:01 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 ,(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 it's just map now

16:16 jonathanj: mmm, the docs don't say it's deprecated

16:16 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 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 or using pipeline

16:21 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:28 * justin_smith buys himsulf a dictoneery.

16:46 rcassidy: been using vim&fireplace with clojure and it's been awesome, but i'm missing one feature

16:49 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 *rely

16:56 emacs has a mode where it lists the hits and there's a keyboard shortcut to visit the next hit etc.

16:56 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 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 and I don't feel like setting up my tagfile right now at work :p

17:02 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 rcassidy: more relevant https://gist.github.com/vladh/1e1e7bc5eb274235e0b9

17:05 rcassidy: found those :)

17:05 like I said, I could just straight use ctags, but that's a lot of cruft just to avoid grepping

17:06 maybe i'll give in eventually

17:06 justin_smith: true that

17:06 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 I still can't get go-loop to work, and probably I don't understand scoping 100% yet

17:14 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 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 * tos9 nods

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 ! 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 the result of my evil handiwork (so far, still needs lots of work)

17:27 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 And also on figuring out why apparently these AJAX requests aren't automatically cached by browsers :/

17:29 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 async/reduce that is

18:34 tos9: https://gist.github.com/noisesmith/4fb0b6fec934128d89e1

18:35 totally works as a async/reduce call, which is cool

18:35 reduce doesn't even need to be in a go block, which makes sense

18:57 nuttynutnut: hi

18:59 is there a simple way to find the longest end subsequence of a number? like for 32541 it would be 541

18:59 for 1428531 it would be 8531, for 61256 it would just be 6

18:59 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 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 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 that took longer than expected

19:13 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 it only gives 14 and not 145

19:16 oh and yeah it needs to be 541 so then i need to reverse

19:17 so it'd be .. (reverse (distinct (flatten (take-while (fn [[l r]] (> (int r) (int l))) (partition 2 1 (reverse (str 32541)))))))

19:17 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 ,(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 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 clojure is missing a function

19:23 there should be something in the core that lets you compare two elements at a time

19:23 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 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 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 it's no for loop

19:25 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 it's not an arbitrary loop

19:26 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 actually even better

19:27 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 ?

19:28 that doesnt run

19:28 justin_smith: nuttynutnut: (reduce max [1 2 3 4 5])

19:28 which is the same as apply max, of course

19:28 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 so you could optionally use the take-while that just looks at the current value

19:29 or the one that looks at both

19:30 i think that'd be pretty cool

19:30 so often with these functions i need to look at the next or previous items in the sequence as well

19:30 and you can't so you have to use some hacky reduce

19:30 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 ,(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 (reverse (distinct (flatten (take-while (fn [[l r]] (> (int r) (int l))) (partition 2 1 (reverse (str 32541)))))))

19:34 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 or something like that

19:35 well yeah flatten is bad too

19:35 im saying there's no good solution

19:35 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 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 zippers huh?

19:37 ive heard of them but no idea what they do

19:37 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 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 ,(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 lol

19:40 filter?

19:40 clojurebot: filter is not map

19:40 justin_smith: irctc: mapcat

19:41 irctc: or keep

19:41 (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 mapcat is more general and allows nil elements and also removing elements

19:42 (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 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 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 the above builds a set with the help of the transducing function generated by the single arity version of map

20:14 *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 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 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 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 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

Logging service provided by n01se.net