Fork me on GitHub
#clojure
<
2017-05-28
>
lvh00:05:06

do people use edn as a configuration format? How’s that working out? It seems like clojure-the-language really wants me to use namespaced keywords, but that seems very verbose when using EDN since it doesn’t seem to have ns aliases

mpenet12:05:47

lvh: we do via juxt/aero and spec for validation

mpenet12:05:21

lvh: namespaced or not doesnt really matter ultimately

lvh04:05:12

Why does namespaced or not not matter?

lvh00:05:28

@noisesmith yeah I guess. That seems iffier than writing the real transducer though 😕

bherrmann00:05:22

kinda noob here, but I just typed in a function into the repl. How do I print the function back out as source code? I tried (clojure.repl/source myfun) but “Source not found”

noisesmith00:05:25

the source function only works for code that came from a file

noisesmith00:05:31

it's really too bad

mfikes01:05:27

We have source for REPL-entered defs working in Lumo, Planck, and Replete—it seems like a reasonable and useful thing to have.

miikka07:05:04

@lvh, I've use EDN (without namespaced keywords) for config for years in various projects and it has worked well, I do recommend it.

miikka07:05:08

Not sure if Clojure in general pushes for namespaced keywords, but clojure.spec does. I like the idea in principle, but haven't used it much in practice. My config-validation specs use (s/keys :req-un [...])

noisesmith07:05:12

for namespaced keywords, shouldn't having a namespace alias in effect apply it to an edn file you read?

jimmy10:05:34

hi guys, can cljfmt rewrite one line if to 3 lines:

(if true true false) to
(if true 
  true
  false)

weavejester12:05:12

@nxqd: no, because both are equally valid from cljfmt’s POV. zprint might be able to, though.

jimmy12:05:50

@weavejester thanks for the info. I will check zprint.

bherrmann13:05:38

is there any best practice for noting something is an element of a collection? (map (fn [fluffy-cow] (fiddle fluffy-cow) fluffy-cows) or is just dropping the “s” the convention?

mobileink18:05:07

bherrmann: i prefer "the-foo" over "a-foo", since the latter implies sth like "any old foo". but we're always dealing with the specific foo we've been handed. works for fn args too.

bherrmann13:05:33

I was thinking perhaps (map (fn [a-fluffy-cow] (…)) fluffy-cows)

bherrmann13:05:56

or (map (fn [single-fluffy-cow] (…)) fluffy-cows)

tatut13:05:41

I think it should be obvious, at least in the map example

tatut13:05:48

Still, I do tend to do the singular/plural thing when naming: (map (fn [row] ...) rows) and so on

bronsa14:05:03

some of the advices there are quite questionable

danielneal15:05:12

@U060FKQPN everyone knows you prefix with ! for a mutable reference

misha16:05:31

@U051H1KL1 this is the first time I hear/see ! for refs in 3 years, but I like it more than *. even though * is a nod to C++/objC pointers

madstap16:05:08

The case against !foo is that it'll look like a negation to java/ruby/etc folks.

bronsa17:05:13

it's got a nice symmetry with the bang! functions tho

qqq15:05:45

;;  import static jcuda.jcudnn.JCudnn.cudnnConvolutionForward;
  ;;  import static jcuda.jcudnn.JCudnn.cudnnCreate;
  ;;  import static jcuda.jcudnn.JCudnn.cudnnCreateConvolutionDescriptor;
  ;;  import static jcuda.jcudnn.JCudnn.cudnnCreateFilterDescriptor;
  ;;  import static jcuda.jcudnn.JCudnn.cudnnCreateLRNDescriptor;
  ;;  import static jcuda.jcudnn.JCudnn.cudnnCreatePoolingDescriptor;

is there a way to import static functions from javak instead of classes ?

misha16:05:20

Is there a rule-of-thumb on "when to use qualified keywords in domain data structures?" E.g. datomic's tx-report has unqualified keys, like :db-before, even though tx-report is not a data structure internal to datomic – it is used all over the client apps.

mobileink18:05:17

misha: that's an interesting topic. consider the html "domain". usually attribs get passed as a kw map, e.g. {:class "foo"}. if you use an ns you could do {:html/class "foo"} and then validate. but then you'd get stuff like {:html/style {:html.style/color :red} or similar. is it worth the trouble? i think there's a convenience tradeoff, similar to the one between strictly and loosely typed languages.

val_waeselynck19:05:30

@U051HUZLD I've learned to use them almost always by default, because the benefits in terms of code clarity and data traceability usually outweigh the slight inconvenience in typing. I believe this idea has matured only recently in the Clojure community (and is notably championed by spec), which is why we still see a lot of unqualified keywords out there.

val_waeselynck19:05:28

A more important point of consideration IMHO is whether these namespace-qualified keys are acceptable by your non-clojure consumers, in which case you may want to use another syntax for namespacing (e.g :html_class instead of :html/class)

mobileink20:05:29

@U06GS6P1N but :html_class is not namespaced.

val_waeselynck20:05:25

@U0LGCREMU it's not in the Clojure sense, but it gives you most of the benefits of namespacing in terms of readability and data traceability

mobileink20:05:39

sure but that misses the point of namespaces. so you don't need to parse global names. compare :html/class, :html/id, etc. to :html_class, :html_id, etc.

mobileink20:05:42

why reinvent the wheel?

val_waeselynck20:05:16

Because the JS guys may not want to consume the dots and slashes in the keys :)

mobileink20:05:02

i guess i don't much care about the js guys when i'm writing clojure code. ;)

val_waeselynck20:05:29

My point being that including the namespace information in this way is a better alternative than giving up on it in this case

val_waeselynck20:05:57

Yeah not a great situation to be in

mobileink20:05:10

you can always translate namespaces to strings for languages that do not support nss.

mobileink20:05:41

or symbols, or any other namespaced thing in clojure.

val_waeselynck20:05:54

yeah basically my approach for now. Slightly inconvenient in JS to write m['my.ns/key'] but it works. Actually, I'd be more worried about languages that rely heavily on classes to represent information, e.g that parse incoming JSON into instances of classes defined ahead-of time. I reckon this is common in the Scala world for example

mobileink18:05:07

bherrmann: i prefer "the-foo" over "a-foo", since the latter implies sth like "any old foo". but we're always dealing with the specific foo we've been handed. works for fn args too.

mobileink18:05:47

e.g. (defn f [the-foo] (let [foo (munge the-foo)]...)) "the-" always tells me i'm dealing with an arg, not something letted or a global.

mobileink18:05:17

misha: that's an interesting topic. consider the html "domain". usually attribs get passed as a kw map, e.g. {:class "foo"}. if you use an ns you could do {:html/class "foo"} and then validate. but then you'd get stuff like {:html/style {:html.style/color :red} or similar. is it worth the trouble? i think there's a convenience tradeoff, similar to the one between strictly and loosely typed languages.

lepistane18:05:32

thank you all for being such a wonderful community ❤️

val_waeselynck20:05:54

yeah basically my approach for now. Slightly inconvenient in JS to write m['my.ns/key'] but it works. Actually, I'd be more worried about languages that rely heavily on classes to represent information, e.g that parse incoming JSON into instances of classes defined ahead-of time. I reckon this is common in the Scala world for example

andrea.crotti20:05:50

question about recur & co, I wrote the following algorithm to fill in an image with a certain colour (inspired loosely on https://en.wikipedia.org/wiki/Flood_fill )

(defn fill-coordinates
  "Recursive function that generates all the coordinates
  which need to be filled in with the new colour.
  It's inspired by the flood-fill algorithm, but had to be
  heavily modified since there is no mutation here."

  ([img coord old-colour new-colour coords]
   (if (or (= new-colour old-colour)
           ;; when outside of the range no need for the extra check
           (not (valid-coord? coord img)))
     coords
     (if (or
          (contains? coords coord)
          (not= (get-in img coord) old-colour))
       coords
       (letfn [(rec-call [direction filled-coords]
                 (fill-coordinates img (move direction coord) old-colour new-colour filled-coords))]

         (let [c-incl (union coords #{coord})
               c-north (rec-call :north c-incl)
               c-east (rec-call :east c-north)
               c-south (rec-call :south c-east)]

           (rec-call :west c-south))))))

  ([img coord new-colour]
   (let [old-colour (get-in img coord)]
     (fill-coordinates img coord old-colour new-colour #{}))))

andrea.crotti20:05:04

now the problem is that on big images I get a stack overflow

andrea.crotti20:05:21

but I don't think I can actually use recur in this case right?

andrea.crotti20:05:50

I was trying to avoid in place mutation, and I also have a letfn there for convenience

andrea.crotti20:05:26

recur doesn't like leftn as point to jump to, but more importantly I'm not sure this is tail recursive or could be written as such

noisesmith21:05:55

wait, why can't you recur inside a letfn? - if you mean jumping from tail of one function to another function, check out trampoline

noisesmith21:05:24

trampoline is another way to avoid growing stack

noisesmith21:05:34

(without being limited to self calls)

andrea.crotti21:05:02

I meant that if I just do a recur it will fail saying it's expecting 5 arguments instead of 2, so it's trying to call the outer function I guess

noisesmith21:05:35

you can only recur into the same function - a recur to a letfn bound function must be done inside that function

andrea.crotti21:05:42

and well these are all self calls in a way, even if there is a chain of them

(let [c-incl (union coords #{coord})
               c-north (rec-call :north c-incl)
               c-east (rec-call :east c-north)
               c-south (rec-call :south c-east)]

           (rec-call :west c-south)))))

noisesmith21:05:47

and you can only recur to the same arity

andrea.crotti21:05:12

ahh ok sorry I understood now

qqq21:05:21

(defn map<-lst [f lst]
  (into {} (map (fn [e] [(f e) e]) lst)))
is there a better way to write this ?

noisesmith21:05:31

move a paren so it uses a transducer

noisesmith21:05:55

(defn map<-lst [f lst]
  (into {} (map (fn [e] [(f e) e])) lst))

qqq21:05:56

how would it look ?

noisesmith21:05:22

one paren moves from being after lst to being after the fn arg to map

qqq21:05:40

I was expecting the (fn [e] [(f e) e]) which looks ugly, to be simplified

qqq21:05:58

(juxt f identity) ?

qqq21:05:04

not sure that's much prettier

noisesmith21:05:12

(defn map<-lst [f lst]
  (into {} (map (juxt f identity)) lst))

qqq21:05:28

hmm, I was hoping for #[(f %) %] but I can't do that

adamvh21:05:59

isn't that like a scanl

adamvh21:05:02

from haskell

adamvh21:05:13

like take 2 scanl

noisesmith21:05:02

not really - there's no accumulated result over args

noisesmith21:05:36

(not in the way scanl does that is - of course it's all accumulated into a hash-map)

john21:05:14

there's always #(identity [(f %) %])

john21:05:49

Or #(do [(f %) %]), which some might consider uglier

noisesmith21:05:56

that's a lot worse than (juxt f identity)

qqq21:05:20

(defn v [& args] (into [] args)) #(v (f %) %) 🙂

john21:05:57

I was surprised juxt returned a vector

noisesmith21:05:08

v is a poor performing version of vector