For the first MadLibs examples, let's try writing some Lisps. People
soetimes talk about 'Lisp' as though it were some specific language,
but Lisp is a family of related languages with some commonalities.
Broadly speaking, Lisps are dynamically typed, have functional
features like closures but aren't necessarily pure, and use a syntax
based on S-expressions. These aren't always the case—Shen is a
statically typed Lisp, Common Lisp has functional features but is
often used imperatively, and Dylan is a Lisp that uses a more
traditional Algol-like syntax—but they are broadly applicable.
The S-expression syntax is often a sticking point for people first
learning Lisp, but it's also one of the powerful features of
Lisp. In a typical Algol-descended language like (say) C, a
compiler will start by taking your textual source and parsing
it into a kind of tree. An expression like `f(3 + x * 2)` has
to be transformed int oa hierarchical representation that the
computer can understand, applying order-of-operations so
that it's clear how to group the relevant operations.
~~~~
|
+--+---+
| |
| +--+--+
| | |
| | +-+-+
| | | |
f ( 3 + x * 2 )
~~~~
In typical Lisp syntax, this tree is written more-or-less
explicitly, using parentheses to indicate the relevant grouping,
as `(f (+ 3 (* x 2)))`. This means that arithmetic expressions
can be a bit syntactically noisy, but has the benefit of being
very clear and uniform. Even higher-level syntactic constructs
use this format: where C would use curly braces or some other
syntactic construct, Lisps continue to use parentheses. For example,
the C program
~~~{.c}
int max(int x, int y)
{
if (x > y) {
return x;
} else {
return y;
}
}
~~~
is analogous to the Scheme program
~~~~{.scheme}
(define (max x y)
(if (> x y) x y))
~~~~
This makes