beginners

Getting started with Clojure/ClojureScript? Welcome! Also try: https://ask.clojure.org. Check out resources at https://gist.github.com/yogthos/be323be0361c589570a6da4ccc85f58f.
Malik Kennedy 2020-10-01T00:01:49.482400Z

Ahhh, I see. (I'm not exactly sure of what a pom is, but) I got it working with your advice to include metal-{core,format} (instead of metal) thanks ❤️

seancorfield 2020-10-01T00:04:58.482700Z

pom (and bom) artifacts on Maven mean: "I am a list of artifacts" (rather than "I am an artifact"). Some systems know how to take a pom (or bom) and figure out the list of things to fetch automatically. Unfortunately for use, neither Leiningen nor the CLI/`tools.deps.alpha` know how, so we have to do it manually.

❤️ 1
seancorfield 2020-10-01T00:05:54.482900Z

If you go look at the URL I posted (http://search.maven.org with the version and pom), you'll see it shows a big ol' XML file and the relevant part is

<modules>
    <module>core</module>
    <module>formats</module>
  </modules>

❤️ 1
seancorfield 2020-10-01T00:06:59.483100Z

so that tells me there will be -core and -formats variants of the artifact that I should be able to download instead.

Malik Kennedy 2020-10-01T00:08:51.483500Z

Thanks! That explanation helps a lot.

2020-10-01T00:20:39.485500Z

Is it possible to access RuntimeMXBean, more specifically http://Is%20it%20possible%20to%20access%20RuntimeMXBean,%20more%20specifically%20(getUptime())[https://docs.oracle.com/javase/7/docs/api/java/lang/management/RuntimeMXBean.html#getUptime()] ? In my namespace, do I need to require something to access ManagementFactory?

alexmiller 2020-10-01T00:50:18.485900Z

you'll need to import the class, and yes should be no problem to do

2020-10-01T09:17:55.498400Z

I’ve been getting by with the core library… this is a whole new world! Thanks!

alexmiller 2020-10-01T00:52:42.486200Z

user=> (import java.lang.management.ManagementFactory)
java.lang.management.ManagementFactory
user=> (.getUptime (ManagementFactory/getRuntimeMXBean))
75162

🙌 1
2020-10-01T03:27:23.490600Z

Any way to automatically reload assets on file save when using deps.edn?

seancorfield 2020-10-01T05:50:58.492800Z

@signup867 I would advise against any sort of automated file reloader and just develop a really good, tight REPL-focused workflow where you evaluate every change as you make it. Watch Stu Halloway's talks on REPL-Driven Development and Running With Scissors; watch Eric Normand's excellent online course about REPL-Driven Development.

2
seancorfield 2020-10-01T05:52:36.494500Z

I have been doing Clojure in production for a decade now and I don't use watchers or auto-loading: I just eval every change I make, often without even saving files, I run tests from my editor, I develop into a live, running server process all the time, with my REPL active for days, sometimes even weeks.

Jim Newton 2020-10-01T07:09:49.496100Z

where in the clojure doc is the explanation of the full syntax of argument lists. I know about stand-alone &, but recently I've seen &env and &something-else which I can't remember.

Jim Newton 2020-10-01T07:10:04.496400Z

I thought this might be in the documentation for fn, but I didn't find it there

phronmophobic 2020-10-01T07:11:21.496700Z

are you thinking about &env and &form? https://clojure.org/reference/macros#_special_variables

Jim Newton 2020-10-01T07:15:11.497300Z

yes, are those variables, or are they syntax for the lambda list of a macro?

Jim Newton 2020-10-01T08:18:57.497900Z

yes, are those variables, or are they syntax for the lambda list of a macro?

Jim Newton 2020-10-01T08:19:25.498100Z

however the page you reference doesn't seem to show any examples or other information about how to use those special variables.

Daniel Stephens 2020-10-01T11:08:17.004100Z

Hi all, trying to work out the best way to install a deps.edn project into my local maven. Currently my process seems like a huge hack but I haven't been able to find much on the process. • generate the pom from the deps.edn with clj -Spom • manually edit the pom, updating the version, group and artifact ids. • run mvn install Seems a bit round-about and I'm hoping I'm missing something obvious.

Daniel Stephens 2020-10-01T11:14:13.004300Z

A couple of more specific questions: • Is there some dep that will do this for me, I found uberdeps and depstar but they both still seem to expect a pom.xml to exist, so at that point I might as well use mvn I suppose. • Is there a way to get the pom generated by clj -Spom to fill out the version, group + artifact id, based on something I can write into the deps.edn itself

alexmiller 2020-10-01T12:54:24.006500Z

they are "magic" args available in any defmacro (in reality, defmacro actually generates a function that takes arity + 2 to pass these). the &env tells you the local bindings in scope when the form is expanded and &form is the actual form being expanded.

alexmiller 2020-10-01T12:57:18.006700Z

user=> (defmacro lookie [x] (println "&form" &form) (println "&env" &env) x)
#'user/lookie
user=> (let [a 100] (lookie 10))
&form (lookie 10)
&env {a #object[clojure.lang.Compiler$LocalBinding 0x749f539e clojure.lang.Compiler$LocalBinding@749f539e]}

alexmiller 2020-10-01T12:58:29.007100Z

notice that the vals of the &env map are actually Compiler$LocalBinding objects out of the internals of the compiler

Jim Newton 2020-10-01T13:16:37.007400Z

@alexmiller Do I recall seeing the &env in the argument list of the macro somewhere? or is it only useful in the body of the macro?

alexmiller 2020-10-01T13:25:15.010300Z

only in the body (it is actually passed as an arg to the macro but that's not visible to you as a macro writer)

Day Bobby 2020-10-01T13:26:26.011200Z

hi everyone, I have a namespaced map that I need to split into 2 separate maps for customer and address . I know I can destructure, however the address namespace has about a dozen things in it so Im wondering is there a quick way to extract keys from the same namespace.

{:customer/id 1 :customer/name "" :address/street "..." :address/city "..."}

Jim Newton 2020-10-01T13:28:37.011400Z

Is there more syntax for the lambda list other than just variable names followed by & and a single trailing variable name?

Jim Newton 2020-10-01T13:29:15.011600Z

as I recall there is something about default values. right?

alexmiller 2020-10-01T13:29:57.011800Z

you can use any destructuring syntax in the arg list

Jim Newton 2020-10-01T13:30:56.012Z

yes right.

Jim Newton 2020-10-01T13:31:06.012200Z

does destructuring have any default value syntax?

alexmiller 2020-10-01T13:31:22.012400Z

it does for maps, with :or

Jim Newton 2020-10-01T13:31:35.012600Z

ahhhh.. Where is the documentation for that?

alexmiller 2020-10-01T13:31:52.012800Z

guide is https://clojure.org/guides/destructuring

alexmiller 2020-10-01T13:32:17.013Z

reference is https://clojure.org/reference/special_forms#binding-forms

alexmiller 2020-10-01T13:32:50.013200Z

(defmacro foo [{:keys [a b] :or {a 1 b 2}}] ... )

alexmiller 2020-10-01T13:33:43.013400Z

or if you're using kw-arg style passing, you can destructure the variable arg seq: (defmacro foo [& {:keys [a b] :or {a 1 b 2}] ...)

Jim Newton 2020-10-01T13:33:55.013600Z

that's only for macros or also for normal functions?

alexmiller 2020-10-01T13:34:04.013900Z

yes!

Jim Newton 2020-10-01T13:34:26.014500Z

I notice (fn [x & rest :as all] ...) triggers an error, but (fn [[x & rest :as all]] ...)`` does not

alexmiller 2020-10-01T13:34:33.014800Z

(let [{:customer/keys [id name] :address/keys [street city]} your-map] ...)

👍 6
🙏 1
alexmiller 2020-10-01T13:35:08.014900Z

the :as is not supported in the fn args

Jim Newton 2020-10-01T13:35:38.015100Z

but it apparently is within the [[]] of a fn args

Jim Newton 2020-10-01T13:35:53.015300Z

curious.

alexmiller 2020-10-01T13:36:48.015500Z

the fn is the exception here, can't say I know the reason why off the top of my head

alexmiller 2020-10-01T13:38:01.015700Z

every place else that has sequential destructuring does support it

alexmiller 2020-10-01T13:40:01.016Z

not sure if that's just a historical quirk or if there's actually a reason for it

Jim Newton 2020-10-01T13:41:25.016200Z

I'm writing a function what wants to provide arglists with the same syntax as fn. To implement this distinction will be tricky.

Jim Newton 2020-10-01T13:41:52.016400Z

as its a recursive function. It'll have to know whether it is the top level recursion or not. guess not so tricky, but good do know.

Jim Newton 2020-10-01T13:43:21.016700Z

In common lisp, destructuring is only allowed in macro lambda lists, not in normal functions. So that's a feature of clojure that I really appreciate.

👍 1
Day Bobby 2020-10-01T13:55:30.020600Z

yes, I know I could do this. However, this gives me id name street city that I have to use to construct my new maps customer & address. I have many keys in the address namespace and would have to type them out twice (once to destructure and once to build new map). Is there a way to group them by namespace automatically from the map so I can save me some typing? Thank you!

alexmiller 2020-10-01T13:57:08.021300Z

don't think so - might depend a bit on what you're doing in between the destructuring and re-building

Day Bobby 2020-10-01T14:02:46.023100Z

I'm just trying to transform the result of a sql query to this form (expected by a lacinia graphql resolver)

{:id "" :name "" :address {:street "" :city ""}}

teodorlu 2020-10-02T08:38:29.091100Z

If so, do you just want to filter on key namespace?

(defn filter-key-ns [m key-ns]
    (->> m
         (filter (fn [[k v]]
                   (= key-ns (namespace k))))
         (into {})))

(let [data {:customer/id 1 :customer/name "Alice"
            :address/street "Jane Street" :address/city "New York"}]
  (filter-key-ns data "customer"))
;; => #:customer{:id 1, :name "Alice"}

teodorlu 2020-10-02T08:41:58.091300Z

(defn filter-key-ns-2 [m key-ns]
    (->> m
         (filter (fn [[k v]]
                   (= key-ns (namespace k))))
         (map (fn [[k v]]
                [(keyword (name k)) v]))
         (into {})))

(let [data {:customer/id 1 :customer/name "Alice"
            :address/street "Jane Street" :address/city "New York"}]
  (merge (filter-key-ns-2 data "customer")
         {:address (filter-key-ns-2 data "address")}))
;; => {:id 1, :name "Alice", :address {:street "Jane Street", :city "New York"}}

👍 1
Day Bobby 2020-10-02T10:56:56.093700Z

yes this is what i wanted. thank you!

teodorlu 2020-10-02T13:43:57.094200Z

Glad it helped!

Chris K 2020-10-01T14:06:04.024500Z

What are some easy and simple options for GUI programming with Clojure. I was looking at seesaw, but it says it is compatible with 1.5, and doesn't mention any of the newer Clojure versions so I am not sure if it will work. If not, any recommendations?

2020-10-01T14:07:37.024900Z

Check out CLJFX (and the #cljfx channel)

alexmiller 2020-10-01T14:09:36.025300Z

seesaw should work just fine with newer Clojure (and Java) versions

alexmiller 2020-10-01T14:10:19.025900Z

javafx (cljfx) is probably the more popular option these days though

WWeeks 2020-10-01T14:24:41.027300Z

I am an experienced network engineer that wants to learn Clojure as my first language, What website should I use to learn to code in Clojure?

2020-10-01T14:29:45.027500Z

Check out http://braveclojure.com

2020-10-01T14:30:21.027900Z

Also http://purelyfunctional.tv if you like video tutorials

practicalli-john 2020-10-01T14:49:06.028400Z

I recommend using the websites that make sense to you most, everyone learns differently. I publish a free book and run a video series via YouTube. https://practicalli.github.io/ I do recommend using http://4Clojure.com to practice using the Clojure core functions. Keeping motivation is important when learning, so building something you find useful in Clojure will help.

WWeeks 2020-10-01T14:57:32.029Z

Thank you. I will give those 3 websites a try for a few hours.

J Crick 2020-10-01T15:41:23.030800Z

I just ran into this syntax in Hiccup (in reagent):

[:> ImportedReactComponent ]
I haven't seen this before, and, I couldn't find anything online in the Hiccup docs about it. Can someone point me to some documentation that discusses it?

Karo 2020-10-01T15:43:38.031300Z

Hi all, how Unauthorizedaccessexception can be thrown in clojure? thanks

J Crick 2020-10-01T15:46:01.031400Z

No need! I just found it in the reagent docs. I was looking in the wrong place 🙂

Daniel Stephens 2020-10-01T16:31:20.032Z

ahh, I have found what I needed! https://clojure.org/reference/deps_and_cli#_local_maven_install had been misread the end of this thinking it still required a pom file

Daniel Stephens 2020-10-01T17:06:26.032400Z

I take it back, I can build a jar seemingly quite easily, but the mvn-install thing seems to corrupt it

Daniel Stephens 2020-10-01T17:14:34.032600Z

ahhh, what I didn't realise is that clj -Spom doesn't override the existing version/group/artifact ids, so I only have to set them once! All sorted

0xclj 2020-10-01T17:23:07.035600Z

Is there a way to escape commas from a string (csv)? Related but the answers are quite old: https://stackoverflow.com/questions/16215169/clojure-csv-with-escaped-comma

alexmiller 2020-10-01T17:29:14.036600Z

you shouldn't escape commas - you should quote the entry. the higher-voted answer there has a link to the "spec" (as much as it is), which is what the org.clojure/data.csv library follows (the only Clojure csv parser I use regularly)

alexmiller 2020-10-01T17:29:58.036900Z

$ clj -Sdeps '{:deps {org.clojure/data.csv {:mvn/version "1.0.0"}}}'
Clojure 1.10.1
user=> (require '[clojure.data.csv :as csv])
nil
user=> (csv/read-csv "\"a,b\",c")
(["a,b" "c"])

0xclj 2020-10-01T17:38:27.039800Z

Got it. Will try that. I'm trying to follow the guide at https://andersmurphy.com/2019/01/06/clojure-sending-emails-with-sendgrid.html However, if the data is like:

[{:id 1, :t_id "1311350232249065472", :text "6b/ Substack: \"We've just been growing fairly consistently, and gradually the how-do-we-keep-up anxiety got bigger and bigger until there wasn't time left in the day to worry about whether we had product-market fit.\" – @cjgbest", :created_at "2020-10-01T12:17:34.611062000-00:00"}]
The resultant csv creates new column for every comma word between the commas (2nd row)

2020-10-01T17:45:02.040300Z

yep, use a real csv library

2020-10-01T17:45:29.040500Z

for example https://github.com/clojure/data.csv

0xclj 2020-10-01T17:49:41.040900Z

Yup, checking it out.

0xclj 2020-10-01T18:49:04.041400Z

alexmiller 2020-10-01T18:53:05.042700Z

Re the \" before We've - I would usually expect that to be escaped with a double quote instead ""We've

alexmiller 2020-10-01T18:54:32.043Z

and from a glance at the data.csv code that's what it's expecting too

alexmiller 2020-10-01T18:56:50.044200Z

but csv is notoriously non-standardized

0xclj 2020-10-01T18:58:54.045100Z

Hmm, the data from the db itself has \"

[{:id 1, :t_id "1311350232249065472", :text "6b/ Substack: \"We've just been growing fairly consistently, and gradually the how-do-we-keep-up anxiety got bigger and bigger until there wasn't time left in the day to worry about whether we had product-market fit.\" – @cjgbest", :created_at "2020-10-01T12:17:34.611062000-00:00"}]
How should I go about turning this into a valid csv structure/string?

alexmiller 2020-10-01T18:59:40.045300Z

yeah, you have to deal with the data you have

alexmiller 2020-10-01T19:01:01.046600Z

if I had to go out on a limb, I suspect you're not going to see that \" other than this case, so you could str/replace that with "", have no idea how often that would go wrong but might be a useful hack

0xclj 2020-10-01T19:06:27.046800Z

I'll try that.

2020-10-01T19:24:34.047200Z

How did you write that csv?

2020-10-01T19:26:17.049200Z

I would say the code generating that csv is not correctly escaping quotes, so if you are generating the csv you should fix that code

alexmiller 2020-10-01T19:26:51.049500Z

it sounds like that's data from someone else

alexmiller 2020-10-01T19:27:03.049800Z

hell is other people's data right?

2020-10-01T19:27:44.051100Z

The linked to blog post includes code for naively creating csvs without any escaping

2020-10-01T19:27:55.051500Z

Which is why I suggested data.csv

2020-10-01T19:29:20.053800Z

But you will need to generate the csv using data.csv, not the obviously incorrect code in that blog post

ryan echternacht 2020-10-01T19:54:17.057Z

Is there a pithy or builtin way to assign a key to a map if that key isn't already set? specifically when using the thread operators?

ryan echternacht 2020-10-01T19:55:44.058Z

I have

(-> map
    (assoc :key (get map key default-value))
But was curious if there is something better

ghadi 2020-10-01T19:55:57.058300Z

(merge defaults-map your-map)

dpsutton 2020-10-01T19:55:58.058400Z

(-> {} (update :key (fnil identity "new-value")))

dpsutton 2020-10-01T19:56:22.058900Z

merge is better if its top level. good call

ryan echternacht 2020-10-01T19:56:27.059100Z

ooo @dpsutton, that might be it too

ryan echternacht 2020-10-01T19:56:39.059500Z

I guess merge could work too. it is top level Merge doesn't seem to work well in threading, or am I missing something?

dpsutton 2020-10-01T19:56:55.059800Z

then that is preferable imo

ryan echternacht 2020-10-01T19:59:01.060700Z

for the merge while using the thread operator, wouldn't I need to do something like

(-> map
    (#(merge defaults-map %))
Or am I wrong?

ryan echternacht 2020-10-01T19:59:12.061Z

or are you thinking of just doing the merge after all of the threading is complete?

ghadi 2020-10-01T20:00:05.061400Z

you should not contort things just for the threading macro

ghadi 2020-10-01T20:00:31.062200Z

Usually I add my defaults upfront, then thread my operations subsequently

dpsutton 2020-10-01T20:01:51.063500Z

(-> (merge map defaults) ...)

ryan echternacht 2020-10-01T20:02:34.064200Z

That makes sense. I have an map (from a db) that's getting a bunch of transformations applied. At the end, some validation logic runs over it. and this key needs to exist, either using what was already there or add in the default value if not. and the whole block is already threaded

ryan echternacht 2020-10-01T20:03:24.065Z

so I was hoping to slip in a 1-liner in the threading without changing too much more. thanks for the help!

0xclj 2020-10-01T20:07:32.065100Z

The data stored in the db is as <the screenshot>. When reading that data using Toucan, I get the vector of maps as shared before: It looks like the following in the REPL:

[{:id 1, :t_id "1311350232249065472", :text "6b/ Substack: \"We've just been growing fairly consistently, and gradually the how-do-we-keep-up anxiety got bigger and bigger until there wasn't time left in the day to worry about whether we had product-market fit.\" – @cjgbest", :created_at "2020-10-01T12:17:34.611062000-00:00"}]
Notice the \" is already present there. Now, I need help with converting that to CSV.

0xclj 2020-10-01T20:07:52.065500Z

cc:// @alexmiller

2020-10-01T20:08:36.066400Z

I heard somewhere (can’t remember if it was a podcast, or article, or something else) about a daily problem/challenge to solve in Clojure. Does this ring a bell for anyone?

2020-10-01T20:14:19.066600Z

you are confusing yourself

2020-10-01T20:14:37.066800Z

the \" is escaping the " for reading in clojure

2020-10-01T20:14:54.067Z

it is not present, what is present is a single "

seancorfield 2020-10-01T20:16:15.067300Z

The closest I can think of is http://www.4clojure.com/

seancorfield 2020-10-01T20:16:54.067500Z

(-&gt;&gt; map
     (merge defaults-map))

seancorfield 2020-10-01T20:17:54.067700Z

Or if you have a whole pipeline of -&gt; stuff but want a merge of defaults somewhere in the middle:

(-&gt; stuff
    (do-things)
    (-&gt;&gt; (merge defaults-map))
    (do-more :things))

2020-10-01T20:19:23.067900Z

yes! this is exactly what I was trying to recall. thanks

seancorfield 2020-10-01T20:23:31.068100Z

(but, in general, it's considered somewhat bad practice to mix -&gt; and -&gt;&gt; in a pipeline -- it generally indicates you're trying to do too much at once and potentially mixing data types, since sequence functions take the sequence last but collection and "object" functions take that argument first)

2020-10-01T20:24:40.068300Z

user=&gt; (def data [{:id 1, :t_id "1311350232249065472", :text "6b/ Substack: \"We've just been growing fairly consistently, and gradually the how-do-we-keep-up anxiety got bigger and bigger until there wasn't time left in the day to worry about whether we had product-market fit.\" – @cjgbest", :created_at "2020-10-01T12:17:34.611062000-00:00"}])
#'user/data
user=&gt; (let [baos (java.io.ByteArrayOutputStream.) w (java.io.OutputStreamWriter. baos)] (write-csv w [[(:text (first data))]]) (.flush w) (String. (.toByteArray baos)))
"\"6b/ Substack: \"\"We've just been growing fairly consistently, and gradually the how-do-we-keep-up anxiety got bigger and bigger until there wasn't time left in the day to worry about whether we had product-market fit.\"\" – @cjgbest\"\n"
user=&gt; (read-csv (let [baos (java.io.ByteArrayOutputStream.) w (java.io.OutputStreamWriter. baos)] (write-csv w [[(:text (first data))]]) (.flush w) (String. (.toByteArray baos))))
(["6b/ Substack: \"We've just been growing fairly consistently, and gradually the how-do-we-keep-up anxiety got bigger and bigger until there wasn't time left in the day to worry about whether we had product-market fit.\" – @cjgbest"])
user=&gt;

2020-10-01T20:25:22.068500Z

you can see when correctly encoded the " is a double " (which is not what you have) which is why read-csv throws an error

2020-10-01T20:26:29.068700Z

if you want to print something without escaping for reading you can use println

2020-10-01T20:26:33.068900Z

user=&gt; (def s "\"")
#'user/s
user=&gt; s
"\""
user=&gt; (println s)
"
nil
user=&gt;

0xclj 2020-10-01T20:33:20.069100Z

Hmm, understood the quotes issue. Thank you.

practicalli-john 2020-10-01T20:49:24.069300Z

There a few good coding challenges websites https://practicalli.github.io/clojure/coding-challenges/ 4clojure is excellent for learning the core functions in Clojure, it sometimes challenges you to rewrite them (at least in part)

0xclj 2020-10-01T20:56:02.069500Z

> if I had to go out on a limb, I suspect you're not going to see that \" other than this case, so you could str/replace that with "", have no idea how often that would go wrong but might be a useful hack The replacing hack also worked btw. Modified the escape-csv-value function to test and it does work.

(defn escape-csv-value [value]
   (-&gt; (str/replace value #"\"" "")
      (as-&gt; rdt (str "\"" rdt "\""))))

2020-10-01T21:07:15.069700Z

ha, that is great. forcing me to rewrite my code such that it really does fir exactly into the blank is a challenge unto itself