Fork me on GitHub
Tessy Thomas11:02:50

I have an array of art pieces. I want to find the route length and associate it with each art pieces. My code will look like: (defn load-art-routes [art-list ctx] (doall (map-indexed (fn [index art] (let [user-location (select-keys (:coords (sub> ctx :geolocation)) [:latitude :longitude]) art-location (:geoLocation art)] (->> (map-request {:origin (str (:latitude user-location) "," (:longitude user-location)) :destination (str (:lat art-location) "," (:lon art-location)) :mode (name (sub> ctx :transition-mode))}) (p/map (fn [data] (let [route-length (ocall js/Math "round" (/ (get-in data [:routes 0 :legs 0 :distance :value]) (* 0.621371192 1000)) 2) route-duration (ocall js/Math "floor" (/ (get-in data [:routes 0 :legs 0 :duration :value]) 60))] (js/console.log "load-art-routes route-length " route-length") (assoc art :route-length route-length)))) (p/error (fn [error] (util/log (str "GOOGLE DIRECTIONS API ERRORS" params) error) ))))) art-list)) art-list) (defn map-request [params] (when params (let [endpoint google-directions-api-endpoint] (->> (make-get-req (str endpoint "&" (encode-query-params params)) {}) (p/map (fn [data] (util/log "GOOGLE DIRECTIONS API " data) data)) (p/error (fn [error] (util/log (str "GOOGLE DIRECTIONS API ERRORS" params ) error) )))))) The route length calculation is correct but, assoc is not working. It is not actually associating it. I don't know what the issue is. Can anyone help me?


you have a " too many in line (js/console.log "load-art-routes route-length " route-length"), is that your problem? or a copypaste problem?

Tessy Thomas14:02:15

that is a copy pase problem. that is not real problem.


I'm trying a write a spec for this map to check its types, but I'm not exactly sure what the best way to spec a nested map is.

Alex Miller (Clojure team)14:02:21

by writing another map spec


well, I did that, but I was confusing qualified and unqualified keys so spec/valid? was returning false

Mario C.16:02:50

Any issues I should be aware of with saving to multiple databases using pmap? Say we have a map that looks like (def engines {:mongodb <mongodb connection> :postgres <postgres-db connection> :mariadb <mariadb connection>}) and I do something to the effect of (pmap <function that uses the connection to save to db> engines)


I'm unsure why that would be a problem, if you're using completely separate DB connections


If you were sharing a single DB connection to a single database, that might be a problem if your driver isn't threadsafe


Make sure you're prepared to handle any exceptions thrown by the save-function

Mario C.16:02:17

What I am unsure is the exception handling. Since pmap uses futures under the hood and Ive come across situations where I wont see the exceptions until I try to deref the future. If an exception occurs in one save function will the process continue to other save functions?

Mario C.16:02:42

How does semi lazy work? Will it save my data as its mapping or not until I try to consume the results?


It's a good question. I don't know the answer. But it might be worth writing code that behaves in exactly the way you want (and makes it explicit to readers of your code), rather than using pmap.


I imagine making use of pmap when the function is not side-effecting

Mario C.16:02:21

Thanks for the link.. I am going to have to some REPL testing then

Alex Miller (Clojure team)16:02:02

I think you have already asked enough specific questions that you will want something more than pmap

Alex Miller (Clojure team)16:02:51

it's a good quick and dirty answer for coarse-grained parallel tasks, but lacks all control over how that happens

Alex Miller (Clojure team)16:02:34

Java's built-in executors (queue + thread pool) gives you many more options

Alex Miller (Clojure team)16:02:50

claypoole is a decent clojure lib that gives you a nicer entry to that and other stuff

Mario C.17:02:13

Oh this looks interesting actually

Daniel Hines19:02:32

Why does comp work from right to left?


I think because it maps what you would write without comp, but cleaner


(count (vec '(1 2 3)))


is rewritten ((comp count vec) '(1 2 3)) if I'm not mistaken


It also mirrors how function composition is written in standard mathematical notation


(g ∘ f )(x) = g(f(x))

parens 5

but yeah that sometimes trips me up, too


right - it keeps the order of the functions, and moves / eliminates parens


In the system I've been working on, I have a complex business logic that must run both on server and client side. (due to performance non-functional requirements) I am writing this business logic in Clojure and it is nicely interacting with the rest of the server side controllers and services in Groovy (Grails). I have no experience on Clojurescript. My question is: Will I be able to use the same business logic functions, the same code itself, I wrote in Clojure, as Clojurescript in the client side? And make it interact with the rest of the client side interface in TypeScript/Angular? Is there any gotcha? That would be a major achievement on the project because we will avoid writing 2 codes, in 2 languages for the same (very) complex business logic. It will save us endless hours in both coding and testing. My understanding is that it is true if we keep the core of my business in "pure" Clojure, I mean, away from fancy dependencies that might exist only in Java world or Javascript world. Is that right?


the typical way to do this is use a cljc file, which allows conditional java side vs. js side code


IMHO using the actual java deps or js deps directly instead of a clojure wrapper is usually the right choice


and your java side or js side functions will be callable easily by java or js, yes

👍 5

If I remeber correctly, there are certain features you can't use on cljs, but once you know them, you can try to avoid them to have valid clj/cljs code


there are also features you can use in cljs but not clj - cljc makes this work


Look at the difference page


Perfect! Thank you guys!


After my first quick read through, I can say that it will work for me. This will be game changer here.


also I recommend using the transit lib for communication between client and server - it supports all the most common clojure data types directly, is easy to extend, and avoids a bunch of problems with just using edn directly


a common pattern when I had a mixed clj / cljs codebase was a core library file (cljc) that was shared, plus implementation files that were conditionally included with anything vm specific


I will take a look on that.

Alex Miller (Clojure team)19:02:19

and is much faster for clj to cljs


It might not be the case. The client side is written in Angular/TypeScript. Only a specific business logic will be written in ClojureScript. A vanilla TypeScript code will call the ClojureScript logic. The communication with server will be handled by TypeScript/Angular.

Alex Miller (Clojure team)19:02:10

there is a transit-js library

Alex Miller (Clojure team)19:02:36

the reason it's faster is that transit is actually done over the top of json and leverages the super fast json parsers in browsers

Alex Miller (Clojure team)19:02:27

and because it also supports caching of repeated map keys and things like that, it can actually be faster than json (even though it's done over json)

Alex Miller (Clojure team)19:02:50

which is admittedly counter-intuitive, but easy to show via measurements, which have been done


I will definitely take a good look on that. Thank you! Very helpful! You guys are awesome.


that's the one for jvm clojure, there's another one for javascript (doesn't even need cljs)