beginners

Getting started with Clojure/ClojureScript? Welcome! Also try: https://ask.clojure.org. Check out resources at https://gist.github.com/yogthos/be323be0361c589570a6da4ccc85f58f.
0xclj 2020-11-02T07:23:49.004700Z

What is a recommended way to parse a multipart form data? In python, using the requests lib, I am able to get the text data in print(request.form.get('text')) . However, using ring, when I do (println request) it prints:

{:ssl-client-cert nil, :protocol HTTP/1.1, :remote-addr 0:0:0:0:0:0:0:1, :headers {accept */*, user-agent insomnia/2020.4.1, host localhost:3002, content-length 22290, content-type multipart/form-data}, :server-port 3002, :content-length 22290, :content-type multipart/form-data, :character-encoding nil, :uri /, :server-name localhost, :query-string nil, :body #object[org.eclipse.jetty.server.HttpInputOverHTTP 0x16fc318a HttpInputOverHTTP@16fc318a[c=0,q=0,[0]=null,s=STREAM]], :scheme :http, :request-method :post}
The body is #object[org.eclipse.jetty.server.HttpInputOverHTTP 0x16fc318a HttpInputOverHTTP@16fc318a[c=0,q=0,[0]=null,s=STREAM]] When doing (println (slurp (:body request))) , it prints the multipart form data with --xYzZY as the boundary: Sample:
--xYzZY
Content-Disposition: form-data; name="headers"
...

--xYzZY
Content-Disposition: form-data; name="text"

Great! Stuff

On Tue, Oct 27, 2020 at 11:05 AM John <John@doe.com>
wrote:

> Deleting the test endpoint

--xYzZY
Content-Disposition: form-data; name="attachments"
0

0xclj 2020-11-02T08:00:27.005100Z

Got it. Tried this:

(defn handler [request]
  (let [dt (-> request
            wrap-params
            wrap-multipart-params)]
    (println dt)
    (println (:multipart-params dt))))
dt is:

#function[ring.middleware.multipart-params/wrap-multipart-params/fn--771]
and the last println is just nil , what am I doing wrong?

phronmophobic 2020-11-02T08:18:13.006100Z

if you’re using it in a handler (rather than as middleware), try multipart-params-request

Jim Newton 2020-11-02T14:17:30.008600Z

I can never remember the name of the function similar to slit-with and partition-by which returns a ?vector? of two sequences, those that make the given predicate true and those that make it false.

alexmiller 2020-11-02T14:18:04.008800Z

group-by

alexmiller 2020-11-02T14:18:29.009Z

https://clojure.org/api/cheatsheet

Jim Newton 2020-11-02T14:20:43.009900Z

no, not group-by, that's similar but not the same. The function I'm thinking about partitions a sequence into two sequences according to the boolean value of the predicate.

Jim Newton 2020-11-02T14:20:59.010300Z

of course you can build the function with group-by, but there's already a function

2020-11-02T14:23:00.011500Z

with all values returning true for the predicate going into one of the two sequences, and all values returning false for the predicate into the other of the two sequences? Or are you thinking of a case where the first element that returns true for the predicate is the dividing point between the two returned sequences?

pithyless 2020-11-05T17:10:07.260500Z

@jimka.issy if you don't mind an additional dependency, cgrand/xforms has x/by-key which will split by predicate and you can transduce the outputs any way you see fit. It's probably not worth it for just one example, but I find the xforms library pretty useful to have around whenever there is data munging to be done. https://github.com/cgrand/xforms#simple-examples

pithyless 2020-11-05T17:10:36.260800Z

(just realized this thread is 3 days old...)

Jim Newton 2020-11-06T10:43:52.273400Z

@pithyless it's great to add such comments to these threads, even days late. The discussion helps posterity, when people search the text later, they'll find useful information. I'm making the dubious supposition, of course, that this text will stay around forever.

2020-11-06T14:48:59.284300Z

The text will not be searchable on the Clojurians Slack free option for more than about the last 10,000 messages worth, because that is what the free Slack channel option provides. Most of these Slack messages are copied automatically to a Clojurians ZulipChat free instance, which does currently support searching of unlimited message history.

2020-11-02T14:24:04.012300Z

Because if you are thinking of what group-by does with a predicate function (one that always returns true or false), I can't think of any other built-in Clojure function that can do that.

Jim Newton 2020-11-02T14:24:48.012700Z

Here is how to implement the function I'm searching for. But I thought It already existed.

(defn partition-by-pred 
  "Apply the predicate to every element of the sequence and return a vector of two
  values, each of which is a vector, the left vector is the set of the items
  in the original sequence for which the predicate returned a Boolean true value,
  the right vector are the other values from the given sequence."  
  [pred items]
  (let [g (group-by (fn [i]
                      (boolean (pred i))) items)]
    [(g true) (g false)]))

Jim Newton 2020-11-02T14:25:27.012900Z

Maybe I once thought that split-with did what I wanted.

2020-11-02T14:25:59.013100Z

You can call filter and remove with the same predicate on the same input sequence, but that will traverse the sequence twice, and call the predicate twice on each of the sequence's elements.

2020-11-02T14:27:30.013400Z

I think lots of people would use the map returned by group-by rather than make a vector with two sequences, because with the vector now you need to remember (or look up) which of the elements is the true sequence, and which the false, whereas with the map you can just look up the map with the key true or false.

Jim Newton 2020-11-02T14:27:48.013600Z

this set of functions is very similar between Scala and Clojure. In Scala the function I'm looking for is called span, which i've always thought was a very unintuitive name, and I have to look it up every time.

Jim Newton 2020-11-02T14:34:56.015200Z

I'd like to know whether there is more than 1 element of a sequence which satisfies a given predicate. Here's what I'm doing. Is it the correct way? It seems obfuscated.

(= 2 (count (take 2 (filter my-predicate my-sequence))))

vlaaad 2020-11-02T15:01:10.015700Z

(juxt filter remove)?

1
vlaaad 2020-11-02T15:01:41.015900Z

elegant, but iterates twice...

2020-11-02T15:23:58.017300Z

I do not understand why you have (rest my-sequence) instead of simply my-sequence there, but if you made that replacement, then it is one correct way.

2020-11-02T15:24:10.017600Z

There is rarely only one "the" correct way.

Jim Newton 2020-11-02T15:25:36.020300Z

yes. that's particular to my application. the first element is special. but for the purpose of the question, I should remove it.. Thanks.

2020-11-02T15:25:37.020400Z

Another correct way (assuming my-sequence is the sequence you are interested in), would be (>= (bounded-count 2 (filter my-predicate my-sequence)) 2)

Jim Newton 2020-11-02T15:26:37.021400Z

bounded-count, excellent! That's much clearer.

Jim Newton 2020-11-02T15:27:24.022400Z

I suppose I could also do some sort of check on the rest of filter, rather than (take 2 ...) but bounded-count is better.

Jim Newton 2020-11-02T15:28:49.023700Z

@andy.fingerhut why not = 2 rather than >= ... 2 ?

2020-11-02T15:29:05.024200Z

I am probably off by one in typing this up, and haven't tested it, but something like (nil? (next (filter my-predicate my-sequence)) probably also works, but seems even harder to tell what the intent was than either of the previous 2

Jim Newton 2020-11-02T15:29:12.024400Z

can bounded-count return something greater than its first argument?

2020-11-02T15:29:30.024700Z

According to bounded-count's doc string, it can

2020-11-02T15:29:52.025Z

user=> (doc bounded-count)
-------------------------
clojure.core/bounded-count
([n coll])
  If coll is counted? returns its count, else will count at most the first n
  elements of coll using its seq

Jim Newton 2020-11-02T15:32:11.025500Z

I see, there are cases when counting the whole sequence is faster than counting part of it. in particular when it has already been counted.

Jim Newton 2020-11-02T17:11:10.029300Z

Perhaps reduce is your friend?

(defn partition-by-pred   
  [pred items]
(reduce (fn [[good bad] item]
            (if (pred item)
              [(conj good item) bad]
              [good             (conj bad item)]))
          [[] []]
          items))

Gang Liang 2020-11-02T17:13:08.030900Z

A noob question on numeric calculation. To my surprise, I found that Math/abs is much slower than a self-defined function abs as below. The function is called 100K times, and Math/abs is about 3 times slower than abs. I know Math/abs has some boxed-math operations, but I assume the same for my self-defined function. Can anyone explain why the speed difference here?

(defn abs [x]
 (if (pos? x) x (- x)))

Jim Newton 2020-11-02T17:14:16.031Z

@andy.fingerhut wrt group-by vs vector, the call site is something like the following, so In my case I prefer the vector being returned. I understand your concern, however, that the caller has to remember whether it is returned in good/bad order or bad/good order.

(let [[goods bads] (partition-by-pred ...)]
 ...)

2020-11-02T17:37:06.031400Z

I would expect that function to box actually

2020-11-02T17:38:54.031900Z

also, in a quick test, Math/abs is significantly faster than that function

2020-11-02T17:41:39.032400Z

but in another test your function is faster

2020-11-02T17:42:08.032700Z

(cmd)user=> (def input (doall (repeatedly 1000 #(- 50 (rand-int 100)))))
#'user/input
(cmd)user=> (time (doseq [i input] (if (pos? i) i (- 1))))
"Elapsed time: 0.644555 msecs"
nil
(cmd)user=> (time (doseq [i input] (Math/abs i)))
"Elapsed time: 9.021566 msecs"
nil

dpsutton 2020-11-02T17:42:57.032800Z

2020-11-02T17:44:03.033600Z

@dpsutton won't that end up testing the inlining of the input that never changes?

dpsutton 2020-11-02T17:44:51.034Z

its a chain of macros so i'm hoping its repeatedly invoking it

dpsutton 2020-11-02T17:45:17.034300Z

(c/quick-bench (prn "hi")) is quite noisy πŸ™‚

dpsutton 2020-11-02T17:45:59.034500Z

oh i misread you

phronmophobic 2020-11-02T17:52:41.034900Z

part of the slow down is probably reflection:

> (time (doseq [i input] (Math/abs i)))
"Elapsed time: 7.279327 msecs"
nil
> (time (doseq [i input] (Math/abs ^long i)))
"Elapsed time: 1.207027 msecs"
if you know the type ahead of time, I would use type hints to speed things up,Β https://clojure.org/reference/java_interop#typehints

πŸ’― 1
2020-11-02T17:53:45.035300Z

Makes sense

WWeeks 2020-11-02T17:53:48.035600Z

I like the culture and philosophy of Clojure development but I have not coded before. It is crazy to start programming with Clojure first?

2020-11-02T17:55:13.036200Z

yeah, on my machine the hint speeds up the Math/abs version enough to be a bit faster than the function, as I'd expect

🀘 1
dpsutton 2020-11-02T17:55:29.036400Z

i threw a call to double around it not thinking

2020-11-02T17:56:20.036700Z

there are many ways Clojure is a messy first language, it exposes details most languages wouldn't about the host, because it's explicitly designed for "experts" who want the flexibility

πŸ™‚ 2
2020-11-02T17:56:49.036900Z

that said, I did learn clojure before I learned java, and that wasn't so bad (I did need to learn to read javadoc though)

πŸ‘ 2
2020-11-02T17:57:47.037100Z

the clojure version would at best be able to hint "Number"

phronmophobic 2020-11-02T17:58:15.037300Z

I would say it depends on your learning goals. I wouldn't say it's crazy, but there are other languages that try to make getting started in programming more approachable. what kinds of programs do you want to write?

πŸ‘ 2
2
2020-11-02T18:06:10.040200Z

There is destructuring of Clojure maps, too, which could be used with group-by like this. It certainly is not obvious what is going on until you become familiar with map destructuring, but then vector destructuring syntax is not exactly obvious what the semantics are the first time you see it, either:

user=> (let [{goods true, bads false} (group-by is-good? [1 2 3 4 5 6])]
         [goods bads])
[[2 4 6] [1 3 5]]

WWeeks 2020-11-02T18:07:40.040800Z

I plan to manage linux cloud servers with Bash and Clojure

Gang Liang 2020-11-02T18:11:02.041300Z

Thanks for checking it out. I will remember to type-hint functions especially heavy computation ones. All in all, clojure is not a lazy language.

dpsutton 2020-11-02T18:12:15.041800Z

What do you mean about laziness in this context?

Gang Liang 2020-11-02T18:14:27.042Z

@dpsutton I just mean I cannot be lazy... sorry for the confusion.

πŸ‘ 1
practicalli-john 2020-11-02T19:25:04.042300Z

Babashka is a tool for writing scripts in Clojure that would otherwise be bash scripts. That seems to be a great starting place for you https://github.com/borkdude/babashka I encourage you to dive in and experiment at the REPL, also try websites such as http://www.4clojure.com/ and https://exercism.io/ Its useful to know a bit about the tooling available, but as the repl gives you fast feedback on each line of code it is a very useful experience. There are lots of tutorials that cover a wide range of things you can do with Clojure and I am working on a range of practically oriented books to help people learn https://practicalli.github.io/

πŸ‘ 2
Endre Bakken Stovner 2020-11-02T20:09:00.046700Z

In my cljs app, I accept user input like (def a "[MAP-VALS]"). When I edn/read-string this, it becomes [MAP-VALS]. I want cljs to understand that it is the symbol MAP-VALS from com.rpl.specter. I can do this with the hash-map {'MAP-VALS specter/MAP-VALS} , but this feels inelegant. Is there any other way to do it?

2020-11-02T20:12:51.048Z

using a hash-map explicitly is the best way to go from arbitrary user input to values to use in code, in clojure you would have the option of using resolve (which doesn't work in cljs) but using an explicit mapping removes a security risk

Endre Bakken Stovner 2020-11-02T20:13:53.049600Z

Okay, thanks πŸ™‚ But is there an elegant way to get all the uppercase macros from specter into a map? I could grep the source-code, but it would be more fun to learn a clojure way πŸ™‚

2020-11-02T20:13:54.049700Z

also, pedantically, you don't want "the symbol MAP-VALS from com.rpl.specter", you want the value that MAP-VALS resolves to in that namespace

2020-11-02T20:14:44.051Z

in clj you could start with: (-> (the-ns 'com.rpl.specter) ns-publics keys) to get all the symbols defined

πŸ‘ 1
Endre Bakken Stovner 2020-11-02T20:15:03.051100Z

I am happy to be corrected. How else would I learn? πŸ™‚

2020-11-02T20:16:29.051600Z

(ins)user=> (->> (the-ns 'clojure.core) ns-publics keys (map name) (filter #(re-matches #".*byte.*" %)))
("aset-byte" "byte-array" "bytes?" "unchecked-byte" "byte" "bytes")

2020-11-02T20:16:50.052Z

with the right regex it should be easy to get all the upper-case names

Endre Bakken Stovner 2020-11-02T20:19:31.052200Z

Thanks. I realized that I need all of the names, not just the uppercase ones πŸ™‚ So the task is straightforward :thumbsup:

2020-11-02T20:22:41.052400Z

in that case you might be able to use the hash-map that ns-publics returns directly - as it's already a mapping from the symbol (name for lookup) to the var (which you can use @ or var-get to properly resolve to the value)

πŸ‘ 1
😎 1
WWeeks 2020-11-02T22:02:11.054200Z

This is an great reply. Thank you for the guidance

πŸ‘ 2
Darrell 2020-11-02T22:50:16.055500Z

I’m trying to test out next.jdbc, going through the REPL tutorial in the docs but when I try to execute a query I get this error:

Execution error (SQLException) at java.sql.DriverManager/getConnection (DriverManager.java:702).
No suitable driver found for jdbc:<mysql://127.0.0.1:3306/clj_test>

Darrell 2020-11-02T22:50:31.055900Z

Here’s my REPL:

clj
Clojure 1.10.1
user=&gt; (require '[next.jdbc :as jdbc])
nil
user=&gt; (def db {:dbtype "mysql" :dbname "clj_test" :user "root" :password "foo" :host "127.0.0.1"})
#'user/db
user=&gt; (def ds (jdbc/get-datasource db))
#'user/ds
user=&gt; (jdbc/execute! ds ["SELECT * FROM address"])

Darrell 2020-11-02T22:50:35.056100Z

What am I missing?

seancorfield 2020-11-02T23:04:53.056600Z

You didn't add a MySQL JDBC driver to your deps @darrell

seancorfield 2020-11-02T23:05:49.057100Z

Per the Getting Started guide *In addition, you will need to add dependencies for the JDBC drivers you wish to use for whatever databases you are using.*

seancorfield 2020-11-02T23:08:34.059Z

The Example REPL Session shows a dependency on the H2 database driver (because that is easy for everyone to play with, without any setup), but if you want to do it on MySQL you'll have to add this to your deps: https://github.com/seancorfield/next-jdbc/blob/develop/deps.edn#L20 and you may well run into syntax differences between MySQL and H2.

Darrell 2020-11-02T23:20:48.059600Z

Bah, you’re right. I had done that and then must have accidentally removed it. Thanks @seancorfield!

j 2020-11-02T23:23:47.061200Z

Where is a good place/site/channel to find fellow clojurians to pair/mob/ensemble program with to learn more Clojure?

teodorlu 2020-11-03T14:11:41.066100Z

If you're after the apropos audience, they have a discord they hang out in: https://clojureverse.org/t/apropos-clojure-panel-live-on-discord/6601

j 2020-11-04T00:17:43.160800Z

Thanks @teodorlu! I joined it yesterday, but they don't seem too active

mathpunk 2020-11-02T23:25:39.061300Z

You might check out the podcast Apropos. The panel often does pairing, so maybe their listeners would be into doing some pairing as well

j 2020-11-02T23:27:46.061500Z

Thanks @mathpunk! Putting the link here for reference (since there's multiple Apropos podcasts): https://www.youtube.com/channel/UC1UxEQuBvfLJgWR5tk_XIXA