#clojure log - Oct 11 2014

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

0:22 s1s2s3: does clojure already have a macro version of map, that lets you apply arbitrary forms to elements of a list and not just functions?

0:23 TEttinger: that sounds pretty useful... would it allow you to omit elements, in theory?

0:24 s1s2s3: You mean ignore certain elements of the list?

0:24 justin_smith: ,(for [x [nil 1 2 false true]] (or x 42))

0:24 clojurebot: (42 1 2 42 true)

0:24 TEttinger: like map mixed with filter

0:25 justin_smith, the point being or is a macro?

0:25 and for

0:25 s1s2s3: That's not what I had in mind but I suppose you could in theory make something like that

0:26 TEttinger: yeah, for sounds like what you're after

0:26 justin_smith: TEttinger: yes, for is a macro, and you can use :when to exclude items, that was going to be my next demo

0:26 s1s2s3: yes for is pretty close to what I want come to think of it

0:26 good point

0:27 justin_smith: ,(for [x (range 10) :when (not (odd? x))] (inc x))

0:27 clojurebot: (1 3 5 7 9)

0:27 TEttinger: ,(for [x [nil 1 2 false true] :when (number? x)] (inc x))

0:27 clojurebot: (2 3)

0:27 justin_smith: yeah, that too

0:31 s1s2s3: actually here is one difference between a macro version of map and for:

0:32 suppose you were mapping a two-argument form to two lists

0:32 like (mapcro .concat ["a" "b"] ["c" "d"])

0:33 TEttinger: I love the name

0:33 justin_smith: ,(for [[a b] (map list (range 10) (range 10 20))] (* a b))

0:33 clojurebot: (0 11 24 39 56 ...)

0:34 TEttinger: ,(for [[a b] (map list (range 10) (range 20))] (* a b))

0:34 clojurebot: (0 1 4 9 16 ...)

0:34 TEttinger: huh

0:34 s1s2s3: the for way is a bit awkward in comparison in my opinion

0:34 TEttinger: yah

0:34 but you could write a wrapper easily enough

0:35 s1s2s3: yes, just wanted to check if it's redundant with what already exists

0:35 TEttinger: I think for is pretty heavily optimized internally, I'd just do a wrapper around it

0:35 similar to map

0:36 s1s2s3: yes I think I will do that

0:37 thank you for your thoughts TEttinger and justin_smith

0:38 clojer: Anyone had any luck with Chestnut. David Nolen had much praise for it yesterday on his blog but I can't get my browser to recognise changes. Also lots of flakey core.async WARNINGs during compilation.

0:39 justin_smith: trying to help people with chestnut has made me wish that lein templates had explicit versions like deps do

0:39 it's cool, but has been changing frequently, and sometimes is broken

0:40 clojer: justin_smith: Sounds like the old story with the fragile cljs/lein/cider/figwheel/Austin/Piggieback toolchain

0:41 This kind of thing really can turn new users away from Clojure/script

0:41 The tooling is just dire

0:41 justin_smith: right, and chestnut is mixing in a bunch of those same elements - but once it is stable it should improve that fragile scenario (or at least we can hope)

0:42 clojer: justin_smith: So many bits and pieces all breaking after updates is strong argument against the small libraries philosophy.

0:42 justin_smith: Monolithic has its uses :)

0:42 TEttinger: and a strong reason why lein uses strict version numbers and not ranges

0:44 clojer: I wish the community would't tout the magic of Emacs/cider when it seems to be impossible to get a decent cljs browser repl with it.

0:44 Lein + Emacs/cider is serverly broken IMHO

0:44 justin_smith: and if we could specify a template version, at least we could say "version $foo of chestnut is known good" or whatever

0:45 technomancy: lein is broken?

0:45 bug report plz

0:45 clojer: technomancy: No, the combination, especially for a cljs browser repl

0:45 technomancy: I never managed to get one working.

0:45 technomancy: so you mean cider

0:46 justin_smith: cider is in alpha status - it's good because they are working on awesome features, and they are being ambitious, it's bad for stability and there should be a clear user flow to choose "many features, often broken" vs. "a few features, just works"

0:46 clojer: technomancy: Yes, especially with Emacs

0:46 TEttinger: lein itself isn't broken by any means.

0:46 justin_smith: saying the combination of lein and cider is broken is silly because cider is a library for using lein from emacs - cider is the broken part

0:46 technomancy: "especially" but cider only works with emacs

0:46 clojer: justin_smith: I'm just thinking about what first imopression this gives to newcomers, that's all. Very bad.

0:47 justin_smith: right - we shouldn't tell people who don't know clojure yet "your best bet is to use this thing that breaks every other day"

0:47 clojer: justin_smith: I have perservered for many months but had to switch to Lighttable in the end.

0:47 technomancy: that's like saying "my linux is broken"

0:48 justin_smith: technomancy: have you tried rebooting? that's the best way to fix a linux

0:48 /s

0:48 clojer: justin_smith: True, but in practice we hear Emacs is the Clojure Way.

0:48 technomancy: who says that ._.

0:48 send em this way and I'll give em what for

0:48 TEttinger: nightcode, tbh, seems to fix a lot of these newbie issues. templates to start that set up everything without hassle, repl built in, paredit optional, integrates lein...

0:49 technomancy: (I always wanted to say that)

0:49 TEttinger: technomancy, would you say leiningen's source is a good example of a well-documented medium-or-larger clojure app's code?

0:49 technomancy: TEttinger: as long as you stay away from a few places

0:50 TEttinger: learn2code_ was asking about it earlier

0:50 technomancy: TEttinger: I am more comfortable pointing people to Syme, though it's small-to-medium.

0:50 TEttinger: never heard of Syme

0:50 ~syme

0:50 clojurebot: It's greek to me.

0:50 TEttinger: $google syme clojure

0:50 lazybot: [technomancy/syme · GitHub] https://github.com/technomancy/syme

0:51 technomancy: ~syme is a web application for setting up disposable EC2 instances on which to pair program https://syme.herokuapp.com

0:51 clojurebot: You don't have to tell me twice.

0:51 technomancy: you say that, clojurebot, but sometimes I do

0:51 justin_smith: ~syme

0:51 clojurebot: syme is a web application for setting up disposable EC2 instances on which to pair program https://syme.herokuapp.com

0:52 TEttinger: technomancy, that readme doesn't tell me anything about what it is

0:55 technomancy: TEttinger: try this instead https://syme.herokuapp.com/faq

0:58 TEttinger: ah, neat. if I had a paired person to program with and could tolerate emacs or vim I would consider it

0:59 justin_smith: I want to see pair programming in ed

1:03 seancorfield: There's a plugin for LightTable to pair via Firebase now. Works pretty well for an early release.

1:04 Or is it Firepad.

1:06 Firepad. So you can pair via LT or a web browser.

1:06 TEttinger: what are you using as an editor these days?

1:11 TEttinger: I write so little in the way of large clojure programs... most of what I do is one-liners, and anything with paren matching works. I did a larger thing in NightCode though, Oakes is doing a great job

1:22 seancorfield: NightCode is a nice simple editor. We looked at it for ClojureBridge but decided the UX wasn't as nice - for beginners - as LightTable.

1:24 And at work we're using LT for all our editing now. 23kloc Clojure, and some ClojureScript too now. Plus it's good for JS and css too.

1:24 TEttinger: I could never get the eval snippet feature to work in LightTable with my play-clj-using game. since it has odd thread reqs.

1:24 numberten: is there any difference between

1:24 flatten

1:24 and 'apply concat'

1:24 TEttinger: yes

1:24 seancorfield: numberten: flatten completely flattens the collection

1:25 numberten: ah

1:25 seancorfield: apply concat only flattens the top level

1:25 numberten: i see thanks

1:25 TEttinger: ,(apply concat[[[1 2][[3 4 5 6][7 8 9]10 11 12]])(flatten [[1 2][[3 4 5 6][7 8 9]10 11 12]])]

1:25 clojurebot: #<RuntimeException java.lang.RuntimeException: Unmatched delimiter: )>

1:25 numberten: yeah I didn't catch that in the docs

1:25 thank you

1:25 TEttinger: ,[(apply concat[[1 2][[3 4 5 6][7 8 9]10 11 12]])(flatten [[1 2][[3 4 5 6][7 8 9]10 11 12]])]

1:25 clojurebot: [(1 2 [3 4 5 6] [7 8 9] 10 ...) (1 2 3 4 5 ...)]

1:25 TEttinger: &[(apply concat[[1 2][[3 4 5 6][7 8 9]10 11 12]])(flatten [[1 2][[3 4 5 6][7 8 9]10 11 12]])]

1:25 lazybot: ⇒ [(1 2 [3 4 5 6] [7 8 9] 10 11 12) (1 2 3 4 5 6 7 8 9 10 11 12)]

1:26 Jaood: seancorfield: but LT's future is dubious since the author has move on to other things

1:26 seancorfield: Typing Clojure on my phone is too hard TEttinger so thank you for the examples!!

1:26 TEttinger: np!

1:27 seancorfield: Jaood: LT is moving to community-supported open source so I'm comfortable with that.

2:53 puyo: Clojure syntax, maps are {a ax, b bx} and vectors are [a b c] - why do you pass a vector to "let", wouldn't a map be more logical? Is it a Lisp hangover?

2:55 TEttinger: puyo: I believe there may be options to the arglist for let. like with for, where you also have a vector of pairs, but then you could have :when (blah) or some theoretical no-arg option like :lazy

2:58 appears that let doesn't take an arglist. HOWEVER, vectors are sorted!

2:58 and maps are not

2:58 and you definitely want the arglist to be assigned in order

2:59 puyo: ohh i see.. maybe the order is significant...

3:06 thanks :)

3:28 justin_smith: numberten: regarding flatten / apply concat / mapcat

3:28 ~flatten

3:28 clojurebot: flatten is rarely the right answer. Suppose you need to use a list as your "base type", for example. Usually you only want to flatten a single level, and in that case you're better off with concat. Or, better still, use mapcat to produce a sequence that's shaped right to begin with.

3:42 cfleming: clojurebot knows what's up.

3:43 numberten: justin_smith: thank you

4:24 kenrestivo: huh

4:24 ,(contains? [1 3 5] (int (byte 1)))

4:24 clojurebot: true

4:24 kenrestivo: ,(contains? [1 3 5] (int (byte 5)))

4:24 clojurebot: false

4:24 kenrestivo: ???

4:24 lazybot: kenrestivo: Yes, 100% for sure.

4:24 justin_smith: kenrestivo: contains on vectors checks for index

4:24 not contents

4:24 kenrestivo: ah, doh, thanks!

4:24 ,(contains? #{1 3 5} (int (byte 5)))

4:24 clojurebot: true

4:25 justin_smith: ,(.contains [1 3 5] 5)

4:25 clojurebot: true

4:25 justin_smith: .contains does what you want

4:25 kenrestivo: so do sets :-P

4:26 hell, there's always

4:26 ,(#{1 3 5} (int (byte 5)))

4:26 clojurebot: 5

4:27 kenrestivo: i'm generally allergic to using java interop, unless absolutely necessary

4:29 justin_smith: if you have one set, that will be used to check multiple items for membership, the set approach makes sense. If you are checking multiple collections for containing an item, then .contains may be better.

4:33 numberten: doesn't doall realize a seq?

4:33 justin_smith: yes, but not recursively

4:34 numberten: why is this a thing then

4:34 ,(->> (map identity (range 10)) doall type)

4:34 clojurebot: clojure.lang.LazySeq

4:34 numberten: shouldn't it be fully realized

4:34 before reaching 'type'

4:34 ?

4:34 justin_smith: ,(do (doall [(range) (range) (range)]) nil)

4:34 clojurebot: nil

4:34 justin_smith: ,((juxt identity type) (range 10))

4:34 clojurebot: [(0 1 2 3 4 ...) clojure.lang.LazySeq]

4:35 justin_smith: even when fully realized, it is still a LazySeq

4:35 numberten: i see

4:35 thanks

4:35 justin_smith: (type (lazy-seq nil))

4:35 ,(type (lazy-seq nil))

4:35 clojurebot: clojure.lang.LazySeq

4:36 justin_smith: empty lazy seq

5:45 tomjack: (let [c (chan 1 cat)] (>!! c (range 1e6)) (count (repeatedly 1e6 #(<!! c))))

5:46 ;; returns 1000000

5:48 (let [c (chan 10 cat)] (>!! c (range 2)) (>!! c (range 2)) (count (repeatedly 4 #(<!! c))))

5:48 ;; returns 4

5:48 (let [c (chan 10 cat)] (>!! c (range 20)) (>!! c (range 20)) (count (repeatedly 40 #(<!! c))))

5:48 ;; doesn't return

5:48 maybe that is the only reasonable behavior?

5:56 dagda1_: what does the carrot and export mean in this function declaration (defn ^:export run [] which I found in some clojurescript code

5:56 tomjack: dagda1_: the function name will not be munged by google closure during advanced optimizations

5:57 dagda1_: tomjack: got it, thanks

6:00 amalloy: dagda1_: spelled caret, by the way, even though it's pronounced like carrot

6:01 dagda1_: amalloy: haha, I know, I did not notice that

6:01 I must be hungry

6:03 mmeix: basic-level follow-up question from yesterday: why are some functions in Clojure implemented as macros instead of "real" functions (for example and, or) - is there an advantage?

6:05 tomjack: (if (and true (do (Thread/sleep 1000) false)) ...)

6:06 er

6:06 (or true ...) I mean :)

6:09 mmeix: hm ... ok ...meditating this - thnx

6:20 Rhainur: I've been doing the problems on 4clojure, and instead of having a steady rise in difficulty, everything seemed straightforward and easy right up until http://www.4clojure.com/problem/28

6:20 I'm straight up stuck and have no idea how to proceed :(

6:20 any hints?

6:30 tomjack: Rhainur: there is always the source of clojure.core/flatten... unless that's cheating? :)

6:32 that uses clojure.core/tree-seq, which you could avoid

6:32 amalloy: Rhainur: consider how you could write a function that flattens a sequence by one level, and then use recursion to keep going until there are no levels left

6:33 mapcat will be the spine of most implementations of such a function

6:33 tomjack: do they teach you nonymous fns?

6:34 I guess they don't teach much

6:43 Rhainur: tomjack, amalloy: this is my first time working in a non imperative language

7:54 hahahahahaha man, I did http://www.4clojure.com/problem/26

7:54 and _pcl's solution is making me laugh so hard

7:54 (fn [i] (take i '(1 1 2 3 5 8 13 21)))

7:54 fucking brilliant.

7:57 mmeix: Which is more idiomatic/recommended to say:

7:58 #(+ % 3)

7:58 #(+ % 3)

7:58 #(+ 3 %)

7:58 (sorry for the doubled line)

7:59 (of course with "/" and "-" it would matter)

8:02 Rhainur: mmeix: in the clojure style guide, it only comes up once, and they use #(+ 5 %)

8:02 so I'd guess it doesn't matter that much

8:02 mmeix: ok

8:02 thnx

8:03 [finding the Clojure Style Guide now]

8:04 maybe as a somewhat parallel case to (partial + 5)

8:09 Rhainur: mmeix: oh sorry https://github.com/bbatsov/clojure-style-guide

8:10 mmeix: I always have that and http://grimoire.arrdem.com/ open when working in clojure

8:10 mmeix: just found the first one, thanks for the second!

8:10 ah, that's a great overview

13:19 CodeWar: Gentlemen Greetings! Parsing Clojure for a hobby project of mine. Does Clojure have a notion of uniquely_owned_ptr. Meaning it could point to a structure which can contain other references to other structures. However the guarantee is that the entire object graph has only one outstanding reference to it. So if I passed the root pointer I can safely operate on it without

13:19 worrying about other references to some of the inner nodes

13:26 dweave: is .emacs ok to use instead of init.el

13:32 i’m trying to install flycheck https://github.com/flycheck/flycheck. do i need this cask thing

13:37 justin_smith: ~gentlemen

13:37 clojurebot: You can't fight in here. This is the war room.

14:57 arrdem: justin_smith: so if you had to write your own transducers explanation... how do? :P

14:57 justin_smith: heh

14:57 I got tripped up on "simple"

14:58 please do give a better explanation if you have it :)

14:59 arrdem: lol. I think the trick is the composable partial builder stuff that Rich was talking about in the strangeloop talk.

15:00 Jaood: java's type system has so many rules

15:00 arrdem: if you think about transducers as just a way to generalize a state machine implemented as impure fns I think it's not too hard.

15:01 Jaood: spambot alert

15:01 justin_smith: Jaood: I blame inheritance

15:20 cshell: Is there a trick to getting Lighttable to be able to open source files from libraries you import?

15:27 arrdem: &(* 15 7.25)

15:27 lazybot: ⇒ 108.75

15:52 pgmcgee: i'm having trouble with *print-length* in nrepl. i'm running user> (binding [*print-length* 2] (range 10)) but i always get (0 1 2 3 4 5 6 7 8 9) in response rather than (0 1 ...) that i expect

15:53 schmir: pgmcgee: it's being printed after the binding has gone out of scope

15:54 pgmcgee: schmir: ah, how can i fix that?

15:54 schmir: pgmcgee: i.e. you're printing the result of the binding expression

15:54 do (println (range 10)) inside the binding

15:55 ben_vulpes: so i'm starting in on a little clojure app that runs from the command line. due to startup time constraints, i want this thing to daemonize itself and to be callable later - are there any examples of clojure projects structured like this that anyone could point me at?

15:55 pgmcgee: ah, is there any way to have the binding apply to the echo nrepl does? that's really what i want to limit automatically

15:56 ben_vulpes: how do you intend to call it?

15:58 schmir: pgmcgee: (set! *print-length* 2)

15:59 ben_vulpes: pgmcgee: $ nifty_app start

15:59 pgmcgee: $ nifty_app operation

15:59 at least that's what i'm thinking at this precise moment

16:00 if there's a more idiomatic approach i'd love to hear it. i've only really been building webapps with clojure for the past year, and now want to build a cli tool.

16:01 pgmcgee: ben_vulpes: i'm not a clojure expert, but i'm thinking that you'll probably need some sort of client/server setup where nifty_app is essentially a client and `nifty_app start` starts the server

16:01 schmir: ben_vulpes: do you know nailgun? http://www.martiansoftware.com/nailgun/

16:02 ben_vulpes: https://github.com/technomancy/grenchman may also be interesting

16:04 pgmcgee: schmir: thanks, that worked!

16:04 ben_vulpes: schmir: nailgun's interesting, for sure.

16:05 schmir: pgmcgee: I set *print-length* in my ~/.lein/profiles.clj file

16:09 pgmcgee: schmir: just did that and it's awesome. thanks for the help!

16:12 schmir: pgmcgee: fine. you may also like to set *print-level*

16:13 justin_smith: ben_vulpes: seconding grenchman

16:17 dnolen_: grenchman hasn't been updated in a year and I never could get it to work even when it was originally released

16:22 ben_vulpes: if you want some deliverable that has decent startup time for other users then just AOT - people keep complaining about startup time but raw Clojure REPL starts in like 1s on a modern desktop/laptop - because AOT

16:23 other option if you can take Node.js as a dep is CLJS

16:30 donbonif_: hello

16:52 DomKM: Is there an easy way to convert a lazy seq of strings into an InputStream without first eagerly consuming the seq?

16:59 arohner: DomKM: not easily, no

17:06 DomKM: arohner: feasibly? Would I be better off writing the lazy seq to a file and creating an InputStream from that?

17:06 arohner: I'm pretty sure it's possible, but it'd be a little complex

17:07 easiest way is probably to write to a byte array, and then IS from that

17:07 easiest way that doesn't involve file I/O, that is

17:07 justin_smith: arohner: but how would you lazily fill the byte array?

17:07 DomKM: arohner: unfortunately, the seq it's larger than memory

17:07 arohner: aha

17:08 justin_smith: I was assuming "easy" wasn't lazy

17:08 justin_smith: he mentioned not eagerly consuming the seq

17:16 amalloy: DomKM: do you really mean an inputstream, not a reader? strings are made of characters, not bytes, so you want to avoid converting for no reason

17:18 but there are a few helpful functions for this in https://github.com/ninjudd/io/blob/develop/src/flatland/io/core.clj

17:19 notably concat-input-streams takes a seq of input streams and returns an input stream which is their concatenation, and bytebuffer->inputstream turns a byte buffer into an input stream

17:36 DomKM: amalloy: I do mean an input stream...I think. I'm taking an input stream, converting it to a lazy seq so that I can filter it, and then I want to convert it back to an input stream. A way to map/filter/etc an input stream without making it a seq would also solve my problem.

17:50 seangrove: What's the shorthand for setting nested fields? e.g. (set! (.. dry .-gain .-value) 1)

17:54 Nevermind, doesn't really look like there is one

17:59 nkozo: core.async question: how you can make a go loop that takes items from a from-chan and put them on a to-chan? the tricky part is to park on from-chan awaiting items but also unpark when to-chan is closed by a remote party. I think I need something like alts! were you can wait items on from-chan but also unpark if to-chan is closed (but *without* reading items from to-chan)

19:10 ben_vulpes: i'm running with cider, and for some reason cider-jump-to-var isn't doing code navigation for me any more. any notion on how to debug this?

19:26 axel_: does anybody know a good way of debugging code inside a domonad macro call?

19:27 justin_smith: ben_vulpes: you could potentially target cider-jump-to-var for debugging and step through it, if you know enough elisp so you would know which part is broken

19:28 M-x debug-on-entry <return> cider-jump-to-var

19:28 chimpboy: hi everyone i am a chimp

19:34 ben_vulpes: justin_smith: i think that i'm going to rip cider out

19:35 chimpboy: ben_vulpes yes but i am a chimp

20:45 squeedee: i wish i could use clojure for my arduino code

23:43 Anyone mind reviewing my code? https://github.com/squeedee/lsystem/blob/master/src/lsystem/core.clj#L11 - just wondering if i've taken a idiomattic approach to recursion

23:44 justin_smith: squeedee: you may want to try making a lazy version - so that instead of providing a count as an argument, you can take as many of the results as you like

23:46 squeedee: i do want to do that.

23:46 i was looking at transducers today

23:46 trying to understand how I write lazy versions of everything

23:47 justin_smith: how would i do it?

23:47 justin_smith: you can basically replace the recur with (cons this-result (lazy-seq (iterate ...)))

23:47 ahh - wait

23:48 squeedee: they do all need to be evaluated

23:48 justin_smith: actually, you could use the clojure.core/iterate, and the nth item of the result is the result of n iteration

23:48 I realized you aren't building a sequence here, so it's not a question of using lazy-seq

23:49 squeedee: i guess when i went and shadowed iterate i should have at least read what it does :P

23:49 justin_smith: (core/iterate #(iterate % axiom) rules) - first item in the resulting sequence is your initial state, second item is first iteration, etc.

23:49 of course it is infinite, so use it with nth / take - don't evaluate directly :)

23:50 squeedee: sure

23:50 i guess it makes sense to return the iteration results

23:51 why hide it and make someone who wants it have to execute each version

23:51 really enjoying this

23:52 justin_smith: also, having two arities at different levels of abstraction (one being repititions of the other) is a little odd

23:52 not bad - I am sure I have seen it before, but a little odd

23:53 squeedee: not sure i understand

23:55 So no point in me providing the 'n' version at all - people should know intuitively (or through docs) to use iterate?

23:55 justin_smith: no - not what I am saying

23:55 squeedee: thats seperate

23:55 I'm asking that by way of looking at iterate

23:56 justin_smith: there's no harm in wrapping it in iterate yourself

23:56 squeedee: i _also_ didnt understand what you were saying about the 2 arities for the abstractions.. Tho i guess if i try to explain it back I do get it.

23:56 justin_smith: it's as if + and * were one function, with two arities

23:56 squeedee: one is 'transform-with-rules' and the other is 'iterate'

23:57 so they're two abstractions, so why smoosh them together

23:57 ?

23:57 justin_smith: yeah, something like that

23:57 squeedee: that the gist

23:57 lemme play with thay

23:57 that

23:57 thanks

23:57 justin_smith: np

23:58 ,(iterate #(+ 5 %) 0)

23:58 clojurebot: (0 5 10 15 20 ...)

23:59 justin_smith: illustrating the +/* thing I was saying above

Logging service provided by n01se.net