Fork me on GitHub
#beginners
<
2022-08-22
>
popeye10:08:10

I have written a below code , but when I call (get guide-user-hint-messages :add) function is calling for substract and multiplication also , which is unnecessary, How can I call other function and run only a function for the key which I need, Probably guide-user-hint-messages is called in compile time ?

(defn perform-math [fn val1 val2]
  (println val1)
  (fn val1 val2))

(def guide-user-hint-messages {:add (perform-math + 1 2)
                               :substract (perform-math - 3 2)
                               :multiplaction  (perform-math  * 5 2)
                               })

(println (get guide-user-hint-messages :add))

rolt11:08:01

it's not calling it when you run (get ...), it's when you run (def ...) you could do something like that

(def x {:add (fn [] (perform-math ...)) :substract (fn [] ...)}

((get x :add))

popeye11:08:46

thats a good point!!! Thanks, Also is there a way where we can write it in Macros ?

Martin Půda11:08:21

There is also https://clojuredocs.org/clojure.core/delay:

(defn perform-math [fn val1 val2]
  (println val1)
  (fn val1 val2))

(def guide-user-hint-messages {:add (delay (perform-math + 1 2))
                               :substract (delay (perform-math - 3 2))
                               :multiplaction (delay (perform-math * 5 2))
                               })

(println @(get guide-user-hint-messages :add))

popeye11:08:26

yeah this alo helped! I think now I understood the delay 😄

Martin Půda11:08:42

I just realized that you don't have to wrap each expression in delay, one delay in perform-math will be enough:

(defn perform-math [fn val1 val2]
  (delay
    (println val1)
    (fn val1 val2)))

(def guide-user-hint-messages {:add           (perform-math + 1 2)
                               :substract     (perform-math - 3 2)
                               :multiplaction (perform-math * 5 2)})

(println @(get guide-user-hint-messages :add))

1
sheluchin11:08:05

I'm often editing my files to comment out some form and replace it with a hardcoded value while testing things from the REPL. Is there any trick that can reduce the amount of comment fumbling in this workflow?

teodorlu11:08:57

oooh, I have something I like here.

(defn avg [& numbers]
  (/ (reduce + 0 numbers)
     (count numbers)))

(comment
  (let [numbers [1 2 3 4 10 20]]
    (/ (reduce + 0 numbers)
       (count numbers))))
Notice that the stuff inside the let is exactly the same as the stuff inside the defn? You can simply copy back and forth. I do this all the time.

Ed12:08:19

If you're using Cider/Emacs there's a keyboard shortcut for setting some values before evaluation as if there was a let around it. I think it's C-c C-v C-b and it will remember the history of bindings so you can just hit the binding again to rerun the same thing.

Ed12:08:21

I assume that other editors have something similar.

sheluchin14:08:17

@U3X7174KS I sometimes use something like that as well. It's okay, but has some drawbacks. You still have to edit your code a bunch, which adds noise to the undo history.

sheluchin14:08:47

@U01AKQSDJUX that sounds interesting. I can't find any docs for that though. Do you happen to know what it's called or some potential search terms to look for it? I use vim + vim-iced and I don't think it has anything like that in there now, but maybe it can be done with another plugin or some other way.

Ed14:08:53

https://github.com/clojure-emacs/cider/blob/master/cider-eval.el#L1060 ... I think that's the code in cider ... in the docs all I can find is this : https://docs.cider.mx/cider/usage/code_evaluation.html#exotic-evaluation-commands which says that it includes > commands that evaluate an expression in a different context (e.g. with user-supplied bindings) for me it looks like this:

sheluchin15:08:04

@U01AKQSDJUX That's pretty cool. Thanks for the added info.

👍 1
teodorlu16:08:48

There's also https://github.com/vvvvalvalval/scope-capture, which does something similar.

sheluchin22:08:51

Just in case anyone else come across this thread, this was recently implemented in vim-iced as well https://clojurians.slack.com/archives/C06MAR553/p1661808166908009

popeye14:08:45

I have written a code to get the key which i true from a vector , But I see that, it looks very verbose code, is there a way where we can improve the filter function? . variable is of type persistentArrayMap

(def variable [{:a true} {:b false} {:c  false}])

(println (first (keys (first (filter (fn [T]
                                       (true? (first (vals T)))) variable)))))

Ed15:08:10

It depends what you mean by "improve". I think I would probably have written something like this:

(let [variable [{:a true} {:b false} {:c false}]]                                          
  (->> variable                                                                            
       (mapcat identity)                                                                   
       (filter second)                                                                     
       ffirst))

rolt15:08:42

it's verbose because your data structure is a bit strange, you're using a seq of maps instead of seq of pairs

tomd15:08:36

(let [variable [{:a true} {:b false} {:c  false}]]
  (some (fn [m] (some (fn [[k v]] (when (true? v) k)) m)) variable))
;; => :a
is another approach

popeye15:08:43

taking a look

tomd15:08:36

if you just want a key with a true val (i.e. order doesn't matter) then this could work:

(let [variable [{:a true} {:b false} {:c  false}]]
  (-> (apply merge variable)
      clojure.set/map-invert
      (get true)))
;; => :a

stantheman19:08:44

As rolt says data structure is easier with seq of pairs

(def variable [[:a true]  [:b false]  [:c false]])(println
   (apply  first (filter
                  #(second %) variable)))

popeye15:08:26

if I use macros, again it is a same function to be called

popeye15:08:07

one more question! how to update if we have vector inside a map ? :w to true

(def abc {:a :b :c [{:p true}
                    {:w false}]})

afleck15:08:08

if you know the map with :w will always be second in the vector then update works with vectors via indexing:

=> (update [5 6 7] 1 inc)
[5 7 7]

👆 1
afleck15:08:22

if you’re always associng true rather than taking complement of the value or something, you can also just use assoc-in (i think the word “update” has very specific meaning to clojurists, namely it entails actually applying a computation to the value at the specified key)

(assoc-in abc [:c 1 :w] true)

3
ahungry15:08:04

if you are doing deep data manipulation like this often, maybe look into https://github.com/redplanetlabs/specter - or maybe if your data structure is just a container for values you control, instead of messing with a deeply nested :w, you could lift it out as an atom and maintain it via changes to the atom (but have the atom itself as your var )

pithyless15:08:39

Also consider whether you have the right data model. The questions you're asking (is something true/false; can I toggle something as true or false) - without knowing anything about your problem - my first question would be: perhaps this should just be a set of true values?

(let [enabled #{:a :b}]
  (seq enabled) ;; all enabled
  (contains? enabled :a) ;; enabled?
  (conj enabled :c) ;; add
  (disj enabled :a)) ;; remove

pithyless15:08:08

Or if it's a group, perhaps a map of sets?

{:feature-x #{:a :b}
 :feature-y #{:a :c :d}}
Or inversely...
{:a #{:feature-x :feature-y}
 :b #{:feature-x}
 :c #{feature-y}
 :d #{feature-y}}

pithyless15:08:55

TL;DR - true/false can often be modeled as existence/absence instead

👍 1
popeye16:08:58

Thanks everyone for your involvement in helping me 🙂 I will go with (assoc-in abc [:c 1 :w] true) as this one holds good for my requirement

popeye16:08:18

@U013CE2GQRH what if my input is `

(def abc {:a :b :c [[:p true]
                    [:w false]]})

afleck17:08:38

you’re changing the {:w false} map to a vector, so the indexing will be different, instead of [:c 1 :w] you’ll do [:c 1 _] , where _ is the appropriate vector index

afleck17:08:45

as above commenters are indicating though if it’s getting complex like this you may want to consider a different abstraction, if you’re trying to update whatever value is associated with :w a first step would just be using maps all the way down

jimmy15:08:21

problem with SEESAW tutorial https://github.com/clj-commons/seesaw/blob/master/project.clj “lein deps” produced the following and I can’t produce a REPL in the project folder. How do I proceed? lein repl Tried to use insecure HTTP repository without TLS: stuartsierra-releases: http://stuartsierra.com/maven2 org/clojure/clojure/maven-metadata.xml This is almost certainly a mistake; for details see https://github.com/technomancy/leiningen/blob/master/doc/FAQ.md

pithyless15:08:53

There are some really old dependencies in that project.clj (e.g. clojure 1.4.0) - you may want to update some of them

pithyless15:08:04

But it may be enough to just comment out this line:

:repositories [["stuartsierra-releases" ""]]

pithyless15:08:37

(assuming the default clojars maven repo has all those deps, it should just work)

jimmy16:08:40

here’s the project.clj file (defproject hello-seesaw “1.0.0-SNAPSHOT” :description “FIXME: write description” :url “http://example.com/FIXME” :license {:name “EPL-2.0 OR GPL-2.0-or-later WITH Classpath-exception-2.0" :url “https://www.eclipse.org/legal/epl-2.0/”} :dependencies [[org.clojure/clojure “1.11.1"] [seesaw “1.4.2”]] :repl-options {:init-ns hello-seesaw.core})

jimmy16:08:33

OK, I copy-pasted the project.clj file from github (instead of copying verbatim from the tutorial) and “lein deps” succecceded.

jimmy16:08:46

now I am down to

WARNING: :warn-on-reflection is deprecated in project.clj; use :global-vars.
As of 2.8.2, the repl task is incompatible with Clojure versions older than 1.7.0.
You can downgrade to 2.8.1 or use `lein trampoline run -m clojure.main` for a simpler fallback repl.
Subprocess failed (exit code: 1)

jimmy16:08:44

changing deps to clojure 1.11.0 made it through. so far..

jimmy16:08:14

(use ’clojure.repl) -> nil (ok) but the following fails: user=> (use ’hello_seesaw.core) Execution error (FileNotFoundException) at hello-seesaw.core/eval2026$loading (core.clj:1). Could not locate seesaw/core__init.class, seesaw/core.clj or seesaw/core.cljc on classpath.

pithyless21:08:23

1. I suggest using require vs use - https://clojuredocs.org/clojure.core/require#example-542692ccc026201cdc326cbb 2. This looks like a classpath issue (ie. you seem to have started a repl where it cannot find seesaw.core dependency). Is your code online somewhere so I can try to run it myself? 3. Less helpful, but may be relevant: you're running seesaw 1.4.2 (published in 2012) vs the newest which seems to be 1.5.0 (published in 2018). No idea how many bugfixes, etc where applied in the meantime, but it may be worth comparing: https://clojars.org/seesaw/versions/1.5.0 4. Even less helpful, but may be tangentially relevant: if you're primarily interested in desktop apps (and not necessarily Swing in particular), you may be interested to know there are some newer alternatives - eg. https://github.com/cljfx/cljfx based on JavaFX

rolt09:08:08

1.5.0 fixes the "Tried to use insecure HTTP repository without TLS" error

jimmy05:08:36

@U05476190 @U02F0C62TC1 thank you both. I am not interested in Swing as such, so I think I will have a look at cljfx. I close this thread now.

cvetan23:08:15

how can I pass json map into function, I have route defined like this:

:post {:summary "This request creates new competition"
             :parameters {:body {:sport-id int?
                                 :name string?
                                 :url string?
                                 :country string?
                                 :enabled boolean?}}
and I want to define function in some separate namespace that will accept this map as input and pass it to hugsql query

cvetan23:08:39

however I do not understand how to pass map as single argument into function, is that possible?