Fork me on GitHub
#clojure
<
2015-07-09
>
zentrope00:07:08

It doesn’t remove complexity, it just creates more moving parts. Each one is simpler, though.

devn00:07:12

java -jar foo.jar --this=1 --that=2 ;; ERROR: You didn't specify other_thing!

devn00:07:28

but for local dev, no thanks

devn00:07:26

./script/build-and-run where lein uberjar && THIS=1 THAT=2 java -jar target/app.jar

devn00:07:28

yet another option

devn00:07:16

@zentrope: thanks for chatting. appreciate the conversation. i have to run and grab some food, see you around!

pupeno10:07:32

Does anybody have a recommendation on libraries to do http requests (get, posts, cookies) and parsing the resulting html?

zoldar10:07:47

@pupeno: enlive is pretty good for the latter

pupeno10:07:12

@zoldar: have you used clj-http? I found 3 so far, clj-http, clojure-http-client and http-kit.

zoldar10:07:47

@pupeno: yes, for basic stuff, nothing fancy though

pupeno10:07:49

clojure-http-client is deprecated, so, that one is out.

tcrayford10:07:03

@pupeno: I use clj-http in prod, have done for ages. It's based on the apache http client, so is very very mature/well tested etc

pupeno10:07:59

Do you use enlive for parsing HTML? it looks like a templating engine.

zoldar11:07:33

@pupeno: there are 3 examples of using enlive for scraping

pupeno11:07:42

Cool. Thanks.

pupeno11:07:26

Is there a more idiomatic way to do two assoc-ins other than nesting them?

andrewmcveigh11:07:35

@pupeno:

(-> thing
  (assoc-in [:k1 :k2] x)
  (assoc-in [:k3] y))

andrewmcveigh11:07:44

Looks nicer to me

dnolen11:07:40

Also merge if the keys you want to update are all at the same level.

pupeno11:07:55

dnolen: yeah, they are not.

dnolen11:07:31

conj also works if they are at the same level, but you see this less than merge I think.

dnolen11:07:57

otherwise agree with ->

pupeno16:07:36

Does anybody know how to find input[name=blah] with enlive? I know (attr= :name “blah”) can filter by the attribute name, but not how to compose it with filtering only inputs.

jakemcc16:07:18

@pupeno: [[:input (attr= :name “blah”)]]

jakemcc16:07:02

@pupeno: https://github.com/cgrand/enlive#selectors explains it in the paragraph that starts with “So "

pupeno16:07:36

Ah, you combine them but putting them in a vector. Thanks.

jakemcc16:07:29

no problem

pupeno16:07:14

I think I just finished prototyping my first ever piece of useful Clojure code. Woohoo! simple_smile

jeff.terrell18:07:37

In case anybody’s interested in some code-review-style ruminations, check out the blog post I just wrote: http://blog.altometrics.com/2015/07/reducing-the-conceptual-load-of-reduce/

jeff.terrell18:07:18

My team and I are fairly split over which alternative we like better, the reduce version or the ->> version. simple_smile

rauh18:07:55

@jeff.terrell: Good post. I like it. I'm also not a huge fan of reduce even though it's very popular. Regarding the score: You should use the max or average of the score as an overall measure simple_smile

agile_geek19:07:12

@jeff.terrell: I think it’s very subjective depending on the readers experience. So, for example, I don’t think I’ve ever used juxt in anger so for me I had to stop and go check what it did. Whereas I frequently use reduce and the [acc val] pattern of the function applied to the sequence has become natural, through practice…though I still remember it making my head hurt up until a few months ago. I think you raise an interesting question though. I would favour the pattern you see most often in code examples, which in my somewhat limited experience is ‘reduce’ but only because of the ‘juxt’ and to some extent the ‘comp’ in the second example. I see reduce more often that either of those. However, YMMV.

jeff.terrell19:07:45

@rauh: Glad you liked it! simple_smile

jeff.terrell19:07:10

@agile_geek: Definitely agreed! I think it’s pretty interesting to try to quantify “legibility” because it’s inherently such a subjective measure.

jeff.terrell19:07:55

And yeah, if you see a lot more reduces than juxts or comps, then you might find reduce to be more legible in this case.

gtrak19:07:40

into calls reduce, sooo... simple_smile

gtrak19:07:07

you could do it as a single call to 'for'

gtrak19:07:08

in general i prefer for over map unless you really need to reify the body into a function.

gtrak19:07:47

and you won't need juxt in that case

gtrak19:07:11

when there is an obvious alternative to reduce, it's less clear to use reduce. reduce should be reserved for true 'accumulator'-style stuff, where the only option is loop/recur.

adamfrey19:07:19

@gtrak: you'd still have to call into in the end, if you use for, right?

adamfrey19:07:30

ok, just checking

jeff.terrell19:07:32

@gtrak: Good point about for! I forgot about that option.

gtrak19:07:44

for :when

gtrak19:07:54

removes the need for a filter

jeff.terrell19:07:20

I think this would be the correct for-based version of the code in the blog post:

jeff.terrell19:07:22

(let [env-vars ["PORT" "DATOMIC_URI" "ASSET_ROOT"]
      specified (into {} (for [var-name env-vars
                               :let [val (System/getenv var-name)]
                               :when val]
                           [(env-var->keyword var-name) val]))]
  ...)

jeff.terrell19:07:34

Yeah, I definitely like that better than the reduce version. I think I may like that better than the ->> version too.

gtrak19:07:44

for is arguably more complicated than reduce, but its' worth it.

jeff.terrell19:07:27

(Hat tip to @adamfrey for the basic code of the for version. simple_smile )

gtrak19:07:17

just doesn't compose as well

gtrak19:07:49

and I guess if you want to use transducers or something, that might be another consideration

agile_geek19:07:33

I like the new ‘for’ version much better. I still think I’ve got used to reading ‘reduce’ to the point where either is equally (il)legible to me. I think someone new to Clojure would definitely find the ‘for’ version much easier to scan.

gtrak19:07:04

I guess my rules of thumb here are that for can do everything that map, filter and take-while and let can do, and if the reduce can be expressed as a map, then it's better to do so.

gtrak19:07:25

because it's lazy and reads better

jeff.terrell19:07:42

Yeah, I think I would agree with that.

gtrak19:07:47

or at least pull apart the parts that can be expressed as map calls

gtrak19:07:55

and reduce over that instead?

jeff.terrell19:07:59

@gtrak: I’d like to add the for-based version to the post and give you credit for suggesting for. Do you want me to use your real name or link anywhere?

gtrak19:07:39

thanks! @gtrakGT on twitter

agile_geek19:07:53

Good point about lazyness.

gtrak19:07:17

there's an uncanny valley between for and mapcat.

gtrak19:07:32

(apply concat (for .. can be pretty ugly

alejandro19:07:53

Huh, I actually find the reduce version easier to read than the for. I guess I just haven’t seen the :when and :let options in for statements used that widely

alejandro19:07:20

I think the for would definitely be clearer for someone coming from python though!

gtrak19:07:01

yea, there's a fixed-cost with learning for, but a recurring with reduce imo

gtrak20:07:23

i never really understood python's simple_smile

teslanick20:07:02

Coming from JS, I find reduce extremely natural and for very difficult to reason about

gtrak20:07:23

except in js you get people writing side effects and pushing to arrays inside the reduce

gtrak20:07:51

makes me want to gouge my eyes out

gtrak20:07:31

mixing functional and imperative is somehow worse than straight imperative

teslanick20:07:29

That's definitely an issue.