#clojure log - Nov 26 2015

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

0:29 kenrestivo: logging change?

0:29 ~java logging

0:29 clojurebot: java logging is clown shoes

0:33 arrdem: the bojth

0:39 tolstoy: How many story points for "Log when the user logs in?" Get out your cards!

0:48 arrdem: heh

1:42 didibus: I'm trying to create a map from a vector as such: [:a "a" :b "b"] would give me a {:a "a" :b "b"} is there a method for that?

1:44 scottj: didibus: (apply hash-map [:a "a" ...])

1:45 didibus: hey, hadn't thought of that

1:54 douglarek: , (apply hash-map [:a "a" :b "b"])

1:54 clojurebot: {:b "b", :a "a"}

1:55 douglarek: , (hash-map :a "a" :b "b")

1:55 clojurebot: {:b "b", :a "a"}

3:23 jonathanj: is there an enlive selector that matches a nonexistent element?

3:23 for example if i want to add a child to the "head" element, if it doesn't exist then i want to create it

3:23 it's not obvious how you achieve this with enlive

3:37 wafflejock: if anyone can tell me how to translate this to a terminal command (or just explain the steps of what's going on) I'd be grateful http://paste.ubuntu.com/13513071/

3:37 So far I tried but it appears my base64 encoded output is longer than the actual passwords in the DB

3:37 echo -n SECRETSALTtest | sha1sum | awk '{print $1}' | base64

3:38 basically inherited this code and trying to figure out how I can verify the passwords using the current method but in another language

3:38 opqdonut: sha1sum outputs the sum as hex

3:38 passing that to base64 sounds weird

3:38 what's "encode" in that snippet?

3:39 oh it's probably https://github.com/clojure/data.codec/blob/master/src/main/clojure/clojure/data/codec/base64.clj#L230

3:39 wafflejock: just made a more full version of the paste and just sanitized the salt value http://paste.ubuntu.com/13513085/

3:40 jonathanj: ugh, learning about enlive is a painful process

3:40 wafflejock: think that's it yeah but I have a tough time reading clojure let me know if you need me to search for anything else int he code

3:40 jonathanj: the documentation is awful

3:40 opqdonut: wafflejock: something like "sha1sum | awk '{print $1}' | xxd -r -p | base64" is what you want

3:41 wafflejock: you want to base64-encode the raw output of sha1, not the hexadecimal representation

3:41 wafflejock: xxd -r -p takes in hex and outputs binary

3:41 wafflejock: opqdonut: okay will give that a go thanks for the help

3:41 opqdonut: wafflejock: and even that might be wrong due to byte order issues

3:43 wafflejock: opqdonut: nope you got it, so this is doing a sha1sum which outputs hexadecimal then that goes to xxd that converts to binary then base64 encodes?

3:44 thanks again for the help too, wasn't likely I was going to stumble on that myself

3:44 opqdonut: wafflejock: yes, which is what the clojure code does too

3:44 no worries

3:52 jonathanj: argh

3:52 i can't figure out how to select a <head> element only when it doesn't exist with enlive

4:08 this can't possibly be the best way to insert a <link>, and a <head> if necessary, surely? https://pb.codehash.net/ec8a2b65ef2c4f83a3f82451d0d96000

4:42 muhuk: suppose you're doing a fold (or reduce) and what happens inside has not clear description, perhaps just massaging data structures. But you still want to call the function you pass something. I'm using folder/reducer as generic names. Do you have a better name for this thing? (suppose I define these functions within some letfn inside another fn)

7:07 visof: hi guys

7:15 the_nona1: hey

7:41 ainu: ciao

7:41 powered: how to make function f such that : (f [:a :b :c :d :e] 1 3 4) = [:a :c :d] ?

7:41 wmealing: later

7:42 justin_smith: ,(map [:a :b :c :d :e] [1 3 4]) ; powered

7:42 clojurebot: (:b :d :e)

7:42 justin_smith: hmm...

7:43 ,(map [:a :b :c :d :e] (map dec [1 3 4]))

7:43 clojurebot: (:a :c :d)

7:43 jeaye: justin_smith: How's that working?

7:43 justin_smith: ,(map (comp [:a :b :c :d :e] dec) [1 3 4])

7:43 clojurebot: (:a :c :d)

7:43 justin_smith: ,([:a :b :C :d :e] 2) ; jeaye

7:43 clojurebot: :C

7:44 jeaye: justin_smith: So vectors, when invoked, behave like nth?

7:44 powered: vector as a function, cool

7:44 justin_smith: jeaye: just like hash maps

7:44 jeaye: Handy.

7:44 justin_smith: well, hash maps are get as a function, and get on a vector does nth

7:44 jeaye: Right.

7:44 justin_smith: see also keywords and symbols which become get as functions

7:45 ,('foo '{foo bar baz quux})

7:45 clojurebot: bar

7:46 justin_smith: jeaye: it can also lead to really weird results...

7:46 jeaye: Yeah, I've seen this sort. Never with vectors though.

7:46 justin_smith: ,('foo nil :huh) - if you didn't know this was calling get

7:46 clojurebot: :huh

7:46 justin_smith: or - even weirder

7:46 ,((get get get get) nil :wat)

7:46 clojurebot: nil

7:47 justin_smith: ,((get get get get) "anything" :umm :wat)

7:47 clojurebot: :wat

7:48 justin_smith: get can be used as (fn [a b c] c)

7:48 (as long as a isn't ILookup)

7:58 phaseNi: @seen onlineperson

7:58 whoops

7:58 wrong channel

7:59 mavbozo: ,(instance? clojure.lang.IFn [])

7:59 clojurebot: true

7:59 mavbozo: ,(instance? clojure.lang.ILookup [])

7:59 clojurebot: true

8:00 mavbozo: (,satisfies? clojure.lang.IFn [])

8:01 ,(satisfies? clojure.lang.IFn [])

8:01 clojurebot: #error {\n :cause nil\n :via\n [{:type java.lang.NullPointerException\n :message nil\n :at [clojure.core$instance_QMARK___4118 invokeStatic "core.clj" 144]}]\n :trace\n [[clojure.core$instance_QMARK___4118 invokeStatic "core.clj" 144]\n [clojure.core$find_protocol_impl invokeStatic "core_deftype.clj" 511]\n [clojure.core$satisfies_QMARK_ invokeStatic "core_deftype.clj" 544]\n [clojure.core$...

8:01 mavbozo: ,(satisfies? clojure.lang.ILookup [])

8:01 clojurebot: #error {\n :cause nil\n :via\n [{:type java.lang.NullPointerException\n :message nil\n :at [clojure.core$instance_QMARK___4118 invokeStatic "core.clj" 144]}]\n :trace\n [[clojure.core$instance_QMARK___4118 invokeStatic "core.clj" 144]\n [clojure.core$find_protocol_impl invokeStatic "core_deftype.clj" 511]\n [clojure.core$satisfies_QMARK_ invokeStatic "core_deftype.clj" 544]\n [clojure.core$...

8:01 justin_smith: ,(doc satisfies?)

8:01 clojurebot: "([protocol x]); Returns true if x satisfies the protocol"

8:02 justin_smith: mavbozo: I think the issue here is that IFn and ILookup are interfaces, not protocols

8:03 mavbozo: ,(doc instance?)

8:03 clojurebot: "([c x]); Evaluates x and tests if it is an instance of the class c. Returns true or false"

8:04 mavbozo: so, something can be a instance of a interface

8:04 justin_smith: yes

8:08 mavbozo: ,(satisfies? CollReduce [])

8:09 clojurebot: #error {\n :cause "Unable to resolve symbol: CollReduce in this context"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.RuntimeException: Unable to resolve symbol: CollReduce in this context, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyze "Compiler.java" 6704]}\n {:type java.lang.RuntimeException\n :message "Unable to resolve symbol: Col...

8:36 newbie75: for systems created with nodejs it is a rather common pattern to hotswap JS source files on a running server. this is also possible with Clojure, but I know that most folks are very concerned about security and Clojure apps usually come as jars

8:36 is there anything that holds me from hotswapping Clojure code?

8:37 justin_smith: even with a jar deployment, you can still load code at runtime if you want things to work that way

8:37 noncom: yeah, i know, i actually did that already

8:37 but otherwise, why is not it so common in this community?

8:37 or is it?

8:39 justin_smith: noncom: in terms of knowing the code works, there's a lot less to go wrong if you can be sure the exact code that was verified on staging can be run on production

8:39 and with hot-swapping there's a lot more ways for that to go wrong

8:39 noncom: that seems to me so too. so the nodejs people are simply more reckless?

8:41 yeah, probably there's not much more to it..

8:41 Glenjamin: erlang is the only language i know where people really hot-swap in prod

8:41 or maybe some lispers

8:41 node & JS swapping in general is generally only a dev tool

8:42 justin_smith: Glenjamin: but for every dev tool, you'll find some dev impatient enough to try it on production

8:43 Glenjamin: and so they should, as long as they let us know how it went

8:43 erlang has been hot-swapping code in prod for decades

8:43 noncom: because erlang simply does not care if anything fails

8:45 justin_smith: see also php, which also cares not (for different reasons)

8:45 sounds like a joke - but the reason is the program is restarted for every request

8:46 with mirage, the vm loads so fast you can load up a new vm instance for a request

8:46 as in, OS level vm

8:50 ane: java, or well, the jvm, also has had hot-swapping for ages

9:02 mpenet: prismatic/schema question anyone knows if it's possible to have custom err message when using "pred" (it must be generated from the result of the predicate actually)?

9:03 since it catches everything it's currently not possible (the pred throws, and is caught by "schema" internals and thrown away...)

9:07 justin_smith: mpenet: what about using s/check instead of s/validate?

9:07 mpenet: I guess I ll have to implement the Schema protocol

9:07 hmm didn't try but I dont' think it makes any difference, "pred" will return the same (and still swallow the exception)

9:08 justin_smith: mpenet: check isn't supposed to throw is it?

9:08 it just returns a true/false

9:08 mpenet: I use check when I want to report that something isn't expected, but continue anyway

9:09 mpenet: see, no throw, just an informative return value https://github.com/Prismatic/schema/blob/master/src/cljx/schema/core.cljx#L136

9:09 mpenet: yeah but it's not what I want, I need to get to the exception thrown by my predicate used with "pred", right not it just says "the pred foo errored" in short.

9:11 The predicate basically compiles a string input (SQL like language) into an AST, and I need to get to that error so that I can show it to the user (it has line/col info etc).

9:12 anyway, I think I know how to do this, but it feels a bit convoluted, I hope I am not reinventing a wheel here

9:14 justin_smith: mpenet: if a function assumes that it can report a state to the top level of the code via a thrown exception, is that really a predicate though?

9:15 mpenet: it's not, but I can change it to return a value, I don't think it makes any difference. the pred must return non nil, rest is ignored

9:15 or maybe I am not using the right fn from their api, I ll re-check

9:16 justin_smith: mpenet: right, sounds like what you have shouldn't be a predicate, it should be a custom validator with custom error output

9:16 mpenet: yeah, that's also my conclusion

10:19 powered: is there a faster way to concatenate a whole bunch of strings together than : (reduce str coll) ?

10:20 muhuk: powered: use a StringBuffer maybe

10:24 justin_smith: powered: apply str will use a StringBuilder, which is faster than what reduce will do

10:25 powered: see here https://github.com/clojure/clojure/blob/clojure-1.7.0/src/clj/clojure/core.clj#L517

10:32 powered: apply str was more than 500 times faster than reduce str

10:33 justin_smith: wow, I knew it would be faster, but that's a LOT faster :)

10:33 powered: how many items were being combined?

10:33 powered: just 11408

10:34 with about 250 characters per string

10:35 tdammers: reduce is forced to concatenate strings one at a time; str can use a hanoi towers style algorithm

10:35 the difference is sth like O(n^2) vs O(n) or sth

10:36 justin_smith: tdammers: also, reduce is generating 11407 immutable objects, while apply str uses one builder

10:50 zacts: hi clojurists

10:51 how does clojure compare to haskell?

10:51 when would I want to use clojure, and when would I want to use Haskell?

10:51 Clojure

10:52 powered: clojure is more dynamic and practical, but I haven't used Haskell so I don't know

10:52 dnolen: zacts: Haskell has a very powerful type system

10:52 this is going to have a big effect on the way you write programs

10:52 ane: they are two different beasts

10:53 dnolen: in terms of prioritizing value oriented programming however they are very much the same

10:53 ane: i agree, there's lots of common ideas

10:53 dnolen: zacts: other things, Clojure has a more complete full stack story as it has a good mature compile to JavaScript story

10:55 zacts: ok

10:55 I know I do find Overtone interesting (the music processing system for Clojure)

10:55 and I think it's more mature for this purpose than anything Haskell offers afaik

10:56 can you metaprogram clojure via lispy () syntax tricks?

10:56 I know that Haskell doesn't use parenthetical syntax

10:56 so perhaps clojure would lend itself well to certain metaprogramming techniques better than haskell would?

10:58 ane: being a lisp, that is a given

10:58 someone wrote a structured haskell editor mode for Emacs, but it's a bit... wobbly

10:58 ARM9: clojure almost has common lisp meta programming (just missing custom reader macros)

10:58 ane: haskell is not a lisp, it's descended from ML and Miranda

11:10 justin_smith: zacts: clojure does runtime metaprogramming like lisp, though it's not as common in normal clojure code. haskell supports compile time metaprogramming via template haskell, but I don't think it has runtime metaprogramming

11:11 zacts: I see, neat

11:12 how is clojurescript coming along these days?

11:12 justin_smith: I use it at work, it's good - the toolchain is a little awkward to set up

11:13 zacts: ah ok nice

11:13 justin_smith: but it is definitely usable, and it is very easy to migrate functionality between server and browser (since of course the backend is jvm clojure)

11:13 zacts: oh nice

11:13 so Clojure and Clojurescript interop is pretty good for most common tasks?

11:14 justin_smith: zacts: figwheel makes cljs development pretty amazing - you have a clojurescript repl, and the code you do in the repl immediately takes effect in the running browser

11:14 zacts: nice

11:14 justin_smith: zacts: I don't know about "interop" - eg the way you can directly use js in cljs, or directly use the jvm in clojure

11:14 but they communicate nicely, and you can share or migrate code between them very reasily

11:49 ARM9: any reason why some? isn't some ?

11:49 since every? is [pred coll]

11:51 dnolen: ARM9: some isn't a predicate

11:51 that is, doesn't return boolean value

11:52 phaseNi: Does anyone know a good example of using aleph to create a line based tcp connection?

11:52 ARM9: some does return a boolean or nil

11:52 dnolen: ,(some #{:foo} [:foo :bar])

11:52 clojurebot: :foo

11:52 dnolen: ARM9: ^

11:52 ARM9: you're right

12:08 juanjo: hi

12:08 how can i replace the last newline of a string by a space?

12:08 like trim-newline but adding a space

12:13 broquaint: juanjo: (clojure.string/replace "foo bar\n" #"\n$" " ")

12:14 perplexa: +

12:14 juanjo: if i want \n or and \r? the same that trim-newline does?

12:15 broquaint: Use moar regexp :) e.g #"[\n\r]+$" that could be fancier but it'll do the job

12:16 juanjo: thanks

12:16 im really new to clojure

12:46 im using enlive

12:53 augustl: when I run "lein uberjar", the next clojure.tools.nameslace.repl/refresh fails with errors about namespaces it doesn't find

12:54 anyone know why that might be? Is it related to aot compilation maybe?

12:58 justin_smith: augustl: yeah, if you move the uberjar out of the target directory, then use lein clean, then the next refresh should not get an error

12:58 augustl: thanks! Will try that

12:58 justin_smith: augustl: I think it's the cached compilation artifacts (class files and such) made by uberjar that cause the problem

12:58 of course if you don't move the jar before running lein clean you lose the jar

13:10 augustl: ah, right :)

13:41 hlolli: ,(def map-with-fn {:a (fn [[x y]] (+ x y))})

13:41 clojurebot: #'sandbox/map-with-fn

13:41 hlolli: ,((:a map-with-fn) [2 2])

13:41 clojurebot: 4

13:42 hlolli: ,(def map-with-values {:a [2 2]})

13:42 clojurebot: #'sandbox/map-with-values

13:42 hlolli: My question is, what is a good syntactic sugared way to apply functions from one map to values of another map that share the same keyword?

13:46 justin_smith: ,(apply apply (map :a [map-with-fn map-with-values]))

13:46 clojurebot: #error {\n :cause "Wrong number of args (2) passed to: sandbox/fn--26"\n :via\n [{:type clojure.lang.ArityException\n :message "Wrong number of args (2) passed to: sandbox/fn--26"\n :at [clojure.lang.AFn throwArity "AFn.java" 429]}]\n :trace\n [[clojure.lang.AFn throwArity "AFn.java" 429]\n [clojure.lang.AFn invoke "AFn.java" 36]\n [clojure.lang.AFn applyToHelper "AFn.java" 156]\n [clojure....

13:46 justin_smith: ergh

13:47 if your fn had just been plus that would have worked

13:47 hlolli: hmm

13:47 justin_smith: ,(apply apply (map :a [{:a +} {:a [2 2]}]))

13:47 clojurebot: 4

13:47 hlolli: ,((:a map-with-fn) (:a map-with-values))

13:47 clojurebot: 4

13:49 justin_smith: ,((fn [[f & args]] (apply f args)) (map :a map-with-fn map-with-values))

13:49 clojurebot: #error {\n :cause "Wrong number of args (0) passed to: PersistentVector"\n :via\n [{:type clojure.lang.ArityException\n :message "Wrong number of args (0) passed to: PersistentVector"\n :at [clojure.lang.AFn throwArity "AFn.java" 429]}]\n :trace\n [[clojure.lang.AFn throwArity "AFn.java" 429]\n [clojure.lang.AFn invoke "AFn.java" 28]\n [clojure.lang.AFn applyToHelper "AFn.java" 152]\n [cloj...

13:49 hlolli: well, Im seeing if I can make my code cleaner by storing functions in a map and call them with another map, each function of course expects different input type.

13:49 justin_smith: ,((fn [[f & args]] (apply f args)) (map :a [map-with-fn map-with-values]))

13:49 clojurebot: 4

15:15 kenrestivo: i have a trivial question: why was there a plushy cthulhu on the podium at the conj?

15:52 waamaral: also, where can I get one?

16:15 beaky: any reason to use lsits over vectors?

16:20 i guess lists are more efficient when i want stack-like behavior?

16:20 and lists are the way to go for macros

16:20 and thats it?

16:40 justin_s1ith: beaky: just about any clojure function that goes through a collection and generates results one by one will return a lazy-seq, which is like a list but lazy

16:41 beaky: often it's a question of what you had to do with the input - and often there's no strong reason to make a vector again later

16:45 beaky: wow my use of multimethods has gone out of hand

16:46 ive got multimethods dispatching via multimethods and invoking other multimethods

16:46 how do you limit use of multimethods

16:52 elvis4526: I'm pretty sure the answer is yes, but is a uberjar generated on one server can be used again on another server?

16:52 If the JRE is the same version & architecture

16:52 justin_s1ith: elvis4526: yes, and with very few exceptions, the OS shouldn't even matter

16:53 and most of the time you just need the JRE to be 1.6 or newer, no other restriction

16:53 elvis4526: that's even better, that's really cool thanks

16:53 justin_s1ith: versions don't need to match

16:53 oh man my nick got changed

16:54 justin_smith: much better

17:57 m1dnight_: Hmm, I finally decided to fix the cider warning that cider-nrepl is not installed but none of the fixes i found online work. I have added it as :repl in my profiles.clj file and even as :plugin, but I still get the warning in emacs.

17:58 I have updated all my emacs packages and updated leiningen as well.

17:59 (ERROR: CIDER's version (0.10.0-snapshot) does not match cider-nrepl's version (not installed). Things will break!)

18:07 justin_smith: m1dnight_: you need the cider-nrepl plugin (usually added through profiles.clj)

18:08 m1dnight_: can you share your profiles.clj on maybe refheap?

18:08 [/win 3

18:12 m1dnight_: I seem to have set it up atm.

18:12 But now `cider-restart` is broken :<

18:12 to the google-copter

18:14 All those different version numbers are so confusing. Am I on 0.10 or on .2.12 or what?

18:14 https://www.refheap.com/112118 <- profiles.clj

18:15 lein repl gives me: REPL-y 0.3.7, nREPL 0.2.10

18:15 but leiningen version is 2.5.3

18:16 and according to clojars 0.10.0-snapshot is the latest.

18:20 Or is this just a bug in the cider.el (or whatever it is)?

18:20 Seems like it as it is an emacs-level error.

18:21 justin_smith: m1dnight_: leiningen and nrepl are two different projects

18:21 and cider is a third - cider requires both the others though

18:21 m1dnight_: okay

18:21 so if I get it right, nrepl is a leiningen plugin?

18:21 like lein-ancient

18:22 so that can be upgraded seperately of all the rest.

18:22 justin_smith: no, cider-nrepl is a middleware for nrepl

18:22 m1dnight_: oh

18:22 justin_smith: nrepl is provided by lein, though cider might want lein to use a different version of nrepl

18:22 m1dnight_: But the error I get now in emacs is "CIDER requires Nrepl .2.12 (or newer) to work properly"

18:23 I dont mind that, but what I do mind is that it really crippled my emacs. Somehow. Im guessing the newest cider package? Because C-c C-k is broken, `cider-restart` throws "wrong type argument: stringp, nil"

18:24 justin_smith: m1dnight_: package.el compiles el files to elc, but cider is not binary compatible between upgrades, so at the very least you have to delete all your old .elc files

18:24 you can optionally recompile them, that helps emacs start up faster, but it's not a requirement for things to work

18:25 s/binary-compatible/api-compatible

18:27 m1dnight_: I have versioncontrolled my entire emacs and setup to autoinstall on boot. so I just did that.

18:27 Reinstalling everything as we speak :p

18:28 justin_smith: m1dnight_: you don't need to reinstall

18:28 in fact, reinstalling won't help

18:28 you need to delete the elc files

18:28 m1dnight_: well, reinstalling emacs == rm -Rf .emacs.d && git clone .emacs.d :p

18:28 so that does help

18:29 justin_smith: oh, and no .elc files in your git?

18:29 m1dnight_: no

18:29 okay lets see

18:29 justin_smith: ok, so that's just a roundabout way of deleting the elc files then :P

18:29 m1dnight_: it is :>

18:30 still the error, though

18:32 Oh, but it seems like it is meant to throw those.

18:32 so all is well.

18:32 now back to what I wanted to do an hour ago.. :p

19:43 ChristopherS: I'm confused about something and am having trouble finding info online. How can I run an application, interact with it in a repl while it's running, and also make changes to the source and have them update in real time? I feel like I've seen things that say Clojure can do this, but I'm having a lot of trouble actually figuring out how.

19:51 bhajana: ChristopherS: do you use leiningen?

19:53 rufoa: anybody familiar with cljs-ajax? It seems if I perform the same ajax.core/GET request several times in a row, only the first one actually causes an XHR to occur? is there e.g. memoization or something going on?

19:58 ChristopherS: bhajana: yep, I use leiningen!

19:59 justin_smith: ChristopherS: this doesn't require leiningen actually - you can start your program from inside a repl, and use (require some.ns :reload) to load the newest version of a namespace

19:59 though some editors have bindings to automate that based on the file you are editing

20:03 ChristopherS: That makes sense! So let's say I wanted to do something like add a route to an already running compojure server. How would I run the server to allow me to do that, and then how would I do that (load in the new changes without stopping the server)?

20:04 justin_smith: ChristopherS: when you pass the routes to the function that starts your server, pass in the var so that when you change the var it sees the new value

20:04 I assume you are either setting a handler in project.clj or using run-jetty ?

20:13 ChristopherS: Hmm should I be using run-jetty? I've been doing `lein ring server`, but I'm pretty new to this

20:15 rufoa: there's also http-kit which works like run-jetty

20:15 justin_smith: ChristopherS: with lein ring server, you set the handler function in your project.clj - that is the other option I mentioned

20:16 ChristopherS: so in your project.clj, where it refers to the handler, what you can do is change some-ns/handler-name to #'some-ns/handler-name and this will pass the var to the http server, so that new values are used when it is redefined

20:23 kenrestivo: there are no apropos vars on async-shell-command to make it stop throwing a window up every time it runs. i want it to run in the background, is there a hook i can use to bury it before it shows?

20:24 oops wron channel

20:27 what i was going to ask here is: is there any way to convert a nested map into a zipper? i.e. {:foo {:bar 1 :baz 2} ?

20:28 it's hard to determine the answer to the predicates that zip/zipper requires in a nested map like that

20:29 justin_smith: kenrestivo: a good predicate is coll?

20:29 ,(coll? [])

20:29 ,(coll? {})

20:29 clojurebot: true

20:29 true

20:29 justin_smith: and then seq to get the individual entries, of course

20:36 kenrestivo: hmm ok will try

21:27 douglarek: , (= ((fn [x y] (keep-indexed #(if (not= 0 (rem (inc %) y)) %2) x)) [1 2 3 4 5 6 7 8] 3) [1 2 4 5 7 8])

21:27 clojurebot: true

21:27 douglarek: , (= ((fn [x y] (keep-indexed #(if (not= 0 (rem (inc %) y)) %2) x)) [1 2 3 4 5 6 7 8] 3) '(1 2 4 5 7 8))')

21:27 clojurebot: true

21:27 douglarek: , (= ((fn [x y] (keep-indexed #(if (not= 0 (rem (inc %) y)) %2) x)) [1 2 3 4 5 6 7 8] 3) '(1 2 4 5 7 8)))

21:27 clojurebot: true

21:28 douglarek: = can be used between seq and vec,

21:28 amazing!

21:31 justin_smith: douglarek: it's called structural equality

21:38 douglarek: justin_smith: thanks, any detail ?

21:39 justin_smith: douglarek: I rich hickey talks about his reasoning for structural equality in one of his videos, I forget which one

21:39 my version of he summary is that when you have immutable data, often what you want to know is if the shape of two collections matches, even if the exact type and instances are different

21:40 douglarek: for example, you expect (int 4) to be equal to (long 4) - same contents, different classes, right?

21:42 douglarek: yeah,

21:43 so '(1 2) will share same structure with [1 2]?

21:43 justin_smith: douglarek: not on a literal sense of existing in the same place in ram

21:44 but they obviously have equal elements in each place

21:44 just as (int 4) and (long 4) are equal, but are not referring to the same object

21:44 douglarek: justin_smith: ok, i must try to understand it

21:45 justin_smith: douglarek: if you have "the joy of clojure" in hardback, and I have the same edition in paperback, we still say we have the same book

21:45 because what's in them is the same

21:46 douglarek: very vivid

21:46 is it a value equality

21:47 justin_smith: right - they are equal by value, despite having different identity and class

21:47 douglarek: justin_smith: thanks a lot, Every time you help me all about it

23:44 kenrestivo: stuart's talk on debugging was great, but he left out the most important debugging technique:

23:45 "copy/paste the error message into google"

23:45 i think that's how 99% of problems are solved

23:47 justin_smith: kenrestivo: I swear one of these days I am going to make a website with the most common clojure error messages and what they usually mean

23:55 elvis4526: You should - most exceptions i encounter when using Clojure aren't terribly useful on their own. In general, would core.typed help against NullPointerException? Is it worth it?

23:57 justin_smith: elvis4526: it seems pretty cool, I have not tried core.typed though. I have tried prismatic/schema which is useful for runtime assertions about the shape of data in your inputs / outputs

Logging service provided by n01se.net