Fork me on GitHub
#clojure
<
2016-11-24
>
tdantas11:11:39

hey guys, I’m doing some clojure study and yesterday I faced a simple problem. the problem says: you have to save to a file the number of characters from a text below is my solution

(defn char-counter [filename text]
  (spit filename
    (reduce +
      (map #(.length %)
           (str/split text #"")))))
can you guys help me to make more idiomatic or a better way to do that ?

slipset11:11:53

(spit filename (count text)) ?

tdantas12:11:39

good @slipset , how to test that ?

tdantas12:11:57

we need to bind to a symbol the expression above, right

tdantas12:11:24

(defn counter [filename text] 
 (spit filename (count text)))

tdantas12:11:30

something like that, right ?

slipset12:11:05

Note that this will count all characters, also “ “ and “\n”,

tdantas12:11:33

no worry ! my concern is more focused on test/design

slipset12:11:36

(count (remove #{\ \\\n} text)) will not count “ “ nor “\n"

slipset12:11:51

the key insight here I guess is that strings in clojure work like sequences, so any function working on a sequence works on a string.

tdantas12:11:40

ya ! that is right

tdantas12:11:00

how would you test ?

tdantas12:11:59

create some text and assert against (slurp filename) value

tdantas12:11:54

I read many articles and almost everyone says (Isolate side-effects)

slipset12:11:03

although, I’d consider the spit part rather uninteresting if I wrote this code, I’d be more concerned with the count bit.

tdantas12:11:03

how could that be applied on the function above

slipset12:11:11

which mirrors what you’re saying.

tdantas12:11:49

> if I wrote this code, I’d be more concerned with the count bit how would be ?

slipset12:11:59

(defn count-chars [text] (count (remove #{\ \\\n} text)))

slipset12:11:09

This is the function I would test

tdantas12:11:41

ok, one function just to count the chars, and other function to save ?

tdantas12:11:50

( isolating the side effect, right ? )

tdantas12:11:55

and other function to combine both

slipset12:11:57

Yes, and that other function would be kind of stupid

slipset12:11:33

(defn count-and-write [filename text] (spit filename (count-chars text)))

slipset12:11:56

which IMHO does not need testing

slipset12:11:09

you run it once in the repl and see that it works.

tdantas12:11:00

I got your point !

tdantas12:11:39

why make count-chars public

tdantas12:11:45

why not private

tdantas12:11:00

I think outside the namespace, nobody will use that

slipset12:11:02

things tend to be public in clojure

slipset12:11:32

besides, when you decouple the logic from the side-effect, the logic tends to become more generic

slipset12:11:52

count-chars might just be usefull, I’m sure apache-commons has something like that.

tdantas12:11:28

and we are doing a pure-function that could be easily optimized

tdantas12:11:35

that is great !

grav12:11:17

How come:

(and (<= 0.1 1/10) (>= 0.1 1/10))
=> true
(= 0.1 1/10)
=> false

niwinz12:11:42

(== 0.1 1/10)
;; => true

katox13:11:39

@grav the docstring in = is really misleading claiming "compares numbers ... in type-independent manner". In reality there are different rules, see https://github.com/jafingerhut/thalia/blob/master/doc/other-topics/equality.md

grav13:11:19

@niwinz Ah - that was my next question 😉

grav13:11:33

@katox thanks for the pointer!

slipset13:11:45

from http://clojure.org/reference/reader I find about keywords that "They cannot contain '.’ or name classes"

slipset13:11:53

clj.user> (def my-map {:foo.bar "baz"})
;; => #'clj.user/my-map
clj.user> (:foo.bar my-map)
;; => "baz"
clj.user> :foo.bar
;; => :foo.bar
clj.user> 

mpenet14:11:17

nothing enforces that (atm)

mpenet14:11:38

didn't know about the dot, I use that all the time 😐

joost-diepenmaat14:11:09

it’s also commonly used by hiccup and other templating tools that use hiccup-style formatting

joost-diepenmaat14:11:09

the restriction makes sense for plain symbols since that clashes with package names, like foo.bar.baz, but :foo.bar.baz by itself has no special meaning in clojure

mpenet14:11:16

it's full of quirks, but I don't think it's considered important atm, maybe specs will come for this stuff but that's it

slipset14:11:51

There has been (lots of) discussion on the clojure mailing list about non-readable keywords

slipset14:11:31

The consensus seems to be that it’s a feature 🙂

mpenet14:11:31

yeah, I couldn't care less personally

chrisblom14:11:06

(keyword " ¯\\(ツ)_/¯") => ¯\(ツ)_/¯

chrisblom14:11:15

keyword just doesn't care

chrisblom14:11:02

non-readable keywords are super annoying when reading edn though

chrisblom14:11:26

reading double colon namespaced keywords like ::foo can also be tricky

chrisblom14:11:54

:अपठनीय कीवर्ड का अस्पष्ट है

lmergen14:11:22

what is the rationale behind / best use of double colons btw ? metadata ?

lmergen14:11:41

I personally feel it's a bit hackish

slipset14:11:53

@lmergen I guess they become valuable when you start using specs

lmergen14:11:27

what I mean is, why did spec choose double colons ?

mpenet14:11:45

it's not a spec thing, it's been in clojure from the start

lmergen14:11:01

right, I saw them a few times in other projects as well. I guess I'm asking my question in the wrong way. :)

lmergen14:11:21

how do I know whether or not I should use double colon or single colon ?

lmergen14:11:35

when designing, say, a library

lmergen14:11:48

I have to assume there is some best practice around them ?

mpenet14:11:19

depends: think about these like vars, you want to have them namespaced

lmergen14:11:52

aha that makes sense. so data / metadata is a good one

Alex Miller (Clojure team)14:11:18

You never have to use :: at all

chrisblom14:11:24

mainly brevity, ::foo it just syntactic sugar for :<current-namespace>/foo

Alex Miller (Clojure team)14:11:56

It's just a tool for typing less to get qualified keywords

Alex Miller (Clojure team)14:11:49

Using :: with an alias is pretty handy though to separate the namespaces in your code from the actual namespaces via indirection

Alex Miller (Clojure team)14:11:32

If you say ::foo/whatever everywhere you can define what foo aliases exactly once at the top of the file (and easily change it)

blkt15:11:55

has anyone tried using clojure 1.8 -Dclojure.server.repl stuff with nrepl and cider?

Alex Miller (Clojure team)15:11:58

It won't work - nrepl is a totally different protocol

blkt15:11:03

I suspected that, but could not find details (didn't look into that that much)

Alex Miller (Clojure team)15:11:10

You could write a server repl accept function that talked nrepl but afaik no one has done so

Alex Miller (Clojure team)15:11:41

The default socket server repl is just stream based

blkt15:11:26

I see, thank you

jjttjj15:11:32

If i have a library that depends on something that is not distributable, ie not on maven or anything, but the jar is available at a public url, is it possible for my library to download this jar from the url and add it to the classpath automatically whenever it's used? Or is this pretty much going to have to be up to the end user

stain16:11:32

you will have to first install it with mvn install-file to your local .m2/repository. or with mvn deploy-file to a locally accessible Maven repository

tdantas20:11:45

still struggling why the code below is considered bad I’m using one global symbol inside the save function. everyone I showed the code said to use the save-explicit but nobody gave me a real reason, only do not use globals. can anyone help me with that ? appreciate guys

(def filename “filename.txt”)

(defn save [text]
 (spit filename text))

(save “hello”)

(defn save-explicit [file text]
  (spit file text))

(save-explicit filename “hello”)

mitchelkuijpers21:11:48

@oliv I think they mean to say that the save function you have declared is way less reusable then the save-explicit function. Globals are not all bad but most of the time it is better to make things an explicit argument to a function.

tdantas21:11:00

yeah ! agree that save function is way less reusable. but on my domain , suppose I don’t need the reusable save because all my use is to save on filename. I’m super lazy, YAGNI is my middle name 😄

jrheard22:11:52

in general, it’s good for functions to take explicit inputs and return an output

jrheard22:11:20

if functions rely on things other than the data they’re given as explicit inputs, they usually end up being harder to think about, maintain, and change over time

jrheard22:11:49

save-explicit is better because it says: this is all the information i rely on in order to work, it’s all right here, look at it

jrheard22:11:00

lets you worry less when you’re reading / thinking about the function

jrheard22:11:27

the world won’t catch fire if you use save for your own personal code fwiw

jrheard22:11:34

do whatever you like best 🙂

tdantas22:11:49

but imagine the simple situation i will call dependency hell suppose the function controller uses the save-explicit

(def file “hello.txt”)

(defn controller [request]
  (save-explicit file (:body request))

tdantas22:11:15

@jrheard ^^ in the above situation, the controller must change the signature to receive the save-explicit dependency

tdantas22:11:51

(defn controller [request file]
  (save-explicit file (:body request))

jrheard22:11:06

or, well, in the first example you gave your save-explicit call uses the global file variable so i don’t think that’s quite the same, but i see your point - yeah, there’s definitely a tension between “all functions should take all their data as explicit inputs” and “oh god now all of my functions take 300 inputs"

jrheard22:11:25

there’s no 100% right answer, your point is completely valid - do what makes the most sense in whatever situation you’re in imo

jrheard22:11:55

i’ve seen this specific topic debated in this channel many times and there are strong arguments on either side, it basically just kinda depends 🙂

tdantas22:11:25

yeah ! ok ! I’m very new on clojure and reading/watching talks a lot. it is unanimous that everyone advocates that ( explicit arguments/dependencies )

jrheard22:11:48

yeah, taking explicit args whenever reasonably possible seems to be a good habit

tdantas22:11:59

thx @jrheard . do you recommend a good talk/book that points that

jrheard22:11:34

hm, i can’t actually think of a good one off the top of my head - if one comes to me later today, i’ll definitely link to it! sorry 😅

jrheard22:11:09

if you can find a good talk or article / etc on pure functions, they’re basically the same idea

jrheard22:11:30

save-explicit is pure because it only relies on its inputs, save is impure because it relies on something in addition to its input

jrheard22:11:39

and well they’re both impure because they presumably write to a file, which is a side effect

jrheard22:11:54

but if you ignore that… 😄

tdantas22:11:18

yep ! and everyone advocates make side-effects explicit