Fork me on GitHub
#beginners
<
2022-01-21
>
w-n-c06:01:49

1. Is there a way to thread the (optional) on-change such that the (or ... (fn [])) goes away, or is the no-op fn fine as is?

(defn text-input [{:keys [attrs subscription dispatch]}]
  (let [local (r/atom (or @subscription ""))
        on-change (or (:on-change dispatch) (fn []))]
    (fn []
      [:input.input
        (merge attrs
          {:type :text
           :on-change #(->> (.. % -target -value)
                            (reset! local)
                            (on-change))
           :value @local})])))
2. Assuming 1 is yes, is there a cleaner way to do this nested de-structure? I saw nested de-structures on http://clojure.org but not with :keys being used at the parent level and my attempts to 'guess' at the syntax all failed:
(defn example [{:keys [attrs sub dispatch]}]
 (let [on-blur   (:on-blur dispatch)
       on-change (:on-change dispatch)]
  ...))

Antonio Bibiano19:01:54

about 2. you could further destructure in the let

Antonio Bibiano19:01:52

(defn example [{:keys [attr sub dispatch]}]
 (let [{:keys [on-blur on-change]} dispatch]
  ...))

Antonio Bibiano19:01:20

Actually this works

(defn example [{:keys [attr sub dispatch] 
                {:keys [on-blur on-change]} :dispatch}]
  (println attr sub dispatch on-blur on-change))

🙌 1
Antonio Bibiano19:01:04

about 1. you can do this

(def dispatch { :on-blur 2})
(let [a 1 {on-change :on-change :or {on-change 3}} dispatch]
  (println a on-change))
=> 1 3

Antonio Bibiano19:01:05

sorry the above is not what you asked, but I think you can use cond->>

(defn text-input [{:keys [attrs subscription] {on-change :on-change} :dispatch}]
  (let [local (r/atom (or @subscription ""))]
    (fn []
      [:input.input
        (merge attrs
          {:type :text
           :on-change #(cond-> %
                            true (other-fn -target -value)
                            true (reset! local)
                            on-change (on-change))
           :value @local})])))
(changed your .. to other-fn as it seems you can do a thread first rather than thread last

🙌 1
w-n-c21:01:28

ohhh I tried to do the second destructure example you showed but I think I was using 'dispatch' instead of ':dispatch' for the inner destructure, that makes sense though thanks for figuring it out!

w-n-c21:01:41

And I was unaware of the cond-> threading so that's cool to see as well. Thanks so much Antonio!

quoll02:01:41

Not executing the function is the best approach, but in case you encounter this again, all forms of get allow for a “not-found” value. So instead of: (or (:on-change dispatch) (fn [])) you can write: (:on-change dispatch (fn []))

nice 1
quoll02:01:06

The primary difference here is that the value you pass is not evaluated if you don’t need it and you use or. So you definitely wouldn’t use this form for: (:on-change dispatch (some-really-expensive-fn))

w-n-c23:01:32

@U051N6TTC thanks for pointing out the optional defaults- I'm coming over from Java and can't get over (in a good way!) the number of convenience overloads that Clojure sneaks in haha. Do you happen to know what the use case is in not having default value producer short-circuited?

quoll00:01:48

Most of the time when you’re doing a lookup (via get, keyword-as-fn, or map-as-fn) then returning nil works just fine, but if you do need a default value, then it’s typically a constant, e.g. :not-found. In that case, it’s perfectly fine to provide it as an argument. Using or to short circuit something away is just useful when there’s some kind of operation that’s going to happen that you want to avoid

👍 1
John Bradens07:01:32

If "namespace a" requires "namespace b" and "namespace b" requires "namespace a" will that cause any issues? If it doesn't, why not? Does it have to do with how the compiler works?

jumar07:01:51

You should get a compilation error mentioning the cyclic dependency

DenisMc07:01:00

Hi, I have a function I want to use to update a set of values for given keys in a map - but I don’t want to create the keys if they don’t already exist. Currently I’m doing this line by line for each key that I want to update , like so:

(update m :key-to-update fn-to-apply)
How do I a) not create the kv in the map m if it’s not already there, and b) once I have done that, combine multiple such conditional updates in a single line (e.g. if I have key-to-update-2, key-to-update-3 etc.? Thanks in advance

dpsutton07:01:26

(defn update-maybe [m k f] (if (contains? m k) (update m k f) m))

dpsutton07:01:31

if you need args (defn update-maybe [m k f & args] (if (contains? m k) (update m k #(apply f % args) m))

Tero Matinlassi09:01:14

(defn update-maybe [m k f & args] (if (contains? m k) (update m k #(apply f % args)) m)) (a missing paren fixed)

DenisMc10:01:45

Thanks very much, I’m using that update maybe function.

Eddy Emmanuel Asturiano Peralta21:01:44

Hey, how can I correctly declare a function that takes another function as a parameter? For example, i tried

(defn make-eta [nu t1 t2 t]
    (* (- t t1) (- t t2) (nu t)))
With my attempt it almost worked, problem is nu is a different function with t as a parameter. What I'm trying to implement is a function make-eta that takes parameters nu, t1, t2 and returns the function eta(t) = (t - t1) (t- t2) nu(t). So t1, t2 are just numbers and nu is a different function that takes t as a parameter. So, correctly calling the procedure I think should look like
((make-eta nu 't1 't2) 't)
instead of the way I'm calling it in the picture. Should have clarified also, I'm using SICMUtils library(?) (don't know yet what's the correct term)

noisesmith21:01:33

functions are not handled specially, they are passed like any other argument

Eddy Emmanuel Asturiano Peralta21:01:04

I see. But the problem I have is say for example a function g takes as parameter t and I want to implement a function f that takes as parameter g but not t

noisesmith21:01:29

so something like

(defn f [g]
  (fn [t] (g t))
returns a new function taking t and applying g

noisesmith21:01:41

if I understand you correctly

noisesmith21:01:30

(of course that simplifies to (def f g) but you could have other logic in there)

Eddy Emmanuel Asturiano Peralta22:01:07

I worked! Thanks for the help. The answer was

(defn make-eta [nu t1 t2]
    (fn [t] (* (- t t1) (- t t2) (nu t))))

🍻 1
noisesmith21:01:57

to return a new function you need to create a function, eg. use fn

👀 1
hiredman21:01:41

you are not doing clojure stuff, you are using some dsl in clojure for math that does some equation rendering, and dsl that si, either it, or whatever the rendering thing is, doesn't understand higher order functions

Eddy Emmanuel Asturiano Peralta21:01:18

Oh I see. I think the key is higher order functions, haven't learned about those yet. I should look into those.

hiredman21:01:35

in clojure those just work, and functions are values that can be passed and returned no different from the number 5

hiredman21:01:13

but I dunno about sicmutils

hiredman21:01:36

do you have a clojure error message, a stacktrace or something?

hiredman21:01:19

there is a #sicmutils so if whatever issue you are having is with that library, and not with clojure in general, you may get better help there

👀 1