"A micro-manual for Scheme"? - lisp

Given that LISP apparently can be expressed in "10 rules" of "A micro-manual for LISP" [1][2] (is this true?), is there a similarly succinct description of Scheme?

McCarthy's "10 Rules" here are essentially an early form of operational semantics. This document comes from 1978, and is written 3 years after the first Scheme Report, wherein Abelson & Steele pull out the simple bits of LISP to create Scheme. Both Scheme and LISP are moving targets, so you have to qualify comparisons by saying, e.g., "this matches the scheme of its day." I claim that you can regard this micro-manual as applying equally to Scheme and LISP.
FWIW, McCarthy's rule for function evaluation (below) uses the phrase "in the original environment", which appears to require capture-avoiding substitution, and thus lexical scoping.
"9. value ((LAMBDA (v1 ... vn) e) e1 ... en) is the same as value e but in an environment in which the variables v1 ... vn take the
values of the expressions e1 ... e1 in the original environment." [emphasis mine]

I'd argue that, at 43 pages, the best succinct description of Scheme is the original. But, then again, I'm a Common Lisp programmer.

Related

LISP lists and normal form

Some LISP expressions evaluate to themselves (examples are MIT-Scheme REPL, though GNU Common Lisp agrees):
1 ]=> 3
;Value: 3
And are in normal form. Evaluation of an expression (such as (+ 2 1)) thus can properly be said to be conversion to normal form. That's nice, because that's how I've always understood evaluation formally.
But with lists we're in trouble:
1 ]=> (list 3 2)
; Value 16: (3 2)
1 ]=> (3 2)
;The object 3 is not applicable.
;To continue, call RESTART with an option number:
; (RESTART 2) => Specify a procedure to use in its place.
; (RESTART 1) => Return to read-eval-print level 1.
Am I right in thinking that:
(many[0]) LISPs don't have normal forms for (non-empty) lists, and
(many) LISPs do not have the property that evaluation is reduction to normal form?
If so, isn't this somewhat at odds with formalisms in PLT such as abstract rewriting systems? What alternative formalisms do capture evaluation in LISPs?
[0] Or perhaps more accurately, "most of the prominent LISPs", such as CL, Clojure, and Scheme. But I'd be interested in less well-known counter-examples!
Lisp can be defined in terms of only a few primitive operators. How many primitives does it take to build a LISP machine? Ten, seven or five? So you could consider there to be a normal form for what you get from expanding to them.
But Lisp isn't the lambda calculus. What type of lambda calculus would Lisp loosely be an example of?
And Lisp wasn't designed to be like the lambda calculus:
To use functions as arguments, one needs a notation for functions, and it seems natural to use the lambda-notation of Church. I didn’t understand the rest of the book, so I wasn’t tempted to try to implement his more general mechanism for defining functions.
-- History of Lisp, Stanford AI Laboratory memo 1979 by J. McCarthy, page 6

Want to distinguish between value and expression

I'd like to know how I can distinguish between 'value' and 'expression'.
In computer science, a value is an expression which cannot be
evaluated any further (a normal form).[1] The members of a type are
the values of that type.[1] For example, the expression 1 + 2 is not a
value as it can be reduced to the expression 3. This expression cannot
be reduced any further (and is a member of the type Nat) and therefore
is a value.
I found a statement above from the url below:
https://en.wikipedia.org/wiki/Value_(computer_science) 2
From this statement I felt like:
I think "value" look like the "atom" in chemistry based upon the
definition of Mitchell, John C.
But someone denied this:
But, even expressions can be (represented as) values. The classic case
being an s-expression in Lisp-like languages. – user2864740
This talk is in another thread : what-is-the-value-in-1st-class-value 3
It would have been so simple if user2864740 didn't say anything. But he said so and I am confused.
Could someone explain me about this situation? or the difference that might exist in lisp like languages?
Thank you in advance!
[1] Mitchell, John C. (1996). Foundations for Programming Languages. The MIT Press.
If you don't know Lisp, read SICP and play with some Scheme implementation.
(the classic SICP book is a must read -it is a very good introductory book about programming-, so even if you know Lisp but didn't read SICP you really should read it; and it is freely available on-line.)
I strongly recommend reading C.Queinnec's Lisp In Small Pieces book, which explains how LISP interpreters or compilers expressions are designed, so cover your question is great details.
(actually your question needs an entire book to be answered, and Queinnec's book is that book)
LISP is an homoiconic language, hence s-expressions are values (but several values are not expressions, in particular closures). But most programming languages -C, Ocaml, Javascript, C++, Java, etc...- are (sadly) not homoiconic: their AST is not a value and expressions cannot manipulate ASTs natively.
BTW, the wikipedia sentence
a value is an expression which cannot be evaluated any further
is not always correct. For example, for the C language, values and expressions are different kind of beasts.
You should also read something about formal semantics of programming languages.
Also, reading Scott's Programming Language Pragmatics will give you a broader view (thru several programming languages).
A value is a datum: the machine representation of some piece of information, such as a number or character string. The datum belongs to a type which has an associated domain: as set of all possible values of that type. The value is an element of that set.
An expression is a datum which represents syntax: usually a structured datum build as an aggregate (usually a tree structure) of other values. However, an individual non-aggregated value can also be an expression.
The purpose of an expression may be to denote the computation of a value; in that situation, ANSI Common Lisp refers to an expression as a form. Not all expressions are forms. For instance in (let ((a 42))), (a 42) is an expression denoting, in the context of let, the variable a and its initializing form 42, and ((a 42)) is an expression denoting the complete list of binding specifications under that let.
If a form is evaluated, and the result is a datum similar to that form itself, then one of the two is the case: the form might be a literal (a value which evaluates to itself if it is treated as an expression) or it might be a quine: a clever form which doesn't directly yield itself as a value (the way a literal does) but cleverly calculates an object which is structurally identical to itself.
A value is not defined as an expression which is irreducible and denotes itself; that is a literal constant. A literal constant denotes a value. Values, however, exist in all contexts, such as the run-time context in which syntax is no longer relevant. When a program is running, it can instantiate values which never exist as a piece of syntax. If we evaluate (+ 2 2), there is a 4 which never appeared in the syntax as the expression 4. Therefore we cannot say that the value 4 is an expression which is irreducible; the value exists even if no such expression does.

Functional programming: Curry & Fold - what are the etymologies?

Curry & Fold - what are the etymologies in the programmatic sense?
I do not see how any of the English meanings of these homonyms is related to the functionality of these terms.
If you had to rename them to something more obvious - how would you do it?
Curry is the last name of Haskell Curry, a prominent 20th century logician after whom Haskell got its name.
And "folding" simply because the fold operator figuratively represents folding, like a hand of cards can be folded to look like a single card. Think of foldr (+) 0 [1,2,3] == 6 as a hand of cards 1, 2 and 3 folded into a single card 6.
The word "reducing", which also means folding, can be illustrated using a similar analogy.
Of course, Haskell is more magic than even the bluffiest and luckiest game of poker, so folds in functional programming can actually produce a deck of cards that holds more cards than the hand it was folded from, or cards can be folded into cats, etc: foldr (\i, acc -> [show i,show i,show i] ++ acc) [] [1,2,3] == ["1","1","1","2","2","2","3","3","3"]. Therefore what started out as folding eventually evolved into an extremely universal operator that can produce map as well as filter etc, so don't get too carried away with the poker comparison and etymology.
As to what to name them to: renaming a dead person might not be the most ethical thing to do. The poor guy is so successful BOTH of his names are used for big things, and then you want to deprive him posthumously of his joy and rename him to something else? Unless perhaps that something else is Newton Watt Scoville or Kelvin Celsius Ângström, I'd seriously not attempt a rename.
However if you meant renaming the programming concept: it could instead be referred to by the name "ricing" in my hungry opinion. But Mr. Curry might still feel intimidated.
Folding could actually be renamed to bluffing, if you're not fulfilled by the multitude of presently available names for it — thanks to som-snytt for the constructive idea.
I believe that the "fold" term comes mainly from the use of the word "fold" in phrases like "to fold into..." which is a term most commonly used by chefs, I believe (I watch a lot of cooking shows...). We use it in the context of functional programming because we say that, for example, for lists, the head of the list is "folded into" the resulting of folding the tail. For example, the function foldr is a "recipe" for how to "cook" a list, and part of that recipe is "fold this into that", if you like.
The oldest reference to "folding" that I could find on the internet in the context of functional programming in this report, published in 1985 by the University of Cambridge, which has this to say:
The function gather applies a function of two arguments “between” each element of a list and a terminal value. [...] This function is also known as reduce or fold in other languages.
So clearly the term "fold" was at least somewhat common even 30 years ago!

What type of lambda calculus would Lisp loosely be an example of?

I'm trying to get a better grip on how types come into play in lambda calculus. Admittedly, a lot of the type theory stuff is over my head. Lisp is a dynamically typed language, would that roughly correspond to untyped lambda calculus? Or is there some kind of "dynamically typed lambda calculus" that I'm unaware of?
Lisp is a dynamically typed language, would that roughly correspond to untyped lambda calculus?
Yes, but only roughly. In the "pure" untyped lambda calculus, everything is coded as functions. (You can google for the popular "Church encoding" and the less popular "Scott encoding".) Lisp has non-functional data, like atoms and numbers and such, so this would count as "untyped lambda calculus extended with constants."
Another important difference is in order of evaluation. Rules for reducing lambda-calculus terms are highly nondeterministic. (There's a theorem, the Church-Rosser theorem, which says loosely that as long as things terminate, order of evaluation doesn't matter.) In practice lambda terms are typically reduced using leftmost-outermost aka "normal-order" reduction because if any reduction strategy terminates, that one does.
This is very different from Lisp which always evaluates arguments to normal form before doing a beta-reduction. This evaluation order is called "call by value."
In summary, Lisp corresponds to an untyped, call-by-value lambda calculus extended with constants.
John McCarthy introduced LISP in his April, 1960 paper "Recursive Functions of Symbolic Expressions and Their Computation by Machine, Part I". The following paragraph is from page 6:
e. Functions and Forms. It is usual in mathematics — outside of mathematical logic — to use the word “function” imprecisely and to apply it to forms
such as y2 + x. Because we shall later compute with expressions for functions,
we need a distinction between functions and forms and a notation for express-
ing this distinction. This distinction and a notation for describing it, from
which we deviate trivially, is given by Church [3].
...
3. A. CHURCH, The Calculi of Lambda-Conversion (Princeton University
Press, Princeton, N. J., 1941).
The Wikipedia article on lambda-calculus has a history of Church's publications. The 1941 paper referenced by McCarthy seems to be about the typed lambda-calculus, in contradiction to the Wikipedia article's introduction.
The lambda keyword in Lisp can be understood to refer to the lambda-calculus only through analogy. A Lisp lambda expression is a type of anonymous function.
Lisp is not 'a lambda calculus', I don't know what 'a lambda calculus' is.
If you want to identify lambda calculi by there type system then Lisp is its own of course. The 'lambda' keyword in any lisp before Scheme is certainly pretentious, and after Scheme there's room too to say it is. Just using 'func' would have been more humble. Lisp is a list processor mainly, not a 'lambda calculus'
I also wrote a rather extensive article about this once that attempts to demonstrate why A: the term 'functional programming' is meaningless and B: why the speaking of 'a lambda calculus' rather than 'a type system' is so too:
http://blog.nihilarchitect.net/archives/289/on-functional-programming/
Also, keep in mind that in Lisp, all functions are in effect single argument and can only be have lists as their arguments.

What makes Lisp macros so special?

Reading Paul Graham's essays on programming languages one would think that Lisp macros are the only way to go. As a busy developer, working on other platforms, I have not had the privilege of using Lisp macros. As someone who wants to understand the buzz, please explain what makes this feature so powerful.
Please also relate this to something I would understand from the worlds of Python, Java, C# or C development.
To give the short answer, macros are used for defining language syntax extensions to Common Lisp or Domain Specific Languages (DSLs). These languages are embedded right into the existing Lisp code. Now, the DSLs can have syntax similar to Lisp (like Peter Norvig's Prolog Interpreter for Common Lisp) or completely different (e.g. Infix Notation Math for Clojure).
Here is a more concrete example:Python has list comprehensions built into the language. This gives a simple syntax for a common case. The line
divisibleByTwo = [x for x in range(10) if x % 2 == 0]
yields a list containing all even numbers between 0 and 9. Back in the Python 1.5 days there was no such syntax; you'd use something more like this:
divisibleByTwo = []
for x in range( 10 ):
if x % 2 == 0:
divisibleByTwo.append( x )
These are both functionally equivalent. Let's invoke our suspension of disbelief and pretend Lisp has a very limited loop macro that just does iteration and no easy way to do the equivalent of list comprehensions.
In Lisp you could write the following. I should note this contrived example is picked to be identical to the Python code not a good example of Lisp code.
;; the following two functions just make equivalent of Python's range function
;; you can safely ignore them unless you are running this code
(defun range-helper (x)
(if (= x 0)
(list x)
(cons x (range-helper (- x 1)))))
(defun range (x)
(reverse (range-helper (- x 1))))
;; equivalent to the python example:
;; define a variable
(defvar divisibleByTwo nil)
;; loop from 0 upto and including 9
(loop for x in (range 10)
;; test for divisibility by two
if (= (mod x 2) 0)
;; append to the list
do (setq divisibleByTwo (append divisibleByTwo (list x))))
Before I go further, I should better explain what a macro is. It is a transformation performed on code by code. That is, a piece of code, read by the interpreter (or compiler), which takes in code as an argument, manipulates and the returns the result, which is then run in-place.
Of course that's a lot of typing and programmers are lazy. So we could define DSL for doing list comprehensions. In fact, we're using one macro already (the loop macro).
Lisp defines a couple of special syntax forms. The quote (') indicates the next token is a literal. The quasiquote or backtick (`) indicates the next token is a literal with escapes. Escapes are indicated by the comma operator. The literal '(1 2 3) is the equivalent of Python's [1, 2, 3]. You can assign it to another variable or use it in place. You can think of `(1 2 ,x) as the equivalent of Python's [1, 2, x] where x is a variable previously defined. This list notation is part of the magic that goes into macros. The second part is the Lisp reader which intelligently substitutes macros for code but that is best illustrated below:
So we can define a macro called lcomp (short for list comprehension). Its syntax will be exactly like the python that we used in the example [x for x in range(10) if x % 2 == 0] - (lcomp x for x in (range 10) if (= (% x 2) 0))
(defmacro lcomp (expression for var in list conditional conditional-test)
;; create a unique variable name for the result
(let ((result (gensym)))
;; the arguments are really code so we can substitute them
;; store nil in the unique variable name generated above
`(let ((,result nil))
;; var is a variable name
;; list is the list literal we are suppose to iterate over
(loop for ,var in ,list
;; conditional is if or unless
;; conditional-test is (= (mod x 2) 0) in our examples
,conditional ,conditional-test
;; and this is the action from the earlier lisp example
;; result = result + [x] in python
do (setq ,result (append ,result (list ,expression))))
;; return the result
,result)))
Now we can execute at the command line:
CL-USER> (lcomp x for x in (range 10) if (= (mod x 2) 0))
(0 2 4 6 8)
Pretty neat, huh? Now it doesn't stop there. You have a mechanism, or a paintbrush, if you like. You can have any syntax you could possibly want. Like Python or C#'s with syntax. Or .NET's LINQ syntax. In end, this is what attracts people to Lisp - ultimate flexibility.
You will find a comprehensive debate around lisp macro here.
An interesting subset of that article:
In most programming languages, syntax is complex. Macros have to take apart program syntax, analyze it, and reassemble it. They do not have access to the program's parser, so they have to depend on heuristics and best-guesses. Sometimes their cut-rate analysis is wrong, and then they break.
But Lisp is different. Lisp macros do have access to the parser, and it is a really simple parser. A Lisp macro is not handed a string, but a preparsed piece of source code in the form of a list, because the source of a Lisp program is not a string; it is a list. And Lisp programs are really good at taking apart lists and putting them back together. They do this reliably, every day.
Here is an extended example. Lisp has a macro, called "setf", that performs assignment. The simplest form of setf is
(setf x whatever)
which sets the value of the symbol "x" to the value of the expression "whatever".
Lisp also has lists; you can use the "car" and "cdr" functions to get the first element of a list or the rest of the list, respectively.
Now what if you want to replace the first element of a list with a new value? There is a standard function for doing that, and incredibly, its name is even worse than "car". It is "rplaca". But you do not have to remember "rplaca", because you can write
(setf (car somelist) whatever)
to set the car of somelist.
What is really happening here is that "setf" is a macro. At compile time, it examines its arguments, and it sees that the first one has the form (car SOMETHING). It says to itself "Oh, the programmer is trying to set the car of somthing. The function to use for that is 'rplaca'." And it quietly rewrites the code in place to:
(rplaca somelist whatever)
Common Lisp macros essentially extend the "syntactic primitives" of your code.
For example, in C, the switch/case construct only works with integral types and if you want to use it for floats or strings, you are left with nested if statements and explicit comparisons. There's also no way you can write a C macro to do the job for you.
But, since a lisp macro is (essentially) a lisp program that takes snippets of code as input and returns code to replace the "invocation" of the macro, you can extend your "primitives" repertoire as far as you want, usually ending up with a more readable program.
To do the same in C, you would have to write a custom pre-processor that eats your initial (not-quite-C) source and spits out something that a C compiler can understand. It's not a wrong way to go about it, but it's not necessarily the easiest.
Lisp macros allow you to decide when (if at all) any part or expression will be evaluated. To put a simple example, think of C's:
expr1 && expr2 && expr3 ...
What this says is: Evaluate expr1, and, should it be true, evaluate expr2, etc.
Now try to make this && into a function... thats right, you can't. Calling something like:
and(expr1, expr2, expr3)
Will evaluate all three exprs before yielding an answer regardless of whether expr1 was false!
With lisp macros you can code something like:
(defmacro && (expr1 &rest exprs)
`(if ,expr1 ;` Warning: I have not tested
(&& ,#exprs) ; this and might be wrong!
nil))
now you have an &&, which you can call just like a function and it won't evaluate any forms you pass to it unless they are all true.
To see how this is useful, contrast:
(&& (very-cheap-operation)
(very-expensive-operation)
(operation-with-serious-side-effects))
and:
and(very_cheap_operation(),
very_expensive_operation(),
operation_with_serious_side_effects());
Other things you can do with macros are creating new keywords and/or mini-languages (check out the (loop ...) macro for an example), integrating other languages into lisp, for example, you could write a macro that lets you say something like:
(setvar *rows* (sql select count(*)
from some-table
where column1 = "Yes"
and column2 like "some%string%")
And thats not even getting into Reader macros.
Hope this helps.
I don't think I've ever seen Lisp macros explained better than by this fellow: http://www.defmacro.org/ramblings/lisp.html
A lisp macro takes a program fragment as input. This program fragment is represented a data structure which can be manipulated and transformed any way you like. In the end the macro outputs another program fragment, and this fragment is what is executed at runtime.
C# does not have a macro facility, however an equivalent would be if the compiler parsed the code into a CodeDOM-tree, and passed that to a method, which transformed this into another CodeDOM, which is then compiled into IL.
This could be used to implement "sugar" syntax like the for each-statement using-clause, linq select-expressions and so on, as macros that transforms into the underlying code.
If Java had macros, you could implement Linq syntax in Java, without needing Sun to change the base language.
Here is pseudo-code for how a lisp-style macro in C# for implementing using could look:
define macro "using":
using ($type $varname = $expression) $block
into:
$type $varname;
try {
$varname = $expression;
$block;
} finally {
$varname.Dispose();
}
Since the existing answers give good concrete examples explaining what macros achieve and how, perhaps it'd help to collect together some of the thoughts on why the macro facility is a significant gain in relation to other languages; first from these answers, then a great one from elsewhere:
... in C, you would have to write a custom pre-processor [which would probably qualify as a sufficiently complicated C program] ...
—Vatine
Talk to anyone that's mastered C++ and ask them how long they spent learning all the template fudgery they need to do template metaprogramming [which is still not as powerful].
—Matt Curtis
... in Java you have to hack your way with bytecode weaving, although some frameworks like AspectJ allows you to do this using a different approach, it's fundamentally a hack.
—Miguel Ping
DOLIST is similar to Perl's foreach or Python's for. Java added a similar kind of loop construct with the "enhanced" for loop in Java 1.5, as part of JSR-201. Notice what a difference macros make. A Lisp programmer who notices a common pattern in their code can write a macro to give themselves a source-level abstraction of that pattern. A Java programmer who notices the same pattern has to convince Sun that this particular abstraction is worth adding to the language. Then Sun has to publish a JSR and convene an industry-wide "expert group" to hash everything out. That process--according to Sun--takes an average of 18 months. After that, the compiler writers all have to go upgrade their compilers to support the new feature. And even once the Java programmer's favorite compiler supports the new version of Java, they probably ''still'' can't use the new feature until they're allowed to break source compatibility with older versions of Java. So an annoyance that Common Lisp programmers can resolve for themselves within five minutes plagues Java programmers for years.
—Peter Seibel, in "Practical Common Lisp"
Think of what you can do in C or C++ with macros and templates. They're very useful tools for managing repetitive code, but they're limited in quite severe ways.
Limited macro/template syntax restricts their use. For example, you can't write a template which expands to something other than a class or a function. Macros and templates can't easily maintain internal data.
The complex, very irregular syntax of C and C++ makes it difficult to write very general macros.
Lisp and Lisp macros solve these problems.
Lisp macros are written in Lisp. You have the full power of Lisp to write the macro.
Lisp has a very regular syntax.
Talk to anyone that's mastered C++ and ask them how long they spent learning all the template fudgery they need to do template metaprogramming. Or all the crazy tricks in (excellent) books like Modern C++ Design, which are still tough to debug and (in practice) non-portable between real-world compilers even though the language has been standardised for a decade. All of that melts away if the langauge you use for metaprogramming is the same language you use for programming!
I'm not sure I can add some insight to everyone's (excellent) posts, but...
Lisp macros work great because of the Lisp syntax nature.
Lisp is an extremely regular language (think of everything is a list); macros enables you to treat data and code as the same (no string parsing or other hacks are needed to modify lisp expressions). You combine these two features and you have a very clean way to modify code.
Edit: What I was trying to say is that Lisp is homoiconic, which means that the data structure for a lisp program is written in lisp itself.
So, you end up with a way of creating your own code generator on top of the language using the language itself with all its power (eg. in Java you have to hack your way with bytecode weaving, although some frameworks like AspectJ allows you to do this using a different approach, it's fundamentally a hack).
In practice, with macros you end up building your own mini-language on top of lisp, without the need to learn additional languages or tooling, and with using the full power of the language itself.
Lisp macros represents a pattern that occurs in almost any sizeable programming project. Eventually in a large program you have a certain section of code where you realize it would be simpler and less error prone for you to write a program that outputs source code as text which you can then just paste in.
In Python objects have two methods __repr__ and __str__. __str__ is simply the human readable representation. __repr__ returns a representation that is valid Python code, which is to say, something that can be entered into the interpreter as valid Python. This way you can create little snippets of Python that generate valid code that can be pasted into your actually source.
In Lisp this whole process has been formalized by the macro system. Sure it enables you to create extensions to the syntax and do all sorts of fancy things, but it's actual usefulness is summed up by the above. Of course it helps that the Lisp macro system allows you to manipulate these "snippets" with the full power of the entire language.
In short, macros are transformations of code. They allow to introduce many new syntax constructs. E.g., consider LINQ in C#. In lisp, there are similar language extensions that are implemented by macros (e.g., built-in loop construct, iterate). Macros significantly decrease code duplication. Macros allow embedding «little languages» (e.g., where in c#/java one would use xml to configure, in lisp the same thing can be achieved with macros). Macros may hide difficulties of using libraries usage.
E.g., in lisp you can write
(iter (for (id name) in-clsql-query "select id, name from users" on-database *users-database*)
(format t "User with ID of ~A has name ~A.~%" id name))
and this hides all the database stuff (transactions, proper connection closing, fetching data, etc.) whereas in C# this requires creating SqlConnections, SqlCommands, adding SqlParameters to SqlCommands, looping on SqlDataReaders, properly closing them.
While the above all explains what macros are and even have cool examples, I think the key difference between a macro and a normal function is that LISP evaluates all the parameters first before calling the function. With a macro it's the reverse, LISP passes the parameters unevaluated to the macro. For example, if you pass (+ 1 2) to a function, the function will receive the value 3. If you pass this to a macro, it will receive a List( + 1 2). This can be used to do all kinds of incredibly useful stuff.
Adding a new control structure, e.g. loop or the deconstruction of a list
Measure the time it takes to execute a function passed in. With a function the parameter would be evaluated before control is passed to the function. With the macro, you can splice your code between the start and stop of your stopwatch. The below has the exact same code in a macro and a function and the output is very different. Note: This is a contrived example and the implementation was chosen so that it is identical to better highlight the difference.
(defmacro working-timer (b)
(let (
(start (get-universal-time))
(result (eval b))) ;; not splicing here to keep stuff simple
((- (get-universal-time) start))))
(defun my-broken-timer (b)
(let (
(start (get-universal-time))
(result (eval b))) ;; doesn't even need eval
((- (get-universal-time) start))))
(working-timer (sleep 10)) => 10
(broken-timer (sleep 10)) => 0
One-liner answer:
Minimal syntax => Macros over Expressions => Conciseness => Abstraction => Power
Lisp macros do nothing more than writing codes programmatically. That is, after expanding the macros, you got nothing more than Lisp code without macros. So, in principle, they achieve nothing new.
However, they differ from macros in other programming languages in that they write codes on the level of expressions, whereas others' macros write codes on the level of strings. This is unique to lisp thanks to their parenthesis; or put more precisely, their minimal syntax which is possible thanks to their parentheses.
As shown in many examples in this thread, and also Paul Graham's On Lisp, lisp macros can then be a tool to make your code much more concise. When conciseness reaches a point, it offers new levels of abstractions for codes to be much cleaner. Going back to the first point again, in principle they do not offer anything new, but that's like saying since paper and pencils (almost) form a Turing machine, we do not need an actual computer.
If one knows some math, think about why functors and natural transformations are useful ideas. In principle, they do not offer anything new. However by expanding what they are into lower-level math you'll see that a combination of a few simple ideas (in terms of category theory) could take 10 pages to be written down. Which one do you prefer?
I got this from the common lisp cookbook and I think it explained why lisp macros are useful.
"A macro is an ordinary piece of Lisp code that operates on another piece of putative Lisp code, translating it into (a version closer to) executable Lisp. That may sound a bit complicated, so let's give a simple example. Suppose you want a version of setq that sets two variables to the same value. So if you write
(setq2 x y (+ z 3))
when z=8 both x and y are set to 11. (I can't think of any use for this, but it's just an example.)
It should be obvious that we can't define setq2 as a function. If x=50 and y=-5, this function would receive the values 50, -5, and 11; it would have no knowledge of what variables were supposed to be set. What we really want to say is, When you (the Lisp system) see (setq2 v1 v2 e), treat it as equivalent to (progn (setq v1 e) (setq v2 e)). Actually, this isn't quite right, but it will do for now. A macro allows us to do precisely this, by specifying a program for transforming the input pattern (setq2 v1 v2 e)" into the output pattern (progn ...)."
If you thought this was nice you can keep on reading here:
http://cl-cookbook.sourceforge.net/macros.html
In python you have decorators, you basically have a function that takes another function as input. You can do what ever you want: call the function, do something else, wrap the function call in a resource acquire release, etc. but you don't get to peek inside that function. Say we wanted to make it more powerful, say your decorator received the code of the function as a list then you could not only execute the function as is but you can now execute parts of it, reorder lines of the function etc.