Fork me on GitHub

I compiled a list of Clojure resources for domain-specific languages and parsing: Suggestions are very welcome. I’m just a lowly programmer trying to educate myself about this space.

👍 47
✔️ 7

maybe routing libs should be included? compojure, bidi, reitit etc.

👍 6

@U055NJ5CC I’ll consider that. I don’t think they should go in the regular data-based/classic DSL subcategories, but perhaps they could get a separate section?


:thinking_face: both ok, I think. Would be easier to compare if they were under same category.


imo, routing dsls are just as dsl as html dsls


Great to have a centralized list of Clojure DSL stuff -- thanks for putting it together!


@U077BEWNQ NP! They’re a useful way for me to get an overview too.

👍 3

@U04V15CAJ Part of the tricky part of defining a DSL in Clojure is that everything blends together. I think there’s a meaningful distinction with the way one uses (what I would call) a DSL and then configuration for a web service. The former is used adhoc in various places, while the latter is often has a much simpler grammar and is more situated in the application process.


Is a hash map used to describe a web service a DSL? I would argue that it definitely could be, but only if it’s used in a distinctly different way from how hash maps are typically used. A DSL sort of requires a grammar that is different from the typical usage of language constructs.


I'm not so sure where to draw the line. The below stuff looks like hiccup to me, but for routing (this is bidi):

 [[["/users/" :user-id]
   [["/topics" [["" :topics] ["/bulk" :topic-bulk]]]]]
  [["/topics/" :topic] [["" :private-topic]]]
  ["/schemas" :schemas]
  [["/orgs/" :org-id] [["/topics" :org-topics]]]]]


Often a distinction is made between eDSLs (using language constructs) and DSLs (usually in text). Almost everything in Clojure is an eDSL if you use data to describe something


I mean that is definitely different from typical usage of vectors, but all it really does is define a tree of routes. Most of what the more data-oriented web libraries do is to combine something like that bidi example with some regular old maps. Is that really a DSL? I think it’s great that Clojure is so focused on data > function > macros, but I think something that is singular in purpose and which can be parsed in a few lines of code can hardly be called a DSL. Something like Hiccup is obviously simple-looking too, but it also comes with - obviously inherited from HTML and XML - a very rich set of semantics and additional syntax, even though on the surface it’s just a bunch of [:tag {:attr ...} [:child ...]]. When you write Hiccup, you’re painting a web page. When you write a bidi route, you’re writing a bidi route.


Not knocking on bidi, reitit, pedestal, compojure and so on AT ALL, but I think they’re quite different.


> Often a distinction is made between eDSLs (using language constructs) and DSLs (usually in text). Almost everything in Clojure is an eDSL if you use data to describe something Seems worth mentioning here (for anyone who hasn't read it) Martin Fowler's book Domain Specific Languages, which I believe initially coined that external/internal DSL distinction, and which IMHO is indispensable for anyone diving into DSLs.

👍 3

Thanks, I’ll check it out 🙂


(on to the Tsundoku pile it goes :P)

😆 3

@U4P4NREBY I still don't really see the difference. The interpreter (or compiler) for reitit routes is quite sophisticated, althought their notation is very simple. So yeah, you could argue, is JSON/YAML/hiccup vector/maps config a DSL when there is a complex interpreter behind it, or what makes the DSL a DSL in that case?


Is a Dockerfile a DSL because of the machinery behind it or because of the superficial syntax? And what if you write this Dockerfile in JSON or YAML, is it then a config file or still a DSL?


I would definitely say that a Dockerfile is a DSL since there are both very specific semantics and syntax involved and the purpose of a Dockerfile is varied enough that I would call it a distinct language. If you write a Dockerfile in a different language, then yes, that’s a DSL too, because you’re still writing using the Docker semantics and some slightly different syntax. At some point a cut has to be made, though. What about a path in a file system? Is that a DSL? I mean, it is a language of sorts. You can compose layers of file system navigation using slashes and there are operators, e.g. .. to backtrack. But all you’re really doing with this language is define routes - kinda like bidi. So using a loose definitions of what makes a DSL, a file path is a DSL and a bidi route is a DSL too. To me, a DSL is not just something that does one very simple thing. If we’re being really pedantic about it, sure, we could always define a DSL to be that. I think that’s setting the bar a bit too low. There has to be cutoff point. Yours is definitely in a different place than mine and that’s okay :-)


Obviously, DSLs are usually meant to do very specific things, so I’m not saying that the purpose of the DSL can’t be simple, but if its grammar is incredibly basic too… then the number of items in the list will definitely need to be of a different magnitude entirely. I’m not sure it would be fit for the purpose I had for it any longer (documenting DSLs in Clojure and tools for making them).


That said, I am definitely considering adding a separate section for data-oriented configuration and alike, since it’s so common in Clojure.


So is deps.edn a DSL: the machinery behind it is certainly not trivial, but the data format is "just EDN". Same with writing Docker semantics in JSON. It's very blurry.


It’s definitely blurry. I already have a disclaimer in the list about that > In either case, a supposed DSL could just as easily be considered a creative use of existing language features or a particularly well-designed API.


Thanks for the interesting discussion :)


You too. 😉 thanks for making cool stuff.

Vincent Cantin18:01:03

@U4P4NREBY Minimallist is missing in the list.

Vincent Cantin19:01:37

@U4P4NREBY Girouette might also be relevant for your list


I added minimallist and vrac (under a new WIP section) since I found the idea really fascinating. On the other hand, I’m not really sure what girouette even does, so I left that out for now.

👍 3

also, your taiwan example in the diffuse readme made me chuckle 🙂

😅 3
Vincent Cantin03:01:21

Minimallist, Diffuse and Girouette were all developed with the purpose if being useful for Vrac - that's the underlying bigger picture. I will document and present Girouette next week, will send you the link once ready.

🙏 3
emil0r08:01:58 updated to 0.2.1 and new fancy documentation/demo showing the library in action. I also made a very bad logo o_O

👍 9
henryw37411:01:37 version 0.1.12. • the major news is that you get helpful error messages (which are lacking in java.time). This is yet another reason to prefer this lib over plain interop with java.time - blogged about here: • also removed is the use of compile-target macros - which should speed things up for babashka users

🎉 39
clj 9
parrot 12

(require '[babashka.deps :as deps])

(deps/add-deps '{:deps { {:mvn/version "0.1.12"}}})

(require  '[ :as ld])

(def a-date (ld/parse "2019-01-01"))

(ld/plus-days a-date 99)
$ time bb /tmp/jtime.clj
#object[java.time.LocalDate 0x35095813 "2019-04-10"]
bb /tmp/jtime.clj   0.03s  user 0.02s system 89% cpu 0.049 total


cheers. yeah It's always going to be slower than (.parse java.time.LocalDate "2020-02-02") (about 3x on my machine) ,on bb because it has to interpret a bunch more code first etc


well, it's still fast :) and writing clojure can be more friendly


I see about 10ms speedup between .11 and .12 on my machine

babashka 3
slipset20:01:54 version 0.1.5 • support for -X, thanks to @rickmoynihan • support for private s3 repositories, also thanks to @rickmoynihan Thanks to @nichols1991 for pushing this release across the finish line and also for providing the upgrade to the s3-wagon dep so it also works with Java 10. Any errors are mine.

🎉 30
parrot 9

Thanks for getting this merged!