Fork me on GitHub
#clojure
<
2017-12-29
>
lemons09:12:08

Hey guys. I'm just starting out with clojure and reagent, was wondering why luminus does this

(defn mount-components []
  (r/render [#'navigation/navbar] (.getElementById js/document "navbar"))
  (r/render [#'router/current-page] (.getElementById js/document "app")))
  ;; --------^ why hash quote? it works fine without it too

carkh10:12:02

that's probably so they reference the var rather than the function itself...so when they reload the file containing router/current-page the new value of the var is taken into account

carkh10:12:26

i guess the router/current-page var must have the ^:dynamic meta data

lemons10:12:02

router/current page is a multimethod. Anyways, it's not a big deal right now, was just curious. I'll read up on vars at some point

carkh10:12:04

what about navbar ?

carkh10:12:37

clojurescript has slightly different semantic for vars, not quite sure that's appropriate or not

lemons10:12:04

simple reagent component.

(defn navbar []
  (fn []
    [:nav.navbar.navbar-dark.bg-primary
     ...

carkh10:12:00

try this : remove the #' for the navbar code ... load that file ...then modify your navbar and load that file

carkh10:12:45

check if you see your modification

lemons10:12:00

i can see the changes

carkh10:12:06

ahwell =)

carkh10:12:26

i use this trick in clojure code

carkh10:12:59

you're using figwheel ?

lemons10:12:24

yep. maybe it's one of those good practice kind of things

carkh10:12:40

for clojure code that's quite necessary during development. I'm not sure about clojurescript

lemons10:12:00

I'll try removing it in clojure code, see if I still get my changes reloaded

carkh10:12:25

#'foo is a shorthand for (var foo)

carkh10:12:57

a simple test, in ns a have : (def a b/b) , in ns b have : (def b 1) ... if you change b and reload the ns b, a should still be 1, unless you set b dynamic and change a to (def a #'b/b)

lemons10:12:24

alright, it's making some sense. thank you for taking your time to explain 🙂

hansw12:12:52

another disillusioned java-dev jumping on board 🙂

hansw12:12:17

i'm not bitter! really!

manutter5112:12:29

I’m not bitter either, I’m having too much fun writing clojure 😉

alexstokes17:12:10

could anyone explain the rationale for the following?

alexstokes17:12:13

(def foo {:a 1})

(when-let [a (:a foo)] (println a))
;; => prints "1", returns nil

(when-let [{:keys [a]} foo] (println a))
;; => prints "1", returns nil

(when-let [a (:a (assoc foo :a nil))] (println a))
;; => returns nil

(when-let [{:keys [a]} (assoc foo :a nil)] (println a))
;; => prints "nil", returns nil

alexstokes17:12:27

i would like for the final expression to not print “nil”, ie the destructuring bind on a nil key to not evaluate the body of the when

alexstokes17:12:48

does clojure have a distinction between a missing and nil key in its map type?

dominicm17:12:55

@alexstokesit's because the value pre-destructuring is not nil.

dominicm17:12:05

It does, you can use contains? to distinguish the 2.

alexstokes17:12:32

so the idea is that the expression used as the value for that binding must be nil for the when to not execute?

bronsa17:12:49

contains has nothing to do with what @alexstokes is asking here -- there's just no way to use when-let/`if-let` on destructured values

bronsa17:12:08

when you do (when-let [{:keys [a]} x] ..) the when-let is testing on the value of x

alexstokes17:12:18

@bronsa no that was helpful! i get its not exactly related to my example under question

bronsa17:12:30

because it expands to something like (when-let [the-map x] (let [{:keys [a]} the-map ..))

bronsa17:12:52

(that's not the macroexpansion at all, just what it's doing logically)

bronsa17:12:29

if you think about it, that's the only behaviour that makes sence as you could do (when-let [{:keys [a b]} c] ..)

bronsa17:12:44

and in this case it would make no sense to test on a or b

alexstokes17:12:14

just because you are looking for a single nil?

bronsa17:12:32

because when-let/if-let don't have semantics for multiple bindings

bronsa17:12:41

i.e. you can't (when-let [a b c d])

alexstokes17:12:46

right — you would have to supply some predicate

alexstokes17:12:56

cool thanks!

souenzzo17:12:21

@alexstokes (macroexpand-1 '(when-let [{:keys [a]} (assoc foo :a nil)] (println a))) =>

(clojure.core/let [temp__5457__auto__ (assoc foo :a nil)]
 (clojure.core/when temp__5457__auto__ (clojure.core/let [{:keys [a]} temp__5457__auto__] (println a))))
temp__5457__auto__ will be a map {:a nil}, that is truly,

johnjelinek19:12:08

how do you require in an eval? ie: clj -e "(require '[clojure.pprint :as pprint]) (pprint '(+ 1 1))"

johnjelinek19:12:00

I'm getting this:

Exception in thread "main" java.lang.RuntimeException: Unable to resolve symbol: pprint in this context

noisesmith19:12:46

well you would need "(require '[clojure.pprint :refer [pprint]]) (pprint '(+ 1 1))"

noisesmith19:12:13

$ clj -e "(require '[clojure.pprint :refer [pprint]]) (pprint '(+ 1 1))"
(+ 1 1)

johnjelinek19:12:25

ah, that works!

johnjelinek19:12:56

now, how could I get it to work if I put it in a single file?

johnjelinek19:12:05

that's where I get the RuntimeException: clojure ...

noisesmith19:12:06

the way I usually do it is (require '[clojure.pprint :as pprint :refer [pprint]))

noisesmith19:12:44

if you put what in a single file? and what’s the full RuntimeException?

noisesmith19:12:21

everything that works in a repl will work in a file - the rules are the same (though there are a couple of things that work in a file that are no-ops in a repl but they aren’t relevant here)

johnjelinek20:12:34

ah, ok -- it's working now

johnjelinek20:12:49

why do you use as and refer?

noisesmith20:12:27

:as means that I can use eg. pprint/print-table instead of clojure.pprint/print-table and :refer means that I can use pprint instead of pprint/pprint

noisesmith20:12:51

the doc for :as is under (doc alias), the doc for :refer is under (doc refer)

noisesmith20:12:07

(that’s clojure.repl/doc but a repl will have clojure.repl in scope normally on startup)

johnjelinek20:12:38

hrmm ... I was hoping pprint would render to stdout without \n

noisesmith20:12:58

you could pass a StringWriter or use with-out-str, then trim the resulting string (hacky, but simpler than any other option I can think of here)

noisesmith20:12:13

@johnjelinek

(ins)user=> (let [sw (java.io.StringWriter.)] (pprint {:a 0 :b 1} sw) (str sw))
"{:a 0, :b 1}\n"
(ins)user=> (let [sw (java.io.StringWriter.)] (pprint {:a 0 :b 1} sw) (clojure.string/trim (str sw)))
"{:a 0, :b 1}"
(ins)user=> (let [sw (java.io.StringWriter.)] (pprint {:a 0 :b 1} sw) (print (clojure.string/trim (str sw))))
{:a 0, :b 1}nil

johnjelinek20:12:30

hrmm ... those aren't spitting out anything for me

noisesmith20:12:50

right, without a newline you need to use (flush) to force output

noisesmith20:12:04

the vm will-auto-flush on newline but without that you need to flush by hand

noisesmith20:12:57

(and of course just making a string won’t make anything print to the console when running a program - in the ones not using print)

johnjelinek20:12:59

something.clj

(require '[clojure.pprint :as pprint :refer [pprint]])

(let [sw (java.io.StringWriter.)]
     (pprint '(+ 1 1) sw)
     (flush))
clj something.clj returns nothing

noisesmith20:12:41

right, pprint with sw as an arg returns a string

noisesmith20:12:44

you need to use print

noisesmith20:12:01

well, it puts something in sw, you need to call str to get a string out of sw

noisesmith20:12:07

then you need to print that string

noisesmith20:12:55

the extra arg to pprint is a writer, it overrides *out* as the place to put the output - and you need to use clojure.string/trim on the resulting string to remove the newline (as in my example above)

johnjelinek20:12:02

hrmm ... and it looks like I'm back to where I was without the sw

noisesmith20:12:20

you need sw in order to trim the string - but I showed everything you need in my example

johnjelinek20:12:25

clj something.clj 

"(ns guestbook.db\n  (:require\n
...

johnjelinek20:12:10

here's my something.clj now:

(require '[clojure.pprint :as pprint :refer [pprint]])

(let [sw (java.io.StringWriter.)]
     (pprint (slurp "./db.cljs") sw)
     (print (clojure.string/trim (str sw)))
     (flush))

noisesmith20:12:32

that should do what you want

noisesmith20:12:48

(you might need to require clojure.string)

johnjelinek20:12:09

but it's resulting in the same output as

(require '[clojure.pprint :as pprint :refer [pprint]])

(pprint (slurp "./db.cljs")

noisesmith20:12:41

well slurp returns a string - pprint of a string just adds “” and otherwise acts like println

noisesmith20:12:04

err… it also prints \n instead of real newlines inside the string etc.

johnjelinek20:12:13

so maybe it's slurp that's messin' me up 😕

johnjelinek20:12:34

😆 all I want is to run https://github.com/weavejester/cljfmt at the CLI without a lein project

noisesmith20:12:57

haha yeah this sounds like a hell of an x/y then

noisesmith20:12:36

it’s too bad cljfmt and lein-cljfmt aren’t separate projects

noisesmith20:12:44

oh wait they are

noisesmith20:12:48

(just one github)

johnjelinek20:12:13

oh -- can I use like deps.edn to grab it and use it via the CLI?

noisesmith20:12:38

yeah - you can use cljfmt without the lein stuff - looks like a straightforward ns to use https://github.com/weavejester/cljfmt/blob/master/cljfmt/src/cljfmt/core.cljc

johnjelinek20:12:23

😆 slurp messes me up there too

johnjelinek20:12:31

same output as pprint

noisesmith20:12:45

cljfmt has functions for forms and for strings though

noisesmith20:12:59

and you can use clojure.edn/read-string to get forms out of a string (or attempt it at least)

qqq20:12:13

(def create-handles           (fn  [] (let [cudnn-h       (cudnn-handle)
                                           _             (cudnn-create cudnn-h)
                                           src-tensor-d  (cudnn-tensor-d)
                                           dst-tensor-d  (cudnn-tensor-d)
                                           bias-tensor-d (cudnn-tensor-d)
                                           filter-d      (cudnn-filter-d)
                                           conv-d        (cudnn-conv-d)
                                           pooling-d     (cudnn-pooling-d)
                                           norm-d        (cudnn-lrn-d) 
                                           cublas-h      (cublas-handle)
                                           _             (cublas-create cublas-h)]
                                       {::cudnn-h       cudnn-h
                                        ::src-tensor-d  src-tensor-d
                                        ::dst-tensor-d  dst-tensor-d
                                        ::blas-tensor-d blas-tensor-d
                                        ::filter-d      filter-d
                                        ::conv-d        conv-d
                                        ::pooling-d     pooling-d
                                        ::norm-d        norm-d
                                        ::cublas-h      cublas-h})))
is there a way to shorten this code? There seems to be too much repetition.

noisesmith20:12:41

that let block is pointless - just put the forms in the hash-map

noisesmith20:12:44

it’s just noise

qqq20:12:54

the order slightly amtters

noisesmith20:12:00

(except for the things to reuse one of the the bindings

noisesmith20:12:05

then call into assoc

qqq20:12:09

I need to create the cudnn handle before calling the other functions, as these are java bindings

noisesmith20:12:03

(defn create-handles
  []
  (let [cudnn-h (cudnn-handle)]
    (cudnn-create cudnn-h)
    (assoc {:cudnn-h cudnn-h}
           ::src-tensor-d (cudnn-tensor-d)
           ...)))

johnjelinek20:12:49

biting the bullet -- /me installing lein

qqq20:12:35

(fn  []
    (into {::cudnn-h  (doto  (cudnn-handle) (cudnn-create))
           ::cublas-h (doto (cublas-handle) (cublas-create))}
          {::src-tensor-d  (cudnn-tensor-d)
           ::dst-tensor-d  (cudnn-tensor-d)
           ::bias-tensor-d (cudnn-tensor-d)
           ::filter-d      (cudnn-filter-d)
           ::conv-d        (cudnn-conv-d)
           ::pooling-d     (cudnn-pooling-d)
           ::norm-d        (cudnn-lrn-d)}))
I think this works too

noisesmith20:12:00

oh, if that’s the only part of the order that matters, yeah

noisesmith20:12:20

but the assoc is nicer imho and does the same thing

noisesmith20:12:30

(and also guarantees evaluation order)

noisesmith20:12:20

I guess it comes down to whether the extra {} are an improvement or background noise

qqq20:12:25

you know, what, I'm going to use assoc, just in case the ordering is stricter than I think it is, - in which case mine may cause a non deterministic bug

noisesmith20:12:56

usage of assoc with many keys in one call us under-appreciated IMHO 😄

qqq20:12:51

to make it all "uniform", I'm going with:

(assoc {}
           ::cudnn-h       (doto (cudnn-handle) (cudnn-create))
           ::cublas-h      (doto (cublas-handle) (cublas-create))
           ::src-tensor-d  (cudnn-tensor-d)
           ::dst-tensor-d  (cudnn-tensor-d)
           ::bias-tensor-d (cudnn-tensor-d)
           ::filter-d      (cudnn-filter-d)
           ::conv-d        (cudnn-conv-d)
           ::pooling-d     (cudnn-pooling-d)
           ::norm-d        (cudnn-lrn-d))
the only slight problem is that cider indent doesn't auto indent the assoc k v pairs for me

arrdem23:12:52

on behalf of Boz I welcome this pull request 😄

bronsa23:12:32

meh, everytime I've aligned arguments in let or in maps I've always regretted it

bronsa23:12:00

it just ends up messing up git history