clojure

New to Clojure? Try the #beginners channel. Official docs: https://clojure.org/ Searchable message archives: https://clojurians-log.clojureverse.org/
emccue 2020-11-11T00:45:47.321200Z

(sort-by string/lower-case ...)

emccue 2020-11-11T00:45:50.321400Z

will also work

jmckitrick 2020-11-11T01:02:30.321600Z

Will that work with loading CIDER as well?

jmckitrick 2020-11-11T01:02:48.321800Z

2020-11-11T03:03:25.322800Z

@alexmiller hmm, seems like the download issue is that it's trying to download from central, instead of clojars

2020-11-11T03:03:38.323Z

any idea why it would do that?

alexmiller 2020-11-11T03:11:32.323700Z

it's probably actually not - the download error message just prints the last (or maybe first) repo it tried (it tries all of them)

alexmiller 2020-11-11T03:15:07.324500Z

you can"remove" the central repo by doing {:mvn/repos {"central" nil}}

alexmiller 2020-11-11T03:15:42.324900Z

if you want to make sure, but really I think that's probably a red herring

alexmiller 2020-11-11T03:17:43.325Z

sorry, not sure what you're asking, sorry

seancorfield 2020-11-11T03:59:10.325600Z

@alexmiller Remind me, does t.d.a look at Maven or Clojars first?

alexmiller 2020-11-11T04:34:40.325800Z

maven

seancorfield 2020-11-11T04:48:04.326800Z

Cool, thanks. That's what I thought. Which is good, because then no one can shadow a Maven artifact on Clojars to "hijack" it (given that it doesn't do signing etc, whereas Maven does).

2020-11-11T04:48:54.327500Z

The Clojars doc I remember also says that you cannot create an artifact with a group-id that exists on maven central

2020-11-11T04:49:29.327900Z

But it does mean that someone could upload to maven possibly and shadow Clojars

2020-11-11T04:49:50.328400Z

But maven does have a bit more of a manual check, so maybe that be trickier to make happen

2020-11-11T04:51:42.329Z

> Clojars no longer allows deployments that shadow artifacts in Maven Central. From: https://github.com/clojars/clojars-web/wiki/About#why-cant-i-deploy-something-that-uses-a-group--artifact-name-that-exists-on-maven-central

seancorfield 2020-11-11T04:53:57.330Z

Oh, interesting. Good to know. I guess that makes sure folks don't upload a "shadowed" artifact and then wonder why it never gets picked up (because tooling favors Maven).

seancorfield 2020-11-11T04:54:24.330300Z

Uploading to Maven is definitely a bit more controlled.

2020-11-11T04:54:50.330800Z

After me thinking about it all, if I ever release a Clojure lib, I would probably just release it on Maven.

alexmiller 2020-11-11T04:58:23.331500Z

tools.deps always searches maven central, then clojars, then other stuff

2020-11-11T05:40:08.333100Z

Is there a predicate for anything that is "list" like. Something that would be true for vector, list and seq, but not map and nil ?

Ben Sless 2020-11-11T05:44:15.333600Z

sequential?

2020-11-11T05:46:37.333800Z

Hum, ya that might work. I guess I would want it to include sets as well, but I think I can live without

2020-11-11T06:27:00.336600Z

Is this a bad idea:

(defn defalias
  "Aliases the given alias-sym in the current namespace to a new namespace
   of `<current-namespace>.alias-sym`."
  [alias-sym]
  (let [sym (symbol (str *ns* "." alias-sym))]
    (create-ns sym)
    (alias alias-sym sym)))
I'm thinking of using this, because often time, I have some entity in a namespace that I want to spec, and I want the keys to be :my-current-namespace.entity-name/entity-attribute But I don't want to actually create a physical file and namespace just for this entity which would only really contain a spec. And I'm too lazy to type out the full namespace in the s/keys. Also, I want it to be dynamic, so if I ever change the namespace name I'm in, I want the entity to reflect. Like so:
(defalias 'bar)

(s/def ::bar/foo string?)
(s/def ::bar/baz map?)

(s/def ::bar
  (s/keys :req-un [::bar/foo ::bar/baz]))

Ben Sless 2020-11-11T06:27:17.336700Z

but a set isn't list like, it's unordered 🙃

2020-11-11T06:27:39.336900Z

Ya, but that's why I said list like 😛

2020-11-11T06:28:00.337100Z

Basically I'm looking for a pred for unordered containers of scalar

2020-11-11T06:28:24.337300Z

Or more like, they can be ordered or not I don't care, just a coll of scalar

2020-11-11T06:28:45.337500Z

So nil would not count, and map would not count, because map contains key/value pairs

Ben Sless 2020-11-11T06:28:48.337700Z

(and (coll? x) (not (map? x)))

2020-11-11T06:29:22.337900Z

Oh, I forgot about coll?, ya ok that works

2020-11-11T06:47:25.339200Z

Using :: is gross

☝️ 1
2020-11-11T06:49:22.339800Z

What do you do instead?

2020-11-11T06:50:11.340Z

Not use it?

2020-11-11T06:50:41.340200Z

Well, I mean then what namespace do you use in your spec

2020-11-11T06:51:03.340400Z

Do you still use the current namespace, but fully type it out?

2020-11-11T06:51:24.340600Z

It seems like people who insist on using it 1. Saw the spec docs use it and 2. Insist on using code namespace names for keyword namespaces

2020-11-11T06:51:35.340800Z

:whatever/foo

2020-11-11T06:53:18.341Z

The spec docs do it for the sake of example brevity, and using code namespace names for data like that is like naming tables in a database after the code that first uses it

2020-11-11T06:54:05.341200Z

Well, I do that sometimes. But here's my problem. Say I have an account entity in one place, so maybe I have :account/name, :account/id, etc. Now I have another account entity somewhere else, but it is different. So how do I distinguish them? So if I have insight on the entire app and am a solo dev, maybe I remember that I already specced an account, so I need a different name now. But if its a big code base with many devs, I could accidentally mess with some other :account spec

2020-11-11T06:55:14.341400Z

;didibus-account/whatever

2020-11-11T06:56:05.341600Z

Make whatever prefix you want, but tying it to code namespaces is bad

2020-11-11T06:56:16.341800Z

And now we're back at my defalias 😛, I guess I don't need to have it use *ns*, I could have it use wtv, but the point is I'm too lazy to type out my "unique-prefix" everytime

2020-11-11T06:56:55.342Z

Then copy and paste or use an editor with completion

2020-11-11T06:57:01.342200Z

So I'm creating a fake namespace, just so I can leverage :: to expand to my prefix

2020-11-11T06:57:39.342500Z

We use a lot of namespaces keywords at work, I don't know when I last type one out in full not at the repl

2020-11-11T06:59:07.342700Z

Using :: at all makes your data brittle and it will be different depending on the value of *ns* at read time

2020-11-11T06:59:29.342900Z

Hum, I mean yes I could copy/paste or use auto-completion. But I'm wondering, is my little defalias util thing to take advantage of :: a bad idea? Or would that be fine.

2020-11-11T06:59:38.343100Z

So you might copy something to another file, and now boom wrong thing

💯 1
2020-11-11T07:00:05.343300Z

Or you copy something from a code file to a configuration file, etc

2020-11-11T07:00:35.343500Z

I agree with you there, I've been bit by :: in keywords before too, there's some namespaces that have a comment: never rename, because we have prod data stored with the namespace name and it break the code to change

2020-11-11T07:01:08.343700Z

But my solution is actually to not namespace my keywords in my data at all, so I use req-un

2020-11-11T07:01:20.343900Z

So this is only for writing s/keys spec and all that

2020-11-11T07:02:54.344100Z

If you are not using namespaces keywords then maybe don't use spec

2020-11-11T07:03:30.344300Z

req-um exists, but spec really wants you to namespace keywords

2020-11-11T07:04:28.344500Z

I haven't found it a big issue. The spec has to be namespaced, but your data can be as you want. I still use it to generate data for tests, validate, and document things

2020-11-11T07:05:30.344700Z

What prompted me with this problem here is, I actually already have a ::type spec, but I need another one for some other map whose :type key is not the same, so it needs its on spec. So my instinct was to do ::wtv/type

2020-11-11T07:06:00.344900Z

But that doesn't work, and I thought, ok, well I need a unique namespace for this spec

2020-11-11T07:09:19.345100Z

By the way, as an aside, because I've been debating with myself if I want to use unqualified keywords, or something more like :entity-name/field-name as you say. Have you found any benefit to the latter? I felt when I thought about it, I couldn't find a use case where I'd be making use of the namespace on my keyword

alexmiller 2020-11-11T07:16:12.345400Z

just fyi, I am currently working on a solution to this (lightweight alias) for Clojure with Rich (probably 1.11)

👏 1
🦜 1
2020-11-11T07:23:05.345800Z

That be great, because like @hiredman points out, tying your keyword qualifiers to your code namespace can be brittle, the risk that your data gets stored or moved around, and that it now no longer maps to your code namespace is there (and we had this issue happen to us). And I don't want to go Java style, where now I have a gazillion files for my data model. My other options were either, go unqualified, but then your data isn't self-describing anymore. Or go with short qualifiers like :entity-name/field-name but that can conflict. And so going with long qualifiers is a drag having to type it all out. So, I still feel I personally need to hammock all that right now, and haven't yet found a best practice I'm happy with for Spec usage. But I trust you and Rich must have had plenty of time in that hammock 😄

2020-11-11T07:42:14.346100Z

I think something like a lightweight qualifier might solve my issue. Fundamentally, I want to say: "this is the spec for this key". But I want this to be resilient to me moving the spec around, so even if one day the spec is in namespace a.b if tomorrow I move it in f.g I don't want the spec key to change, so my old data will still say, the spec for this key is a.b/key. Same thing on the key side, if I change where I create my map, I don't want the keys to change to saying their spec have moved, because it may or may not. So where the keys or specs are defined/created in the code shouldn't matter. What matters is the name of the spec in the global spec registry. So going with :entity/field over using :: does solve the above, but because the Spec is a global registry it is at risk of conflicts. So ideally I'd want my spec to be URIs like namespaces: com.organization.application.context.entity/key. But now its just a whole lot of typing and risk of typos. So ya, I think if I could alias keyword namespaces, that are not code namespaces, then I could have nice URIs for all my keywords and my specs, which are fully separate to the namespaces I use in my code.

Steiner 2020-11-11T12:05:58.350100Z

hey, I want to join the discussion of Chez Scheme, I can't join them in freenode now, anyone know other channel ??

zilti 2020-11-11T12:45:15.350800Z

No idea, only ever used/contributed to Chicken Scheme, is the channel private or does it just not exist?

2020-11-11T12:47:18.351300Z

You might want to ask in the #other-languages or #other-lisps channels.

Steiner 2020-11-11T13:19:54.351800Z

@zilti it just tell me can't join in the channel

zilti 2020-11-11T13:33:02.353800Z

Maybe you need to have a registered Freenode account. If that doesn't help, it is a private channel.

2020-11-11T15:56:36.355500Z

@alexmiller Found the issue - turns out my project deps.edn had an old http://central.maven.org/maven2/ that wasn't resolving anymore. However the packages still tried to download and just got corrupted. Any way to improve it so it rejects the package outright if it fails the checksum instead of keeping the corrupted version? might bite someone in the future.

alexmiller 2020-11-11T16:09:08.356700Z

I don't actually think that's knowledge I have access to via the maven libs but if you can file a question at https://ask.clojure.org I will make an issue and look into it

2020-11-11T16:17:29.357700Z

cool, done

2020-11-11T16:38:47.361700Z

Hi folks, I'm wondering if someone can help me understand what I'm doing wrong when trying to parse large XML files lazily. I'm using clojure.data.xml/parse, and I keep getting GC overhead errors, mostly likely from retaining the head of some lazy sequences. I've tried to reduce the problem for something simple. The following works and uses very little memory:

(with-open [r (io/reader "path-to-huge-file.xml")]
  (->> (xml/parse r :skip-whitespace true)
       :content
       first
       :content
       (#(nth % 3))
       :content
       count))
Whereas the following uses massive amounts of memory and eventually throws a GC error:
(with-open [r (io/reader "path-to-huge-file.xml")]
  (doseq [node (->> (xml/parse r :skip-whitespace true)
                    :content
                    first
                    :content
                    (drop 3))]
    (count (:content node))))
I'm not sure what could be hanging on to the head in the second example. Any help would be much appreciated.

alexmiller 2020-11-11T16:51:58.364200Z

the seq returned by ->> effectively contains all but the first children, so the entire "rest" of the xml document

2020-11-11T16:57:29.365500Z

Thanks for the response, Alex! So I actually want to process all the children at that depth, one at a time, lazily. Shouldn't the doseq help do this without retaining the head? I don't even get through the first one (it's a really big seq), basically it runs out of memory on what is effectively (#(nth % 3)). And the result of ->> should be lazy, so my understanding of the problem is that it should not matter that it contains the "rest" of the xml document. We don't even get to the rest of the document.

2020-11-11T17:07:46.365700Z

Basically I want to avoid:

(dotimes [n figure-out-what-n-is]
  (with-open [r (io/reader "path-to-huge-file.xml")]
    (->> (xml/parse r :skip-whitespace true)
         :content
         first
         :content
         (#(nth % n))
         :content
         process-lazily)))

alexmiller 2020-11-11T18:19:19.366500Z

sorry, was in a meeting

alexmiller 2020-11-11T18:19:56.366700Z

I don't remember how much of the xml stuff is lazy - I think reading xml off a stream is but it's not lazy in depth

alexmiller 2020-11-11T18:20:23.366900Z

but it might depend what's around that with-open - how are you actually using the result?

timsgardner 2020-11-11T19:01:17.368900Z

Not sure if this is a clojure question or a node question, but I'm running a clojure program (via lein run -m) as a spawned child process in an electron project. When the electron program closes the JDK sticks around indefinitely, wondering how to really close it.

timsgardner 2020-11-16T18:42:31.114Z

though ideally I wouldn't have to, the node process should be able crash without clojure sticking around

borkdude 2020-11-16T18:46:30.114200Z

@timsgardner Babashka supports killing all sub-processes on shutdown. It has great startup time. So you could consider booting node from bb and then kill all on shutdown

timsgardner 2020-11-16T18:47:12.115100Z

I might switch to it, thanks

borkdude 2020-11-16T18:48:54.115300Z

An example using clojure:

$ bb -e "(require '[babashka.process :as p]) (p/process [\"clojure\"] {:inherit true :shutdown p/destroy-tree}) @(promise)"
Clojure 1.10.1
user=> (+ 1 2 3)
6
user=> ^C%

borkdude 2020-11-16T18:51:03.115500Z

You can also do this in Clojure proper btw, babashka/process is also available on the JVM. Or you could just write the JVM interop code yourself

2020-11-11T19:05:49.369Z

Probably you need to call shutdown-agents and/or System/exit

2020-11-11T19:17:51.369200Z

At depth 3, I have a very large lists of small nodes. I want to process each node independently into a small RDF graph and store in a db. The (dotimes [n figure-out-what-n-is]...) approach, while slow, actually does technically work, and is not the end of the world. But I was also worried that I had misunderstood something fundamental about the nature of laziness with respect to holding on to the head of lists.

timsgardner 2020-11-11T19:19:25.369400Z

I'll try that, thanks

borkdude 2020-11-11T20:11:45.369800Z

@timsgardner I also have some logic for this in https://github.com/babashka/babashka.process, see destroy-tree

timsgardner 2020-11-11T20:12:10.370Z

Thanks!

timsgardner 2020-11-11T20:51:46.370600Z

Turns out I was also neglecting to call process.kill('SIGINT') from node