clojure code modification preserving reader macros - clojure

In clojure, read-string followed by str will not return the original string, but the string for which the reader macros have been expanded:
(str (read-string "(def foo [] #(bar))"))
;"(def foo [] (fn* [] (bar)))"
This is problematic if we want to manipulate a small part of the code, far away from any reader macros, and get back a string representation that preserves the reader macros. Is there a work around?

The purpose of read is to build an AST of the code and as such the function does not preserve all the properties of the original text. Otherwise, it should keep track of the original code-layout (e.g. location of parenthesis, newlines, indentation (tabs/spaces), comments, and so on). If you have a look at LispReader.java, you can see that the reader macros are unconditionally applied (*read-eval* does not influence all reader macros).
Here is what I would recommend:
You can take inspiration of the existing LispReader and implement your own reader. Maybe it is sufficient to change the dispatch-table so that macro characters are directed to you own reader. You would also need to build runtime representations of the quoted forms and provide adequate printer functions for those objects.
You can process your original file with Emacs lisp, which can easily navigate the structure of your code and edit it as you wish.
Remark: you must know that what you are trying to achieve smells fishy. You might have a good reason to want to do this, but this looks needlessly complex without knowing why you want to work at the syntax level. It would help if you could provide more details.

Related

Abstract structure of Clojure

I've been learning Clojure and am a good way through a book on it when I realized how much I'm still struggling to interpret the code. What I'm looking for is the abstract structure, interface, or rules, Clojure uses to parse code. I think it looks something like:
(some-operation optional-args)
optional-args can be nearly anything and that's where I start getting confused.
(operation optional-name-string [vector of optional args]) would equal (defn newfn [argA, argB])
I think this pattern holds for all lists () but with so much flexibility and variation in Clojure, I'm not sure. It would be really helpful to see the rules the interpreter follows.
You are not crazy. Sure it's easy to point out how "easy" ("simple"? but that another discussion) Clojure syntax is but there are two things for a new learner to be aware of that are not pointed out very clearly in beginning tutorials that greatly complicate understanding what you are seeing:
Destructuring. Spend some quality time with guides on destructuring in Clojure. I will say that this adds a complexity to the language and is not dissimilar from "*args" and "**kwargs" arguments in Python or from the use of the "..." spread operator in javascript. They are all complicated enough to require some dedicated time to read. This relates to the optional-args you reference above.
macros and metaprogramming. In the some-operation you reference above, you wish to "see the rules the interpreter follows". In the majority of the cases it is a function but Clojure provides you no indication of whether you are looking at a function or a macro. In the standard library, you will just need to know some standard macros and how they affect the syntax they headline. (e.g. if, defn etc). For included libraries, there will typically be a small set of macros that are core to understanding that library. Any macro will to modify, dare I say, complicate the syntax in the parens you are looking at so be on your toes.
Clojure is fantastic and easy to learn but those two points are not to be glossed over IMHO.
Before you start coding with Clojure, I highly recommend studying functional programming and LISB. In Clojure, everything is a prefix, and when you want to run and specific function, you will call it and then feed it with some arguments. for example, 1+2+3 will be (+ 1 2 3) in Clojure. In other words, every function you call will be at the start of a parenthesis, and all of its arguments will be follows the function name.
If you define a function, you may do as follow:
(defn newfunc [a1 a2]
(+ 100 a1 a2))
Which newfunc add 100 and a1 and a2. When you call it, you should do this:
(newfunc 1 2)
and the result will be 103.
in the first example, + is a function, so we call it at the beginning of the parenthesis.
Clojure is a beautiful world full of simplicity. Please learn it deeply.

What's the purpose of #_ in Clojure?

I was going through a library code in which they used #_. As gone through multiple references, I understand #_ is discard symbol, which tell the reader to ignore whatever comes next.
Why it is even needed in the first place? If we have something to be ignored, why can't we remove it or just comment it? What's the significance of #_ over commenting?
It's super handy when debugging or writing some altered code.
Say you have some massive function, and you want to comment it out for a bit. You have a few options:
You can use line comments:
; (defn some-huge-thing []
; ... Many lines)
But that's painful unless your IDE has an commenting shortcut, and even then it takes some work. Plus, I've found most IDE's handling of comment-shortcuts to work less than ideally. Sometimes they just add another "layer" of comments instead of removing the existing ones. Line comments also don't help if you only want to comment out a small piece of a function since they aren't context sensitive.
You could use comment:
(comment
(defn some-huge-thing []
... Many lines))
But I personally don't like comment because here, it requires either nesting the entire thing, or violating Parinfer just to add the comment. Also as #amalloy points out, it ends up expanding to nil, so it can only be used in a context where a stray nil won't effect anything.
... Or, you can use #_:
#_
(defn some-huge-thing []
... Many lines)
It doesn't require altering the function at all. It's just two keystrokes to put in, and two to remove. It also doesn't evaluate to nil; it's simply ignored. That means you can use it, for example, to comment out arguments inside of a function call.
I personally use #_ quite often when playing around with different implementations and when I'm trying to isolate a bug. It causes anything comming immediately after it to be ignored, so it's very easy to control what is and isn't executing.

What is the difference between "regular" and "reader" macros?

I am relatively new to Clojure and can't quite wrap my mind around the difference between reader macros and regular macros, and why the difference is significant.
In what situations would you use one over the other and why?
Reader macros change the syntax of the language (for example, #foo turns into (deref foo)) in ways that normal macros can't (a normal macro wouldn't be able to get rid of the parentheses, so you'd have to do something like (# foo)). It's called a reader macro, because it's implemented in the read pass of the repl (check out the source).
As a clojure developer, you'll only create regular macros, but you'll use plenty of reader macros, without necessarily considering them explicitly.
The full list of reader macros is here: https://clojure.org/reference/reader and includes common things like # ', and #{}.
Clojure (unlike some other lisps) doesn't support user-defined reader macros, but there is some extensibility built into the reader via tagged literals (e.g. #inst or #uuid)
tl;dr*
Macros [normal macros] are expanded during evaluation (E of REPL), tied to symbols, operate on lisp objects, and appear in the first, or "function", part of a form. Clojure, and all lisps, allow defining new macros.
Reader macros run during reading, prior to evaluation, are single characters, operate on a character string, prior to all the lisp objects being emitted from the reader, and are not restricted to being in the first, or "function", part of a form. Clojure, unlike some other lisps, does not allow defining new reader macros, short of editing the Clojure compiler itself.
more words:
Normal non-reader macros, or just "macros", operate on lisp objects. Consider:
(and 1 b :x)
The and macro will be called with two values, one value is 1 and the other is a list consisting of the symbol b (not the value of b) and the keyword :x. Everything the and macro is dealing with is already a lisp (Clojure) value.
Macro expansion only happens when the macro is at the beginning of a list. (and 1 2) expands the and macro. (list and) returns an error, "Can't take value of a macro"
The reader is reasponsible for turning a character string into In Clojure a reader macro is a single character that changes how the reader, the part responsible for turning a text stream into lisp objects, operates. The dispatch for Clojure's lisp reader is in LispReader.java. As stated by Alejandro C., Clojure does not support adding reader macros.
Reader macros are one character. (I do not know if that is true for all lisps, but Clojure's current implementation only supports single character reader macros.)
Reader macros can exist at any point in the form. Consider (conj [] 'a) if the ' macro were normal, the tick would need to become a lisp object so the code wold be a list of the symbol conj, an empty vector, the symbol ' and finally the symbol a. But now the evaulation rules would require that ' be evaluated by itself. Instead the reader, upon seeing the ' wraps the complete s-exp that follows with quote so that the value returned to the evaluator is a list of conj, an empty vector, and a list of quote followed by a. Now quote is the head of a list and can change the evaluation rules for what it quotes.
Talking shortly, a reader macros is a low-level feature. That's why there are so few of them (just #, quiting and a bit more). Having to many reader rules will turn any language into a mess.
A regular macro is a tool that is widely used in Clojure. As a developer, you are welcome to write your own regular macroses but not reader ones if you are not a core Clojure developer.
Your may always use your own tagged literals as a substitution of reader rules, for example #inst "2017" will give you a Date instance and so forth.

can defmacro quota parameter in clojure?

I have a string which will evaluate to true or false, can I use macro and pass the string as parameter? I write the following, but the result is string of (= 0 0) instead of true. How to get true result?
(def a "(= 0 0)")
(defmacro test [code-string] code-string)
(test a)
update:
The purpose is replace dynamic SQL. Currently we store code like 'column_a > 1' in database, and then we will get the code, and assemble a sql like
select case when column_a>1 then 0 else 1 end as result from table
There are many such code, and I hope to use clojure run in parallel to speed it up. To use clojure I could store '(> row["column_a"] 1)' in database, and then in jdbc looping, call (> row["column_a"] 1) to do my logic, like storing some code section in database and need to run it.
As TaylanUB already said, Clojure provides eval to evaluate some expression at run-time. However, using eval is frowned upon unless you have very good reasons to use it. It's not clear what you're really intending to do, so it would be helpful to provide a more real world example. If you don't have one, you don't need eval.
Similarly, macros are used to transform code and are not run at run-time, instead the code to which the macro evaluates gets run. The typical approach would be to try to solve a problem with a mere function, only if a macro would buy you something in terms of applicability to a wider range of code, consider turning the code into a macro. Edit: take a look at some introduction to macros in Clojure, e.g. this part from Clojure from the ground up
No, you cannot directly use a string as code. Defmacro takes s-expressions not strings. Clojure might have something like read which can parse a string and make an s-expression out of it which you might then be able to execute as code via something like eval.
There is usually no good reason to put code in strings or other data structures which will exist during program execution anyway, try to just work with first-class functions instead. Or mention the precise problem you're trying to solve and people might be able to give better answers. This might be an instance of the XY problem.
Note: I don't know Clojure, but all of this is pretty Lisp-generic.
(defn eval-code [code-string]
(eval (read-string code-string)))
(eval-code "(= 0 0)")
;; you don't need macro here.

Avoid name clashes in a Clojure DSL

As a side project I'm creating a Clojure DSL for image synthesis (clisk).
I'm a little unsure on the best approach to function naming where I have functions in the DSL that are analogous to functions in Clojure core, for example the + function or something similar is needed in my DSL to additively compose images / perform vector maths operations.
As far as I can see it there are a few options:
Use the same name (+) in my own namespace. Looks nice in DSL code but will override the clojure.core version, which may cause issues. People could get confused.
Use the same name but require it to be qualified (my-ns/+). Avoids conflicts, but prevents people from useing the namespace for convenience and looks a bit ugly.
Use a different short name e.g. (v+). Can be used easily and avoid clashes, but the name is a bit ugly and might prove hard to remember.
Use a different long name e.g. (vector-add). Verbose but descriptive, no clashes.
Exclude clojure.core/+ and redefine with a multimethod + (as georgek suggests).
Example code might look something like:
(show (v+ [0.9 0.6 0.3]
(dot [0.2 0.2 0]
(vgradient (vseamless 1.0 plasma) ))))
What is the best/most idiomatic approach?
first, the repeated appearance of operators in an infix expression requires a nice syntax, but for a lisp, with prefix syntax, i don't think this is as important. so it's not such a crime to have the user type a few more characters for an explicit namespace. and clojure has very good support for namespaces and aliasing. so it's very easy for a user to select their own short prefix: (x/+ ...) for example.
second, looking at the reader docs there are not many non-alphanumeric symbols to play with, so something like :+ is out. so there's no "cute" solution - if you choose a prefix it's going to have to be a letter. that means something like x+ - better to let the user choose an alias, at the price of one more character, and have x/+.
so i would say: ignore core, but expect the user to (:require .... :as ...). if they love your package so much they want it to be default then they can (:use ...) and handle core explicitly. but you choosing a prefix to operators seems like a poor compromise.
(and i don't think i have seen any library that does use single letter prefixes).
one other possibility is to provide the above and also a separate package with long names instead of operators (which are simply def'ed to match the values in the original package). then if people do want to (:use ...) but want to avoid clashes, they can use that (but really what's the advantage of (vector-add ...) over (vector/+ ...)?)
and finally i would check how + is implemented, since if it already involves some kind of dispatch on types then georgek's comment makes a lot of sense.
(by "operator" above i just mean single-character, non-alphanumeric symbol)