#clojure log - Sep 11 2015

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

0:00 justin_smith: nowprovision: why not nth?

0:01 nowprovision: justin_smith, that seems better, im very rusty.. tahnks

0:01 justin_smith: nowprovision: it might read better if you bind the (iterate ...) in the let block, then use nth on that

0:10 nowprovision: okay now I have https://www.refheap.com/20d51c2bb7ea776d05824a862 any further thoughts

0:14 ska-fan: So (:a {:a 4}) is 4, but ("a" {"a" 4)) throws an exception - does key as a function just doesn't work for strings?

0:15 TEttinger: ska-fan: ah this is neat

0:15 so keywords like :a actually do more than just store text conveniently

0:15 tolstoy: But ({"a" 4} "a") is 4.

0:16 ska-fan: tolstoy: Ha! indeed. /me goes of simplifying.

0:16 nowprovision: a keyword is a function

0:16 justin_smith: ska-fan: clojure always calls the first thing after the paren

0:16 TEttinger: a keyword also implements IFn (meaning, it can be called as a function), but they are fns that can be called with a map as an arg (possibly other stuff too)

0:16 justin_smith: ska-fan: it just so happens that keywords are callable

0:16 ,(:a :a :a)

0:17 TEttinger: maps also implement IFn and can be called with a key

0:17 clojurebot: :a

0:17 TEttinger: wha

0:17 ,(:a :a)

0:17 clojurebot: nil

0:17 TEttinger: ha!

0:17 it's a get

0:17 ,(:a :a :b)

0:17 clojurebot: :b

0:17 justin_smith: TEttinger: demonstrating that :a is callable, and it isn't something being done by the map

0:17 TEttinger: ,({:a 5} :a)

0:17 clojurebot: 5

0:18 TEttinger: ,({"a" 5} "a")

0:18 clojurebot: 5

0:18 TEttinger: maps are fns too, but like justin_smith is saying, the first thing after the '(' is what gets called

0:18 tolstoy: ,({2 4} 2)

0:18 clojurebot: 4

0:18 TEttinger: threeve_: is that nick a celebrity jeopardy reference?

0:26 devtrope: ,(supers (class :a))

0:26 clojurebot: #{java.util.concurrent.Callable clojure.lang.IFn java.lang.Runnable java.lang.Comparable java.io.Serializable ...}

0:29 TEttinger: ,(clojure.string/join " " (supers (class :a)))

0:29 clojurebot: "interface clojure.lang.IHashEq interface java.util.concurrent.Callable interface clojure.lang.IFn interface java.lang.Runnable interface java.lang.Comparable interface java.io.Serializable interface clojure.lang.Named class java.lang.Object"

3:13 deiodeiodeio: I want to be able to run my tests in parallel (selectively). Currently, I'm using midje, and my naive approach of wrapping parallelizable sections of my test code in futures seems to break it. What's a good way of doing this?

3:15 ordnungswidrig: deiodeiodeio: that's actually a good question. But why want you to run tests in parallel?

3:16 deiodeiodeio: I'm doing integration tests involving spinning up and taking down a lot of services

3:17 naturally, this takes a while

3:17 ordnungswidrig: deiodeiodeio: I see. In which way do futures break it?

3:17 deiodeiodeio: I'm assuming there are no race conditions or the tests influencing easch other

3:21 deiodeiodeio: ordnungswidrig: it doesn't seem to be my code, no..

3:22 ordnungswidrig: can you distill an example? just how you use midje and futures?

3:22 deiodeiodeio: yeah, sorry, I'm working on it

3:29 ordnungswidrig: basically, I did something along the lines of (facts (future (fact 1 => 0)) (future (fact 1=> 0) ...)), and got a bunch of Exception in thread "main" java.lang.AbstractMethodError: clojure.core$promise$reify__6363.invoke()Ljava/lang/Object

3:30 ordnungswidrig: deiodeiodeio: oh weird

3:30 deiodeiodeio: ordnungswidrig: yeah. but I'm now not entirely convinced it's midje's fault. if it is, it seems to be flaky

3:30 so I guess I'll have to investigate it a bit closer

3:30 ordnungswidrig: deiodeiodeio: I would macroexpand the (facts) expression

6:30 namra: j/quit

7:30 deiodeiodeio: what's a good, simple way of doing concurrent printing without using core.async or a logging library?

7:30 (i.e. without multiple lines printing concurrently)

7:40 mnngfltg: deiodeiodeio, using an agent perhaps?

7:40 luma: yep, create an agent and then send each printing to it

9:19 galaux: I can't find some kind of "fail" method for Clojure unit tests …

9:19 Does it exist somewhere?

9:21 snowell: Wouldn't you generally want to assert the opposite of what's happening?

9:21 galaux: well: nothing is happening, that's the idea

9:21 snowell: What are you testing for?

9:21 galaux: I'm testing for a particular function NOT to be called

9:22 This is a function I pass to some other function … I want to check it has not be called

9:22 So I thought I would just make this second method something like `(fail "Error")

9:23 snowell: I mean…you could always assert false ;)

9:23 galaux: yes …

9:23 snowell: Sorry that's not a whole lot of help

9:24 galaux: no but still it would work … even though a "fail" method would have been perfect (especially for handling a test failing messge)

9:24 snowell: thanks

9:25 snowell: I've not done much unit testing in clojure. When I have, it was with https://github.com/marick/Midje

9:26 dstockton: galaux: assert can take an option message

9:26 (defn fail [message] (assert false message))

9:28 or you could throw an exception

9:29 galaux: An exception is not a failing test

9:29 I don't want to crash it, just flag it as failed

9:29 but it would work in some way

9:32 I am going to go for `(is (true? false) "Something went wrong")`

9:32 snowell: thanks for the link,looks nice !

9:33 snowell: With both Midje and clojure.test, you can assert that exceptions are thrown/not thrown

9:34 So if you pass in a function that just throws an Exception, you can assert that said Exception isn't thrown

9:34 Without crashing the test execution

10:13 justin_smith: e


10:21 clojurebot: 16045690984503098077N

10:21 justin_smith: I hear that number is prime

10:26 gfredericks: ,(.isProbablePrime (biginteger 0xDEADBEEFCAFEBADD) 100)

10:26 clojurebot: true

10:33 troydm: which function should I use for lenghth of string in Clojure? .length or count?

10:41 justin_smith: well only one of those is a function

10:41 use count

12:52 mdeboard: Ok so in cider, I'm running this long-running async process in a goroutine. How the heck do I kill it?

12:59 justin_smith: mdeboard: write it such that it checks some condition you have control over, and it exits gracefully

12:59 or kill your vm

13:00 mdeboard: ok, that's what I figured (the last)

13:00 justin_smith: mdeboard: is it reading from some channel? closing the channel would help in that case

13:00 (I was being slightly glib)

13:00 mdeboard: Yeah I just added some logic to close

13:05 I assume the value of `(<! ch)` if there are no messages on the channel is `nil`, is that right?

13:08 justin_smith: no

13:08 it doesn't return to your process

13:08 nil is if the channel is closed

13:09 (which is why I mention that closing a channel could communicate to a go block that it should exit)

13:09 mdeboard: forgot to highlight you in my reply ^

13:10 mdeboard: I see

13:10 Hmm

13:10 Because I want to flush my buffered writer if there's nothing on the channel

13:10 so I don't have half a message in the log

13:10 just chilling, waiting for more data

13:11 justin_smith: mdeboard: check out alts!

13:11 then you can have a timeout, and flush if the timeout is hit

13:11 mdeboard: Cool

13:11 Very nice

13:12 justin_smith: like (alts! [ch (timeout 10000)]) either gets data from ch, or from the timeout after 10 seconds

13:12 and in the return value you can test which you got

13:13 mdeboard: Frustrated with Clojure's documentation atm.

13:13 As I have been since 2010 or something.

13:13 justin_smith: mdeboard: this is what makes our lovely community so valuable :)

13:14 mdeboard: the official core.async api is a bit disorganized maybe, but it is comprehensive https://clojure.github.io/core.async/#clojure.core.async/alts!

13:14 official core.async api docs, that is

13:17 mdeboard: yeah that's what I'm frustrated with :P

13:17 It's definitely exhaustive

13:17 Not sure how useful it actually is, but it's exhaustive

13:18 justin_smith, So where can I find a full example of this alts functionality

13:18 justin_smith: mdeboard: I think my skill as a developer has been helped quite a bit by my extensive experience reading postmodern literature - fragmented, odd points of view, strange aporias ...

13:18 mdeboard: hmm, maybe conj.io, checking

13:19 mdeboard: Is that another stab at community-curated docs?

13:19 Ah this is uh

13:19 justin_smith: mdeboard: if not i'll share a quick repl demo of it

13:19 mdeboard: Oh the guy lives here in Austin

13:19 Can't remember his name, but this is his thing

13:19 justin_smith: mdeboard: arrdem

13:19 mdeboard: arrdem, yeah

13:19 justin_smith: I thought he had core.async on here but I can't find it

13:20 mdeboard: Here's my function https://gist.github.com/mattdeboard/ecd0d033d1977bf6da78

13:21 I think the alts! call would go on like line 7 (and I'd need to refactor a little to remove the arg to recur

13:21 )

13:23 justin_smith: mdeboard: working demo of alts! from the repl https://www.refheap.com/109440

13:23 mdeboard: you can test via the second item in that returned vector which channel the value came from

13:23 mdeboard: paste updated to show this fact https://www.refheap.com/109440

13:25 mdeboard: yeah, I would put the alts on line 7, and if the channel the value comes from does not = ch, then flush, otherwise use the value

13:26 mdeboard: using my own repl example of alts as a basis for that should be easy enough

13:34 mdeboard: Nice, thanks

13:35 mungojelly: why do i need to say var# to get unclobbered variables in macros, do y'all also use macros to intentionally clobber variables?

13:42 sdegutis: Is there a simpler way of mapping characters in a string to their line/char position than this? https://gist.github.com/sdegutis/ff476b6efef23e7a5a1d

13:42 This function seems overly complex.

13:42 mdeboard: justin_smith, Sorry if I'm being a huge dunce but the alts! syntax doesn't make sense to me. it takes an array of "ports", and does what?

13:43 It says it "does at most one of several channel operations"

13:43 What operations is it talking about?

13:43 snowell: mdeboard: It accepts any number of channels and performs a take on whichever one of them *first* returns a value

13:43 mdeboard: Oh

13:43 What the hell?

13:44 wth @ the docs

13:44 arrdem: mdeboard: o/

13:44 mdeboard: that's 100% impenetrable

13:44 arrdem: are we on about docs again

13:44 mdeboard: and also just seems inconsistent with actual functionality?

13:44 arrdem, lol

13:44 I don't want to get you in any legal trouble

13:45 or something (recalling some blog post about something like that)

13:45 snowell: I do. I'd love an excuse to go back to Austin ;)

13:45 mdeboard: "Completes at most one of several channel operations." <-- actually means "Performs a take on at most one of several channels"?

13:46 Ok now that I understand alts! because of the explanation in IRC, the docs make sense. That's not how docs are supposed to work.

13:47 arrdem: welcome to Clojure

13:48 mgaare_: mdeboard: actually that's not what it means. because you can also do a put inside of alts!

13:48 mdeboard: Yeah was just saying this has been constant source of irritation for like 5 years

13:48 mgaare_, Yeah I see that now

13:48 I'm tempted to do a PR to improve that docstring

13:48 snowell: Sorry…I knew there was a chance I only partially understood it :/

13:49 mdeboard: but by "several" it just means "two" right? Either put or take?

13:49 mgaare_: that's why it says channel operations.

13:50 snowell: "several" refers to its args

13:50 mdeboard: wat

13:50 clojurebot: Titim gan éirí ort.

13:51 snowell: You pass in several operations, it will perform at most one of them

13:51 mdeboard: Ok, maybe I am misunderstanding the word operation.

13:53 mgaare_: operation in this context is the combination of action + channel. So "put on channel x" is an operation, "take from channel y" is an operation, and you can have an arbitrary number of these in what you pass to alts!

13:54 seancorfield: clojars.org seems to be struggling... very very slow to respond / occasional 500 server error messages

13:54 mdeboard: ok so you can do like `(alts! [ch-foo [ch-bar 1] ch-baz [ch-qux 2]])` ?

13:55 mgaare_: mdeboard: that's right

13:55 mdeboard: Ok. Thanks for the clarification

13:55 Does it just iterate left-to-right looking for the first valid operation?

13:56 and a put is invalid only if the channel is closed?

13:57 mgaare_: mdeboard: if you pass :priority true as an opt, then they will be tried in order, otherwise there is no order guarantee. a put will only succeed if the channel is open and not blocked

13:58 mdeboard: Understood, thank you

13:59 mungojelly: why the ! does it change something

14:03 _alejandro: it modifies the channel it reads from / writes to

14:12 mdeboard: That's just a freaking hard function to explain. Takes more than the dry matter-of-fact tone of docstring.

14:12 (I'm sitting here trying to write better documentation.)

14:14 geet: Hi! I'm new to Clojrue, I'd like to start contributing. Where would you suggest I do?

14:15 mungojelly: hmm so you only get tail-call optimization if you ask for it with "recur"?

14:17 arrdem: mungojelly: correct

14:18 mungojelly: ok thanks well that's clear enough anyway. what do you want to contribute to what, geet, i don't understand?

14:19 arrdem: note that the JVM itself doesn't have TCO yet due to reliance on stack frame counting for some security stuff

14:22 geet: Contributing to clojure

14:22 mungojelly:

14:23 mungojelly: personally what i think it needs is more toys

14:24 i'm learning by poking at lists of meaningless numbers, i'm bored, someone hand me a toy

14:25 mdeboard: Is there any kind of proscription against calling `recur` in a `do` block

14:26 justin_smith: mdeboard: only that it needs to be in the tail position (that would always be the end of a do block, or the end of a branch in a do block)

14:26 mdeboard: Alright, cool

14:34 I think this will do what I am wanting but not entirely sure https://gist.github.com/mattdeboard/ecd0d033d1977bf6da78

14:34 It didn't, actually. I wonder if it closed too quick or something.

14:35 justin_smith: mdeboard: (if (nil? entry) ...) should be (if (nil? (first entry)) ...)

14:35 mdeboard: remember alts returns a two part vector

14:35 even better, it could be (if-not (= ch (second entry)) ...)

14:36 mdeboard: similarly with your other usages of entry I think you want (first entry) to actually get the data, rather than the data/channel pair

14:37 mdeboard: or, perhaps the easier change is (let [[entry source] (async/alts! ...) ...] ...) and then the rest of the code can stand unchanged

14:37 mdeboard: Are you sure about the vector thing?

14:37 https://gist.github.com/mattdeboard/f15ff4454ffd1c570ca2

14:37 justin_smith: mdeboard: absolutely sure

14:37 mdeboard: it's not timeout that returns the vector

14:38 it is alts! that is returning a vector

14:38 mdeboard: Oh!

14:38 Ok.

14:38 justin_smith: mdeboard: see my example - no matter which data source is acessed, you get a two element vector of the data and the channel it came in on

14:38 alts! would not be very useful without that feature

14:38 mdeboard: Why is this so hard for me to grok

14:39 justin_smith: mdeboard: it's new?

14:47 mdeboard: Nice, it works

14:47 Thanks for the help all youse

14:48 justin_smith: cool

14:50 mdeboard: Hm maybe not.

14:51 This is really hard to troubleshoot, the asynchrony. Feel like I'm doing JavaScript

14:52 Writing javascripts*

14:53 justin_smith: jabbyscraps

14:54 yes, core.async can be weird to figure out when misbehaving

16:52 ben_vulpes: so i'm wiring a figwheel server setup into my clojure projects own reloaded flow, and i've bumped into an issue managing the figwheel server's state

16:52 i new up a figwheel server, stop it, and then bind the result to fig-server

16:53 pass that into the watcher as (fig/autobuild* {... :fig-server fig-server})

16:53 call (fig/stop-server ...) on the value for the :fig-builder key in my system object

16:54 get a repl print line that claims that the fig-server has been started on :3449

16:54 but then i simply get websocket errors in the browser, a la 'ws://localhost:3449/figwheel-ws/dev failed' ERR_CONNECTION_REFUSED

16:55 * ben_vulpes shrugs in confusion

16:56 nooga: I just had the weirdest node.js like experience with clojure

16:56 ben_vulpes: oh fascinating. it's not even recompiling the cljs.

16:56 * ben_vulpes back to spelunking

16:56 mdeboard: ben_vulpes, Is your project.clj set up right?

16:57 nooga: timbre was throwing an exception because something inside manifold returned an exception instead of a value I wanted to log

16:57 mdeboard: Here's a year-old project.clj of mine from a cljs project I was working on that uses figwheel and all that https://github.com/mattdeboard/dots/blob/master/project.clj

16:57 nooga: and I saw manifold's exception with meaningless timbre call stack

16:58 took me a while

16:58 mdeboard: ben_vulpes, figwheel used to be super, super hard to set up then... something changed that I can't remember

16:59 maybe I just stopped being dumb

16:59 nooga: heheh

16:59 mdeboard: Gosh darnnit I hate that i have to have the source code ordered correctly in order to compile

16:59 like if function A calls function B, function B has to be physically above function A in the source

17:00 is that unavoidable?

17:07 oddcully: ,(doc declare)

17:07 clojurebot: "([& names]); defs the supplied var names with no bindings, useful for making forward declarations."

17:08 nathanmarz: Clojurescript question for any of the experts here

17:09 Trying to implement IFn protocol for more than 20 arguments, but this isn't working: https://gist.github.com/nathanmarz/e932e11c523fe90b1850

17:10 when I invoke with 21 args it just binds "rest" to the 21st arg (instead of a seq), and when I bind with more it gives an arity exception

17:11 @dnolen any ideas?

17:14 ben_vulpes: mdeboard: no clue, boss.

17:14 i've fallen back to using lein-figwheel

17:14 but now it's not watching files

17:14 * ben_vulpes flaps hands

17:16 ben_vulpes: clean-builds and build-once work handily from the repl, but figwheel is refusing to reload changes.

17:18 dnolen: @nathanmarz probably just a bug

17:19 @nathanmarz oh right, but there's no support for this at the protocol level in ClojureScript (and unlikely unless somebody else wants to do the work)

17:19 ben_vulpes: (i'm a derp, disregard)

17:20 nathanmarz: @dnolen: ok

17:20 dnolen: JavaScript doesn't support variadic methods in the nice way that Java does

17:20 so you will need a fn to pull apart the args for you (fns produce a bunch of dispatching logic)

17:20 nathanmarz: @dnolen: I though that 21 arity version of -invoke (not including the "this" param) handled that case

17:20 dnolen: but this completely undesirable at the protocol level for perf reasons

17:21 protocols are at the very bottom

17:21 they are literally nothing but the host

17:21 i.e. JavaScript methods

17:21 Bronsa: dnolen: isn't this the same for clojure on the jvm? IFn vs RestFn

17:22 nathanmarz: @dnolen: ok

17:22 dnolen: Bronsa: but Clojure separated these things out, Java doesn't have functions

17:22 nathanmarz: @dnolen: why to functions like assoc and + allow for more than 20 args?

17:22 dnolen: JavaScript does

17:22 nathanmarz: var args support at the compiler level

17:22 every function emits dispatching code to handle this stuff

17:23 nathanmarz: oh i see

17:23 dnolen: this code is not expressed at anything shareable (via a class)

17:24 but also protocols do not support var args, neither Clojure nor ClojureScript

17:24 IFn in Clojure is a Java thign

17:24 nathanmarz: yea, IFn in clojure has applyTo

17:25 I thought the -invoke definition in cljs was the equivalent, but it just gets interpreted as a 21 artity invoke

17:25 dnolen: nathanmarz: nope

17:25 the 21st arity is just to support fns that dispatch to protocols

17:26 which will have already pulled apart the args

17:27 @nathanmarz there's probably some way to make this work, but I'm not going to stick my brain there right now

17:27 nathanmarz: oh I just mean for my own extension of IFn to my own type

17:27 yea it's not that big of a deal

17:30 dnolen: nathanmarz: Bronsa: actually scratch everything I just said

17:30 I'd just forgotten how this worked (I did this so long ago)

17:30 it's a simple bug

17:31 nathanmarz: http://dev.clojure.org/jira/browse/CLJS-1447

17:31 not sure when I'll get around to this though

17:34 nathanmarz: @dnolen: I'll keep my test for this commented out in the meantime ;)

17:36 dnolen: nathanmarz: yeah ok now I remember the issue :)

17:36 so ClojureScript functions are just JavaScript functions, there is no arity limit

17:36 but this of course doesn't make sense for the IFn protocol, the change is actually pretty simple, the ticket is updated with some simple details on how to do it

17:54 berns_: When I merge maps with merge-with, is there any way to maintain the order of the values?

17:54 amalloy: what do you mean, the order of the values?

17:55 eklo: Hello, I'm working on a recursive fn for counting the number of solutions to the n-queens but it seems slower then it should be. I'm just trying to learn if I used the correct structure for recursing and stopping branches early. https://www.refheap.com/109449

17:59 berns_: amalloy: ({:foo 1} {:foo 2} {:bar "a"} {:foo 3}) -> {:foo (1 2 3) :bar "a"}

17:59 amalloy: as opposed to...?

17:59 berns_: {:foo (3 1 2) :bar "a"}

18:00 amalloy: the function that you give to merge-with will receive the values it needs to merge in the same order that they are present in the map you give to merge-with

18:01 eklo: it looks reasonable enough to me

18:02 berns_: but if I merge with conj, it prepends. If I merge with vector, it does [1 [2 3]]

18:03 amalloy: berns_: if you merge with conj it doesn't work at all, because (conj 1 2) is an error

18:03 nooga: btw. what is the best place to start learning about cljs compiler? (I mean the code, obviously, but it's a big program and it's hard to understand its structure eight away)

18:03 right*

18:58 seako: hello fellow clojurians, i'm wondering if anyone has any wisdom to share re: tuning garbage collection and jvm options or articles they can point me to? as i'm new to the jvm, nothing is too elementary.

18:59 tcrayford____: seako: I was just reading just the thing!

18:59 http://insightfullogic.com/2013/Feb/20/garbage-collection-java-1/, http://insightfullogic.com/2013/Mar/06/garbage-collection-java-2/, http://insightfullogic.com/2013/May/07/garbage-collection-java-3/, http://insightfullogic.com/2013/Jun/24/garbage-collection-java-4/

19:00 seako: thanks!

19:00 tcrayford____: that's for GC at least. RE JVM options, I mention them a bit in a talk I gave at euroclojure this year: http://yellerapp.com/posts/2015-06-29-performance-and-lies.html

19:00 (there's a table in the slides that you can skip to, but it ain't useful without me talking over it)

19:01 seako: thanks so much, really appreciate it!

19:02 tcrayford____: s'cool. Feel free to PM me on freenode if you have questions, I have done a lot of stuff with the JVM and perf/tuning/etc (I have an irc bouncer so I may not reply immediately, but I will get your message and reply eventually)

19:04 seako: super generous of you, i just might take you up on that :)

20:39 felipedvorak: http://pastebin.com/EWqrjtBs can somebody help me with that? It's ultra basic baby so probably won't take more than a few seconds of your time. I'm trying the classic "get me the odd numbers out of this sequence". What am I doing wrong?

20:40 justin_smith: felipedvorak: when would tail be 0?

20:40 ,(rest ())

20:40 clojurebot: ()

20:41 felipedvorak: hmmm

20:41 would (nil? tail) work?

20:41 justin_smith: also why (into () resul) - you could just conj the items onto () in the first place if you want a reversed list instead of an in-order vector

20:41 felipedvorak: no

20:41 amalloy: also, this looks like you are trying to do the classic CL/scheme "accumulate a list and then reverse it"

20:41 justin_smith: err, maybe

20:42 but empty

20:42 felipedvorak: amalloy: I don't really know what I'm doing hehe

20:42 amalloy: nil? would be fine

20:42 justin_smith: oh, yeah he is using destructuring and not rest

20:42 amalloy: although uh, you then lose the last element of the sequence

20:42 you can't just check the tail of the list and then ignore the head

20:43 justin_smith: felipedvorak: also, this is very much common-lisp style imperative code, and we have much simpler ways to do operations like this (but I trust if you stick to clojure you'll learn those eventually)

20:44 felipedvorak: I hope so, I'm only a few days in

20:46 I still don't get it though

20:46 dbasch: felipedvorak: you probably want to start by looking at some of the built-ins that come with clojure http://clojure.org/cheatsheet

20:46 justin_smith: felipedvorak: rule of thumb, if what you are doing involves going through a sequence one item at a time, clojure probably has something much nicer than loop you can use for that

20:47 dbasch: felipedvorak: e.g. in this particular case, odd? and even?

20:47 justin_smith: felipedvorak: which part don't you get?

20:47 xzilend: noob question, I have a {:email ".." :password ".."} map. I'd like a validation function to add: {:errors ["error 1"]} to the initial map. I currently have (update-in creds [:errors] conj "error 1"), but that creates {:errors ("error 1")}, is there anyway I can enforce a vector instead?

20:47 justin_smith: xzilend: (fnil conj [])

20:47 felipedvorak: dbasch: I have that on my bedroom wall hehe will check it more often

20:48 justin_smith: ,((fnil conj []) [] :a)

20:48 clojurebot: [:a]

20:48 justin_smith: ,((fnil conj []) nil :a)

20:48 clojurebot: [:a]

20:48 dbasch: felipedvorak: I haven’t read your code but it sounds like you want (filter odd? your-seq)

20:48 justin_smith: dbasch: I think he still could learn a few things by making the loop work (though your version is canonical, of course)

20:49 dbasch: justin_smith: agreed

20:50 felipedvorak: lol, (filter odd? sequence) looks beautiful. Must love this language.. I'll try to fix this code for learning purposes

20:53 xzilend: justin_smith: thanks!

20:53 justin_smith: xzilend: fnil is almost as awesome to use as it is to say

20:53 fnil

20:53 rolls right off the tongue

20:55 oddcully: close to fna

20:56 lodin-: justin_smith: There's also a more esoteric solution, and that's to use a lens library and do (update creds (lookup :errors []) conj "error 1") where lookup is the lens with default value [].

20:57 justin_smith: one of my first experiences with my new job was introducing my coworkers to fnil, only to have them laugh at the word

20:57 lodin-: I was once talked out of trying to use lenses in clojure, do you think it's worth it?

20:57 xzilend: lodin-: thanks! I'll keep that in mind :D

20:58 lodin-: justin_smith: Yes!

20:59 justin_smith: I really miss a solid lens library though. One day I might find the time to write one myself.

21:01 felipedvorak: hmm, and now hehe still get an error, I believe it may have to do with conj? (trying te primitively read the error output)

21:01 http://pastebin.com/4M78iwvJ

21:01 justin_smith: felipedvorak: yeah, your args to conj are flipped

21:01 lodin-: justin_smith: I benched the functor implementation of lenses (my own, adapted from https://speakerdeck.com/markhibberd/lens-from-the-ground-up-in-clojure), against a 100 keys deep get-in. Lenses were faster. Blew my mind. I still believe the benchmark was wrong.

21:02 justin_smith: felipedvorak: it will still have the issue amalloy_ mentioned where if the last item is odd it will throw it away erroneously

21:02 felipedvorak: lol, now it gives me (6) as a result, but at least it runs

21:03 lodin-: Or was it update-in? Don't remember.

21:03 justin_smith: felipedvorak: oh, you flip the input and the result in your recur too

21:03 (in the first recur that is)

21:05 lodin-: justin_smith: Anyway, the point is that you don't need to worry about overhead, which leads us to the benefits.

21:06 felipedvorak: I still don't get why I loose the last item

21:06 lodin-: justin_smith: The biggest benefit is not actually lenses, but traversals.

21:09 xzilend: Can anyone tell me why I would prefer one of these over the other? (defn fun [s] (-> s f1 f2 f3)) or (def fun (comp f1 f2 f3))?

21:11 lodin-: xzilend: I opt for the first. The argument is explicit. (You have the order wrong in one of them though.)

21:13 xzilend: makes sense! thanks

21:13 lodin-: xzilend: Assuming the first version is correct, then it is clear that f1 takes just one argument. In the second, f1 could take any number of arguments.

21:15 xzilend: I think linters like eastwood will help you out as well with the first, but not the second, if you do (fun x y) or (fun) etc. But I'm not sure.

21:18 xzilend: lodin-: good point! thanks :D was reading http://drboolean.gitbooks.io/mostly-adequate-guide/ and it's very keen on the (comp ..) (although in JS) form

21:20 justin_smith: xzilend: clojure definitely has its population of point-free fans

21:20 (point free programming being the style where you avoid named arguments, so frequently use constructs like comp or juxt)

21:21 lodin-: xzilend: At the top-level I think you should just spell out your function. Anonymous functions, like functions passed to e.g. filter, is another thing.

21:23 xzilend: In practice, I find that I end up using #(-> % ...) anyway, since it's easier to do things like (get foo) there, rather than doing #(get % foo) in a comp.

21:25 xzilend: If you do use comp a lot, I recommend using (defn => [f & args] #(apply f % args)) too. It will be cleaner.

21:25 Especially since you can't nest #().

21:26 xzilend: lodin-: yeah those arguments definitely make sense

21:26 I've been using -> since I started clojure about a month or two ago, hadn't really seen comp used anywhere

21:27 lodin-: I'm not sure, but I think point-free makes more sense in "curried" languages, i.e. where multiple arity is just sugar for nested unary functions.

21:51 felipedvorak: justin_smith: with reduce I managed to get a list of the odd items BUT they are not in the correct order :/ http://pastebin.com/RXjZxAcH

21:52 hehe but I'm almost there

21:52 justin_smith: felipedvorak: if you want to keep the order, use [] instead of ()

21:52 also, '() is the same as (), you never need the former

21:52 felipedvorak: hmm

21:52 justin_smith: ,(= () '())

21:52 clojurebot: true

21:53 felipedvorak: but if the answer must be given in a list format, I use `into`?

21:53 justin_smith: no, into will reverse the order

21:53 use seq if you need the result to be a list - but why do you need a list?

21:54 felipedvorak: justin_smith: because the 4clojure problem, as far as I understood, asks for a list output

21:54 justin_smith: felipedvorak: I doubt it will reject a vector

21:55 but wrap the whole thing in seq if it rejects the vector

21:55 ,(= [:a :b :c] '(:a :b :c)) ; felipedvorak: in clojure lists and vectors are equal if they have the same content in the same order

21:55 clojurebot: true

21:56 felipedvorak: hmm, thats new to me

21:57 justin_smith: must go out for a bit, thanks for your help, I'll keep trying when I come back

21:59 it works! hehe thanks

22:37 pydave6377: Probably a stupid question, but is there a way of combining a HOF with the threading macro? Something like: (-> rtm-conn :start :users (filter :is_bot) first :id)

22:38 justin_smith: pydave6377: that works if you use ->> instead of ->

22:38 lodin-: pydave6377: You want to use ->> in front of filter.

22:38 justin_smith: since your collection needs to be the last arg

22:38 pydave6377: also, ->> can be used inside of -> if you need to combine the behaviors

22:40 ,(-> {:a [1 2 3 4]} :a (->> (map inc)))

22:40 clojurebot: (2 3 4 5)

22:40 lodin-: pydave6377: Has nothing to do with HOF though.

22:40 pydave6377: justin_smith: lodin- This is fantastic! Thank you both so much! I always had trouble working out the difference between -> and ->> so I'm ecstatic to have finally learned! Thank you both again!

22:41 lodin-: apologies - perhaps I mispoke. Still getting the hang of FP!

22:42 lodin-: pydave6377: Ah, wait. Did you mean "partial"?

22:43 pydave6377: lodin-: partial would have been a much more apposite description.

22:45 lodin-: pydave6377: All the forms in -> and ->> are "partial". That's the point of ->. That's not always clear because you often see it with unary functions and symbols are rewritten to have a parenthesis around them.

22:45 pydave6377: justin_smith: sorry, took me a moment to grok that. I had no clue that was possible! Thank you

22:45 lodin-: pydave6377: In other words, (-> x foo bar) is really (-> x (foo) (bar)).

22:46 felipedvorak: How do I get a number, say 424 and interpret it like a list (1 2 3 4 5...) so I can iterate?

22:46 justin_smith: lodin-: it's not really partial application though, -> / ->> don't operate on runtime functions and values, the operate on compile time forms

22:46 lodin-: pydave6377: And (-> x (foo y)) is (foo x y).

22:47 justin_smith: ,'(-> x (foo y))

22:47 clojurebot: (-> x (foo y))

22:47 lodin-: justin_smith: Yeah, I know. But you could say that the form is partial.

22:47 justin_smith: ,(macroexpand1 '(-> x (foo y)))

22:47 clojurebot: #error {\n :cause "Unable to resolve symbol: macroexpand1 in this context"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.RuntimeException: Unable to resolve symbol: macroexpand1 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:...

22:47 justin_smith: err

22:47 lodin-: pydave6377: And (->> y (foo x)) is (foo x y).

22:47 pydave6377: lodin-: that's really interesting. I've been using it the whole time as a substitute for (bar (foo (x)))

22:47 justin_smith: ,(macroexpand-1 '(-> x (foo y)))

22:47 clojurebot: (foo x y)

22:51 sotojuan: kool

22:51 lodin-: pydave6377: The name comes from how you do stitches with a needle. Thread, as in yarn.

22:55 pydave6377: lodin-: that's just made everything so much clearer. I've never thought of it like that. You guys have been incredibly helpful. Thank you so much!

22:57 lodin-: pydave6377: But don't start abusing it. :-)

22:57 ,(->> n dec f (* n) (if-not (pos? n) 1) (defn f [n]))

22:57 clojurebot: #'sandbox/f

22:57 lodin-: ,(f 5)

22:58 clojurebot: 120

22:58 justin_smith: oh my god that's terrible

22:58 haha

22:58 lodin-: justin_smith: This is how I write all my code. ;-)

22:59 kavkaz: D:

23:00 pydave6377: lodin-: that's the most egregious abuse of a well-intentioned feature that I have ever seen.

23:00 (inc lodin-)

23:14 justin_smith: this article about fortran covers clojure, and has some invalid common lisp code in it too http://arstechnica.com/science/2014/05/scientific-computings-future-can-any-coding-language-top-a-1950s-behemoth/

23:15 felipedvorak: What is the clojure equivalent of (i = 1; i < 1000; i++) ?

23:15 lodin-: felipedvorak: Depends on what you want to do, but probably (range 1 1000).

23:16 justin_smith: felipedvorak: (loop [i 0] (if (> i 999) nil ...) (recur (inc i)))

23:16 your code goes in the ... part

23:16 lodin-: I guess we interpreted that differently

23:17 another possibility is (doseq [i (range 1000)] ...)

23:17 lodin-: justin_smith: I'd doseq instead.

23:17 Yeah.

23:17 felipedvorak: hmm

23:17 justin_smith: felipedvorak: what are you actually trying to do?

23:17 lodin-: But using range with doseq or what-not only works if you don't plan to change i in the loop.

23:18 felipedvorak: get as input a number and use it as a list to check each number for a condition

23:19 also known as project euler problem 1 hehe

23:19 justin_smith: felipedvorak: what happens to the numbers you check?

23:19 do you return some of them?

23:19 do you print them?

23:19 felipedvorak: yeah

23:19 if a number is multiple of 3 or 5

23:20 justin_smith: yeah, use doseq with a print inside

23:20 lodin-: I'd first filter and then doseq over the ones I want to print.

23:20 felipedvorak: my prowess is still very basic, I still don't know doseq

23:20 let me check it

23:21 justin_smith: ,(doseq [i (range 10)] (println i))

23:21 clojurebot: 0\n1\n2\n3\n4\n5\n6\n7\n8\n9\n

23:21 felipedvorak: in the end you must output the sum of the numbers

23:21 justin_smith: ahh, so you need to keep track and sum, you'll want more than just doseq for that yeah

23:21 felipedvorak: ^ what is this output?

23:21 lodin-: felipedvorak: Then let me point you towards reduce.

23:22 felipedvorak: You can use a combination of reduce, filter, and range.

23:22 justin_smith: yeah, that's probably the best bet

23:23 felipedvorak: i'll try that, thanks

23:25 lodin-: felipedvorak: The "easy" solution if you are used to using loops is to use loop/recur, but resist the temptation. :-)

23:25 felipedvorak: wouldn't reduce be even easier?

23:25 justin_smith: felipedvorak: simpler vs. more familiar

23:25 lodin-: felipedvorak: Simple vs easy. ;-)

23:26 felipedvorak: I'm really looking for the hard but still "clojury" solution hehe

23:26 kavkaz: Not Clojure related but I'm expecting I'll have a quick answer, is there a MELPA package I need to download for emacs to enable spellcheck?

23:27 justin_smith: kavkaz: ispell comes with emacs, flyspell-mode is a nice way to use it

23:31 kavkaz: justin_smith: Ah cool, thanks

Logging service provided by n01se.net