Fork me on GitHub
#clojure
<
2022-12-19
>
Martynas Maciulevičius09:12:13

Is there a HTTP mimetype for EDN?

p-himik09:12:50

Nothing that's truly agreed upon, IIRC. Same for Transit.

Rupert (All Street)09:12:09

I think it is fairly common to use a generic one like text/plain or perhaps application/octet-stream .

mpenet09:12:07

application/edn is used by a few notable libs

Martynas Maciulevičius09:12:48

I thought about application/edn too, it seems "natural" after what JSON does

👍 1
Martynas Maciulevičius10:12:00

The only problem with application/edn is that the browser doesn't care to display it as text and downloads it instead.

phill12:12:10

If you're inclined to try to mention edn in the content-type, you may use an "x-" prefix (application/x-edn??) to avoid trespassing on the IANA's namespace. But as you mentioned, only the universally-accepted, IANA-registered types really accomplish anything. Better choose text/plain and get predictable results than invent something clever and get undefined results.

jjttjj12:12:13

@U028ART884X > The only problem with application/edn is that the browser doesn't care to display it as text and downloads it instead. > I think there's another header that sets that behavior though I'm not at a computer to check

Martynas Maciulevičius12:12:48

I bet there is a header for cooking an egg 😄

Martynas Maciulevičius12:12:16

I used Content-Disposition and application/edn :thinking_face: It's going to download into a file but I'll choose the filename because I actually would like to not use the URL as filename.

jjttjj12:12:44

Yup that was what I was thinking of

Madara Uchiha22:12:00

Yo, F# had a really neat feature where you could provide a format (like the one passed to format) and a string, and get back a tuple of the variables after parsing, does Clojure have anything like that?

(parse "abc, 123, true" "%s, %i, %b"); => ("abc", 123, TRUE)

respatialized23:12:05

Closest thing I can think of is re-seq to find matches in a regex

1
isak01:12:26

It is dynamically typed, so you would normally just use clojure.edn/read-string

dumrat03:12:01

It's scanf in C. Don't think there's a corresponding Clojure version.

Miķelis Vindavs09:12:09

(defn parse [s r & fs]
  (mapv (fn [f x] (f x))
        fs
        (rest (re-find r s))))

(-> "abc, 123, true"
    (parse #"(\w+), (\d+), (true|false)"
           str parse-int boolean))

=> ["abc" 123 true]

phill09:12:05

Looks a bit like java.util.Scanner:

Scanner s = new Scanner(input);
     s.findInLine("(\\d+) fish (\\d+) fish (\\w+) fish (\\w+)");
and can parse BigDecimal, etc.

nice 4
Miķelis Vindavs09:12:11

oh cool i didn’t know that existed

Joshua Suskalo15:12:10

or just (comp rest re-matches)

Madara Uchiha15:12:44

I don't want regex though, as that requires me to specify the parsing function myself. I want, essentially, the opposite of (format), it takes a bunch of values and serializes them into a string based on the template, I want to take the template and the serialized string, and get back the values used

Joshua Suskalo15:12:57

There is no existing function in core that does this, dunno about libraries, but you could do it yourself without too much effort by matching on those % dispatches and just throwing them through a hashmap to get corresponding regex fragments, cat them together, use re-pattern to compile it, and then use rest on re-matches

Madara Uchiha15:12:28

True, with some special behavior for things like %07d etc.

Joshua Suskalo15:12:55

if you need those advanced ones then yeah, you could do something like that as well with a little more complexity.

Joshua Suskalo15:12:45

Like making the values in the map be functions that return regex fragments rather than regex fragments themselves, and the arity you call determines if you're using the default version vs the one with an argument or more

Joshua Suskalo15:12:32

Doing it this way with re-pattern and fragments that get catenated together will probably be slower than writing a full eager parser yourself, but it would likely require less work.

Joshua Suskalo15:12:09

This mostly being because unless you memoize the creation of the regex patterns you'll be compiling regexes often.

Miķelis Vindavs15:12:36

I thought I posted this before but apparently not-- this would be similar to what Joshua is describing.

(def formats
  {"%s" ["(.+)" str]
   "%d" ["(\\d+)" parse-int]
   "%b" ["(true|false)" boolean]})

(defn parse [s pat]
  (let [re (re-pattern (clojure.string/replace pat #"%[sdb]" (comp first formats)))
        fs (map (comp second formats) (re-seq #"%[sdb]" pat))]
    (mapv (fn [f x] (f x))
          fs
          (rest (re-find re s)))))

=> #'user/formats
=> #'user/parse
(parse "abc, 123, true" "%s, %d, %b")
=> ["abc" 123 true]

Joshua Suskalo15:12:42

And compiling regexes is an O(n^2) operation, although if you do memoize it then it could be effectively the same as a handwritten parser since regex matching with re-matches is O(n).

Joshua Suskalo15:12:22

(notably re-find is O(n^2) as well, but is useful if you don't know that the string will match the pattern exactly)

Miķelis Vindavs15:12:28

:thinking_face: i don’t think there’s an O(n) guarantee on matches unless you use greedy patterns exclusively

Madara Uchiha15:12:05

I don't actually care about the O complexity here, we're talking less than 1KB of strings both for templates and haystacks

Joshua Suskalo15:12:07

ah, right, sorry. Crossed wire in my brain. Regular grammars are O(n), but regex aren't regular grammars.

Madara Uchiha15:12:49

I'm looking to save myself work by giving a template and getting already formatted values (i.e. "56" -> 56) on the other end

Madara Uchiha15:12:04

This isn't going to be my hot path in any case

Joshua Suskalo15:12:08

Yeah that's easily done with the method mikelis suggested

Madara Uchiha15:12:43

Aye, I'll look and tweak it to my needs. Thank you all very much ❤️