#clojure log - Dec 24 2015

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

0:00 devth: good point. i should start doing that.

0:00 justin_smith: like I might have :sql/db and :mongo/db as two bindings in the same config

0:00 devth: cool

0:00 justin_smith: devth: in practice you want to minimize the amount of code that uses the config map

0:01 mostly you should be able to use pure functions that don't need config

0:01 devth: in my chat adapters, almost everything i care about doing is side-effectful :)

0:01 justin_smith: but some functions need to guide or negotiate stateful stuff, or interact with the real world, and they all need the config

0:01 devth: recieve messages, list users, list channels, post messages, connect, disconnect

0:02 justin_smith: devth: it doesn't need to be that way, there are ways to do pure calculations on data structures, and derive the side effects at the system boundary. This tends to lead to contagious sanity.

0:02 devth: using free monads? :)

0:02 justin_smith: heh, if you want to use that terminology you may, but I don't think I am talking about that specific thing

0:03 devth: i haven't really seen clj in that style

0:03 justin_smith: devth: I was thinking more of eg. what they call the interpreter pattern - in your pure code you build up data describing your decisions / needs. Then at the system boundary you do all the side effects this implies, and propagate the resulting data back to where it might be needed.

0:04 devth: reagent is a good example of this

0:04 devth: like haskell

0:04 cool

0:04 justin_smith: devth: in clojure it's a little more ad-hoc, we don't have the implicit stuff haskell gives you

0:04 but hey, less magic is good right?

0:05 devth: depends on the magic :)

0:06 neoncontrails: justin_smith: I just jumped in, in what way is Clojure less magical than Haskell?

0:06 justin_smith: neoncontrails: no monads!

0:07 neoncontrails: justin_smith: is an atom not a monad?

0:07 justin_smith: neoncontrails: so you need to explicitly pass the pure context describing operations to the boundary layer code that does effects, if you want that kind of design

0:07 TEttinger: Scala's implicit keyword is also pretty much forbidden blood magic

0:07 sohail: justin_smith: I tried the following where src/cljs/test.clj exists: http://pastebin.com/tb2JdHMC

0:07 devth: i.e. clj is not a pure FP lang like haskell

0:07 sohail: but when starting the repl, I get clas not found exception: test.repl

0:08 justin_smith: sohail: right, you haven't required test.repl yet

0:08 devth: TEttinger: implicit is what powers type classes in scala :)

0:08 sohail: justin_smith: how do I do that?

0:08 neoncontrails: In what way does Clojure's atom type differ from monads in Haskell?

0:08 justin_smith: sohail: with the require function, of course

0:08 neoncontrails: It seems like the motivation is very similar.

0:09 devth: maybe similar motivation, but with an atom actual mutation is happening. just happens to be thread-safe.

0:09 TEttinger: devth: and it does totally different things depending on where it occurs

0:09 devth: TEttinger: yeah, can be a night mare

0:09 justin_smith: neoncontrails: a monad carries an implicit context between chained operations, an atom manages shared state between threads. There are specific monad using things in haskell that are much like clojure atoms, but I don't think it's an apple to apple comparison.

0:10 devth: monads let you simulate imperative-style coding while still being pure

0:10 justin_smith: neoncontrails: for the IO monad in haskell, you cannot do operations that interact with the real world outside of the monadic context that chains effects

0:11 this is very different from clojure, where we can easily insert a println call into any function we like

0:11 devth: and even when you use the IO monad, you're not performing side effects. you're describing them. it's up to the haskell runtime to perform them for you.

0:12 justin_smith: devth: exactly - you are building up a description of the tasks, the compiler decides how it all works out

0:12 and you can even do pure operations to build those chains of task descriptions

0:13 sohail: you can use the require function

0:13 ,(doc require)

0:13 clojurebot: "([& args]); Loads libs, skipping any that are already loaded. Each argument is either a libspec that identifies a lib, a prefix list that identifies multiple libs whose names share a common prefix, or a flag that modifies how all the identified libs are loaded. Use :require in the ns macro in preference to calling this directly. Libs A 'lib' is a named set of resources in classpath whose contents...

0:13 neoncontrails: Gotcha. devth: so what you're saying is that swap! functors are still mutative, because they're changing the value associated with the atom, even if they're not changing the literal contents of the atom?

0:14 devth: not sure what you mean by changing value vs literal contents. aren't you changing the literal contents?

0:15 atom is a container right? you can put things in it. and mutate them.

0:15 justin_smith: neoncontrails: value vs. identity - atoms change value - have different contents - do not change identity

0:16 neoncontrails: devth: my understanding is that swap! just creates a new data structure and changes the pointer, so the old one can still gracefully persist, eventually to be garbage collected

0:17 this could be wrong, of course

0:17 justin_smith: neoncontrails: swap! does not change the identity, but it does replace the contents

0:17 I think talking about pointers here only muddies the issue

0:17 devth: right. i didn't mean mutate the data structure inside of an atom. i mean change the value of an atom.

0:18 justin_smith: but you are right, it does not mutate the contents, it replaces them

0:18 neoncontrails: got it. I think we're on the same page

0:19 devth: now i'm thinking about transients inside of atoms :)

0:20 justin_smith: transients are allowed to mutate, but make no promise to do so, and correct code must be written as if they did not mutate their contents

0:20 devth: yeah. too bad correctness verification is left up to humans in this case.

0:20 justin_smith: yes, this is the general theme of the differences between haskell and clojure

0:21 in haskell, the machine will enforce all sorts of things for you, but there's more effort needed to describe things in the proper way that makes haskell's compiler happy

0:33 I found the primate Rich Hickey https://www.youtube.com/watch?v=Snl4U8HPdtQ TEttinger did you know apes could tie knots?

0:35 TEttinger: https://www.youtube.com/watch?v=EMbWDRzqNhc

0:36 primate prometheus

0:37 justin_smith: TEttinger: oh, *that* promethius - the earlier horrifying stuff we were talking about had me worried for a moment

0:37 TEttinger: haha

0:39 justin_smith: TEttinger: man if I had to choose from being able to put up a hammock or start a fire, I don't even know which one I would pick

0:39 TEttinger: "he likes the taste of cooked food"

0:45 TimMc: OK, maybe I'll go with "earnest".

1:08 justin_smith: oh wow, I almost want to throw a script at this page http://christmasinfairbanks.com/

1:10 turbofail: needs sandstorm playing in the background

1:10 justin_smith: easy enough to fix

1:11 turbofail: and a script to sync the lights to it

1:11 justin_smith: you could take over a light via a PWM derived technique

1:12 you send repeated commands for a given light

1:12 if you want the off state, you leave it off longer than on

1:12 if you want the on state, you leave it on longer than off

1:13 everyone else with their individual clicks would hardly effect things at all

1:14 turbofail: until somebody else gets the same idea anyway

1:14 justin_smith: heh, right

1:29 mindbender1: How best to apply a sequence of functions to an object?

1:29 I need the output of the previous fn to be the input of the next and yet I don't know the actual fns until run time.

1:30 turbofail: ((apply comp [- (partial + 3) (partial * 10)]) 1)

1:30 ,((apply comp [- (partial + 3) (partial * 10)]) 1)

1:30 clojurebot: -13

1:31 rhg135: reduce

1:32 comp too

1:34 mindbender1: rhg135: example?

1:34 turbofail: ,(reduce (fn [a f] (f a)) 1 [- (partial + 3) (partial * 10)])

1:34 clojurebot: 20

1:35 mindbender1: turbofail: I gues I need to reverse a normal list to apply'ing comp to it?

1:35 *before apply'ing

1:36 turbofail: no, a normal list works the same way

1:36 ,((apply comp (list - (partial + 3) (partial * 10))) 1)

1:36 clojurebot: -13

1:36 turbofail: if you're going to use reduce you'd need to reverse the sequence of functions relative to how you'd use it with apply comp

1:38 mindbender1: turbofail: okay. thanks

1:53 TEttinger: so... lein repl seems to be completely clueless about unicode on windows

2:00 justin_smith: your prior recommendation of java -jar clojure.jar works fine though

2:33 visof: hi guys

2:33 how can i connect to the current clojure process from repl?

2:34 and interact with the loaded in memory variables

2:36 turbofail: you can only do that if you're running an nrepl server in that clojure process

3:47 jonathanj: can't you use liverepl to connect to it even if you're not running an nrepl?

3:48 https://github.com/djpowell/liverepl

3:48 Start a Clojure REPL connected to any running Java or Clojure process

3:48 without needing the process to be setup in any special way beforehand.

4:31 domgetter: Are there any good Youtube videos showcasing this "repl development" thing I keep hearing about?

4:33 jonathanj: can i use `memoize` with defrecord or reify?

4:33 domgetter: I'm under the impression that it's something more than just firing up lein repl and typing in stuff. Then it'd be no more than irb. If there aren't any good youtube vids, lemme know if you know any good blog posts explaining it

4:38 jonathanchu: I don't think so because memoize takes a referentially transparent function, and defrecord and reify are both macros.

5:19 jeaye: Is there a cleaner way to do:

5:19 (into [(nth item 0) (nth item 1) (nth item 2)] (some-data))

5:19 (take 3 item) gives a list, but I need a vector.

5:24 domgetter: jeaye does this cut it? (into [] (take 3 (range)))

5:25 jeaye: domgetter: I also need (some-data) to go in.

5:25 domgetter: jeaye what is (some-data) ? a list? vector? map?

5:25 jeaye: both item and (some-data) are vectors.

5:27 domgetter: ,(into [] (take 3 (concat [3 4] [ 7 8 9])))

5:27 clojurebot: [3 4 7]

5:28 jeaye: ah, close

5:28 ,(into [] (concat (take 3 [1 2 3 4 5]) [4 5 6]))

5:28 clojurebot: [1 2 3 4 5 ...]

5:28 jeaye: More accurately represents my issue, but concat will do it.

5:28 Thanks, domgetter

5:28 domgetter: ah you wanted the first three and then all of some-data. got it

5:28 jonathanj: can i provide a default implementation for a protocol method?

5:29 domgetter: and also, concat is lazy

5:29 ,(into [] (take 5 (concat (take 3 [ 5 6 7 8]) (range 1000000))))

5:29 clojurebot: [5 6 7 0 1]

5:30 jeaye: Doesn't affect anything, in this case.

5:30 spacepluk: is there any good commandline autoformatter I can use with vim?

5:31 jeaye: spacepluk: gg=G

5:31 spacepluk: Or do you want more?

5:31 spacepluk: jeaye: I'm using that but it doens't work when the code is in a single line (aka. stuff from the repl)

5:31 jeaye: Right.

5:32 spacepluk: You can easily hook one up using pprint

5:32 It allows you to set max width and the like. I haven't seen any that're vim-ready.

5:33 spacepluk: does pprint indent "code" taking into account special forms, etc?

5:34 jeaye: Hm, no, it doesn't take into account special forms.

5:35 ridcully: spacepluk: cljfmt?

5:36 jeaye: spacepluk: If you get something hooked into vim, ping me. I'd be interested in using it.

5:36 spacepluk: jeaye: sure :)

5:38 ridcully: I'm trying that, thanks

5:44 domgetter: What is an "nrepl server"?

5:44 spacepluk: oh, it has the same problem with huge single line expressions

5:45 domgetter: what sorts of things can connect to the "nrepl server" that lein has created when I ran lein repl?

5:52 spacepluk: domgetter: usually you evaluate stuff in your program straight from your editor

5:53 domgetter: so you can change things while the program is running

5:53 domgetter: or inspect the program's state

5:55 domgetter: spacepluk: I'm not sure what you mean. " straight from your editor " You mean like a watchter? Or copy-paste? or something else more magical?

5:55 spacepluk: domgetter: this is clojurescript but is very illustrative -> https://www.youtube.com/watch?v=KZjFVdU8VLI

5:56 domgetter: So does Figwheel load the whole file over again?

5:57 spacepluk: figwheel yes

5:57 but you can evaluate only parts if you want to

5:57 domgetter: and I thought Figwheel uses websockets to do it's job. Is that not the case?

5:57 spacepluk: you can use it with nrepl with piggieback

5:58 it's a bit tricky though

5:58 domgetter: I don't understand that statement

5:58 spacepluk: https://github.com/cemerick/piggieback

5:58 domgetter: "You can use it with nrepl" I don't even know what this means

5:59 I read that nrepl was a network repl, and I don't know what a network repl is

5:59 spacepluk: nrepl runs on the jvm

5:59 your program runs the nrepl server

5:59 and you send expressions to evaluate through the network

6:00 domgetter: Okay. "nrepl runs on the jvm" I understand what this means. "your program runs the repl server" I'm lost again.

6:00 If the jvm runs nrepl, how does my program run nrepl?

6:01 spacepluk: because the are in the same jvm instance

6:01 domgetter: so does my program run it, or does it just interact with it?

6:01 spacepluk: or if you're using clojurescript then the jvm runs nrepl+piggieback and you program runs somewhere else

6:01 ridcully: spacepluk: you mean, you have a huge oneliner in your vim, you save it while the cljfmt plugin is on and it wont format that line properly?

6:01 spacepluk: domgetter: they run side by side as far as I can understand

6:01 ridcully: yes

6:02 ridcully: how long is that line? i have not used it other than regular code

6:02 domgetter: spacepluk: okay. so "you send expressions to evaluate through the network".

6:02 I send (+ 2 3) from where to where?

6:02 spacepluk: ridcully: stupidly long hehe, it's an edn I get from the repl as one line

6:03 domgetter: from some nrepl client (your editor, leiningen's console, etc.)

6:04 jeaye: spacepluk: Maybe you want vim-fireplace.

6:04 domgetter: spacepluk: Wait, isn't leiningen running an nrepl server? Or is it doing both at the same time?

6:04 spacepluk: jeaye: I'm already using that :)

6:04 domgetter: nREPL server started on port 60261 on host - nrepl:// is what I get when I run lein repl

6:04 ridcully: spacepluk: have you tried running it standalone. never used it - but iirc you can also use it from lein (cljfmt that is)

6:04 jeaye: spacepluk: Then, instead of using the repl, you can use vim and properly format your code.

6:04 spacepluk: domgetter: I think the console is also a client but I'm not sure

6:05 domgetter: spacepluk: alright no prob. Thank you for taking time to explain this to me

6:05 spacepluk: domgetter: np :)

6:08 jeaye: the problem is that oneliners aren't formatted properly afaict

6:08 ridcully: I'll try that in a bit

6:42 troydm: dnolen: http://dev.clojure.org/jira/browse/LOGIC-177

6:43 dnolen: the thing I've talked about yesterday

7:30 NockNocx: would you delcare this definiton "a function f assigns an output f(x) to every input x" by an expression?

7:30 I mean in clojure function style

8:27 noncom: NockNocx: what do you mean?

8:27 NockNocx: nevermind

8:28 noncom: NockNocx: to me there's too much noise in the statemtnt.. for example, "assigns" - what do you mean by that? functions do not assign anything... but i don't know what you implied

8:28 ah ok

9:42 dnolen: troydm: ok I can reproduce that. Not sure when I will have time to look at it - so patch welcome.

9:45 troydm: dnolen: okey, I'll try to investigate the root of the issue, if I'll find the cause I'll let you know

9:46 dnolen: troydm: it's definitely as you say something to do with the output bit

9:46 I suspect reification

10:38 troydm: dnolen: so far from what I see the problemy is indeed in reifyg function

10:39 dnolen: also as I'm not familiar with how this whole reification works it's hard to understand if the issue is related to walk* function or not

10:40 dnolen: troydm: it's likely

11:16 justin_smith: pi@raspberrypi ~ $ time java -cp bench.jar clojure.main -e '(println "hello")'

11:16 pi@raspberrypi ~ $ time java -cp bench.jar clojure.main -e '(println "hello")'

11:17 pi@raspberrypi ~ $ time java -cp bench.jar clojure.main -e '(println "hello")'

11:17 pi@raspberrypi ~ $ time java -cp bench.jar clojure.main -e '(println "hello")' => hello => real 0m7.345s

11:17 oh sorry!

11:28 anyway, about 8 seconds startup, uses about 30 megs for a repl

11:28 now to do some testing with criterium

11:32 so (assoc {} :a 0) takes 25 ns on this box, 673 ns on the raspberry pi

11:38 xemdetia: justin_smith, just to be nosy what jvm are you using on the pi

11:39 justin_smith: java version "1.8.0" Java(TM) SE Runtime Environment (build 1.8.0-b132) Java HotSpot(TM) Client VM (build 25.0-b70, mixed mode)

11:42 xemdetia: is that oracle though

11:42 justin_smith: yeah, hostspot is oracle

11:43 xemdetia: I am too used to looking at non-Oracle JVM outputs apparently!

11:44 justin_smith: this is the java that came pre-installed on the default raspbian distro

11:46 xemdetia: yeah I am just reading about that, I didn't realize they actually were shipping a full oracle jvm

12:32 sohail: is there a way to "look up" a function value at the time of invocation? The problem I'm having is trying to make a page reloadable via figwheel: (.requestAnimationFrame js/window -interpolation-loop) <-- if figwheel reloads, it seems to still use the old value for the function

12:33 zophy: hi

12:39 sohail: nevermind, the issue was actually with reloadability via clojure.async

12:43 raeTae9a: So I want to create an eDSL and I don't want to manually walk and parse incoming sexps, what library can help me with that?

12:44 I'm sure I've seen a talk about something like what I need on the late clojure\conj or some other conference, but I can't find the library the talk was about.

12:46 justin_smith: raeTae9a: maybe you want instaparse?

12:46 xemdetia: raeTae9a, instaparse? edn?

12:47 justin_smith: raeTae9a: if the data is coming in as sexps, you could use read / read-string and then work with the nested structures returned

12:47 ,(read-string "(+ (foo bar) (baz) quux)")

12:47 clojurebot: (+ (foo bar) (baz) quux)

12:47 justin_smith: it gives you the parsed structure, but doesn't evaluate anything

12:48 raeTae9a: justin_smith: um, the problem is not to parse the string, the problem is to transform the given data (which is already in edn).

12:48 I'm sorry I confused you by using the word "parsing".

12:48 I need something like instaparse, but for sexps, not for plain text.

12:49 So I can specify the structure of sexps I expect and it would "parse" it and throw error if the structure doesn't match.

12:50 justin_smith: prismatic/schema is good for describing structures you expect

12:53 raeTae9a: I'm not being clear enough. Schema is not what I want either. Imagine you're writing some def* macro: (defmacro deffoo [& more]) - here you have to manually "parse" that more collection. What I want is something like: (defmacro' deffoo [name doc-string? (foo bar? :as coll)*] ...), and then it would return arguments in a map: {:name ..., :doc-string nil, :coll [{:foo ... :bar ...}]}

12:55 justin_smith: ,((fn [name doc-string & [foo bar :as coll]] {:name name :doc-string doc-string :foo foo :bar bar}) 'a 'b 'c 'd)

12:55 clojurebot: {:name a, :doc-string b, :foo c, :bar d}

12:56 raeTae9a: Ah, here is that talk: https://www.youtube.com/watch?v=kt4haSH2xcs -- but that guy's github doesn't have that lib, guess he's still working on it.

12:56 justin_smith: raeTae9a: that stuff is going to be in his cursive editor

12:58 lambda-11235: Another talk is https://www.youtube.com/watch?v=o75g9ZRoLaw, the library is at https://github.com/jclaggett/seqex.

13:00 raeTae9a: lambda-11235: thanks, I guess that's it! I'll the talk right now, thank you once again.

13:09 sohail: is there a way with leiningen to compile clj file as cljs?

13:09 I've got some common logic and I want to use it both client and server

13:09 justin_smith: sohail: this is what cljc is for

13:10 if a cljc file is on the source-path, both cljs and clj can use it

13:10 sohail: cool, thanks justin_smith

13:37 in world.cljc, I have (defrecord World ...) but when I :refer map->World it doesn't seem to exist. Am I missing something?

13:38 justin_smith: the syntax would be :refer [map->World]

13:38 sohail: I am using that syntax

13:39 justin_smith: then you are doing something else wrong, because that works

13:39 sohail: "referred var world/map->World does not exist"

13:39 justin_smith: do you have a world.clj or world.cljs that the compiler might pick up instead?

13:39 sohail: I do not

13:39 justin_smith: and are you using clojure 1.7 or newer?

13:40 sohail: clojure 1.7.0, clojurescript 1.7.170

13:42 so I have client.cljs referring to world.cljc

13:42 I confirmed that it IS using the right file

13:43 justin_smith: sohail: when I make a file with (defrecord World []) and then require it with (require '[world :refer [map->World]]) it works

13:44 sohail: justin_smith: world.cljc and client.cljs?

13:44 justin_smith: sohail: this is from clj, I didn't set up cljs for this

13:44 sohail: yeah I suspect it's a cljs issue

13:44 justin_smith: no

13:45 one moment, getting cljs, this works

13:45 sohail: why so certain?

13:45 justin_smith: sohail: because I do this every day at work

13:45 this isn't a broken feature

13:45 sohail: ok

13:47 so odd

13:47 I added (defn make-world [] (-> World)) and :refer [make-world] and it works fine

13:49 justin_smith: make-world returns the class not an instance

13:49 sohail: I meant the referring

13:50 justin_smith: sure, just saying

13:50 sohail: oops I see the typo

13:50 was actually using map->World

13:57 justin_smith: sohail: it works https://gist.github.com/noisesmith/8127c7e3540c6333f9f3

13:57 and now I know how to use cljs.jar directly, which is cool

13:57 sohail: omg

13:57 I had deftype... /facepalm

13:58 justin_smith: sohail: well I glad you figured it out, and I got something out of it anyway because I finally got off my ass and learned how to use cljs.jar :)

13:58 sohail: everyone wins!

13:58 :)

13:58 thanks for helping though... pebkac

14:13 BRODUS: the clojurescript channel is dead so i'll ask here, is anyone here familiar with om?

14:13 sohail: BRODUS: I'm using it right now, but I probably can't help you

14:14 BRODUS: I'm trying to grok whats happening in the second code block here, https://github.com/omcljs/om/wiki/Advanced-Tutorial , specifically the IDidMount implementation

14:15 sohail: what's the issue

14:20 BRODUS: i just don't understand the motivation for whats happening there, data about the table is being put on the request channel that the owner exposes, including a response channel

14:21 justin_smith: BRODUS: this is being done so that the reply to the response channel can be propagated back - sending a message including a response channel is a common core.async idiom

14:21 BRODUS: and in the second sexp in that go block, it looks like the code waits to take an item from the response channel and update the table state

14:22 justin_smith: BRODUS: go blocks return immediately

14:22 the set-state! call will happen after the response is read

14:22 (async, of course)

14:22 BRODUS: right, but youre still creating code that waits for something to appear on the channel

14:23 justin_smith: yes

14:24 BRODUS: the message will be handled by the serve function defined prior, and it will put the result on res

14:26 BRODUS: ok i get it

15:09 sohail: is there a double-ended queue in clojure?

15:10 justin_smith: BRODUS: the message will be handled by the serve function defined prior, and it will put the result on res

15:10 sorry

15:14 hiredman: not included in the languge, the jvm has mutable deques built it though, and immutable deque libraries exist

15:16 sohail: hm, I'd rather stick to clojure data structures. Maybe I can just take the performance hit for the infrequent operation

16:40 domgetter: Is this a place to ask clojurescript questions or is there a different more appropriate channel?

16:41 If so, why does (js/console.log 6) not print to the console in Firefox?

16:44 ridcully: there is also #clojurescript, but usually no one minds

16:44 above statement prints just fine in firebug

16:44 do you have switched your console to a higher loglevel by accident?

16:45 domgetter: Interesting. You're right that it prints in firebug

16:46 I get this from the console (from right-click Inspect-Element console): https://gist.github.com/domgetter/4d995efa1f86c1e4be43

16:47 ridcully: yeah don't see output on the internal console too with fx43

16:48 didn't bother me, since i don't use it

17:01 felixn: does clojure have something like haskell `where`? my problem inherently has a lot of branching, and the code is hard to understand with lots of nested lets. it would be nice if I could just declare all the bindings, then lazy eval bindings as needed

17:03 justin_smith: felixn: why do your lets need to nest?

17:04 also you can do something like a lazy binding with (delay (f x)) - you need @ to access the value, and the first time you do so it is forced

17:04 felixn: justin_smith: only when I know something about the value, can I then check for nested values in the data

17:04 :O

17:06 justin_smith: ,(let [a (delay (do (println "forced a") (+ 1 1))) b (delay (do (println "forced b") (+ @a 22))] nil)

17:06 clojurebot: #<RuntimeException java.lang.RuntimeException: Unmatched delimiter: ]>

17:06 justin_smith: oops

17:06 ,(let [a (delay (do (println "forced a") (+ 1 1))) b (delay (do (println "forced b") (+ @a 22)))] nil)

17:06 clojurebot: nil

17:06 justin_smith: ,(let [a (delay (do (println "forced a") (+ 1 1))) b (delay (do (println "forced b") (+ @a 22)))] a)

17:06 clojurebot: #object[clojure.lang.Delay 0x20ae4a7b {:status :pending, :val nil}]

17:07 justin_smith: ,(let [a (delay (do (println "forced a") (+ 1 1))) b (delay (do (println "forced b") (+ @a 22)))] @a)

17:07 clojurebot: forced a\n2

17:07 justin_smith: ,(let [a (delay (do (println "forced a") (+ 1 1))) b (delay (do (println "forced b") (+ @a 22)))] @b)

17:07 clojurebot: forced b\nforced a\n24

17:07 justin_smith: felixn: maybe that helps?

17:08 usually you won't even need delays though

17:08 felixn: https://gist.github.com/munro/8a7073b09dc3e02d7605 <-- justin_smith: yea thanks a lot, that's so cool!

17:09 justin_smith: felixn: does the delay do anything there?

17:09 felixn: in that example it would obviously return nil, but I have some bindings that try to do calculations on wrong types

17:09 justin_smith: oh, got it

17:10 felixn: it's also useful for error handling / short circuiting - being able to build up nested calculations but not realizing the ones you don't need in a particular conditional branch

17:18 felixn: also, notice you can use bindings from one let clause in the next

17:18 within a single block (unlike eg. the let in common lisp)

17:18 felixn: justin_smith: oh yea I'm doing that, I smashed a bunch of branching into one cond :D

17:23 it felt wrong even doing (count x) multiple times, so I was using nested lets. not sure if memoizing is faster than recounting, but pulling all the binding setup out of my logic made the code way more readable

18:28 j-pb: deftype can't implement finalize right?

18:30 justin_smith: ,(deftype T [] Object (finalize [this] (println "gone")))

18:30 clojurebot: sandbox.T

18:31 justin_smith: j-pb: finalizers run much later than you might expect

18:32 sometimes, never

18:34 j-pb: here I use a function that will create a lot of churn, to make the gc happen that will clean up the object: https://gist.github.com/noisesmith/73a632ff0bf2774c2958

18:37 j-pb: justin_smith: yeah, I need it to release some JNI resource :/

18:37 I'd prefer to avaoid it as well ^^

18:37 justin_smith: j-pb: what about allowing the code to manually release the resource, then releasing in the finalizer just in case?

18:38 well, only releasing if it is hanging around, of course

18:39 j-pb: justin_smith: yeah, but that might accidentally invalidate a lot of other stuff

18:39 I'm writing a rocksdb wrapper

18:39 you get a connection object, then you can deref it to get a snapshot of the current db state

18:39 the problem is that the snapshots need to be manually released

18:39 however, you can iterate over the snapshots with seq's and the like

18:40 so releasing a snapshot might invalidate a lot of seqs mid read

18:41 justin_smith: do deftypes require their super finalizer to be called somehow?

18:42 justin_smith: "super finalizer" ?

18:42 j-pb: faik finalize doesn't propagate up the object hierarchy, so if a superclass requires the call of finalize, it has to be done manually in java

18:42 super.finalize()

18:43 justin_smith: j-pb: a deftype can't have a super

18:43 j-pb: yeah, I was just wondering if maybe there is some clojure implementation detail that actually requires this ^^

18:44 justin_smith: j-pb: clojure just uses the jvm, it doesn't change any of that core stuff - the closest you might get is the extra stuff it makes for protocols that make them different from interfaces, but even that doesn't change how interfaces work

18:44 j-pb: yeah, actually protocols led me to that thought

18:45 thanks ^^

18:58 sohail: is there some simple way to check if a value falls in a range? like a in [0,4)

18:59 justin_smith: ,(< 10 42 1000)

18:59 clojurebot: true

18:59 justin_smith: ,(< 10 420 100)

18:59 clojurebot: false

18:59 sohail: ah

19:00 clever

19:00 j-pb: ,((into #{} (range 10 100) 42)

19:00 clojurebot: #<RuntimeException java.lang.RuntimeException: EOF while reading>

19:00 j-pb: ,((into #{} (range 10 100)) 42)

19:00 clojurebot: 42

19:00 j-pb: ,(boolean ((into #{} (range 10 100)) 42))

19:00 clojurebot: true

19:00 j-pb: ,(boolean ((into #{} (range 10 100)) 101))

19:00 clojurebot: false

19:00 justin_smith: j-pb: sure, if you want to do it the hard way

19:00 j-pb: :P

19:01 yeah I was about to add, don't do this it's just a horrible proof of concept to show off as many clojure features in one go as possible :D

19:01 justin_smith: haha

19:01 TEttinger: now add destructuring

19:01 j-pb: better

19:01 core.match

19:01 TEttinger: Om

19:01 j-pb: om.next

19:02 justin_smith: swearjure

19:02 TEttinger: seq abstraction...

19:02 j-pb: lol

19:02 TEttinger: transducers

19:02 tolstoy: Generate the byte-code to a file, then load it back in?

19:04 j-pb: alright guys I'll head to bed, it's late here in germany, have a nice feast everybody :D

19:04 justin_smith: I've got to use that saying more often

19:04 have a nice feast!

19:04 j-pb: :D

19:05 tolstoy: Better ring then, "Enjoy a delightful repast."

19:27 justin_smith: ,(do (def a 'b) (def b 'c) (def c 'd) (def d 'e) (def e 'f) (def f 'g) (def g 'a))

19:27 clojurebot: #'sandbox/g

19:27 justin_smith: ,(apply str (iterate eval 'a))

19:27 clojurebot: eval service is offline

19:27 justin_smith: oh wait, that won't work

19:28 ,(apply str (take 400 (iterate eval 'a)))

19:28 clojurebot: "abcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefg...

19:29 justin_smith: ,(def m {:a :b :b :c :c :d :d :e :e :f :f :g :g :a})

19:29 clojurebot: #'sandbox/m

19:29 justin_smith: ,(apply str (take 400 (iterate m :a)))

19:29 clojurebot: ":a:b:c:d:e:f:g:a:b:c:d:e:f:g:a:b:c:d:e:f:g:a:b:c:d:e:f:g:a:b:c:d:e:f:g:a:b:c:d:e:f:g:a:b:c:d:e:f:g:a:b:c:d:e:f:g:a:b:c:d:e:f:g:a:b:c:d:e:f:g:a:b:c:d:e:f:g:a:b:c:d:e:f:g:a:b:c:d:e:f:g:a:b:c:d:e:f:g:a:b:c:d:e:f:g:a:b:c:d:e:f:g:a:b:c:d:e:f:g:a:b:c:d:e:f:g:a:b:c:d:e:f:g:a:b:c:d:e:f:g:a:b:c:d:e:f:g:a:b:c:d:e:f:g:a:b:c:d:e:f:g:a:b:c:d:e:f:g:a:b:c:d:e:f:g:a:b:c:d:e:f:g:a:b:c:d:e:f:g:a:b:c:d:e:f:g:a:b:c:...

19:31 ridcully: is this your ipv16 addy?

19:31 justin_smith: heh

19:34 TimMc: justin_smith: Oh man, I haven't done any swearjure in forever. I'm probably out of practice!

19:35 justin_smith: TimMc: since Raynes will be taking refheap down for good, I am trolling through to find the stuff I need to turn into gists, and as I go I'm also finding some old code memories

19:37 TimMc: Wait, refheap is going away? D-:

19:37 justin_smith: TimMc: haxors were using it for haxing

19:37 TimMc: Raynos: Say it ain't so!

19:38 justin_smith: Nooo, Raynes should just turn off writes.

19:39 Existing pastes could be rendered to static pages so it wouldn't even need a DB or a JVM.

19:39 justin_smith: TimMc: that will be the first step

19:39 or so he said

19:40 TimMc: Maybe I'll archive all refheap links from this room.

19:40 If he's planning on taking it down, I should contact The Angel of Death over at the Internet Archive to make sure they get a scan of it.

19:41 ridcully: darn, now it's slayer time

19:41 TimMc: https://en.wikipedia.org/wiki/Archive_Team

19:52 This gets me the IDs of all refheap links in my IRC: grep '(https?://)?(www\.)?refheap\.com/(paste/)?[0-9a-f]+' -P -rho chatlog/ | sed 's|/paste/|/|' | sed 's|.*\.com/||'

19:58 OK, archiving.

20:08 TEttinger: awww crap how's my lazybot going to paste stuff

20:08 TimMc: fffff, efnet IRC thinks I'm running a Tor exit and won't let me connect

20:18 princeso: How to create a function by a macro that may be called by itself? http://pastebin.com/L2CN57uB

20:32 TimMc: princeso: I'm unclear on what you're trying to make.

20:35 TEttinger: princeso: essentially a function that is executed when it's read, right?

20:35 I am pretty sure clojure doesn't allow that except with reader literals, and even then it's rather limited

20:36 princeso: TimMc thanks: A looping function. repeat the body for new bindings

20:36 TEttinger: what about loop doesn't work here?

20:36 (doc loop)

20:36 princeso: TEttinger thanks: yes

20:36 clojurebot: "([bindings & body]); Evaluates the exprs in a lexical context in which the symbols in the binding-forms are bound to their respective init-exprs or parts therein. Acts as a recur target."

20:38 princeso: TEttinger jusot was playing with loop-recur and it failed at some point

20:50 TimMc: 3619 refheap pastes archived so far

21:00 Hmm, should have used the JSON API so I could get author information.

21:11 sohail: is there a way to generate a permutation of elements in two lists? so [a b] [c d] -> [[a c] [a d] [b c] [b d]]

21:12 presumably doseq has to do this

21:13 justin_smith: sohail: doseq can only generate nil

21:14 sohail: right, I mean a way to generate the *permutation* so that I can map over it

21:14 justin_smith: like I said, doseq can only return nil

21:15 it never returns any other value

21:15 ,(for [x '[a b] y '[c d]] [x y])

21:15 clojurebot: ([a c] [a d] [b c] [b d])

21:15 sohail: I see

21:15 thanks

21:43 amalloy: sohail: that's called the cartesian product, by the way, not permutations

21:47 sohail: amalloy: right, brain fart AxB

21:47 learning clojure, clojurescript and trying to do a programming challenge... #nerdholidays

21:49 so what happens when you build up a whole whack of teeny modifications to an object? say (-> obj tweak tweak tweak tweak). Are these ever optimized? Can they be?

21:50 say tweak is something like assoc

21:50 justin_smith: sohail: clojure itself does almost 0 optimization. The vm does some optimizations, the kinds it does are complex but well documented.

21:52 sohail: it just seems wasteful to create 4 new objects to modify 4 fields in a loop

21:52 justin_smith: sohail: so you are always better off doing (assoc m :a x :b y :c z) rather than (-> m (assoc :a x) (assoc :b y) (assoc :c z)) - clojure won't change the latter (much slower) into the former for you

21:53 sohail: what makes you think that creates 4 objects?

21:53 it's 4 calls, sure

21:53 sohail: the docs: "When applied to a map, returns a ***new*** map of the same (hashed/sorted) type"

21:54 justin_smith: OK, in the sense of the container object yes. But likely the structure is shared between them.

21:54 some structure, at least

21:55 but yeah, don't do 4 assoc calls in a row, it's wrong and clojure won't fix that for you

21:55 assoc is varargs for a good reason

21:56 ben_vulpes: so i've got a project with ~180 lines of source and takes over 10 minutes to produce an uberjar with lein. where should i start poking to optimize this compile time?

21:57 justin_smith: ben_vulpes: you can trade shorter compile time for longer startup by making a shim that calls require and resolve inside a function to load your real code at runtime

21:58 or even turn off aot altogether and manually specify the namespace that clojure.main should load at runtime

21:59 ben_vulpes: so if i specify the :main ns, and attach some aot never metadata to my -main fn, i might see speedup in compiling?

21:59 justin_smith: ben_vulpes: by not compiling

22:00 by not specifying a :main, and not :aot compiling

22:00 by not having an actual -main, and using clojure.main, telling it to load and run your ns

22:01 well you should still have a -main I guess - it just won't generate the class java runs

22:02 ben_vulpes: :aot is recursive - things you require will get aot compiled too - which is why the shim thing works out

22:02 only aot the one ns, that's super fast because it doesn't have any top level deps except clojure.core (already compiled in clojure.jar)

22:02 ben_vulpes: hm

22:02 these are new depths for me

22:03 justin_smith: then you have (defn -main [& args] (require 'my-actual-ns) (apply @(resolve 'my-actual-ns/my-actual-main-fn) args))

22:03 that way, the stuff still gets launched, despite not being aot compiled

22:04 ben_vulpes: gotcha

22:04 justin_smith: the resolve is needed, of course, because otherwise the function would fail to compile

22:04 ben_vulpes: okay, so i'm somewhat accustomed to just uberjar'ing these things up via lein: where would i stick that -main fn, and how would i boot it with clojure?

22:05 justin_smith: ben_vulpes: you still run uberjar

22:05 ben_vulpes: java -jar my.jar my/-main << something like that?

22:05 justin_smith: ben_vulpes: I described two approaches

22:05 if you use the shim with resolve, just java -jar my.jar

22:06 if you don't aot (not even a shim) you do java -cp my.jar clojure.main my.ns

22:06 ben_vulpes: another fun trick up this same alley: java -cp my.jar clojure.main gives you a repl with all deps and code of your project

22:08 ben_vulpes: aha, i think i get it now.

22:09 needed to reread thrice to understand the shim ns

22:09 justin_smith: ben_vulpes: it just avoids compiling because its real deps (your actual code) are not loaded until -main is called

22:10 so it breaks the "recursive aot" chain

22:10 ben_vulpes: right on

22:11 justin_smith: ben_vulpes: chances are you have some dep that compiles slowly - maybe one of those macro castles like core.match, core.logic

22:11 ben_vulpes: i just ripped byte-streams out

22:11 might be datomic at this point

22:18 justin_smith: ben_vulpes: if you do the shim, that should show you the minimal compile time, and you could see what happens if you add certain deps to the shim namespace (even if they are not explicitly used)

22:19 that might help you narrow down what takes so long to compile

22:19 oooh - or you could profile the uberjar process

22:20 ben_vulpes: good thinking, justin_smith

22:21 on the dep-muntzing via shim ns

22:22 interestingly, this still takes longer than booting via leiningen and them compiling my tiny core ns from emacs

22:23 justin_smith: ben_vulpes: any chance you are using a weird filesystem for target/ ?

22:24 ben_vulpes: nope, vanilla mac drive

22:28 ah jesus i know precisely what the problem is.

22:28 justin_smith: oh?

22:28 lemme guess "sh sleep 50000" as a prep task?

22:29 ben_vulpes: well defs with side effects but yeah

22:30 justin_smith: oh that'll do the trick, lol

22:30 ben_vulpes: dirty secret: a big reason for my using the shim method above is that it is easier than teaching and reteaching all my coworkers how shitty defs with side effects are and how not to do them

22:31 TimMc: oh dear

22:31 ben_vulpes: 24s

22:31 TimMc: Certainly not the only reason, though.

22:31 ben_vulpes: Coming into this in media res, but are you looking to find out why compilation is slow?

22:31 justin_smith: a more pleasant way to put it is "not aot compiling reduces the differences between development environments and deployed code"

22:33 ben_vulpes: TimMc: more or less

22:33 and pebkac was the diagnosis

22:34 TimMc: Ah, what was it?

22:35 ben_vulpes: side effects in defs

22:36 TimMc: fun times

22:36 ben_vulpes: This is a script that will modify your codebase to show compilation progress, by the way: https://gist.github.com/timmc/7359898

22:37 I've used this before to locate a thing that was making the compiler freak out and give a useless error message.

22:37 justin_smith: TimMc: my least favorite part of switching from linux all the time to using osX at work was finding out that osX sed -i is weird

22:38 TimMc: Uh oh, what does it do?

22:39 justin_smith: TimMc: http://blog.remibergsma.com/2012/09/18/sed-inline-editing-different-on-mac-osx/

22:39 amalloy: osx grep is terrible too. doesn't support a bunch of stuff i use regularly. but you can install the gnu tools on top of them

22:39 TimMc: ben_vulpes: If compilation is still too slow, I also have this lovely hack for compiling onto a ramdisk: https://gist.github.com/timmc/6c397644668bcf41041f

22:39 justin_smith: amalloy: you can, but I was making a tool that a whole team of osx users were running :( it was sad

22:41 TimMc: justin_smith: I don't understand "sed: -i may not be used with stdin" -- the example specifies a file argument, so why is it trying to read from stdin?

22:41 justin_smith: TimMc: the message is garbage, the fix is to supply '' as your backup file suffix

22:42 TimMc: lovely

22:42 justin_smith: so -i becomes -i ''

23:00 ,(= (sort "mr. creamy shirts") (sort " merry christmas."))

23:00 clojurebot: true

23:01 ben_vulpes: clever ramhack TimMc

23:03 TimMc: I have no idea if it works on mac. :-P

23:04 justin_smith: TimMc: if I had a mac here I'd test, I left my work machine at the office

23:04 TimMc: It works *really* well for me on linux. I have a script I run atfter startup that runs that script in every dev directory, and I can't recommend it enough.

23:06 Bear in mind that the reason I need this is probably because I have an encrypted hard drive.

23:07 justin_smith: TimMc: same here, so it looks interesting

23:08 TimMc: have you considered making it a plugin I could add as a prep-task in my repo?

23:08 (maybe with a conditional "is this linux" check)

23:09 I guess it could just be put in there via lein exec now that I think about it

23:12 TimMc: It needs sudo to mount the fs. Maybe there's a FUSE thing I could do...

23:14 TEttinger: ,(= (hash (sort "mr. creamy shirts")) (hash (sort " merry christmas.")))

23:14 clojurebot: true

23:14 TEttinger: (what did I expect)

23:16 justin_smith: TEttinger: I was using sort / = as an anagram test

23:24 TEttinger: ,(= (sort "injured this smut") (sort "rude justin smith"))

23:24 clojurebot: true

23:24 justin_smith: haha

23:30 TEttinger: ,(= (sort "some menger kitty treat") (sort "tommy streak ettinger "))

23:30 clojurebot: false

23:30 TEttinger: mmm

23:31 justin_smith: ,(defn anagram-helper [original] (fn [new] (reduce #(update % %2 (fnil dec 0)) (frequencies original) new)))

23:31 clojurebot: #'sandbox/anagram-helper

23:32 justin_smith: ,(def tettagram (anagram-helper "tommy streak ettinger "))

23:32 clojurebot: #'sandbox/tettagram

23:32 justin_smith: ,(tettagram "injured this smut")

23:32 clojurebot: {\space 1, \a 1, \d -1, \e 2, \g 1, ...}

23:32 TEttinger: ,(= (sort "some menger kitty tart") (sort "tommy streak ettinger "))

23:32 clojurebot: true

23:33 justin_smith: ,(tettagram "some menger kitty tart")

23:33 clojurebot: {\space 0, \a 0, \e 0, \g 0, \i 0, ...}

23:33 justin_smith: see- all zeroes means it's correct

23:33 TEttinger: heh

23:33 justin_smith: but it helps you see which chars need adjusting

23:33 TEttinger: yep!

23:34 oh yeah, that classic clojure one-liner I always paste to summon nyarlothotep, I keep finding ways to improve on the technique now. it's longer, but I have the same algorithm in a java program now.

23:36 Жыдотуф руц пйцас, гогутяр шыскучэбаб - гйчапофёглор гюнуз ъсказюжин.

23:36 I'm sure in any actual russian-like language that's gibberish

23:36 it wasn't made using any dictionary

23:37 romanized, it's Zhydotuf ruts pitsas, gogutiar shyskuchebab - gichapofeglor giunuz ieskaziuzhin.

23:37 TimMc: You take that back! My grandmother would never do such a thing.

23:37 (No, I don't know Russian either.)

23:38 justin_smith: ,(defn an [original new] (remove (comp zero? val) (reduce #(update % %2 (fnil dec 0)) (frequencies original) new)))

23:38 clojurebot: #'sandbox/an

23:38 justin_smith: ,(an "cat" "taco")

23:38 clojurebot: ([\o -1])

23:38 justin_smith: that's the way to do it

23:38 tells you exactly what needs adjusting - negative means remove from right or add to left, positive means visa versa

23:38 TEttinger: khuy, baba yaga, nyet, da. that's pretty much all I can remember

23:39 justin_smith: TEttinger: there's lots of useful day to day russian in clockwork orange

23:39 moloko, horoshow, droogs

23:39 etc.

23:39 TEttinger: "one of the four principal cusses in russian", "a famous mythological witch", "no", "yes"

23:40 TimMc: kvass

23:41 justin_smith: vodka: diminutive of water, like a cutesy name for some water

23:41 (voda is water)

23:42 TimMc: hah

23:42 justin_smith: eg. katka is a nickname for kat

23:42 same form

23:43 TimMc: I bought some kvass from the local Russian market last year. It's pretty good for something that tastes like raisin bread soda.

23:43 justin_smith: we have a lot of russians here, I went to an awesome russian restaurant recently, they had like 30 different kinds of pickled things and 100 different kinds of vodka

23:44 I tried a vodka from vermont that tasted just a little bit like maple

23:45 TimMc: It would be hard not to, it gets into the groundwater.

23:45 the people smell faintly of syrup

23:46 justin_smith: TimMc: ages ago, when I lived in vermont, there were squirrels that learned how to chew through the tubing that collected sap from the trees, and they would get fat on delicious maple sap in the fall and spring

23:47 TEttinger: hahaha

23:48 my brother wants one of these fat squirrels now

23:49 justin_smith: haha

23:49 fat squirrels can be kind of cute

23:50 TEttinger: it's interesting, on the house balcony (which now has an area we use as a "cat-io", fenced in so the cats can go outside-ish and get sun and watch birds but not catch em), we used to get both squirrels and rats at different times of day

23:50 the squirrels were ALWAYS territorial. but despite a nasty reputation, the rats were always friendly with other rats

23:52 (my 2 rat bites on my fingers have healed btw. the cat-io wasn't always sealed from rats... and a cat brought one downstairs like a baby. after 30 minutes, the rat was just fine but now outside, and I had mostly stopped bleeding profusely)

23:55 sohail: what is people's favourite websocket implementation for clojure + clojurescrpit? mostly for prototype purpose so productivity is important

23:56 justin_smith: sohail: sente is a cinch

23:56 (= (sort "yo justin, too rare festivus smith") (sort "some furtive joints, that is yours")

23:56 oops!

23:56 ,(= (sort "yo justin, too rare festivus smith") (sort "some furtive joints, that is yours"))

23:56 clojurebot: true

Logging service provided by n01se.net