beginners

Getting started with Clojure/ClojureScript? Welcome! Also try: https://ask.clojure.org. Check out resources at https://gist.github.com/yogthos/be323be0361c589570a6da4ccc85f58f.
dpsutton 2021-01-18T00:25:22.474700Z

(reduce (fn [xs i] (conj xs i)) () (range 6)) always use an initial value. otherwise reduce uses the first value of the collection for the accumulator

solf 2021-01-18T03:02:21.475Z

Everyday I learn new things from reading #beginners

Mno 2021-01-18T09:03:29.476500Z

If you do a get request it works correctly though?

gibi 2021-01-18T09:07:34.476800Z

yep

Mno 2021-01-18T09:11:38.478700Z

Very odd, don't think I can guess an answer

lassemaatta 2021-01-18T09:12:01.479300Z

I'm guessing the indentation is wrong? I think you need to give create-default-handler as the second parameter to ring-handler perhaps?

gibi 2021-01-23T23:47:07.195200Z

@lasse.maatta apologies for the late reply. Yes, it was in the wrong position

gibi 2021-01-23T23:47:26.195400Z

create-resource-handler too

gibi 2021-01-23T23:47:29.195600Z

(def handler
  (reitit/routes
    (reitit/create-resource-handler
      {:path "/resources/"})
    (reitit/ring-handler
      (reitit/router routes)
      (reitit/create-default-handler
        {:not-found
         (constantly (response/not-found "404 - Not Found"))
         :method-not-allowed
         (constantly (response/method-not-allowed "405 - Method not allowed"))
         :not-acceptable
         (constantly (response/not-acceptable "406 - Not acceptable"))}))))

gibi 2021-01-23T23:47:36.195800Z

this way it works, thanks 👍

Yang Xu 2021-01-18T09:13:52.480900Z

Hi, I want to pass the PersistentVector to Clojure as a parameter when I invoke it from Java. How to do that?

PersistentVector fiedls = PersistentVector.create(Keyword.intern(null, "d"));
mergeSelect.invoke(m, fiedls);

(defn ms [m fields]
  (println (-> m (merge-select  fields) sql/format)))

Yang Xu 2021-01-19T11:36:08.114500Z

Thank you first, But I wonder why cannot use class of Clojure in Java? And I saw some project using it directly.

alexmiller 2021-01-19T13:52:24.133300Z

As a concrete class, it’s considered part of Clojure’s internals

alexmiller 2021-01-19T14:08:34.135600Z

the official Java API for invoking Clojure is the clojure.java.api.Clojure class. https://clojure.github.io/clojure/javadoc/clojure/java/api/Clojure.html

Yang Xu 2021-01-20T02:21:39.247700Z

Thank you again.

lassemaatta 2021-01-18T09:17:51.481300Z

evocatus 2021-01-18T09:34:16.482Z

Can macro be recursive?

evocatus 2021-01-27T23:41:36.023500Z

made another version https://github.com/reflechant/binary-pow/blob/main/src/binary_pow/core.clj

2021-01-18T09:35:48.482100Z

yes

2021-01-18T09:39:00.482600Z

(defmacro rec-example [n]
  (when (not= n 0)
    `(do ~n (rec-example ~(dec n)))))
as an example

evocatus 2021-01-18T09:43:26.482800Z

thanks!

evocatus 2021-01-18T09:44:11.483Z

Look what I did:

(defn square [x]
  (* x x))

(defmacro pow [x n]
  (cond (zero? n) 1
        (even? n) `(square (pow ~x ~(/ n 2)))
        :else `(* ~x (pow ~x ~(dec n)))))

evocatus 2021-01-18T09:44:30.483200Z

it's Newton-Raphson fast exponentiation

2021-01-18T09:47:45.483400Z

but why macro?

2021-01-18T09:47:51.483600Z

looks good btw

😀 1
evocatus 2021-01-18T09:49:37.483800Z

classic algorithm is not tail-recursive and I couldn't write a tail-recursive version for some time

evocatus 2021-01-18T09:49:55.484Z

but it's possible

evocatus 2021-01-18T09:50:26.484200Z

but I think a more elegant way would be to generate a sequence (lazy?) of numbers to multiply and then just reduce *

evocatus 2021-01-18T10:03:34.484600Z

no, actually it needs to be some kind of a stack to have logarithmic number of multiplications

evocatus 2021-01-18T10:04:17.484800Z

basically we square x and then optionally multiply once by x

jaihindhreddy 2021-01-18T10:12:44.485Z

@gr.evocatus The caveat to your macro version is that it will work only with numbers. For example, the following will fail:

(def x 2)
(def n 7)
(pow x n) ;; will blow up
Here's the same thing as a function, and a macro on top optimising some very simple cases:
(defn pow-fn [x n]
  (loop [base x
         prod 1
         exp n]
    (if (zero? exp)
      prod
      (recur
        (* base base)
        (if (even? exp)
          prod
          (* prod base))
        (quot exp 2)))))

(defmacro pow [x n]
  (cond (zero? n) 1
        (= x 1) 1
        (zero? n) 0
        (= n 1) x
        (= n 2) `(let [x# ~x] (* x# x#))
        :else `(pow-fn ~x ~n)))
This way, if the base or the exponent is 0 or 1 (the literal), evaluation happens at compile time. Similarly, if the exponent is the literal 2, then it macroexpands into a multiplication (with let used so that any side effects only happen once). For example, check out (macroexpand '(pow 3 2))

😮 1
evocatus 2021-01-18T10:18:48.485300Z

Great! But I believe you mistyped in the macro. Third line in cond form should be (zero? x) 0

💯 1
jaihindhreddy 2021-01-18T10:29:35.485500Z

Oops! Good catch.

Piotr Brzeziński 2021-01-18T12:19:10.488300Z

Hello 🙂. Following the “Living Clojure” I’ve ran into another issue that I’m unable to resolve. I am setting up clojurescript in my project and I was asked to run lein trampoline cljsbuild repl-rhino in my project root. It downloaded bunch of things and then failed when trying to build (I suppose?)

Exception in thread "main" Syntax error compiling at (cljsbuild/repl/rhino.clj:1:1).
.....
Caused by: java.io.FileNotFoundException: Could not locate cljs/repl/rhino__init.class, cljs/repl/rhino.clj or cljs/repl/rhino.cljc on classpath.
does rhino have to be added as one of dependencies/plugins? My deps look like that
:dependencies [[org.clojure/clojure "1.10.0"]
                   [compojure "1.6.1"]
                   [ring/ring-defaults "0.3.2"]
                   [ring/ring-json "0.5.0"]
                   [org.clojure/clojurescript "1.10.764"]]

Piotr Brzeziński 2021-01-19T13:32:13.130800Z

Sorry, I haven’t noticed your answer. Thanks for looking into my problem!

Christian 2021-01-18T12:51:40.491500Z

If I have something like

(vector (* 2 (range 1 100)))
Will the calculation of this will be done in parallel? I don't know how to pose the question. I want want to know, if I have to put in special measures to make clojure use the full potential of my machine with multiple threads, cores and cpus?

Hagenek 2021-01-18T12:52:51.492Z

I am getting some strange error from compojure, must be something silly. Here is my code:

(defn splash []
  {:status 200
   :headers {"Content-Type" "text/plain"}
   :body "Hello from Heroku"})

(defroutes app []
  (GET "/" [] splash)
  (ANY "*" []
       (route/not-found (slurp (io/resource "404.html")))))

(defn -main [& [port]]
  ; (setup-state)
  (let [port (Integer. (or port (env :port) 5000))]
    (jetty/run-jetty (site #'app) {:port port :join? false})))
And output from terminal:
➜  clojure-getting-started git:(main) ✗ lein run
2021-01-18 13:51:54.389:INFO::main: Logging initialized @3562ms to org.eclipse.jetty.util.log.StdErrLog
2021-01-18 13:51:54.802:INFO:oejs.Server:main: jetty-9.4.12.v20180830; built: 2018-08-30T13:59:14.071Z; git: 27208684755d94a92186989f695db2d7b21ebc51; jvm 11.0.7+10
2021-01-18 13:51:54.865:INFO:oejs.AbstractConnector:main: Started ServerConnector@6432fa28{HTTP/1.1,[http/1.1]}{0.0.0.0:5000}
2021-01-18 13:51:54.865:INFO:oejs.Server:main: Started @4039ms
2021-01-18 13:52:05.203:WARN:oejs.HttpChannel:qtp197080602-17: /
java.lang.IllegalArgumentException: Key must be integer
	at clojure.lang.APersistentVector.invoke(APersistentVector.java:294)
	at compojure.core$routing$fn__2329.invoke(core.clj:185)
	at clojure.core$some.invokeStatic(core.clj:2701)
	at clojure.core$some.invoke(core.clj:2692)

roelof 2021-01-18T13:25:53.005600Z

Do not kmow if this is the right channel but if there is here a exercism mentor can he/she look at my bob challenge . I almost wait for a week for mentoring

Ilmari Pohjola 2021-01-18T13:28:43.007600Z

Hello everyone! I'm new here. Could anyone recommend any tutorial on how to publish a VERY simple web service on any cheap server using Clojure. F.E.. I have done one locally using Ring and some other libraries and I can return json as a response (this one https://github.com/anan44/it-starts-with-clojure). So it works in local server, but I want to apply it globally. Basically I just want expose a simple API (no need for Database or such). I am very uneducated in web-programming and Clojure (I'm a mathematician), so my questions might not even make any sense (please don't get frustrated), but I do have some decent experience in coding OOP-languages generally.

1
Ilmari Pohjola 2021-01-19T09:03:15.105700Z

Thanks a lot!! Yeah I am going to use Azure App Service later, but maybe the manual steps will help me to understand some of the magic of web-development.

Ilmari Pohjola 2021-01-24T13:12:58.213Z

I tried to deploy a very simple Api to Heroku, but the heroku instructions used compojure, and the tutorial I followed did not. I ran into lot's of difficulties. Currently the app crashes, and the stack trace shows the problem. There seems to be a syntax error in ring/util/servlet.clj:1:1 if I understand correctly. However I have not touched or even found the ring source code, so how can there be a syntax error? Is it likely that I am missing a depency? Picked up JAVA_TOOL_OPTIONS: -Xmx300m -Xss512k -XX:CICompilerCount=2 -Dfile.encoding=UTF-8 2021-01-24T12:54:12.831812+00:00 app[web.1]: Syntax error (ClassNotFoundException) compiling at (ring/util/servlet.clj:1:1). 2021-01-24T12:54:12.831836+00:00 app[web.1]: javax.servlet.AsyncContext

Ilmari Pohjola 2021-01-24T13:20:26.213200Z

(ns mutable-app.web   `(:require`    `[ring.adapter.jetty :as jetty]`    `[environ.core :refer [env]]`    `[ring.middleware.params :as params]`    `[reitit.ring.middleware.muuntaja :as muuntaja]`    `[muuntaja.core :as m]`    `[reitit.ring.coercion :as coercion]`    `[reitit.ring :as ring]`    `[endpoints]))` (def app   `(ring/ring-handler`    `(ring/router`     `[endpoints/math-routes]`     `{:data {:muuntaja   m/instance`             `:middleware [params/wrap-params`                          `muuntaja/format-middleware`                          `coercion/coerce-exceptions-middleware`                          `coercion/coerce-request-middleware`                          `coercion/coerce-response-middleware]}})`    `(ring/create-default-handler)))` (defn -main [& [port]]   `(let [port (Integer. (or port (env :port) 5000))]`     `(jetty/run-jetty #'app {:port  port`                             `:join? false})))`

Ilmari Pohjola 2021-01-24T13:21:05.213400Z

(ns endpoints (:require [ring.util.http-response :as response])) (def addition  ["/addition" {:get (fn [request]                                      `(let [params (:query-params request)`                                            `x (Long/parseLong (get params "x"))`                                            `y (Long/parseLong (get params "y"))]`                                        `(response/ok {:total (+ x y)})))}])` (def math-routes   `["/math"`    `addition])`

Ilmari Pohjola 2021-01-24T13:22:15.213600Z

And the project file (defproject mutable-app "1.0.0-SNAPSHOT"   `:description "FIXME: write description"`   `:url "http://mutable-app.herokuapp.com"`   `: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.10.1"]`                  `[ring "1.8.1"]`                  `[metosin/reitit "0.4.2"]`                  `[metosin/ring-http-response "0.9.1"]`                  `[ring/ring-jetty-adapter "1.2.2"]`                  `[ring/ring-devel "1.2.2"]`                  `[environ "0.5.0"]]`   `:min-lein-version "2.0.0"`   `:plugins [[environ/environ.lein "0.2.1"]]`   `:uberjar-name "mutable-app-standalone.jar"`   `:profiles {`       `:production {:env {:production true}`        `:uberjar {:aot :all}}})`

Ilmari Pohjola 2021-01-24T13:28:19.213900Z

And finally the procfile: web: java $JVM_OPTS -cp target/mutable-app-standalone.jar clojure.main -m mutable-app.web

jumar 2021-01-25T06:35:22.233900Z

There might be something bad with the dependencies - like version conflicts. You can use lein deps :tree to investigate that. Also please include the whole stacktrace - you only pasted a very small portion of it. Slack tip: Use tripe backticks for longer code blocks:

<your code here>

Ilmari Pohjola 2021-01-18T13:31:58.007800Z

Heroku seems to be a good place to start.

👍 1
jumar 2021-01-18T13:40:50.008200Z

The typical advice is to "build an uberjar" and "run it wherever you like". You can just spin up a virtual machine at any provider like AWS, Digital Ocean, Hetzner (quite limited but cheaper) - but it depends on what kind of project this is. Does it have to be always available? Is it just for you and/or friends or something more serious?

Mno 2021-01-18T13:45:16.008400Z

fairly certain it’s not done in parallel/concurrently

2021-01-18T13:46:16.008600Z

If you mean map , then no, it will be applied sequentially:

(map #(do (print %) (* 2 %)) (range 1 10))
;; 123456789
;; =&gt; (2 4 6 8 10 12 14 16 18)
For simple cases of parallelization you could use pmap

Mno 2021-01-18T13:49:10.008800Z

ohhh today I was reminded of the existence of pmap

👍 1
Mno 2021-01-18T13:53:24.009100Z

I suppose if you want to do truly concurrent stuff you could take a look at: https://clojure.org/about/concurrent_programming or Rich’s http://2.hr talk on the matter: https://www.youtube.com/watch?v=nDAfZK8m5_8

👀 1
Mno 2021-01-18T13:53:53.009400Z

maybe even core.async, manifold, Java threads, etc… but that’s a bit overkill

pavlosmelissinos 2021-01-18T13:58:30.009900Z

you could also check out #code-reviews

alexmiller 2021-01-18T14:00:32.013100Z

Don’t call that - you should consider PV to be Clojure internals. Either use Clojure.read() to read a literal vector or obtain the vector function with Clojure.var() and .invoke() it.

Andrei Stan 2021-01-18T14:11:38.017Z

Hi guys, i'm struggling to get out from this problem i have: I am trying to write a function to get from:

(let [data ([{:id 1 :client-data [{:tag "client data here"}]}
               {:id 1 :document-data [{:tag "docs all around"}]}
               {:id 1 :document-data [{:tag "docs here"}]}
               {:id 1 :document-data [{:tag "docs there"}]}]
              
              [{:id 2 :client-data [{:tag "client2 data here"}]}
               {:id 2 :document-data [{:tag "docs2 all around"}]}
               {:id 2 :document-data [{:tag "docs2 here"}]}
               {:id 2 :document-data [{:tag "docs2 there"}]}])]
    ...........
    )
a new set of data like this form:
{
 {:client-data [{:tag "client data here"}]
   :document-data [[{:tag "docs all around"}]
                  [{:tag "docs here"}]
                  [{:tag "docs there"}]]
 {:client-data [{:tag "client2 data here"}]
  :document-data [[{:tag "docs2 all around"}]
                  [{:tag "docs2 here"}]
                  [{:tag "docs2 there"}]]
                                     
}
Thanks

Andrei Stan 2021-01-18T14:27:40.021400Z

@qmstuart hi, can u please write again your solutio, i would like to try it. Thanks

2021-01-18T14:27:52.021700Z

I realised after it was putting rogue nils in

Andrei Stan 2021-01-18T14:28:01.021900Z

Oh. Ok

2021-01-18T14:28:07.022100Z

(-&gt;&gt; (apply concat data)
       (group-by :id)
       (mapv (fn [[_ x]]
               {:client-data   (:client-data (first x))
                :document-data (-&gt;&gt; (map (fn [i] (:document-data i)) x) (remove nil?))})))

Ilmari Pohjola 2021-01-18T14:29:38.022300Z

It is just for learning purposes. I have built an uberjar, but the parts "run it wherever you want" and "spin up a virtual machine" are something, that I don't understand. Also in my current code I have specified a port for the server. I have no idea, what effect this has if I just "insert" the uberjar to some other environment than my own laptop. By the way. How do you paste code neatly here. I've seen others do it.

Ilmari Pohjola 2021-01-18T14:31:54.022800Z

I don't expect anyone to answer all these questions, and was hoping there would be some tutorial project you could point me to.

2021-01-18T14:32:18.023Z

Not a complete solution (+ should the result really be a map?), but something hopefully helpful:

(-&gt;&gt;
 [{:id 1 :client-data [{:tag "client data here"}]}
  {:id 1 :document-data [{:tag "docs all around"}]}
  {:id 1 :document-data [{:tag "docs here"}]}
  {:id 1 :document-data [{:tag "docs there"}]}]
 (map #(select-keys % [:client-data :document-data]))
 (apply merge-with vector))
;; =&gt; {:client-data [{:tag "client data here"}],
;;     :document-data
;;     [[[{:tag "docs all around"}] [{:tag "docs here"}]] [{:tag "docs there"}]]}

2021-01-18T14:37:21.023700Z

You can make that last bit a little cleaner: (-&gt;&gt; x (map :document-data) (remove nil?))

Ilmari Pohjola 2021-01-18T14:39:48.023800Z

All tutorials that I have found which say "from start to the end - complete etc..." usually miss this part. I have found this "real" deployment -part somewhere else, but they have used some Visual Studio -machinery which basically hides the magic and prevent the understanding (although later on I would use them). I have written an application with VS-code and run it with Leiningen right now. It runs locally. Now I just want to make it so, that I can send the http-requests from the internet. I do believe "complete web-application" -tutorials should always include this part.

2021-01-18T14:40:31.024600Z

I'm sure there must be a way to do this with merge?

Andrei Stan 2021-01-18T14:40:51.025Z

Thanks guys, i’ll check it when i’ll get back home

Ilmari Pohjola 2021-01-18T14:43:36.025200Z

(def app
    (ring/ring-handler
     (ring/router
      [endpoints/math-routes]
      {:data {:muuntaja   m/instance
              :middleware [params/wrap-params
                           muuntaja/format-middleware
                           coercion/coerce-exceptions-middleware
                           coercion/coerce-request-middleware
                           coercion/coerce-response-middleware]}})
     (ring/create-default-handler)))

(defonce running-server (atom nil))

(defn start
  []
  (when (nil? @running-server)
    (reset! running-server (jetty/run-jetty #'app {:port  3000
                                                   :join? false})))
  (println "Server running in port 3000"))

Mno 2021-01-18T14:43:41.025400Z

merge-with is probably much more suited for this, but I’m a bit too lazy atm to draw up some code

Ilmari Pohjola 2021-01-18T14:47:47.025800Z

This is the essential part. If I just build an uberjar, and "place it" to f.e. Azure App Service with some Azure -instructions, should it be ready to go then?

2021-01-18T14:55:01.026Z

see above -- iianm something like (map (partial apply merge-with vector)) on grouped map values here should be close to what OP wanted

Mno 2021-01-18T14:59:27.026200Z

:thumbsup:

roelof 2021-01-18T15:03:20.027100Z

anyone who can give me a hint how I can make palingdrome checker that works for this case (true? (__ [:foo :bar :foo]))

clyfe 2021-01-18T15:04:13.028100Z

is the thing equal to it in reverse?

roelof 2021-01-18T15:05:25.028600Z

I thought so but with this code #(= (clojure.string/join (reverse %) %)))  it fails

Eamonn Sullivan 2021-01-18T15:06:35.028800Z

user&gt; (defn palindrome? [thing] (= thing (reverse thing)))
#'user/palindrome?
user&gt; (true? (palindrome? [:foo :bar :foo]))
true
Is that what you are looking for?

clyfe 2021-01-18T15:07:28.029100Z

string join operates on strings not lists; why do you need joining anyway? compare collections! https://clojure.org/guides/equality

roelof 2021-01-18T15:07:31.029300Z

nope, that one fails on a string

roelof 2021-01-18T15:08:11.029500Z

lets say I have "racecar"

roelof 2021-01-18T15:08:30.029700Z

when I reverse it , I get a collection of characters

roelof 2021-01-18T15:08:38.029900Z

and those two are not the same

clyfe 2021-01-18T15:08:47.030100Z

https://clojuredocs.org/clojure.core/seq ponder on this thing

roelof 2021-01-18T15:09:00.030300Z

so I thought joining them will solve it , but not

roelof 2021-01-18T15:09:21.030500Z

ponder ?

clyfe 2021-01-18T15:09:23.030700Z

tip: make the string a list not the list a string

roelof 2021-01-18T15:10:05.030900Z

oke, time to experiment more

Eamonn Sullivan 2021-01-18T15:16:24.031700Z

(defn palindrome? [thing] (cond 
                            (string? thing) (= (clojure.string/reverse thing) thing)
                            (seq? thing) (= (reverse thing) thing)
                            :else false))
One way. Probably not the best way.

yonatan braude 2021-01-18T15:16:58.032400Z

hi everyone 🙂 what does ^ mean in ^{key: "value"} ?

roelof 2021-01-18T15:18:45.032500Z

can be a lot shorter

#(= (reverse %) (seq  %))
@claudius.nicolae @eamonn.sullivan

🎉 2
2021-01-18T15:18:47.032700Z

The ^ indicates that the map that follows is metadata that is associated with the thing that follows, where the thing that follows is usually a collection or symbol.

2021-01-18T15:19:47.033Z

You can see read some more about it here if you wish: https://clojure.org/guides/weird_characters#_and_metadata

👍 1
🙏 1
2021-01-18T15:20:05.033200Z

the rest of that page has lots of good description of other special syntax characters in Clojure

Daniel Stephens 2021-01-18T15:26:17.033500Z

something similar:

(let [data '([{:id 1 :client-data [{:tag "client data here"}]}
              {:id 1 :document-data [{:tag "docs all around"}]}
              {:id 1 :document-data [{:tag "docs here"}]}
              {:id 1 :document-data [{:tag "docs there"}]}]

             [{:id 2 :client-data [{:tag "client2 data here"}]}
              {:id 2 :document-data [{:tag "docs2 all around"}]}
              {:id 2 :document-data [{:tag "docs2 here"}]}
              {:id 2 :document-data [{:tag "docs2 there"}]}])]
  (map
    #(do {:client-data (some :client-data %)
          :document-data (keep :document-data %)})
    data))

Christian 2021-01-18T16:14:11.033900Z

I was mainly interested in knowing how much concurrency is applied automatically behind the scenes

Christian 2021-01-18T16:14:25.034100Z

Thanks for the link, I'll take a look

2021-01-18T16:26:09.034300Z

I don't think concurrency/parallelization can be applied behind the scenes as long as we allow for functions with side effects. Unless of course we never want determinism guarantees 🙂 But even then, I'd be surprised if performance would not soon become a problem in behind-the-scenes-auto-parallelized computations (but happy to be shown otherwise)..

Andrei Stan 2021-01-18T16:29:43.034500Z

@qmstuart @dstephens thank you guys for your time, Daniel's solution works better

jumar 2021-01-18T16:39:37.034900Z

Yes, you should. THe cloud offerings are vastly different. One way is to: 1. register an account at AWS / Digital Ocean / Hetzner / whatever 2. Create a machine from a template (e.g. Ubuntu version x.y) 3. SSH into the machine 4. Build your uberjar 5. Copy the uberjar to the machine 6. Run it via java -jar my-uberjar.jar 7. Make sure to expose the port on the instance firewall (e.g. AWS uses "Security groups" for that) 8. Check if you can access it This is of course a lot of manual work so for anything more serious you want to improve and consider other offerings. One option is to have Azure App Service where you can define a dockerfile to run your service (it can be a really simple wrapper around the uberjar)

frankitox 2021-01-18T16:42:04.035500Z

Hi! I'd like to know what's the best practice when using a library that is not an explicit dependency but transitive of an already declared dep. Should I make it explicit adding it to the list of dependencies?

frankitox 2021-01-18T16:43:11.035600Z

For example, taoensso.timbre depends on taoensso.encore. I'd like to use taoensso.encore/filter-kvs on my project. I did clj -Stree to list the dependency tree. Now to make the dependency explicit I added taoensso.encore to the list of :exclusions of timbre and then added taoensso.encore in a new line. I used to do this on leiningen, but I'm not completely sure this translates 1 to 1 to clj deps. Hope I'm not missing something here 😅

2021-01-18T16:50:53.035800Z

It is better to explicitly declare all dependencies. For example taoensso.timbre might remove taoensso.encore from provided dependencies without changing its API. And your application suddenly will stop working. and this will nether be a case if your explicitly depend on it.

2021-01-18T16:52:19.036Z

in clj cli top-level dependencies takes precedence over transitive one (if the version is higher). so you probably don’t need exclusions either. Only in rare cases when you need top-level dependency to have lower version than the one comming with another lib

alexmiller 2021-01-18T16:58:41.037700Z

Declare all deps that you explicitly use. Don’t declare deps that you don’t explicitly use (let them be selected as transitive deps).

alexmiller 2021-01-18T16:59:04.038200Z

That should be the general practice

alexmiller 2021-01-18T17:00:35.040600Z

The most common reason to diverge from that is if you are resolving a conflict between versions when the same transitive dep is included multiple times (either by declaring a top level dep/version or by using exclusions)

dgb23 2021-01-18T17:10:39.042100Z

Is my assumption correct that the textual representation of keywords gets compiled away, which could have positive implications on performance over using strings in some cases?

bronsa 2021-01-18T17:13:22.042500Z

no, a keyword is always backed by a string

2021-01-18T17:14:42.044Z

The Clojure/Java implementation does store the string representing a keyword at most once for each keyword, whereas many strings with the same sequence of characters have no such guarantee (i.e. they might all be different JVM objects in memory for strings)

dpsutton 2021-01-18T17:15:24.044700Z

when keywords are compared, are the underlying strings compared for equality (and therefore each character in turn compared i guess) or is there a faster compare?

2021-01-18T17:16:02.045800Z

Clojure/Java uses reference (i.e. pointer) equality between keywords, identical? . I think ClojureScript is different, but don't know the details.

2021-01-18T17:17:16.047200Z

When Clojure/Java reads a keyword, there is a hash lookup on the text of the keyword to see if there is already a keyword object with the same string, part of the process called 'interning', which guarantees that there is at most one JVM object for each keyword.

dpsutton 2021-01-18T17:17:23.047500Z

ok. so it would be the case that keywords could have positive implications on performance over using strings in some cases?

2021-01-18T17:17:34.047800Z

yes

bronsa 2021-01-18T17:17:34.047900Z

yep

dpsutton 2021-01-18T17:18:12.049Z

ah, your "no" was about the textual representation of keywords compiled away, not about the possibility of some positive performance gains

👍 2
dgb23 2021-01-18T17:18:21.049200Z

Thank you @andy.fingerhut, @bronsa and @dpsutton.

frankitox 2021-01-18T17:26:47.050300Z

Thank you so much both 😀, that's what I suspected but wanted to be sure. In this other case you mention Alex, is there any tool to check if there's such a conflict? Or will I get a warning from the cli? Or I need to keep an eye on the output of clj -Stree each time I add a new library?

alexmiller 2021-01-18T17:29:58.053400Z

You won’t get any error or warning from the cli - it has no way to tell whether there is an issue and will generally just pick the newest version of the library. You might encounter issues at runtime if a newer version of a lib breaks backwards compatibility

alexmiller 2021-01-18T17:31:11.054900Z

In the Clojure community there is a culture of minimizing such changes so this is relatively uncommon

dpsutton 2021-01-18T17:44:35.055600Z

this seems kotlin related. does this have any tie to Clojure?

frankitox 2021-01-18T17:52:44.055900Z

Ahh, alright. Yess, I think I only had trouble once with dependencies. Just realized https://github.com/SevereOverfl0w/vizns can help me here, it shows non-declared transitive deps as red nodes. I'll take a peep to that now. Thanks!!

popeye 2021-01-18T18:22:18.057300Z

I have similar condition in my script

(and (nil? cond1) (nil? cond2) (nil? cond3) )

popeye 2021-01-18T18:22:27.057600Z

can this be shortened ?

popeye 2021-01-18T18:22:53.058300Z

lets consider we have n number of nil? condition

2021-01-18T18:22:54.058400Z

(every? nil? [cond1 cond2 cond3])

🙌 1
dpsutton 2021-01-18T18:23:31.058900Z

this might change the semantics if you rely on short circuiting and side effects

dpsutton 2021-01-18T18:24:23.059600Z

oh nevermind. every should be fine

2021-01-18T18:24:23.059700Z

are you saying every doesn't short circuit?

dpsutton 2021-01-18T18:24:47.060400Z

was thinking there might be some laziness underneath so it might run into chunking issues but just read the source

popeye 2021-01-18T18:25:34.060900Z

how laziness causes here?

ghadi 2021-01-18T18:26:54.061500Z

use truthiness to your advantage (and cond1 cond2 cond3)

🙌 1
dpsutton 2021-01-18T18:27:47.061800Z

it doesn't. i was completely mistaken

2021-01-18T18:33:08.063300Z

it is more like (and (not cond1) (not cond2) (not cond3)) assuming you are fine treating nil and false the same, which can then be (not (or cond1 cond2 cond3))

Mno 2021-01-18T19:21:07.064200Z

Lesson learned there’s quite a few ways to do things. 😅

roelof 2021-01-18T19:56:01.065100Z

is there somewhere a example how to send data to a template with ring and compojure ?

roelof 2021-01-19T09:22:10.105900Z

so as I understand you all well. I do not have to make a seperate template but it is also a method ?

2021-01-19T15:26:09.141600Z

the "template" is a clojure data structure, you can use standard clojure functions to construct that data structure and include the items you need to display

2021-01-19T15:30:45.141800Z

this example might help:

$ clj -Sdeps '{:deps {hiccup/hiccup {:mvn/version "1.0.5"}}}'
Clojure 1.10.1
(ins)user=&gt; (require '[hiccup.core :as hic])
nil
(ins)user=&gt; (hic/html [:img {:src "foo.png"}])
"&lt;img src=\"foo.png\" /&gt;"
(ins)user=&gt; (def images ["foo.png" "bar.png" "baz.png"])
#'user/images
(ins)user=&gt; (hic/html [:div (for [img images] [:img {:source img}])])
"&lt;div&gt;&lt;img source=\"foo.png\" /&gt;&lt;img source=\"bar.png\" /&gt;&lt;img source=\"baz.png\" /&gt;&lt;/div&gt;"
(ins)user=&gt; (hic/html [:html [:body [:div (for [img images] [:img {:source img}])]]])
"&lt;html&gt;&lt;body&gt;&lt;div&gt;&lt;img source=\"foo.png\" /&gt;&lt;img source=\"bar.png\" /&gt;&lt;img source=\"baz.png\" /&gt;&lt;/div&gt;&lt;/body&gt;&lt;/html&gt;"

roelof 2021-01-19T15:31:38.142Z

oke im used to that template are seperate files in a seperate directory

roelof 2021-01-19T15:31:58.142200Z

but that seems to be not needed here

2021-01-19T15:40:34.146300Z

right "template" is a more abstract concept here haha - using a file is one convention for templating, but eg. format is documented to take a "template string" as an argument

2021-01-19T15:41:32.146500Z

if you prefer a separate template file, you can actually do this with hiccup, with an edn file (plus a function to fill in your input...) but it's often simpler and clearer to do inline definitions of data structures

roelof 2021-01-19T15:42:38.146700Z

oke, time to experiment

roelof 2021-01-19T15:42:58.146900Z

and later to see how I can add css to the mix

roelof 2021-01-19T15:43:23.147100Z

Right now I have a big css file that does things and I use there before and after filters

2021-01-19T15:46:15.147300Z

that works just fine with hiccup (you can add the style names in the {} attribute maps of the elements, and use a [:style "..."] or [:link {:rel "stylesheet" :href "/foo.css"} ...] or whatever to include the css in the page

2021-01-19T15:46:34.147500Z

and of course you can put string html snippets inside a hiccup if that's easier

roelof 2021-01-19T15:48:38.147700Z

oke, one small step at the time

roelof 2021-01-19T15:48:53.147900Z

first experiment till I have the html I want

2021-01-19T15:49:17.148100Z

yeah - the hiccup rules are very simple once you get used to them, and it's easy to test any helpers with string comparison

roelof 2021-01-19T15:56:05.148300Z

as everything in clojure 😛

2021-01-19T15:57:07.148500Z

ideally :D

roelof 2021-01-19T15:57:36.148700Z

was joking

roelof 2021-01-19T16:02:17.150200Z

but clojure is al totally other beast then the languages I worked with

2021-01-19T16:03:18.150800Z

have you seen the "simple vs. easy" talk? in many ways clojure is simpler than mainstream options, but less easy

roelof 2021-01-19T16:03:55.151100Z

nope,I did not see that talk

2021-01-19T16:04:31.151600Z

it's an enjoyable talk, and might help you understand clojure's design

roelof 2021-01-19T16:07:40.151800Z

oke will do that

dgb23 2021-01-18T20:00:41.065400Z

an html template?

2021-01-18T20:01:25.065700Z

neither ring nor compojure offer templates, so you need to pick a templating library implementation, the answer will depend on which one you use

2021-01-18T20:02:02.065900Z

hiccup has the advantage that the whole thing is vanilla clojure data until you compile to html, selmer has the advantage of being a normal templating language

roelof 2021-01-18T20:02:15.066100Z

yep, and im thinking of using hiccup first

roelof 2021-01-18T20:02:25.066300Z

later maybe use one of the react one

dgb23 2021-01-18T20:02:34.066500Z

Hiccup is simple and popular, other, more advanced libraries are using its syntax or depending on it

2021-01-18T20:02:49.066700Z

https://github.com/weavejester/hiccup the README should be enough to get you started

dgb23 2021-01-18T20:03:51.067Z

a similar dichotomy exists with honeysql and hugsql

dgb23 2021-01-18T20:04:15.067200Z

one defines sql as clojure data-structures and the other is a nice abstraction over templating sql

2021-01-18T20:04:33.067400Z

regarding react: you'll likely find it much easier to start with server side rendering, cljs and react wrappers add a lot of new weirdness beyond what you are working with now

dgb23 2021-01-18T20:04:55.067600Z

I very much agree with this!

roelof 2021-01-18T20:05:24.067800Z

I know that is why I said that maybe later I will do that

roelof 2021-01-18T20:11:26.068Z

I will again google to find a answer

roelof 2021-01-18T20:11:47.068200Z

What im trying to do is to display data I fetched from a external api

2021-01-18T20:12:16.068400Z

I linked to the hiccup readme, it uses the same syntax as the popular react frontends, and it includes multiple examples

roelof 2021-01-18T20:18:50.069700Z

I will and had take a look at it but could not find what im looking foor

sova-soars-the-sora 2021-01-18T20:18:53.069900Z

Hi everybody. Hope you are happy and having a smooth day. I was wondering just now... Is there a way I can "screen scrape" content that is loaded by javascript? If I retrieve the HTML of the page it does not have the info I want on it [yet]. Is there a way to programmatically scrape a page after the javascript loads?

Andrew 2021-01-19T08:58:31.105500Z

Is there a reason that you can’t use Puppeteer or Selenium ? https://pptr.dev/ https://www.selenium.dev/

2021-01-18T20:19:41.070Z

could you describe what you are looking for? when I look at it that's the first thing I see, it's a function that takes a data structure and returns html

2021-01-18T20:20:08.070200Z

your "templating" is done by filling in the data in the data structure (a normal function does that, you don't need anything special)

2021-01-18T20:21:19.071200Z

this library uses a normal web browser as a tool for that task https://github.com/igrishaev/etaoin

2021-01-18T20:21:56.071500Z

I don't know of something that is just java/clojure that would reliably fill in the html in a compatible way

sova-soars-the-sora 2021-01-18T20:21:59.071700Z

interesting! it seems like I just have to invoke "render" on the html somehow...

AC 2021-01-18T20:22:09.071900Z

one option I have used in the past (with python+beautifulsoup) is geckodriver to fetch and render the page and then grab/interact with the DOM. https://github.com/mozilla/geckodriver

sova-soars-the-sora 2021-01-18T20:22:19.072200Z

Right on. Well I might be able to use some python thing to scrape and then clojure to render later...

2021-01-18T20:22:25.072400Z

right - the problem is that frontend devs are not targetting the html spec (which some clojure lib might implement), they are targetting specific browsers

sova-soars-the-sora 2021-01-18T20:22:47.072600Z

Ah, right.

2021-01-18T20:22:54.072800Z

@agile-cactus yeah etaoin uses geckodriver, but it also works with chrome

👍 1
sova-soars-the-sora 2021-01-18T20:23:21.073100Z

There is also something called PhantomJS ...

2021-01-18T20:23:39.073300Z

really the ideal thing is to be able to drive the exact renderer / browser that the web app dev is targetting

roelof 2021-01-18T20:23:51.073500Z

The last few days I make a method called get-data that fetches some data from a external api. Now I try to find a way to send the output of that method to hiccup so I can display it

roelof 2021-01-18T20:24:15.073700Z

or that hiccup can ask for that data

2021-01-18T20:24:22.073900Z

@sova it exists but is no longer maintained, and I assume no web app dev is ensuring their code works with phantomjs

2021-01-18T20:25:22.074100Z

hiccup takes one kind of data: a clojure dta structure

dgb23 2021-01-18T20:25:25.074300Z

In simple terms: hiccup is not an object, its just a data structure. If you put in symbols they get evaluated just normally

2021-01-18T20:25:33.074500Z

in order to use it, you fill in your data into that structure first

sova-soars-the-sora 2021-01-18T20:26:27.074700Z

mmm right on.

sova-soars-the-sora 2021-01-18T20:26:36.074900Z

Well, cool! Looks like etaoin is the ticket.

sova-soars-the-sora 2021-01-18T20:26:39.075100Z

thx

2021-01-18T20:26:43.075300Z

there are a few examples in this repo: https://github.com/yokolet/hiccup-samples/blob/master/src/hiccup_templating/views/contents.clj#L20 - in the linked function you pass in a "label", and it returns html data that uses that label

2021-01-18T20:27:05.075600Z

that's the general pattern - it's very simple IMHO

roelof 2021-01-18T20:28:29.075900Z

oke, I will sleep about it, I now have a collection of collections that holds the data

roelof 2021-01-18T20:29:17.076300Z

maybe im overthinking things

2021-01-18T20:29:40.077Z

to expand an example from the README:

user=&gt; (html [:span {:class "foo"} "bar"])
"&lt;span class=\"foo\"&gt;bar&lt;/span&gt;"
(defn foo-span
   [txt]
   [:span {:class "foo} text])

(html (foo-span "bar"))

2021-01-18T20:30:04.077600Z

hiccup is simpler than most people expect, since it just expects you to use standard clojure features to do anything interesting

2021-01-18T20:32:21.079800Z

I deserialize a json response from a webserver, but I end up with way more data than I need. After deserialzing I end up with a collection of maps, is their a way to get rid of most fields I don't care about?

(map (fn [{:keys [EndPoint, InstanceName, DatabaseName, DaysSinceLastBackup, LastDataBackupStartDate, DataSizeGb, RecoveryModelDescription, LogSizeGb, StateDescription]}]
         {:EndPoint EndPoint :InstanceName InstanceName ,,,,,} response)
? Or shoudl I just ignore the fields I don't care rather than creating a map with the fields I do care about? There is about 61 fields or so and I only care about 10 or so.

roelof 2021-01-18T20:32:29.079900Z

oke

roelof 2021-01-18T20:33:11.080300Z

so I can write a function that calls the function that outputs this :

clj꞉paintings.core꞉&gt;  
({:object-number "SK-A-4830"
  :width 175
  :height 136
  :url
  "<http://lh3.googleusercontent.com/i9rZKO23qEyRg9TE5VN5_v4AAzwqPdFZunfhpfxV7llT1mk593mMhS3gmQW8_HpA0FmqfVLcDuXXf0UonINGwGxp1JY=s0>"}
 {:object-number "SK-A-1451"
  :width 186
  :height 127
  :url
  "<http://lh3.googleusercontent.com/QomBqMQhWieJvwxIBGEq8oS7gJkwv3XesSktJqJOkwui6NU_0UIniYoTDzl6aByGrKS4SVg0nwIGr9OgGEA91WooJF8=s0>"}
 {:object-number "SK-A-1505"
  :width 127
  :height 198
  :url
  "<http://lh3.googleusercontent.com/PCRHxBNtKpz9lDX_9VAHAOKE5tYwNLl75e2E1Fas2KAXWI3afrE-r4EWmtlz3Vk8xNptPPxqTzE9MvCzs9KneTnNK3uu=s0>"}
 {:object-number "SK-A-3841"
  :width 191
  :height 143
  :url
  "<http://lh3.googleusercontent.com/yTYAzH_q-M6GxEnaCeeQC6e1pbm6XwUDO5XDtUmYlanAtAoF6hxUdhbGyIO6L9dCKHLwae1lEHAuMuveaIi4LuEt0g=s0>"}
 {:object-number "SK-A-2963"
  :width 145
  :height 184
  :url
  "<http://lh3.googleusercontent.com/zn02IemnhpAqcCMKmNkxPBVGM9CvROqaSVbpSkMfTv-DheNPS6KiLszq5totiyShZX5Tl92gbydlmOYhxkeWAusJKg=s0>"}
 {:object-number "SK-A-135"
  :width 144
  :height 169
  :url
  "<http://lh3.googleusercontent.com/QDhLN0_5UUhlmn9jC1LNFcYzbXYKea5LjZNuo4-33HWbRP_wm5H_5QYZr5a-Gsaeri8mKFk4D49uRIju12p-9ET06TQ=s0>"}
 {:object-number "SK-A-2099"
  :width 145
  :height 179
  :url
  "<http://lh3.googleusercontent.com/pHfJFrggTcDq2cLxQxgnnxR151IChSk6k8Q1pbXWunqRg6avfCdjo4LjfmnMd8QVCxqTkvb-qu_bJxkmRJVytmDR8DQ=s0>"}
 {:object-number "SK-A-1796"
  :width 202
  :height 113
  :url
  "<http://lh3.googleusercontent.com/sbCWPXJFQ0-fgMkmBILH--QpyKU4xcXGfRHRjcuCHt_UHC7ZwhE_83-l_hJ_DIhMwVVJiU7PixtArU4gb6VuRAN7pVc=s0>"}
 {:object-number "SK-C-2"
  :width 136
  :height 56
  :url
  "<http://lh3.googleusercontent.com/gjsM0sJclVJ8rkta7ppoGI63RmNdSZAvbkXLKd7T1xFXE5WzPoQGyi3Y0zQXXcBeMr0Q4kSCjghstIvGr_3Pl6SYag=s0>"}
 {:object-number "SK-A-180"
  :width 146
  :height 179
  :url
  "<http://lh3.googleusercontent.com/dgdeRabPYriIi7v5R3fAk6cudxssTV_oEVaXz1zSo9UPlTcUPAJgZan9jhCfAPzjwtpDTb0v5vSja0uyrSR4LatmTw=s0>"})
clj꞉paintings.core꞉&gt;

roelof 2021-01-18T20:33:34.080800Z

what I want to do is to display all images with a <img> tag

2021-01-18T20:33:41.081100Z

that's a lot of bindings to stick into one command line destructure

roelof 2021-01-18T20:33:46.081300Z

but for now GN

2021-01-18T20:33:57.081700Z

yeah, i know 😞

2021-01-18T20:34:06.082100Z

the same syntax works in let

2021-01-18T20:34:22.082600Z

it looks like you are just doing select-keys

2021-01-18T20:34:54.084200Z

(select-keys response [:EndPoint InstanceName ...]) - that vector can be a separate def

2021-01-18T20:35:00.084500Z

my concern is i have over a thousand maps being created, ancd each with 61 fields. WHen I want the thousand maps, but i only care about 10 of the fields.

seancorfield 2021-01-18T20:35:11.084800Z

@qmstuart It's probably more idiomatic to just ignore the keys you don't care about -- unless you have a very specific context in which extra fields are not allowed (such as storing the hash map in a database).

2021-01-18T20:36:24.084900Z

I would recommend starting by writing the hiccup data manually (not created via a program) that produces what you want for one or two images.

💯 1
2021-01-18T20:36:55.085200Z

Once you get that working, then you will know what "shape" of data structure you want to create via a function that works for N images on a page.

2021-01-18T20:37:11.085400Z

the result will probably look kind of like [:div (for [img ...] [:img ...]])

2021-01-18T20:37:13.085600Z

walk before you run

👍 1
🎉 1
2021-01-18T20:38:25.086200Z

no, im not storing this stuff. Just processing it. I was thinking having large maps would be a performance issue maybe.

2021-01-18T20:38:28.086400Z

but it might be fine

2021-01-18T20:39:48.087600Z

well, if large maps turned into an issue, I'd use select-keys (maybe with clojure.set/rename-keys too...) upon acquiring the data, but @seancorfield is right that most of the time you can just ignore the keys you don't want

2021-01-18T20:39:55.087900Z

thanks, @noisesmith I wasn't aware of select keys

2021-01-18T20:40:59.089500Z

Map lookup for large maps with N key/value pairs is O(log N) in Clojure, where the base of the log is 32, not 2, and pretty decent on constant factors, too. I wouldn't worry about their performance, until and unless you actually do some benchmarking to determine where most of the time is spent in your code. Clojure maps aren't going to outperform custom-made maps tailored to particular situations, but they are usually close enough that they aren't the performance issue in your application.

💯 1
2021-01-18T20:41:22.090Z

maybe there's some fancy json parser that allows you to whitelist parts of the structure you want, but the complexity that introduces is worse than the cost of unused keys for 99.9999% of cases

Christian 2021-01-18T20:43:24.091Z

There is a ton of pure functions though. In my naiv understanding these are pretty inviting to be run in parallel. Maybe I should spend more time on the basics, but it with cpus commonly offering dozens of threads and cores it seems like a waste when everything runs sequential

roelof 2021-01-18T20:47:53.091200Z

I know

dgb23 2021-01-18T20:48:43.091500Z

@andy.fingerhut I’m going to include this in my “programming mantras” sheet that we use to teach introductory programming!

Hagenek 2021-01-18T21:33:26.092800Z

Ok, so this is a terrible function. How would I write it to accept a map with keys instead (if that is a better idea).

(defn save-create-order
  [external-id service-company-id elevator-id
   contract-id description status due-date
   actual-start-time actual-end-time checklist-id]
  (swap! orders conj (create-order
                      external-id service-company-id elevator-id
                      contract-id description status due-date
                      actual-start-time actual-end-time checklist-id)))

2021-01-18T21:34:16.093200Z

often when you have that many args to a function, it should take a map in the first place, by which I mean create-order might need a smaller number of maps as args, and save-create-order would not have to care about all the keys in those maps

2021-01-18T21:34:39.093700Z

or perhaps a small number of maps (eg. one for the customer data and one for product related data?)

2021-01-18T21:36:53.094800Z

but to literally answer the question: replace (defn save-create-order [external-id ... ] ...) with (defn create-save-order [{:keys [external-id ...]}]) and pass a map that has the matching keys

2021-01-18T21:38:09.095Z

I don't know if it adds much, but REPLs can make it much quicker to try out many tentative walking steps very quickly.

👍 1
2021-01-18T23:57:12.095600Z

Rhino is deprecated, and has been removed in newer versions of ClojureScript

2021-01-18T23:58:24.095800Z

It was removed in version v1.10.738