Fork me on GitHub
#beginners
<
2020-07-27
>
Joshua13:07:47

I want to map the values in a hash map {}. What's the best way to do this? Why isn't there a core library function (unless I'm mistaken)?

jaihindhreddy13:07:00

You can write your own mapvals:

(defn mapvals [f m]
  (into (empty m) (map (fn [[k v]] [k (f v)])) m))

delaguardo13:07:54

reduce-kv maybe?

(reduce-kv #(assoc %1 %2 (f %3)) {} m) 

gerritjvv13:07:55

darn you beat me to it 🙂

gerritjvv13:07:56

(defn mapvals [f m] (reduce-kv (fn [m k v] (assoc m k (f v))) (empty m) m))
I made a gist that shows how to walk a map with nested maps and vectors: https://gist.github.com/gerritjvv/c41f67050dad8804010b657474971f21

gerritjvv13:07:40

there is also: https://github.com/redplanetlabs/specter, for deep levels of maps.

Joshua13:07:33

I came up with:

(defn hmapv [f map]
  (into {}
        (for [[k v] map]
          [k (f v)])))

jaihindhreddy14:07:41

When there's only one level of unwrapping in for, we might as well use map:

(defn mapvals [f m]
  (into {}
    (map (fn [[k v]] [k (f v)]) m)))
And we can get rid of the intermediate data (lazy sequence) created by map, by using arity-1 of map that returns a transducer, and arity-3 of into that accepts a transducer:
(defn mapvals [f m]
  (into {}
    (map (fn [[k v]] [k (f v)]))
    m))
Finally, if m is a sorted-map, or some other kind of map, the output will still be a hashmap, which is probably not what we want. To fix this, we can use empty:
(defn mapvals [f m]
  (into (empty m)
    (map (fn [[k v]] [k (f v)]))
    m))
This way, we're pretty fast and also preserve the type. This doesn't preserve metadata. That's another thing to think about. See also: https://ask.clojure.org/index.php/1926/adding-functions-map-vals-and-map-keys

Joshua14:07:36

Thank you for the in-depth reply. Makes more sense

Joshua13:07:49

but I'm thinking it's just an odd missing piece of the core library

Joshua13:07:04

So I wondered if I missed something or is this the start of my own util library

Joshua13:07:05

Ahh thanks. I'll take a look at these util libraries I'd missed

raphaelkieling13:07:29

hi guys, i'm a beginners and i would know how i can made a http request without download a library like cli-http

raphaelkieling13:07:55

i not found a simple to do that like

(simple-request :POST "...")

Joshua13:07:16

Are you looking for a simpler interface? Or to see what it's doing under the hood?

raphaelkieling13:07:31

yes for a simple interface without download a dependency

Alex Miller (Clojure team)13:07:09

well those goals are in conflict :)

Joshua13:07:52

Why are you avoiding a dependency?

Joshua13:07:24

If you do want to avoid a dep then I suppose you're limited to the core library. Try (slurp "")

Alex Miller (Clojure team)13:07:48

can't do a post that way

Alex Miller (Clojure team)13:07:54

at the bottom they're all using Java so you'd be doing a whole bunch of interop (something like https://www.baeldung.com/java-http-request)

raphaelkieling13:07:58

well, i'm question about that just because i was used to javascript and python that have simples interfaces like request and fetch

raphaelkieling13:07:49

but maybe this is a different way that i need to get used to

gerritjvv13:07:16

imho. After doing some python with its requests module, I really wished Java/Clojure any lang had something like this. Then I realised python's requests is a module you have to install, just like http-kit 🙂

gerritjvv13:07:42

pip install requests

Joshua13:07:56

I'm not familiar with those, but have you seen these examples? https://github.com/dakrone/clj-http#post Specifically (http/post "" {:body "hello!"}

Joshua13:07:03

It seems quite simple (to me)

Joshua13:07:46

There's an extra {:body ...} instead of just passing it. but that's where future options (which there likely will be) would go

raphaelkieling13:07:55

yess! i m using this to my study and i like that, maybe using javascript and script languages got me unaccustomed kk

gerritjvv13:07:29

clj-http does a nice job yes.

sova-soars-the-sora14:07:03

i'm trying to use a single .cljc file to span 2 projects... the namespace is messing it up so i'd like to make a library of it... i'm not sure how i would make it a usable local library file i could include with :require ... presumably i can compile it and put it on the classpath? not certain

dpsutton14:07:43

are you using deps.edn or lein?

dpsutton14:07:12

while i wait i'll explain the differences. If you are using deps.edn this is trivial. Just add a dependency on this new project and give it local coordinates while you develop it. I've also seen examples where this stays local coordinates and always just refer to the sibling projects the whole time. If lein, you can look into lein checkouts to have your local copy while developing. Will have to switch back to an artifact when done developing.

bartuka14:07:53

I used this https://github.com/s3-wagon-private/s3-wagon-private to create a private s3 bucket to host my local artifacts, so other projects could use it

sova-soars-the-sora14:07:05

haven't used deps.edn much but that sounds like a more convenient approach. there's one component file i need to stay synced between projects (it's rum/react stuff) so i think this is the way to go... how can i make sure a project is using deps.edn?

sova-soars-the-sora14:07:17

it's confusing, i thought it would be pretty smart to have the server and then a nested cljs project for the realtimey stuff, but now if i am trying to share a source file across 2 projects i make a library and every time i update the code i need to require a new library version?

kennytilton14:07:45

@watchtheblur When I wanted to get fancy with time I looked at the source. Turns out there is not a lot there:

(defmacro time
  "Evaluates expr and prints the time it took.  Returns the value of
 expr."
  {:added "1.0"}
  [expr]
  `(let [start# (. System (nanoTime))
         ret# ~expr]
     (prn (str "Elapsed time: " (/ (double (- (. System (nanoTime)) start#)) 1000000.0) " msecs"))
     ret#))
So I just wrote my own using that as a starting point.

dpsutton14:07:49

maybe don't nest them. make them the same project with two build artifacts?

dpsutton14:07:10

or a single build artifact. a jar that includes your cljs stuff

sova-soars-the-sora15:07:20

yeah maybe just de-nesting is the easiest way

herald15:07:19

Is (comp - compare) a good approach for reversing sort order? It seems to work perfect as far as I can tell, but it's not mentioned in any comment on ClojureDocs which makes me doubt myself.

dpsutton15:07:05

#(compare %2 %1)

dpsutton15:07:55

oh misread. that actually looks fine. was thinking it was using - as the compare function

herald15:07:06

ah, i forgot about swapping the arguments!

herald15:07:05

now I'm tempted to add both of them to clojuredocs since these tricks are easy to forget

herald15:07:01

thanks! I'll link that in the clojuredocs example.

jpmicena16:07:15

Hi all! When I using the next.jdbc.sql/insert! I noticed that I get a return such as {:last_insert_rowid() 5}. I was trying to get the returned id by using something like (:last_insert_rowid() insert-return) but that doesn’t work. Also, I noticed that I cant define the map {:last_insert_rowid() 5} (it gives me a (err) Map literal must contain an even number of forms) Am I getting something wrong here? the return from insert! is not an actual hash map?

ghadi16:07:17

this is a case of something creating a keyword programmatically that is not readable by the reader

ghadi16:07:20

so you can't type it

ghadi16:07:39

you can do (get thing (keyword "last_insert_rowid()"))

👍 6
Aviv Kotek17:07:35

hi, I have a function foo that receives n params (predicates), and i'd like to re-use some of them, is there any way to "def" the params? (defn foo [x & preds]) (foo x :a :b :c) i'd want something like that (def base :a :b) => (foo x base :c)

phronmophobic17:07:05

does the order of predicates matter? This would work if the order doesn't matter

(def base [:a :b])
(apply foo x :c base)

phronmophobic17:07:07

if the order does matter, than you can use the slightly clumsier:

(def base [:a :b])
(apply foo x (conj base :c :d :e :f) )

Aviv Kotek17:07:58

yep, forgot about apply, thanks!

noisesmith19:07:25

@aviv the normal idiom is something like this:

(let [base [:a :b]
      f (apply partial foo base)]
   ... ; assumed multiple uses of f
   (f :c :d :e :f))

noisesmith19:07:12

you could skip the def of base and the apply and just have f (partial foo :a :b) if that makes sense in your context

noisesmith19:07:41

oh never mind, you need a hole for x

sova-soars-the-sora21:07:01

client.cljs , server.clj , components.cljc ... but the components.cljc has a call to a javascript function in .cljs ... what do I do

sova-soars-the-sora21:07:26

because i tried naively including it via require refer and got circular dependency

phronmophobic21:07:33

@sova, there's not enough info to answer your question. Generally, some options are: • move the cljs function into the cljc file • use reader conditionals, https://clojure.org/guides/reader_conditionals depending on what the use case is, there are other options that might be better suited

sova-soars-the-sora21:07:41

Thanks @smith.adriane! details: sente project, using rum for components server and clientside; trying to call chsk-send! from components.cljc is not working. will try including it in the file + reader conditional. the whole file is reader conditionals but i'm a little confused on how to make the javascript components have access to my cljs functions

sova-soars-the-sora22:07:36

come to think of it, i'm not sure how to include the rum components either

sova-soars-the-sora22:07:48

because normal refers don't seem to do the trick

phronmophobic22:07:13

what’s in the components namespace that is used from clj?

phronmophobic22:07:52

ie. what’s the reason to not make components a cljs file

sova-soars-the-sora22:07:06

serverside rendering / all the components

sova-soars-the-sora22:07:37

figuring it would make more sense to put them in one file because then they can't be out of sync as they were getting...

sova-soars-the-sora22:07:54

(the serverside-pre-render and the clientside ui)

phronmophobic22:07:42

I'm not familiar with rum, but you might be able to export (https://clojurescript.org/reference/advanced-compilation#access-from-javascript) some functions like chsk-send! so that you can reference them in the server side rendered components

phronmophobic22:07:29

rum does mention server side rendering, https://github.com/tonsky/rum#server-side-rendering but it doesn't give much guidance. maybe there's a #rum channel where you can get rum specific advice for server side rendering

sova-soars-the-sora22:07:52

it's not important to have the serverside have js functionality to me, it just has to be an identical component in order to "hydrate" ... which inflates the dry html components with a javascript/reactive thingy without redrawing the whole page. pretty neat. but things gotta line up perfectly

phronmophobic22:07:00

where is chsk-send! being called then? seems like you could just use reader condtionals to remove those calls

sova-soars-the-sora22:07:26

it's being called inside the cljs versions of the components, yes i could remove it but how do i make them do stuff?

sova-soars-the-sora22:07:01

thanks for your help, i feel like i'm missing something obvious

phronmophobic22:07:26

i'm imagining something like:

[:div {:on-change #?(:cljs (fn [] (chsk-send! my-args))
                     :clj nil)}]

phronmophobic22:07:15

I'm assuming that the rehydration will fill in the correct on-change handler assuming the html matches

sova-soars-the-sora22:07:59

oh it will, but that means i have to keep this component inside the client.cljs file and not the .cljc file it seems.

phronmophobic22:07:31

the reader conditional means it should be fine in the cljc file

sova-soars-the-sora22:07:47

hmm okay, maybe the error is elsewhere.

phronmophobic22:07:51

you may also need a reader conditional around the require statement that brings in chsk-send!

sova-soars-the-sora22:07:21

i'm stumped about how to refer these rum components into the client.cljs

sova-soars-the-sora22:07:49

the line in components.cljc is (rum/defc component-name) ... not a (defn ...)

phronmophobic22:07:53

according to https://github.com/tonsky/rum#server-side-rendering, it seems like that it should be fine to have rum/defc in a clj file

phronmophobic22:07:52

that does make sense

ozzloy22:07:51

i see some projects have {:paths ["src"]} and some have {:paths ["src/clj" "src/cljs" "src/cljc"]}. i know that clj is clojure, cljs is clojurescript, and cljc is common stuff. what are the pros/cons of using one directory structure for all the code, vs separating code out into different directories?

sova-soars-the-sora22:07:04

at least, i try and keep a minimal number of files, other projects have different philosophies... for me it's simpler to reason about as "client/server/etc" but some people like having many cljs files or many clj

ozzloy22:07:57

so you prefer just having src, and not src/clj.?

sova-soars-the-sora22:07:03

personally, yes, i think if the number of files started getting large it would make sense to divide it up.

sova-soars-the-sora22:07:18

it usually looks like projectname/src/projectname/source.clj(s) for me. more interestingly you can use dots in the project name to create subfolders, you might see that in stuff like ring.util and ring.middleware

neilyio22:07:57

I was surprised to see how (), the empty list, behaves with when and if, as below.

(when () (prn "Am I really being printed?"))
;; prints "Am I really being printed?"

(when nil (prn "Am I really being printed?"))
;; does not print anything

neilyio22:07:32

Particularly because (true? ()) returns false.

neilyio22:07:58

I figure this has something to do when when and if being macros, but it feels like inconsistent behaviour. Could someone help me rationalize it? I think if I understand the reasoning, I'll be able to remember this behaviour better.

dpsutton22:07:11

(doc true?) might shed some light

dpsutton22:07:17

note its not truthy?

phronmophobic22:07:58

rather than true?, I think you might be looking for boolean

dpsutton22:07:25

(doc if) and (doc when) should give some light as well

neilyio22:07:41

Thanks, this is exactly what I was looking for. Clearly, "the thing I don't understand" is true? vs. truthy? vs. boolean, and it sounds little research into those will clear this up.

dpsutton22:07:21

The docstring of if gives the definitive answer here. The rest are some helper functions that might help you along the way

dpsutton22:07:39

> Evaluates test. If not the singular values nil or false, evaluates and yields then, otherwise, evaluates and yields else

dpsutton22:07:10

there are two values that "choose" the else branch, otherwise the then branch is chosen

neilyio22:07:48

Great! Someone also wrote a very helpful example on https://clojuredocs.org/clojure.core/if .

dpsutton22:07:25

clojuredocs is great. i'd recommend always read the docstring first and then look for examples and clarification after reading. your repl and doc are very powerful tools

👍 6