Fork me on GitHub
#beginners
<
2019-01-21
>
jumpnbrownweasel02:01:42

When nil should result if a test is false, and only one form is needed when the test is true, is it more idiomatic to use (when test xxx) or (if test xxx)? Or is neither really more idiomatic?

jumpnbrownweasel02:01:20

Let me try one more time mentioning side effects: When nil should result if a test is false, and only one form is needed when the test is true and there are no side effects, is it more idiomatic to use (when test xxx) or (if test xxx)?

jumpnbrownweasel02:01:19

It depends whether when should imply side effects, I think.

seancorfield02:01:18

@mark540 Have you looked at what the Community Style Guide has to say about that?

seancorfield02:01:56

(I wasn't sure what it said, so that was just a suggestion... now I look, it seems to only make a recommendation of (when cond form1 form2) over (if cond (do form1 form2)) which, yeah, I'd agree with... but doesn't cover simple (if cond form) vs (when cond form)...)

seancorfield02:01:13

Personally, I would use (when cond form) instead of an if without an else form, since that makes it clear (to me) that you are deliberately returning nil for (not cond) rather than you just accidentally omitted the else form in an if.

jumpnbrownweasel02:01:00

Right, the style didn't say, so I thought I'd see what you all thought. I like that about when also. But I wasn't sure if side effects were implied. I guess you don't think so.

seancorfield04:01:41

(sorry, was having dinner)

seancorfield04:01:21

No, I don't think if vs when is a good indication of pure functions vs side-effects -- that's far too subtle of a choice, IMO @mark540

jumpnbrownweasel04:01:03

Thanks @seancorfield

seancorfield04:01:43

Good naming should make that clear I think (have you read Elements of Clojure by Zach Tellman?).

๐Ÿ’ฏ 1
jumpnbrownweasel04:01:13

I'm reading it now, really impressive.

seancorfield04:01:51

There is a camp that uses a ! suffix to indicate side-effects but that's never really been a consistent convention (and side-effects have a tendency of propagating throughout your program so you'd have! exclamation! marks! everywhere! ๐Ÿ™‚ )

๐Ÿ˜‚ 1
jumpnbrownweasel04:01:26

Yes. I was thinking of functions like doseq that are only useful with side effects and probably shouldn't be used when there are none. when could be thought of in that category since if is an alternative without side effects, but I think you're right that when is also used instead of if for clarity.

seancorfield04:01:46

I find (when cond form) more natural than (if cond form nil) to be honest

โž• 1
seancorfield04:01:30

But maybe that's because I've been doing Clojure a long time now and my brain automatically sees when as returning nil in the non-`cond` case...?

seancorfield04:01:19

A lot of Clojure's idioms are non-obvious at first, and also depending on what your language background is...

seancorfield04:01:31

An example where I think when is much more natural -- when you're constructing a string, using str, and you have a bunch of conditional parts:

(str "something"
     (when cond1
       "option 1")
     (when cond2
       "option 2")
     "end")

โœ”๏ธ 2
Shriyans08:01:02

Hi everyone ! :hugging_face: been a long time admirer of clojure and especially the vibrant community but didn't have a chance learning it yet I am planning to start learning clojure and will be for playing with quil (processing library) mostly which books or materials would you recommend for someone who has prior knowledge of functional languages (OCaml, haskell, javascript , bit of elixir) but little to no experience in java

schmee09:01:12

if you have some previous programming experience (like you seem to have) I highly recommend https://www.amazon.com/Joy-Clojure-Michael-Fogus/dp/1617291412/

schmee09:01:44

it covers pretty much everything, except the more recent additions to the core like transducer

Shriyans10:01:55

great . Thanks for the recommendation quick question though, does it cover tooling and java side of clojure ?

schmee10:01:34

it has a chapter on Java interop, donโ€™t remember about the tooling though

schmee10:01:19

if you learn the basics of Leiningen you will be set for tooling for a good while

Shriyans10:01:05

Thank you for the reply i'll be buying the book now

Shriyans10:01:31

Also omg!! lein is really easy to setup. ๐Ÿ’ฏ on user on boarding after coming from js, having a single tool is such a relief

schmee10:01:30

haha yeah ๐Ÿ˜„ there are a couple of different build tools in Clojure as well (Leiningen, Boot, clj), but for beginners I recommend sticking to Leiningen since it is by far the most used and because of this you can find a solution to most common issues on SO

Eric Ervin00:01:49

@U7W7M34UQ, there is a #quil channel. it's really quiet down there right now. maybe I'll make some noise.

Shriyans12:01:53

@U9U0G3Q8Y Thanks for link ๐Ÿ™‚

Lu09:01:41

If you want to have a go with a server/client environment to apply the theory you will be learning, you can def try ... https://github.com/juxt/edge

Shriyans09:01:49

thanks i'll keep an eye on it. but currently looking for learning the language features more

a5anka09:01:05

What would be a good book/resource to start learning ClojureScript? http://braveclojure.com was a good resource to learn about Clojure. Now I am at the latter part of the books, I am looking for a good resource to learn ClojureScript.

Lu09:01:06

@asanka.abeyweera you really want to get familiar with libraries like reagent, hiccup, and reframe .. once you know those, you can potentially build anything.. ๐Ÿ‘Œ:skin-tone-3:

๐Ÿ‘ 2
fricze13:01:02

@asanka.abeyweera do you know JavaScript?

a5anka13:01:37

I am not an expert. Just know the basics. ๐Ÿ™‚

Ian Fernandez13:01:34

there's some way to convert a curl request to a httpkit request?

Sy Borg17:01:11

hi. I'm trying to solve problem #22 on 4clojure. I know this code is stupid and not optimal, but it works in my REPL. However 4Clojure complains on bad count. Can anyone please explain why?

tim17:01:20

are you wanting a fix? or just an explanation?

Sy Borg17:01:08

a fix for what? explanation would be nice

tim17:01:19

a fix to your code that solves the problem

tim17:01:28

#(reduce (fn[i _] (inc i)) 0 %)

tim17:01:38

np, btw the reason yours failed is because the underlying code in for uses count. I imagine the restriction check sees it too. https://github.com/clojure/clojure/blob/clojure-1.9.0/src/clj/clojure/core.clj#L4590

duncanmak17:01:47

thatโ€™s weird

duncanmak17:01:55

@sy_borg youโ€™re thinking of cnt as a variable, not a binding

duncanmak17:01:09

youโ€™re incrementing it, which means youโ€™re thinking of it as something with state

duncanmak17:01:40

the classic way to do that is the loop form

Sy Borg17:01:48

well, with all respect, you can't know what I'm thinking. my question was why the code behaves differently.

andy.fingerhut17:01:12

Are you expecting that cnt will have a different value than 0, ever?

hiredman17:01:12

what makes you think that works in your repl?

hiredman17:01:46

I mean, I guess it does

hiredman17:01:14

I wonder what input 4clojure is giving it

andy.fingerhut17:01:50

Basically the for is returning a sequence of N 1's, where N is the number of iterations through the for, which is one for each element in (seq s) (I think)

andy.fingerhut17:01:12

So yeah, I can't see why 4clojure complains that it is giving the wrong answer.

Sy Borg17:01:56

yes, that was my idea to generate a seq of 1s

Sy Borg17:01:08

(in a bit weird way, I know)

madstap17:01:27

Why not just (for [i s] 1)?

hiredman17:01:35

oh, I bet it is because the macro expand of for calls count

hiredman17:01:01

so if you can re-formulate that to not use for (which is pretty straightforward) it will work

Sy Borg17:01:34

@madstap too simple ๐Ÿ™‚

hiredman17:01:41

yeah, for calls count when dealing with chunked seqs

hiredman17:01:05

4clojure must be checking for verboten function calls after macro expansion

hiredman17:01:33

(for [i s] 1) can be expressed almost as nicely as a call to map

Sy Borg17:01:22

one of the proposed solutions - (fn [coll] (reduce (fn [x y] (inc x)) 0 coll))

borkdude17:01:22

slightly more obscure solution: (fn [coll] (last (map (fn [_ x] x) coll (rest (range)))))

Sy Borg17:01:22

so may it be considered ok also - (defn mycount [s] (reduce + (for [i s] 1)))?

borkdude17:01:26

note that collections often define their own version of count thatโ€™s optimized for their type, so in production code no, but 4clojure yes

Sy Borg17:01:17

sure thanks, guys

hiredman17:01:26

stylistically I think you should always pass reduce an initial value

โœ”๏ธ 3
borkdude17:01:01

although in the case of + youโ€™re lucky it also has a 0-arg

enforser17:01:22

why would you pass the init value if it is identical to the 0-arg call of f? I don't see the benefit of being extra verbose in that case

hiredman18:01:30

the 0 arg version is only called if the collection is empty

hiredman18:01:06

passing in a 0 value at the beginning helps you write the function being reduced as a proper monoid sum

enforser18:01:26

ah, I didn't realize the 0-arg was only called given an empty collection. I thought it was always called if no initial value was given. Makes sense!

hiredman18:01:03

for some newer variants of reduce I believe it is always called if there is no init

๐Ÿ‘ 1
hiredman18:01:14

maybe transduce does that

enforser18:01:33

I think I was under this impression from fold

madstap18:01:27

Yeah, transduce always calls (f) to get an init. Contrast that to what happens when reduce has no init (from the docstring).

If val is not supplied,
returns the result of applying f to the first 2 items in coll, then
applying f to that result and the 3rd item, etc. If coll contains no
items, f must accept no arguments as well, and reduce returns the
result of calling f with no arguments.  If coll has only 1 item, it
is returned and f is not called.
I've found this very error prone, so to avoid thinking about it it's better to just always supply the init.

hiredman18:01:02

from the other side of things, there are some clojure interfaces that allow for collections with a specialized version of reduce, or defined entirely in terms of reduce, and those interfaces (clojure.langReduce and clojure.lang.ReduceInit) are distinct and are different only on if you pass in the initial value or not, and usually implementing ReduceInit (where you pass in the initial value) is easier then implementing Reduce

Sy Borg18:01:03

again, #23 on 4Clojure - why not just into ()? instead of, for example, (fn [coll] (reduce conj '() coll))

tim20:01:32

using into () seems reasonable to me.

Mattias21:01:56

Very important question (:thinking_face:) here - need to know why I figure the doc for clojure.string/join and the implementation seems to have the parameters switched. Am I right or is there some hidden greatness?

dpsutton21:01:12

source and doc string both seem to be ([coll] [separator coll])?

Lennart Buit21:01:32

str/join is multi arity, if you pass it one arg, its only a collection, if you pass it two, you pass both a seperator and a collection

dpsutton21:01:47

what do you mean by switched?

borkdude21:01:39

I think he means flipped?

Mattias21:01:14

Yeah. Sorry. Trying to copy from Emacs to iPhone ๐Ÿ˜…

dpsutton21:01:14

that's what i thought. but both source and doc show separator and then coll. (or just coll)

dpsutton21:01:27

i never see coll then separator

borkdude21:01:00

interpose also has [sep coll], this seems to be the pattern all over

Lennart Buit21:01:01

is also great for partial application (def comma-joiner (partial str/join ","))

borkdude21:01:29

also, (interpose sep) gives you a transducer, which is nice

dpsutton21:01:47

i had a question about something similar. the metadata can be modified to clarify the docstring beyond what the "source" docstring actually is

borkdude21:01:06

is that what spec uses?

Mattias21:01:19

Sorry. I really canโ€™t figure out how to do the darn code markings in the chat...

Mattias21:01:21

noob.core> (clojure.string/join [1 2 3 4] ":") ":" noob.core> (clojure.string/join ":" [1 2 3 4]) "1:2:3:4"

Lennart Buit21:01:54

yeah, the last is correct, its seperator first and collection second

tim21:01:07

surround with back-ticks

Lennart Buit21:01:12

that the first does something is mere accident I would say

dpsutton21:01:44

its similar to (+ :cow) happens to work

Lennart Buit21:01:06

yeah, mere accident ๐Ÿ˜›

dpsutton21:01:22

ah but only cljs

dpsutton21:01:25

clj has a cast in it

borkdude21:01:52

in the first one it uses [1 2 3 4] as the separator, but since you have only one character, itโ€™s return as it is

Mattias21:01:22

Ok. Thanks. In that case Iโ€™m reading the doc wrong, I think.

borkdude21:01:34

(str/join [1 2 3 4] "foo")
"f[1 2 3 4]o[1 2 3 4]o"

Lennart Buit21:01:45

how does that even work

dpsutton21:01:53

it just calls str on the separator

Lennart Buit21:01:58

strings are not seq right

hiredman21:01:18

they are seqable

Mattias21:01:39

Ah. Hum. So the doc describes two different arity implementations? (It took a while to sink in ๐Ÿ˜‹)

borkdude21:01:53

two different arities

Mattias21:01:09

Thanks. All is well in the world again. Back to noob.core ๐Ÿ˜€

Mattias22:01:42

Being on guard about undefined things silently working is new for me. Silently failing is one thing, but... hmm. Very philosophical experience, getting into Clojure.

borkdude22:01:21

@mattias504 this is not undefined behavior

Mattias22:01:17

Right, thanks. Had to double check the history, you already explained. Thanks for the patience!

dfcarpenter23:01:28

Can anyone point me towards more good, non-trivial open source projects that have rest APIS? I have been looking at https://github.com/braidchat/braid/ and https://github.com/metabase/metabase so far.