Fork me on GitHub
#clojure
<
2021-02-22
>
jumar05:02:35

Is there a way to make Clojure/REPL automatically recognize tagged data literals like joda time DateTime objects? I have a collection of maps like this which I can dump in stdout and want to copy paste and read elsewhere (e.g. in my unit tests).

[{:started-at #object[org.joda.time.DateTime 0x45879b4a "2021-02-19T04:55:14.000Z"],
  :ended-at #object[org.joda.time.DateTime 0x5f60296a "2021-02-19T06:25:26.000Z"]}
  ,,,]

jumar05:02:35

Currently it fails with No reader function for tag object . It would be great if it could automatically read those objects ad DateTime instances since joda-time is on classpath.

hiredman05:02:51

What I would do is install a print-method for kids time dates to print as #inst literals

jumar05:02:02

Perfect, thanks!

Alex Miller (Clojure team)06:02:03

you can actually do better than that if you like

Alex Miller (Clojure team)06:02:38

oh nvm, you've got all the pieces there

Alex Miller (Clojure team)06:02:34

the one thing you might also want is to extend the Inst protocol to these types

Alex Miller (Clojure team)06:02:09

that would make inst? and inst-ms work for them too

👍 6
henryw37410:02:23

fyi here is a lib to do this for java.time objects https://github.com/henryw374/time-literals

👍 3
lambdam13:02:11

Hello, I'm trying to pretty print the report of a Datomic transaction but the :tx-data entry prints on a single line :

{:db-before datomic.db.Db@a151f72f,
 :db-after datomic.db.Db@9d6a8eca,
 :tx-data
 [#datom[13194139564015 50 #inst "2021-02-22T13:40:49.287-00:00" 13194139564015 true] #datom[17592186072237 106 "Foo BAR" 13194139564015 true] #datom[17592186072237 106 "Old name" 13194139564015 false]],
 :tempids {}}
When I convert every datom into a string, it wraps correctly:
{:db-before datomic.db.Db@a151f72f,
 :db-after datomic.db.Db@eb370c84,
 :tx-data
 ["#datom[13194139564015 50 #inst \"2021-02-22T13:21:08.348-00:00\" 13194139564015 true]"
  "#datom[17592186072237 106 \"Foo BAR\" 13194139564015 true]"
  "#datom[17592186072237 106 \"Old name\" 13194139564015 false]"],
 :tempids {}}
I digged into the source code of pprint but it is quite hard to understand. Is there a simple way to make pprint wrap lines for datoms (or any class)? Thanks

ghadi13:02:07

what are you calling to pretty print?

lambdam14:02:15

I tried

(clojure.pprint/write tx-data :stream nil)
and
(-> tx-data clojure.pprint/pprint with-out-str)

Ramon Rios18:02:06

Did someone recomends a lib to deal with responses pagination?

hiredman18:02:02

if you mean unpaginating api responses, this is the basic pattern I use https://gist.github.com/hiredman/022e617e37f9c5622e1a943a5c34afe5#file-scratch-clj-L1-L18 I've written a lot of different versions of that. that particular unfold doesn't create a lazy seq

hiredman18:02:07

there is also a ticket to add similar functionality to core https://clojure.atlassian.net/browse/CLJ-2555 which supersedes an older ticket with more of a write up and commentary on it https://clojure.atlassian.net/browse/CLJ-1906

jumar07:02:42

The iteration function looks useful. Here's my attempt to use it fetch repositories with installed github app: https://github.com/jumarko/clojure-experiments/blob/master/src/clojure_experiments/collections.clj#L434-L449

(let [my-installation-token "generate-jwt-and-get-installation-access-token-from-that"
          api (fn fetch-page [page-url]
                (log/debug "Fetch all installation repositories - page: " page-url)
                (let [response (http/get page-url {:accept "application/vnd.github.v3+json"
                                                   :headers {"Authorization" (str "Bearer " my-installation-token)}
                                                   :as :json
                                                   :query-params {:per_page "100"}})]
                  (log/debug "Fetch all installation repositories - page FINISHED: " page-url)
                  response))
          api-reducible (iteration api
                                   :kf #(get-in % [:links :next :href])
                                   :vf #(-> % :body :repositories)
                                   :initk "")]
      ;; flatten the pages
      (into [] cat api-reducible))

jumar04:02:06

I noticed that there's CollReduce protocol but the functions use IReduceInit - I guess the main reason is performance? https://groups.google.com/u/1/g/clojure-dev/c/SNGLEJ4POnw

hiredman05:02:33

There are some java odds and ends (I think particular the implementation of range) that need to supply a custom reduce

hiredman05:02:30

CollReduce being a protocol, it does generate an interface, but in the clojure build process the java bits are compiled first, so it is kind of a bootstrapping issue

👍 3
pez18:02:25

Is it correct to describe a predicate like so? > a function that takes one argument, treating it as an expression to test for truth

pez18:02:02

(I’m writing a Clojure tutorial and don’t want to be spreading lies.)

pez18:02:53

Assuming it is an OK description, what do we call functions that takes predicates and returning booleans themselves? (Like every?)

pez18:02:01

@U0NCTKEV8: > a predicate is a function whose result you can use `if` to do case analysis on That would make every? a predicate too, but you can’t send that to function which advertise that they take a predicate as an argument, can you?

seancorfield18:02:38

It may perhaps be important to distinguish between "functions that can be used as predicates" (anything that returns truthy/falsey) and the stricter sense of predicate: "functions, whose name ends in ?, that return either true or false". (the Clojure core folks have been pretty careful to ensure that distinction in the "standard" functions)

seancorfield18:02:04

But I think it is reasonable to consider "predicates" restricted to a single argument that they test, yes.

seancorfield18:02:36

every? is a function that returns strictly true or false but I would not consider it a predicate directly, since it takes two arguments. But this does make me wonder whether http://clojure.org has something specific to say about this...

hiredman18:02:52

the term predicate comes to programming from logic, where the number of arguments passed is not restricted to one, although it may be more common to call predicates in logic that have multiple inputs relations (but outside of logic programming no one in programming calls those relations)

pez18:02:00

I’m not writing a logic tutorial, though. 😃

seancorfield18:02:17

"The contains? function is a predicate for checking containment." -- that's in the hashed_colls guide -- so that consider a two-argument function a predicate 👀

pez18:02:55

And the docstring for filter does not say that it takes a predicate, but rather (pred item)….

seancorfield18:02:40

The contrib how to (style guide) says pred - a predicate closure is a common short name for an argument.

dpsutton18:02:55

this feels like a place where being really "correct" would be quite the detriment to the beginner readers of your article

seancorfield18:02:10

The lisps page on http://clojure.org refers to = as "the equality predicate"

dpsutton18:02:23

most domains aren't "technically correct" for quite a while (if ever) and still build up teaching and predicting models

pez18:02:30

@U11BV7MTK Yeah, I am actually aiming for not being full out incorrect. 😃

seancorfield18:02:31

So there's definitely precedent there for a predicate not being just a unary function.

dpsutton18:02:41

chemistry, mathematics, etc. lots of incorrect stuff at the beginning that helps people with their day to day stuff

hiredman18:02:49

there are really two different definitions of predicates, there is one that people think of when they are "writing a predicate", which is the true/false ends in ?, single argument one

hiredman18:02:30

and there is the one that you use when using predicates, which I think is what I described, basically whatever can have its result passed to if

dpsutton18:02:42

i'd go with the truthy version that hiredman is talking about. truthy is quite easy in clojure. nil, false otherwise truthy.

hiredman18:02:16

a predicate is a function whose result you can use if to do case analysis on

noisesmith19:02:40

I fat fingered with compose-keys turned on, and accidentally discovered that if the ns name in the ns form has an em-dash instead of a dash, require returns without error but it creates a broken namespace. of course the answer is "don't use em-dash in the namespace symbol", but I wonder if there's a linter that checks for things like that

andy.fingerhut20:02:55

borkdude enhancing clj-kondo in 5... 4... 3... 2... 🙂

andy.fingerhut20:02:44

Certainly sounds like a linter that checks for strict ASCII subset (for some fraction of developers), or a larger set that includes other alphabets could find this quickly.

borkdude07:02:24

I missed this. We actually had an issue in the analysis export when we had invalid keywords (that could not be roundtripped) and I already thought of a linter for this, will post an issue

jcburley14:02:31

Well, I’ve really gone done the rabbit hole on this one. Didja know Clojure allows (lexically speaking) symbol names beginning with control characters (including NUL)? Pretty much any character not specifically allocated for some other token/purpose can be the first/subsequent character in a Symbol. ClojureScript isn’t quite that permissive…but why would any modern language permit any non-printables (at the very most) in symbol/keyword names, if not their source files entirely? What’s the reasoning there: the ability to support radically obfuscated source code? I’ll probably gist-ize the various little .cljc files I’ve created with wacky ASCII, Latin1, and Unicode characters.

andy.fingerhut15:02:12

I doubt it was a conscious decision to allow weird control characters. Here is the JVM regular expression for what Clojure/JVM allows as a symbol: https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/LispReader.java#L66

andy.fingerhut15:02:53

\D matches a "non-digit [^0-9]" according to the Java doc page: https://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html

andy.fingerhut15:02:09

It would be too English-centric to disallow letters from other alphabets. Perhaps there is an obvious brief replacement for \D that matches a smaller subset of Unicode code points that better represents "an alphabetic character from any language's alphabet, but not a digit".

noisesmith19:02:56

usually (doto foo.bar-baz (require :reload) in-ns) is safe because if the ns is broken I won't land my repl in that ns

vemv20:02:21

Is there such a thing as "print x's stacktrace very concisely"? Perhaps some lib has made an attempt at it? Background: sometimes a dev process can experience stacktraces and needs to print them accordingly to my IDE. More often than not the actual errors will be pretty trivial so it seems like the stacktraces (otherwise annoyingly large) could be compressed to between 1-3 lines

dpsutton21:02:19

(clojure.repl/pst *e) is quite nice. and a template for anything else you might want to do

dpsutton21:02:49

if in CIDER there's a project-only option that might be up your alley as well

vemv21:02:42

> (clojure.repl/pst *e) magic! it's quite shorter :) thanks, I wasn't aware of the difference (vs. (-> e .printStacktrace)). I think it's good beginning, perhaps I could use AvisoNovate/pretty as it further trims clojure stacktraces (although, IIRC it doesn't do a specific attempt at shortening the stacktrace, in a repl-oriented manner)

Alex Miller (Clojure team)21:02:50

pst will only print the root exception trace (which is usually the one you care about), and it also elides some top frames related to the exception throwing itself, and limits to depth of 12 by default (but you can limit that even more if needed)

🙌 3
vemv22:02:07

In a similar vein to my previous question, how can I make the single line IllegalArgumentException No single method: xxxxxxxxxxxxxxxxx of interface: yyyyyyyyyy found for function: zzzzzzzzzz of protocol: aaaaaa fit into e.g. 80 columns? I have the string at hand, I just need to process that string (i.e. it's easier than whole-stacktrace manipulation) (this is called sometimes "fill-column" style I think)

vemv22:02:38

one simple heuristic is "every two spaces, insert a newline" but I'm open to fancier solutions :)

hiredman22:02:37

this is actually two problems, one is you have to parse it into some kind of structure, the second it pretty printing the structure

hiredman22:02:39

turning it into a vector where each element was separated from the next by two spaces, is an example of a very naive parse

hiredman22:02:54

which is why it gives you very poor pretty printing

hiredman22:02:49

so come up with a grammar, parse the messages, and then you can use something like http://homepages.inf.ed.ac.uk/wadler/papers/prettier/prettier.pdf (a naive, but nice enough pretty printer algorithm and interface) to print it

👍 3
vemv22:02:33

Pretty-printing sounds like a good idea, I hadn't immediately thought of clojure.pprint Splitting by " " seems sensible (as these messages tend to be expressed in English), then I could try using pprint with a width of my choice