简体   繁体   中英

How do I write DSLs in Clojure(Script) without parenthesis?

As Clojure(Script) is a Lisp, all examples of DSLs (Domain Specific Languages) in it use parenthesis to encode were expressions begin and end (as Lisp does). However, at least another Lisp dialect ( Racket ), has many examples of "parenthesis less" DSLs ( Creating Languages in Racket , DSL1 , DSL2 ). I can use some ad hoc method to convert:

if (a > 10) { print "Ok!" }    ==>    (if (> a 10) (print "Ok!"))

I would like to know if there is some best practice guide or library to do these transformations in Clojure. Or maybe someone has ported Racket's functions that do these transformations to Clojure (I am not a Racket user). Can a Racket user point me to some Racket documentation about how it processes such DSLs?

Clojure intentionally did not add user-definable reader-macros. Which are a feature that is used to do top level code transformations. Clojure does include these, they are just not user-definable so there are a fixed number of them.

One example is the #_ reader macro that removes the next expression entirely. (you can stack them)

#_#_#_(:println  1) (println 2) (println 3) (println 4)
4

What you can do is define tagged literals which solves many of the same problems though they are not really intended for defining external DSLs. Most of the time you would have a top level dsl-start macro and then you don't have to use any () s beyond the initial two surrounding the start symbol. With the limitation that what you present in your language must consist of readable expressions (symbolc, maps, vectors, lists, etc.)

(with-my-special-language
   if (a > 10) { print "Ok!" }
   if (a > 42) { print "Even Better!" }
)

If you really want to avoid exposing the two () to the person writing this code you can read that code into a string, add the () your self and then evaluate it. It's very handy having direct access to the reader like this.

There is a library called chiara which lets you write Clojure without using parentheses. From the README:

(ns my-ns
  (use chiara))

(use-chiara) (chiara

defn foo [x]
  map inc (range x)

def my-list
  foo 10

)

It introduces syntax macros which let you do the kind of transformations you're after.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM