#clojure log - Nov 30 2014

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

0:17 xelxebar: gfredericks: just saw your sped up primes version. finding it quite instructive! in practice how often do you usually have to dig down into native Java structures? are we just hitting a "primes are particularly hard" wall?

0:19 justin_smith: xelxebar: it is more that in a tight loop the speed of a mutable thing can beat the safety and predictability of a clojure persistent data structure I think

0:20 but of course you want to ensure you are doing this in the place where that speed is actually making a difference

0:28 xelxebar: justin_smith: with an IPersistentList are we really copying the whole structure around every time we do something as simple as say (cons angelina-jolie justin-smith-list-of-booty)?

0:37 zanes: What’s the rule of thumb for when to reach for a lazy sequence vs a channel?

0:41 rs0: xelxebar: do you mean a persistent vector?

0:43 justin_smith: xelxebar: conjing to either a persistent list or vector does not copy the whole thing

0:44 but it still does more allocation than conjing to a mutable structure, and sometimes that matters

0:44 the jvm can allocate efficiently, but it isn't perfectly efficient

0:52 xelxebar: rs0: was trying to say "persistent list" as opposed to a mutable one

0:53 justin_smith: does the allocation really differ enough to see a speedup of 30x or so like in gfredericks' case?

0:54 I guess if I really want to know what's going on I can look at the code...

0:54 rs0: xelxebar: i'm not sure what code you're referring to, but there are many reasons that mutable collections can be a lot faster. one of the biggest reasons is actually locality

0:54 xelxebar: rs0: locality? is this about caching?

0:55 justin_smith: xelxebar: yes, java.util.ArrayList is more efficient than a regular linked list. It has more cache coherency (the items are closer together in the heap) and that matters in tight loops.

0:55 rs0: xelxebar: yeah. with immutable persistent collections, the data in the collection tends to be more spread out across memory, which leads to more cache misses

0:55 justin_smith: https://www.refheap.com/94188 rs0 <- that is the code

0:57 xelxebar: going from randomly positioned items in a very tight loop to cache-friendly all-in-a-row can give 2 or 3 orders of magnitude improvement. Clearly this was not a super tight loop, so you only got ~30x improvement between the arraylist and the type hinting

0:57 xelxebar: rs0: here's a paste of both the slow and fast version https://www.refheap.com/94198

0:58 justin_smith: xelxebar: yeah, the type hinting also can prevent boxing / reflection, which may be the bigger deal than the cache friendliness here actually

0:59 xelxebar: justin_smith: oh! so persistent lists can be thought of as being backed by linked lists or something and mutable lists as C-like arrays?

0:59 rs0: xelxebar: rich hickey actually gave at least one talk on persistent collections, let me find it...

0:59 justin_smith: xelxebar: depends on the specific list - ArrayList is backed by an array in memory, yes

1:00 xelxebar: java also has a LinkedList, it isn't used as often for obvious reasons

1:01 xelxebar: vectors on the other hand are made internally of a bunch of smaller underlying arrays but not quite as linear and coherent as an ArrayList

1:01 xelxebar: justin_smith: what about a seq?

1:01 justin_smith: xelxebar: seq is not an implementation, it's a protocol

1:01 a while bunch of things implement seq

1:02 which kind of seq do you mean?

1:02 xelxebar: well, what types are involved when I do (seq [1 2 3])?

1:02 justin_smith: if you mean PersistentList or LazySeq, those are linked lists

1:02 that's a view of a vector

1:03 so it's as I said above about vectors, a bunch of smaller arrays in a tree

1:03 so not as bad as a simple linked list, not as linear as an ArrayList

1:03 that's a tradeoff made in order to do persistence, basically

1:03 (as in the structural sharing part of persistence)

1:03 rs0: https://www.youtube.com/watch?v=UXdr_K0Lwg4 here's a talk on finger trees

1:04 justin_smith: rs0: but none of the vanilla clojure datastructures are fingertrees

1:04 rs0: i know that rich hickey has talked about clojure's persistent collections in some of his talks, i think at least one of The Value of Values and Are We There Yet talks about them

1:04 justin_smith: yeah, they're HAMTs

1:04 xelxebar: ha. okay. so '(1 2 "mimosa") is a PersistentList?

1:04 justin_smith: xelxebar: rs0: hyperion has a good series of blog posts about how clojure vectors are implemented

1:05 xelxebar: use type and find out

1:05 ,(type '(1 2 "mimosa"))

1:05 rs0: ,(type '(1 2 3))

1:05 clojurebot: clojure.lang.PersistentList

1:05 clojure.lang.PersistentList

1:05 xelxebar: justin_smith: that's the kind of answer I like!

1:05 ,(type [1 2 3])

1:05 clojurebot: clojure.lang.PersistentVector

1:05 justin_smith: http://hypirion.com/musings/understanding-persistent-vector-pt-1 the start of the hypirion blog posts

1:05 xelxebar: ;(type (seq [1 2 3]))

1:05 ,(type (seq [1 2 3]))

1:05 clojurebot: clojure.lang.PersistentVector$ChunkedSeq

1:06 rs0: ,`ISeq

1:06 clojurebot: sandbox/ISeq

1:06 xelxebar: rs0, justin_smith: thanks for the links

1:06 justin_smith: rs0: ?

1:06 xelxebar: what black magic did clojurebot just do??

1:06 rs0: justin_smith: at the REPL you can normally say `symbol to get the fully qualified symbol name. isn't the class for seq clojure.lang.ISeq?

1:06 lazybot: xelxebar: Definitely not.

1:07 justin_smith: rs0: clojure.lang is not in scope by default

1:07 rs0: so you just get a locally namespaced symbol

1:07 rs0: justin_smith: ah, i'm thinking of java.lang and clojure.core i guess

1:07 xelxebar: lazybot: ummm... thanks?

1:07 justin_smith: xelxebar: which magic?

1:07 kenrestivo: wel that's a first, i just got a spam email with a zipfile with a minified javascript payload virus: https://www.refheap.com/94199

1:07 justin_smith: lazybot: are you confusing the newcomers again???

1:07 lazybot: justin_smith: Yes, 100% for sure.

1:08 justin_smith: lazybot, are you sure that is a good idea??

1:08 lazybot: justin_smith: What are you, crazy? Of course not!

1:08 xelxebar: what's sandbox/ISeq?

1:08 justin_smith: xelxebar: a symbol, he was trying for something else

1:08 rs0: ,`methods

1:08 clojurebot: clojure.core/methods

1:08 rs0: ,(methods clojure.lang.ISeq)

1:08 clojurebot: #<ClassCastException java.lang.ClassCastException: java.lang.Class cannot be cast to clojure.lang.MultiFn>

1:08 rs0: er

1:08 oh, that's right

1:08 justin_smith: methods doesn't work on regular classes

1:09 rs0: i'd have to go through clojure.reflect i guess

1:09 justin_smith: rs0: you may want clojure.reflect/reflect, but that is super verbose

1:09 heh

1:10 xelxebar: that hyPiRion blog post does a great job of illustrating why vector uses smaller underlying arrays for structural sharing

1:11 rs0: will Java 6 still be supported by Clojure 1.7?

1:11 justin_smith: rs0: I think the minimum is still 1.5

1:12 likely will be for a while

1:12 rs0: rich hickey mentioned a while back that invokedynamic could make type hinting obsolete

1:12 but that it would have to be done in addition to the current techniques, because it's only available on JDK7+

1:12 justin_smith: yeah, it would be a great win, but they want to be compatible with as many existing java ecosystems as possible

1:13 xelxebar: reading the hypirion post now! I'd kind of like to know what PersistentList is doing just for comparison.

1:13 rs0: xelxebar: i'm pretty sure PersistentList is just an immutable linked list

1:13 xelxebar: Also, what is the 'I' in IPersistentList as opposed to PersistentList? "implementation"?

1:14 justin_smith: Interface

1:14 rs0: xelxebar: the opposite, Interface

1:15 xelxebar: have you looked at the clojure source code?

1:15 https://github.com/clojure/clojure

1:15 xelxebar: ha! okay. just found the java file in the source

1:15 public interface IPersistentList extends Sequential, IPersistentStack{}

1:16 rs0: xelxebar: ag and selecta are your friends

1:17 xelxebar: are these functions?

1:17 and ag looks like silver to me, hehe

1:17 rs0: https://github.com/ggreer/the_silver_searcher

1:17 https://github.com/garybernhardt/selecta

1:18 justin_smith: xelxebar: if you don't know what an interface is, you may want to spend a few hours on a "java basics" tutorial, it will help you understand clojure a little better I think

1:18 oh wait, you meant is ag a function, never mind :)

1:19 rs0: ag and selecta are amazing. you can tear through very large code bases in any language

1:20 xelxebar: selecta looks really nifty

1:20 rs0: yeah, i mainly use it from within vim

1:21 justin_smith: you can also use those (or even rgrep) with emacs and M-x rgrep (it lets you select the command it actually runs, and creates clickable / enter-to-follow links for each match)

1:21 xelxebar: never have used ack myself, always just grepped stuff

1:21 rs0: xelxebar: yeah, i did that for years. trust me, ag and ack are better (for source code)

1:21 especially when you're searching source code under version control and you've got huge .git and .hg and .svn directories to ignore

1:22 catern: use git grep?

1:22 rs0: if you want

1:23 but git grep is coupled to a particular version control system

1:23 ag works with everything

1:23 catern: hg grep

1:23 svn probably has something as well

1:23 justin_smith: source-safe grep oh wait there is no such thing just kill myself

1:23 rs0: heh

1:24 justin_smith: catern: rs0: I say we have a chemical showdown between hg and ag

1:25 rs0: hg seems to require a lot of plugins to be useful

1:26 xelxebar: justin_smith: this? https://www.youtube.com/watch?v=-mdHoImEt3Q

1:28 ggreer: what?

1:28 clojurebot: what is a software archeologist

1:28 ggreer: oh, someone mentioned ag

1:28 not me

1:31 xelxebar: god. the bots here sure are chatty

1:32 clojurebot, lazybot: if you've achieved sentience, no offense

1:32 clojurebot: No entiendo

1:32 ggreer: http://geoff.greer.fm/ag/speed/ <-- in case you're curious

1:32 ack took 3 minutes to find the same results in that benchmark on my amd a4-5000

1:32 xelxebar: ggreer: I was just peeking at that actually

1:33 what's going on with the i7??

1:33 lazybot: xelxebar: Uh, no. Why would you even ask?

1:34 ggreer: earlier versions of ag ignored too much stuff because they obeyed ignore rules incorrectly

1:34 one of the directories in my ~/code on that machine contains dogecoin, which has a * in its .gitignore

1:35 and old versions of ag made that a global *, not just an ignore rule in ~/code/dogecoin

1:35 basically, ag gets slower as it obeys .gitignore rules more correctly

1:36 oh and the bottom graph with the i7 is old. I need to re-run it, but it takes about 10 hours and nothing else can run on that machine

1:36 right now I'm fuzzing ag on that server

1:36 no crashes/errors so far

1:36 xelxebar: dogecoin! didn't know anyone legit used it

1:37 well, the A4-5000 seems to behave as expected? is it just fewer data points?

1:37 ggreer: it has a smaller ~/code

1:37 because it's a newer machine

1:38 and the ignore rules in the codebases on that machine are a little different

1:38 I should really create some canonical test data

1:38 just clone some popular projects like nodejs, the linux kernel, etc

1:38 and benchmark ag searching them

1:38 xelxebar: oh okay. so these graphs aren't all precisely comparable

1:39 mongosssssssssss: Hi, can I ask a noob question here or is there another channel that would be more appropriate?

1:39 ggreer: right. notice the "16GB directory, ≈2.4GB searched" and "8.3GB directory, ≈0.7GB searched"

1:39 xelxebar: mongosssssssssss: I have been blasting these guys with noob questions all day

1:41 ggreer: in the interest of science, I think the idea of a canonical test data is a good one

1:41 ggreer: yeah. toss in on the giant list of stuff to do :)

1:42 *it

1:42 mongosssssssssss: :) question: I'm trying to determine if a file is present in a directory (think trigger file). I'm using (def dirlisting (.list (io/file "path"))) as per the clojure.org docs and that sorta appears to be working, not sure how to actually examine the contents. a (count dirlisting) gives me the right count. The question is, how can I access each file in that list? (doseq [f dirlisting] (print f))) just gives me lots of

1:42 (I'll get to actual filename comparisons once I can actually determine what's going into that array)

1:44 xelxebar: ggreer: now I'm stalking you. lol. I see you're on LessWrong! Several years back. I went on a binge and went through all the sequences over the course of a few weeks.

1:46 mongosssssssssss: Okay, nevermind, it appears Lighttable just doesn't show me what I need to show.. just did the same through the lein repl and it gives me what I'm looking for

1:46 i wish there were a drclojure

1:46 :/

1:47 have a great night everyone

1:47 rritoch: mongosssssssssss: You can always filter the results of https://clojuredocs.org/clojure.core/file-seq for just the files with the parent directory your looking for

1:48 mongosssssssssss: It isn't efficient if you have deep directories, but it saves coding time.

1:50 ggreer: :)

2:01 kenrestivo: i've found a heisenbug. (for [[foo bar baz] (make-stuff blah)] foo) won't compile, says there's either 1 or 3 args to for. and (for [x (make-stuff blah) :let [[foo bar baz] x]] foo) won't compile either. but (for [x (make-stuff blah] (let [[foo bar baz] x] foo)) works fine

2:02 magthe: how do I get leiningen to copy data files?

2:09 justin_smith: magthe: into a jar for example?

2:11 ,(for [[a b c] (repeat (range))] c) ;; kenrestivo

2:11 clojurebot: (2 2 2 2 2 ...)

2:11 kenrestivo: huh

2:11 justin_smith: ,(for [[a b c] (repeat (range))] b c) ;; kenrestivo

2:11 clojurebot: #<ArityException clojure.lang.ArityException: Wrong number of args (3) passed to: core/for>

2:11 magthe: justin_smith: ah, should have mentioned I'm playing with cljs, so just straight forward copy for now (but into jars would be good to know too)

2:12 justin_smith: ~ping

2:12 clojurebot: PONG!

2:12 kenrestivo: so, what am i seeing there? is destructuring not supported in for forms?

2:12 justin_smith: kenrestivo: the error is for having too many things in the body

2:12 has nothing to do with the destrucuring (see my first example)

2:12 kenrestivo: in the body?

2:13 justin_smith: after the binding form

2:13 kenrestivo: oh... but isn't the body an implicit do?

2:13 justin_smith: nope

2:13 kenrestivo: aha! that's it then, thanks.

2:13 justin_smith: you would expect that, wouldn't you? but no

2:14 kenrestivo: wow, i could swear i've had multiple forms inside the body of a for, but i guess not.

2:24 magthe: justin_smith: :resource-paths doesn't seem to offer any way of copying files into place (I'd like to get both "static CSS" and generated CSS to end up in the same folder on compile)

2:25 justin_smith: lein-resource threw an UnsupportedOperationException on me when I tried using that

2:33 justin_smith: magthe: yeah, I am less familiar with the ins and outs of where things can go with clojurescript

2:42 magthe: justin_smith: oki, I just posted a question to SO... hopefully someone will bite :) and I can put up the christmas tree instead of hanging in here ;)

2:44 justin_smith: thanks, you'll likely see me drop in here again in the future... clojure/clojurescript is absolutely interesting, but there is quite a lot of options and details to familiarise oneself with

2:53 hiredman: [clojure.test.check.clojure-test :refer [defspec]]

2:53 [clojure.test.check.generators :as gen]

2:54 geez, sorry, mispasting out of control

2:54 rritoch: Is there any decent documentation or tutorial on making leiningen hooks? For situations like the one magthe is explaining I've needed to resort to creating custom plugin/tasks to manually wrap compile, but per the documentation it seems that it should be possible to do using hooks.

2:55 I've yet to find any example of a post-compile hook though

3:11 ffwacom: is there a way to get the fully qualified symbol for let?

3:12 nvm got it

3:13 rritoch: ,`let

3:13 clojurebot: clojure.core/let

3:14 ffwacom: cheers :)

3:14 rritoch: ffwacom: That is how I'd do it, but I'm still not entirely sure how ` functions, and regularly run into problems from unexpected behaviors

5:01 afhammad: Can someone explain what this macro does in cljs.core.clj (defmacro js-str [s] (core/list 'js* "''+~{}" s))

5:28 rritoch: lafhammad: That appears to cast a clojure value into a javascript string. In javascript ''+ casts the remaining values into strings, so ''+7+1 equals "71"

5:48 yguan: hi there, I know there is destructive assignment for vector in 'let': (let [[a b] [1 3]] (println a b), is there something smilar for map in 'let'?

5:51 luxbock: yguan: yep there's a lot you can do

5:51 http://blog.jayfields.com/2010/07/clojure-destructuring.html

6:33 foodoo: I have several subnamespaces and I like to declare one of these subnamespaces as private so that I can break things in the future. What is the idiomatic way to do this?

8:27 I have several subnamespaces and I like to declare one of these subnamespaces as private so that I can break things in the future. What is the idiomatic way to do this? [repost from 2 hours ago]

8:27 Bronsa: foodoo: clojure doesn't have any notion of subnamespaces or private namespaces

8:28 foodoo: `foo.bar` is not related to `foo` in any way

8:28 foodoo: usually when people need a "private" namespace, they use a .impl segment in the ns name

8:29 foodoo: Bronsa: I see. Thanks

8:54 SagiCZ1: can i define two defn functions in one namespace with the same name? i thought it was impossible

8:56 Morgawr: SagiCZ1: you can use defmulti and multimethods to achieve something like that

8:57 or use function definitions with multiple number of parameters

8:57 SagiCZ1: Morgawr: yeah but the repl didnt complain when i loaded the file.. seems like repl bug

8:57 Morgawr: ah

8:57 it probably gets re-defined

8:57 in order of evaluation

8:57 SagiCZ1: i see

8:57 Morgawr: so the latter definition overrides the previous one in the repl (I assume)

8:57 SagiCZ1: makes sense

8:57 kinda

9:03 Bronsa: SagiCZ1: (def foo 1) (def foo 2) is always allowed

9:03 SagiCZ1: Bronsa: ok.. didnt know that

9:03 Bronsa: SagiCZ1: it should only be used for repl interaction though

9:03 SagiCZ1: yeah i expected my editor to warn me about refedining the var in the file

9:04 Bronsa: SagiCZ1: the eastwood linter will warn you about that

9:04 SagiCZ1: maybe its no var, sorry my terminology is not perfect

9:04 Bronsa: https://github.com/jonase/eastwood

9:04 https://github.com/jonase/eastwood#redefd-vars

9:04 gfredericks: SagiCZ1: it is a var

9:05 SagiCZ1: ok good guess

9:29 how could i obtain the index of a smallest number in a vector?

9:30 ,(.indexOf [-10 1 2 3] (apply min [-10 1 2 3]))

9:30 clojurebot: 0

9:30 SagiCZ1: any way to make this better?

9:34 gfredericks: ,(def nums [-10 1 2 3])

9:34 clojurebot: #'sandbox/nums

9:35 gfredericks: ,(->> nums (map-indexed vector) (apply min-key second) (first))

9:35 clojurebot: 0

9:35 SagiCZ1: seems more clojury to me.. thanks

9:35 (inc gfredericks)

9:35 lazybot: ⇒ 112

9:43 justin_smith: $mail yguan that's not destructive update, that's shadowing, things that use the previous binding won't be affected eg. (let [a 0 b (fn [] a) a 1] [a (b)])

9:43 lazybot: Message saved.

9:57 gfredericks: man I'm learning all sorts of weird things about regexes

9:57 SagiCZ1: i need to mimick simple comparison of each element with each, which is simple achievable by classical for loop, but i strugle with it in clojure.. example [:a :b :c] --> ([:a :b] [:a :c] [:b :c])

9:58 ,(def x [:a :b :c])

9:58 gfredericks: ,(def xs [:a :b :c])

9:58 clojurebot: #'sandbox/x

9:58 #'sandbox/xs

9:58 SagiCZ1: wow

9:58 ok

9:58 gfredericks: ,(for [i (range (count xs)) j (range i)] [(xs i) (xs j)])

9:58 clojurebot: ([:b :a] [:c :a] [:c :b])

9:58 SagiCZ1: oh.. indexes

9:58 why not

9:58 thanks again gfredericks

9:59 gfredericks: there's another approach that's not quite solidifying for me

9:59 that avoids indexes

9:59 SagiCZ1: this relies on the fact that xs is a vector huh?

9:59 gfredericks: yeah

9:59 here I'll get a better one

9:59 SagiCZ1: maybe some partition magic

10:00 gfredericks: ,(for [[x & xs] (iterate rest xs) :while xs, y xs] [x y])

10:00 clojurebot: ([:a :b] [:a :c] [:b :c])

10:00 gfredericks: ambiguous naming there

10:00 ,(def my-things (range 5))

10:00 clojurebot: #'sandbox/my-things

10:00 gfredericks: ,(for [[x & xs] (iterate rest my-things) :while xs, y xs] [x y])

10:00 clojurebot: ([0 1] [0 2] [0 3] [0 4] [1 2] ...)

10:01 SagiCZ1: i dont understand the comma in the while statement

10:01 AimHere: Clojure commas are whitespace

10:01 gfredericks: I shoulda put even more commas

10:01 ,(for [[x & xs] (iterate rest my-things), :while xs, y xs] [x y])

10:01 clojurebot: ([0 1] [0 2] [0 3] [0 4] [1 2] ...)

10:01 gfredericks: like that

10:01 SagiCZ1: oh of course

10:01 gfredericks: I only use commas for multiple pairs on one line

10:02 SagiCZ1: good idea, i shall adopt that if you dont mind

10:02 gfredericks: not at all

10:02 so here's what I learned about regexes

10:02 ,#"normal stuff {"

10:02 clojurebot: #<NoClassDefFoundError java.lang.NoClassDefFoundError: Could not initialize class java.util.regex.PatternSyntaxException>

10:02 gfredericks: ,#"\Q{"

10:02 clojurebot: #"\Q{"

10:03 gfredericks: oh geez guess what #"\Qabc\E*" does

10:04 this is getting a lot harder to parse

10:04 I think I need a separate analyzer phase

10:20 oh here's a good one; try to justify this:

10:20 ,#"x++"

10:20 clojurebot: #"x++"

10:20 gfredericks: ,#"x+++"

10:20 clojurebot: #<NoClassDefFoundError java.lang.NoClassDefFoundError: Could not initialize class java.util.regex.PatternSyntaxException>

10:20 gfredericks: ,#"x+++"

10:20 clojurebot: #<NoClassDefFoundError java.lang.NoClassDefFoundError: Could not initialize class java.util.regex.PatternSyntaxException>

10:20 gfredericks: clojurebot that is a weird exception

10:20 &#"x+++"

10:21 lazybot: java.util.regex.PatternSyntaxException: Dangling meta character '+' near index 3

11:17 gfredericks: having a surprising hard time figuring out how to express "anything but this specific character" in instaparse

11:53 verma: hey any clojuredocs devs around?

11:53 I wonder what is used to handle Ctrl+P, Ctrl+N stuff

11:53 I think the code is open, I can jump in :)

12:02 gfredericks: ,(pr-str "\u0000")

12:02 clojurebot: "\"

12:03 gfredericks: &(pr-str "\u0000")

12:03 lazybot: ⇒ "\"

12:05 justin_smith: &(map int "\u0000")

12:05 lazybot: ⇒ (0)

12:06 justin_smith: &"\u0000"

12:06 lazybot: ⇒ "

12:06 justin_smith: wtf

12:06 what happened to the other "

12:07 gfredericks: ,#"*"

12:07 clojurebot: #<NoClassDefFoundError java.lang.NoClassDefFoundError: Could not initialize class java.util.regex.PatternSyntaxException>

12:07 justin_smith: oh, it's an irc client thing

12:07 gfredericks: &#"*"

12:07 lazybot: java.util.regex.PatternSyntaxException: Dangling meta character '*' near index 0

12:07 gfredericks: &#"{0}"

12:07 lazybot: ⇒ #"{0}"

12:08 DrCherry: Tried to learn clojure in a weekend for job programming challenge. Whoops!

12:09 andyf: DrCherry: Depending upon how much the challenge expected you to learn, that could be a very difficult thing to accomplish.

12:11 DrCherry: @andfy, I thought I was pretty smart. Lol. I haven't given up but my expectations are adjusted on an hourly basis.

12:13 AimHere: Learning a new language in a weekend is likely feasible if you're not being exposed to a new paradigm or two

12:13 andyf: I came to Clojure after having serious hobby time with Common Lisp and Scheme, and I still found it to be a bit of a learning curve, getting used to immutable data structures by default especially.

12:13 AimHere: I'd expect it would help loads to have been exposed to a functional programming language, or a lisp

12:15 andyf: DrCherry: I don't know what the job interviewers expect, but I bet partial credit will be given based upon what you were able to learn, and explain about what you did.

12:16 DrCherry: I've kept a journal of all the work I've done and illustrated my methodology.

12:17 I don't know what they expect exactly but this has been one rabbit hole after another. I'm using all the time I was given and feel pretty okay about it.

12:17 I have no lisp background and they know.

12:17 nicl_: Hey all, is it a crazy abuse to introduce an edn tag which accepts arguments?

12:17 I was thinking of using it as a simple templating library

12:18 (where the underlying structure is edn, but I want to inject some values and nest things)

12:18 DrCherry: This weekend has been my kobayashi maru.

12:19 nicl_: alternatively, can anyone suggest a simple, non-html-oriented, templating library for this?

12:30 justin_smith: nicl: there are already edn tags that take arguments

12:30 #inst "0000-01-01T00:00:00.000-00:00"

12:30 &#inst "0000-01-01T00:00:00.000-00:00"

12:30 lazybot: ⇒ #inst "0001-01-01T00:00:00.000-00:00"

12:31 nicl: Sorry, I meant a context provided to interpret the tag, but which exists outside of the edn datastructure

12:32 justin_smith: Sorry, I meant a context provided to interpret the tag, but which exists outside of the edn datastructure

12:32 justin_smith: nicl: yeah, sounds like you want a templating library

12:35 nicl: justin_smith: yeah, I think you’re right. I could probably do it with edn, but it would be messy

12:35 justin_smith: (to ensure the right context was used at the right time)

12:35 justin_smith: edn is really meant for vanilla clojure stuff, the "extensible" stuff if limited

12:35 nicl: although, I could create clojures for it

12:35 and pass those in to the reader function at each stage

12:36 hmm

12:36 still an abuse

12:36 *closures

13:54 danielszmulewicz: technomancy: ping

14:17 kenrestivo: is there a way to sub to a *set* of topics in core.async?

14:17 i naively tried (async/sub pub #{:test :blah} sub) ... didn't work. can't find docs and having trouble finding where the source of sub* is

14:17 because sub just wraps sub* and i can't seem to locate it

14:21 ered: kenrestivo: have you tried using a mix?

14:22 kenrestivo: oh, good idea, thanks. i'm still trying to wrap my brain around core.async. really enjoying it.

14:23 mix is hilarious. it's so obvious rich started out as an audio engineer. "A mix supports soloing, muting and pausing ..."

14:24 ered: i found it by searching for mux actually

14:25 which is weird because i've never done hardware either

14:27 kenrestivo: i guess i could create multiple subs and mix them

14:28 it just seems heavyweight and kind of verbose to me.

14:28 and maybe slow? not sure what the peformance implications are of all these abstractions

14:34 munderwo: Hey all. Im trying out generative testing. I have a map that has a structure, and I was to create the string values from a generator. Is there a declarative way I can just build a map, and generate the values?

14:35 I can generate a random map, but Im really looking to be able to build {:foo “somerandomstring :bar “someotherstring”}

14:35 where :foo and :bar are always set.

14:44 poushkar: Could someone help me here: https://gist.github.com/vitaly-pushkar/61daa08c9cefb78a5395 - It logs error “Uncaught Error: Assert failed: Invalid Hiccup form: [nil] (valid-tag? (nth v 0))”

14:44 it comes from line 9

14:47 Frozenlock: poushkar: first off, I think your line 8 will never appear...

14:47 should be something like [:div [layout/menu] [...]]

14:48 poushkar: @Frozenlock I am following this tutorial: https://github.com/reagent-project/reagent-cookbook/tree/master/recipes/adding-a-page

14:48 they do it like that. here https://github.com/reagent-project/reagent-cookbook/blob/master/recipes/adding-a-page/src/adding_a_page/core.cljs line 9

14:48 shit :D

14:48 thanks

14:48 Frozenlock: :-p

14:49 poushkar: I am blind

14:49 Frozenlock: I'm not sure this will solve your error however

14:50 poushkar: I am blidnly following that example, and sometimes I don’t really understand what I am doing. For example, this “component-will-mount” doesn’t seem to run my routes code and so app state is not set, so it is null.

14:55 Frozenlock: I'm not fond of secretary and routes myself. I would suggest you make a '1 page' app as a tutorial.

15:01 devn: So, I know it's *kind of* self-explanatory, but if I asked you what the docstring for clojure.core/destructure is, what would you say?

15:02 gfredericks: I would not know

15:07 looks like it doesn't have one? it's not really useful for users, so I think the worst possibility is somebody confuses it for something useful

15:14 bbloom: ,(java.util.Date.) ; dammit irc

15:14 clojurebot: #inst "2014-11-30T20:12:23.505-00:00"

15:14 bbloom: gfredericks: i was time traveling again. wtf is wrong w/ my irc client?

15:16 justin_smith: bbloom: in erc there is a numeric "lag" indicator

15:16 bbloom: so when I get in a weird time warp, I always notice the lag tells me so as well

15:16 gfredericks: bbloom: perhaps your client is a late bloomer?

15:17 bbloom: textual has /lagcheck apparently

15:17 justin_smith: also, you can always /msg lazybot $ping

15:17 and see how long it takes to reply

15:18 if it takes a while, one of you is lagged :)

15:18 gfredericks: and it's not lazybot

15:19 justin_smith: gfredericks: well, lazybot could also be lagging...

15:19 * gfredericks is starting to use "bbloom is lagging" as his goto explanation for strange phenomena

15:35 kenrestivo: bbloom: it might not be your client, but rather your internet connection?

15:35 bbloom: kenrestivo: maybe, but my connection is otherwise fine... unless time warner is fucking w/ IRC traffic

15:36 gfredericks: haha why would a ISP care what you're using their network for right haha that'd be silly

15:36 kenrestivo: tcpdump -w wtf.pcap -s 2000 port 6667 ... run that for a while, then dump it into xplot.org ?

15:38 i dunno, i've just spent the last month or so debugging weird internet latency problems, it's not fun.

15:40 justin_smith: TIL irc servers are coordinated in a tree structure

15:40 what a weird architecture

15:40 kenrestivo: actually tcpdump -w wtf.pcap -s 2000 port 6667 or port 6697 if you use ssl. plot/graph that with xplot.org, it'll show you latency, broken connections, etc

15:41 irc is kind of a quirky protocol.

15:41 btw, i found a bug in irclj, it doesn't handle QUIT messages.

15:42 so if a user QUITs, they show as perpetually connected. PARTs work fine though.

15:42 justin_smith: also TIL /ping - 00:00.00 to bbloom from me, 00:00.04 to kenrestivo

15:42 kenrestivo: oh, interesting

15:42 kenrestivo: this is with the latest irclj?

15:43 it seems like this would be easy to fix

15:43 kenrestivo: "0.5.0-alpha4"

15:43 dunno if that's "latest", but it's the latest i was using in this app last i noticed the bug and decided "meh, i'll deal with it later"

15:43 gfredericks: I quit using irclj because it seemed to silently just not work right

15:44 was working fine for a while, and with no changes it just ceased to function

15:44 justin_smith: kenrestivo: seems like a small fix that could be done right here https://github.com/Raynes/irclj/blob/master/src/irclj/process.clj#L133

15:44 gfredericks: maybe freenode changed something?

15:44 kenrestivo: i had a problem with irclj not reconnecting properly

15:45 justin_smith: gfredericks: I updated lazybot to the latest irclj, and since then lazybot has been very reliable (compared to when it was using the previous version)

15:45 kenrestivo: justin_smith: yeah, copy/paste the process-line "PART" and change it to "QUIT". i think i tried that, didn't work, don't remember, it was a few months ago

15:45 justin_smith: remember when lazybot would always go offline on weekends?

15:45 gfredericks: justin_smith: yeah I updated too and it didn't seem to make a difference

15:45 now I'm using a dang Socket and everything seems okay

15:45 I figured out how to do it by reading the irclj code, go figure

15:45 kenrestivo: those dang sockets

15:46 socketing all over the place.

15:46 justin_smith: gfredericks: well, next step is to reify it into another irc lib, right?

15:46 gfredericks: justin_smith: inevitably

15:46 make a yak pile

15:46 justin_smith: that would be a good name for an irc client library

15:46 kenrestivo: what is a yak pile?

15:47 justin_smith: kenrestivo: the line at a yak barbershop

15:47 kenrestivo: shave shave shave

15:47 i dunno if that'd be considered yak shaving or NIH.

15:48 what? fix another library? feh. i'll just start from scratch and write another one.

15:48 justin_smith: NIH would be if he never even tried irclj

15:48 starting from scratch rather than fixing is a gray area I think

15:48 kenrestivo: it's always a tough decision

15:49 and a gamble on two unknowns

15:49 the thing you don't know how to fix, and the thing you haven't written yet.

15:50 justin_smith: kenrestivo: I didn't figure out how to use core.async until I made my own totally silly CSP lib. It's a learning strategy.

15:50 or can be

15:50 kenrestivo: yeah, i do that too. sometimes it helps to understand things from first principles.

15:50 right now i invested a lot of time in gloss, and am rewritign to just use bit-and, bit-or, etc

15:51 justin_smith: because gloss was insufficient?

15:51 kenrestivo: it was overly sufficient.

15:51 justin_smith: haha

15:51 kenrestivo: i mean

15:51 (.get (gio/contiguous (gio/encode (apply g/bit-seq (repeat 8 1)) [0 1 2 3 4 5])))

15:52 versus (apply bit-or (for [bn [0 1 2 3 4 5 6 7]] (bit-shift-left 1 bn)))

15:53 someone looking at that first line would go "aaaah! wtf is he doing there?!" versus looking at the second line, they'd be all, "oh, he's just doing x << y"

15:54 i suspect there are a lot of bald yaks running around the mission.

16:35 danneu: i have a list of 175,000 words that i'm turning into a single regexp by joining them together like /^foos|^foo|^bar|.../ to create one massive regexp i can apply on a constantly-changing string to see if it starts with any of those 175k words. (from longest to shortest)

16:35 it performs much faster than i thought it would. is it compiling into something smarter than a iterative compare on each word?

16:36 gfredericks: probably

16:36 a simple enough regex can be compiled into a state machine that only has to look at each char once

16:36 and the regex you describe is definitely simple enough

16:37 danneu: my bottleneck seems to be GC pauses on the "constantly-changing string"

16:37 clojurebot: Huh?

16:38 gfredericks: danneu: you could maybe optimize that with a custom CharSequence?

16:38 danneu: gfredericks: oh yeah, this is clojurescript

16:39 gfredericks: nevermind then :)

16:41 danneu: it's kinda shamefully dumb, too: http://jsfiddle.net/prsgju91/

16:42 gfredericks: well if you wanted to push that bottleneck by using some sort of custom mutable "string", it's conceivable you could compile your regex yourself into a function that operates on those mutable strings

16:45 justin_smith: danneu: have you thought about building a trie?

16:46 that should perform much better than an re, and the code to build it would be much more readable than the re or re-builder code

16:47 danneu: oh, i'm just being limited by react batching

16:47 justin_smith: danneu: https://gist.github.com/samuelclay/4596630

16:47 danneu: i mean, that's why the ui gets so slow

16:47 justin_smith: danneu: well, I think the intelligibility bonuses are good regardless of the perf

16:48 danneu: justin_smith: i agree, thanks

16:48 that's all this project is

16:49 justin_smith: of course the trie should be built server side, and the client should only have to do the lookup part

16:56 andyf: danneu: https://github.com/noprompt/frak

17:12 gfredericks: justin_smith: why would a trie perform better than an re?

17:16 justin_smith: gfredericks: there are more ways to get RE construction wrong

17:16 gfredericks: though an optimal re will effectively be a trie anyway

17:17 gfredericks: though to be fair the example I was thinking of was routing, which is a comparison of multiple regex checks vs. one trie, which doesn't apply here

17:21 gfredericks: roger

17:21 clojurebot: No entiendo

17:22 gfredericks: ~roger is <reply> Yes entiendo

17:22 clojurebot: Roger.

17:22 gfredericks: clojurebot is just a big pile of easter eggs

17:25 hiredman: clojurebot: clojurebot is just a big pile of easter eggs

17:25 clojurebot: c'est bon!

17:31 TEttinger: ~roger

17:31 clojurebot: Yes entiendo

17:31 TEttinger: what is the <reply> ?

17:31 gfredericks: ~TEttinger is Yes Entiendo

17:31 clojurebot: A nod, you know, is as good as a wink to a blind horse.

17:31 gfredericks: ~TEttinger

17:32 clojurebot: TEttinger writes really hideous clojure

17:32 gfredericks: ~TEttinger

17:32 TEttinger: lol

17:32 clojurebot: TEttinger writes really hideous clojure

17:32 gfredericks: ~TEttinger

17:32 clojurebot: TEttinger is Yes Entiendo

17:33 TEttinger: so it just takes out the "{topic} is " part

17:33 gfredericks: yep

17:33 highly useful:

17:33 ~ping

17:33 clojurebot: PONG!

17:33 gfredericks: ~guards

17:34 SIEZE HIM!

17:34 TEttinger: $guards

17:34 lazybot: SEIZE HIM!

17:34 gfredericks: ~botsnack

17:34 Thanks can I have choclate next time.

17:34 TEttinger: ~gourds

17:34 clojurebot: SQUEEZE HIM!

17:36 arrdem: anyone know of a phrase chunking engine in clojure or with clojure bindings?

17:37 nevermind google results were good

18:34 justin_smith: gfredericks: also, tries are guaranteed linear (worst case) on the input, regardless of dictionary size. I don't know if a regex has that guarantee in general?

18:35 metellus: doesn't seem like it would

18:35 gfredericks: justin_smith: I think a classical regex does

18:36 i.e., you just convert it into a DFA and that's linear

18:38 so I was guessing that in practice a hand-rolled trie would be slower, since the regex is presumably implemented at a pretty low level

18:40 justin_smith: yeah, that's a good guess, as long as you aren't using backtracking or anything

18:41 gfredericks: I wonder if matching groups is a non-classical feature...

18:46 justin_smith: gfredericks: I don't think so. I can't think of a matching group that would require a backtrack of any sort.

18:47 gfredericks: what's the easiest backtracking regex?

19:00 TEttinger: gfredericks: \b ?

19:02 http://www.regular-expressions.info/wordboundaries.html if unfamiliar

19:10 gfredericks: hmmm

19:10 I'm trying to think of an example with \b that isn't obviously linear

19:10 justin_smith: TEttinger: I'm not even sure - is it possible to create a regex that doesn't backtrack if the re-engine is a backtracking one? I saw one result that seemed to imply that regular meta-characters like + or * would backtrack...

19:11 it was from that same regular-expressions.info site actually

19:11 http://www.regular-expressions.info/catastrophic.html

19:12 gfredericks: ((abcd)+(abce)+)+

19:12 that's still not backtracky

19:13 I don't think

19:15 TEttinger: ,(re-find #"x+x+y" "xxxxxxxxxxxxxxxx")

19:15 clojurebot: nil

19:16 TEttinger: ,(re-find #"(x+x+)+y" "xxxxxxxxxxxxxxxx")

19:16 clojurebot: nil

19:16 TEttinger: hm

19:16 gfredericks: ,(re-find #"(x+x+)+y" "xxxxxxxxxxxxxxxxy")

19:16 clojurebot: ["xxxxxxxxxxxxxxxxy" "xxxxxxxxxxxxxxxx"]

19:17 TEttinger: ,(time (re-find #"(x+x+)+y" (apply str (repeat 1000 \x))))

19:17 clojurebot: eval service is offline

19:17 TEttinger: lol

19:17 see???

19:17 lazybot: TEttinger: How could that be wrong?

19:18 TEttinger: ##(time (re-find #"(x+x+)+y" (apply str (repeat 1000 \x))))

19:18 lazybot: Execution Timed Out!

19:18 TEttinger: ##(time (re-find #"(x+x+)+y" (apply str (repeat 100 \x))))

19:18 lazybot: Execution Timed Out!

19:18 TEttinger: wow

19:18 that is catastrophic

19:33 justin_smith: TEttinger: so get this - there is a port of nethack to emacs, where all interaction with the game engine is via stdin / stdout / stderr and all output from the game engine is sexprs

19:33 so I am messing around with a clojure program that does something interesting with those sexprs... or will eventually

19:34 maybe starting with an ai-assist, and building up to a full AI I am thinking

19:34 for values of AI ~= "can beat a few levels of nethack"

19:36 TEttinger: nice, justin_smith

19:38 an AI that can beat a human at Go is considered an extreme challenge to write, but human vs. human is probably 50/50 at equivalent skill levels/ranking. a human that can ascend in Nethack normally takes hundreds of serious attempts before succeeding. An AI that can perform better than a human at nethack, well...

19:39 to be fair, the AI can be aware of the entire nethack wiki with a few (slurp)s

19:39 justin_smith: yeah, I'll start with "gets as far as the oracle half the time", then maybe start beating sokoban if I get that far

19:39 yeah

19:40 or even the spoiler files that come in easily parsible form from a standard package

19:40 but before that I can even just hard code a bunch of reasonable default choices

19:40 and start with a barbarian (fewer choices to make)

19:41 TEttinger: DCSS might be an interesting newer game to try to beat, a lot of options there. just a bot that can uncover new strategies to some of these games would be amazing

19:41 justin_smith: you can get pretty far in nethack with barbarian, + walk up to every monster and bash it over and over + a blacklist of monsters to not touch or run from

19:42 TEttinger: I can't remember, do you heal over time in nethack?

19:42 justin_smith: yeah

19:42 but you get hungry too

19:43 but even a bot that gets your char to the first condition of "got to level 10" or "something happened it doesn't know how to deal with" is a cool thing to have

19:44 and remember that a bot that succeeds in getting to level 10 in 1% of trys can probably get you a good playable leveled up character in under a minute

19:45 TEttinger: the thing is that DCSS doesn't likely have an emacs backend, whereas nethack already has a version that is tailored to interact with a lisp

19:45 TEttinger: ah yeah

19:49 justin_smith: here's a screen dump of me interacting with it via the repl, and just dumping everything it sends to *out* https://www.refheap.com/94226

19:51 looks like it will be pretty trivial to turn those numbers into glyphs, and get the status line into a hashmap

20:13 https://github.com/noisesmith/nethacker/blob/master/src/org/noisesmith/nethacker.clj -- what I have so far

20:20 maybe I should start by making a json API

20:39 mdeboard: ping

20:39 &(ping)

20:39 lazybot: java.lang.RuntimeException: Unable to resolve symbol: ping in this context

20:44 justin_smith: $ping

20:44 lazybot: justin_smith: Ping completed in 0 seconds.

21:02 gfredericks: ,(def ping '$ping)

21:02 clojurebot: #'sandbox/ping

21:02 gfredericks: ,ping

21:02 clojurebot: $ping

21:02 lazybot: clojurebot: Ping completed in 0 seconds.

21:02 clojurebot: No entiendo

21:47 justin_smith: is it possible to express "a future that will be a number when dereffed" in prismatic/schema?

21:47 maybe I don't want that because it would block when validating if it hasn't returned yet...

22:56 gfredericks: &#"x{]" ;; sure fine

22:56 lazybot: java.util.regex.PatternSyntaxException: Illegal repetition near index 0

22:56 gfredericks: &#"[]{]" ;; wat

22:56 lazybot: ⇒ #"[]{]"

22:58 gfredericks: &#"abc[]def{]"

22:58 lazybot: ⇒ #"abc[]def{]"

22:58 gfredericks: &#"abcdef{]"

22:58 lazybot: java.util.regex.PatternSyntaxException: Illegal repetition near index 5

22:59 gfredericks: how can that even

22:59 oh wait

22:59 that's one big character class

23:01 TimMc: So... [ is greedy?

23:02 gfredericks: not quite

23:02 just that [] is special-cased

23:02 TEttinger: ,#"[a]{]"

23:02 clojurebot: #<NoClassDefFoundError java.lang.NoClassDefFoundError: Could not initialize class java.util.regex.PatternSyntaxException>

23:02 TEttinger: wat

23:02 gfredericks: such that the second bracket is always a literal and never the closer

23:02 TEttinger: &#"[a]{]"

23:02 lazybot: java.util.regex.PatternSyntaxException: Illegal repetition near index 2

23:03 gfredericks: the meaning of ] changes based on whether or not it's the first character in the class

23:03 same with - I think

23:06 TimMc: oy

23:06 That's just not right.

23:06 gfredericks: I'm going to sleep. Three internet points to anybody who can figure out these guys:

23:07 &#"\pC"

23:07 lazybot: ⇒ #"\pC"

23:07 gfredericks: &#"\pD"

23:07 lazybot: java.util.regex.PatternSyntaxException: Unknown character property name {D} near index 2

23:07 gfredericks: I scanned the docs and can't figure out what the first one means

23:09 TEttinger: gfredericks: property

23:09 http://www.fileformat.info/info/unicode/category/index.htm

23:10 ,(re-find #"\pC" "\u0001")

23:10 clojurebot: ""

23:10 TEttinger: ,(re-find #"\pC" "\t")

23:10 clojurebot: "\t"

23:11 TEttinger: the first is Control properties, the whole set including format and miscellaneous C properties

23:11 ,(re-find #"\pL" "alpha")

23:11 clojurebot: "a"

23:11 TEttinger: letters

23:12 N number, P punctuation, S symbol, Z separator (does not include the chars in \s)

23:13 M is mark, not sure what that is

23:13 justin_smith: TEttinger: so I got rid of the global in my nethack lib, and added schemas via prismatic/schema (I'd been meaning to try it for a while now), next step is to make a json/edn api I think (via a server or calls in the same process)

23:14 TEttinger: wowza

23:14 justin_smith: Nethack As A Service

23:15 which will make it easy to make a frontend with 3.js or whatever else

23:16 * justin_smith still needs to get around to writing 1.js (advanced features for rendering lines) and 0.js (advanced functions for creating a single pixel)

23:24 TEttinger: heh.

23:25 4.js for visualizing hypercubes and 120-cells

23:27 who needs drugs when you have geometry, anyway https://en.wikipedia.org/wiki/120-cell#mediaviewer/File:120-cell-inner.gif

23:28 justin_smith: nice

23:35 allenj12: hey im having a math brain fart can someone take a look at this? http://pastebin.com/XeBSbgCM

23:37 TEttinger: ,(mapcat #(vector % % % %) (range))

23:37 clojurebot: (0 0 0 0 1 ...)

23:37 TEttinger: allenj12: ^

23:38 allenj12: TEttinger: but it needs to be robust, so if the number was 8 it would need to be 0 0 1 1... when the size of the pattern is 4

23:39 TEttinger: ,(mapcat #(repeat 3 %) (range))

23:39 clojurebot: (0 0 0 1 1 ...)

23:39 allenj12: TEttinger: isnt there a way of doing it with just modulo?

23:39 TEttinger: sure

23:40 allenj12: TEttinger: what would that look like? i think im close but not quite there

23:40 TEttinger: ,(map #(mod (/ % 3) 3) (range))

23:40 clojurebot: (0 1/3 2/3 1 4/3 ...)

23:40 TEttinger: hm

23:40 ,(map #(mod (int (/ % 3)) 3) (range))

23:40 clojurebot: (0 0 0 1 1 ...)

23:41 TEttinger: there's a better way, I just can't remember...

23:41 ,(map #(mod (rem % 3) 3) (range))

23:41 clojurebot: (0 1 2 0 1 ...)

23:41 TEttinger: ,(map #(mod (div % 3) 3) (range))

23:41 clojurebot: #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: div in this context, compiling:(NO_SOURCE_PATH:0:0)>

23:41 TEttinger: ,(map #(mod (quot % 3) 3) (range))

23:41 clojurebot: (0 0 0 1 1 ...)

23:41 TEttinger: there we go

23:41 &(map #(mod (quot % 3) 3) (range 100))

23:41 lazybot: ⇒ (0 0 0 1 1 1 2 2 2 0 0 0 1 1 1 2 2 2 0 0 0 1 1 1 2 2 2 0 0 0 1 1 1 2 2 2 0 0 0 1 1 1 2 2 2 0 0 0 1 1 1 2 2 2 0 0 0 1 1 1 2 2 2 0 0 0 1 1 1 2 2 2 0 0 0 1 1 1 2 2 2 0 0 0 1 1 1 2 2 2 0 0 0 1 1 1 2 2 2 0)

23:42 TEttinger: that what you're looking for, allenj12?

23:42 allenj12: TEttinger: i think so! thanks! need to go test it

23:42 TEttinger: no prob

Logging service provided by n01se.net