~brenns10/funlisp

942e18b8455c81dd7caa5d3763f89613902bee00 — Stephen Brennan 1 year, 10 months ago adf1bdf
Update docs
1 files changed, 108 insertions(+), 0 deletions(-)

M doc/language.rst
M doc/language.rst => doc/language.rst +108 -0
@@ 163,6 163,39 @@ Since we try to make everything in funlisp into an expression, if statements
must have both a "value if true" and a "value if false". You cannot leave out
the else.

Funlisp also has the ``cond`` statement, which allows you to test whether one of
several conditions match. To test this out, we'll define some functions that use
cond.

.. code:: lisp

  (define divisible
    (lambda (number by)
      (= number (* by (/ number by)))))

  (define talk-about-numbers
    (lambda (number)
      (cond
         ((divisible number 2) (print "The number " number " is even!"))
         ((divisible number 3) (print "It may not be even, but " number " is divisible by 3!"))
         (1 (print "The number " number " is odd, and not even divisible by 3.")))))

Don't worry about the function stuff, we'll revisit it later. Next is an example
using these functions in the interpreter.

.. code::

  > (talk-about-numbers 6)
  The number 6 is even!
  > (talk-about-numbers 5)
  The number 5 is odd, and not even divisible by 3.
  > (talk-about-numbers 9)
  It may not be even, but 9 is divisible by 3!

The cond statement can use "1" as a default truth condition. However, it need
not have a default case - when cond falls through, it returns nil, the empty
list.

Funlisp doesn't currently have any form of iteration. However, it supports
recursion, which is a very powerful way of iterating, and handling objects like
lists.


@@ 207,6 240,32 @@ list processing functions that do the following:
- ``(car l)`` - return the first item in l
- ``(cdr l)`` - return the elements after the first one in l

Scoping
-------

Sometimes, you want to evaluate a value once, and save it for use multiple
times. You can achieve this with ``let``. Let has the syntax ``(let BINDING-LIST
expressions...)``. BINDING-LIST is a list of pairs, mapping a symbol to a value.
Here's an example:

.. code::

  > (let ((x (+ 5 5)) (y (- x 2))) (+ x y))
  18

Here the binding list contains the pair ``(x (+ 5 5))``, mapping ``x`` to the
evaluated value 10. The next binding, ``(y (- x 2))`` maps y to 8. Notice that
the second binding may refer to the earlier one in the list. This can happen in
reverse as well, if for example the first binding is a function:

.. code::

  > (let ((return1 (lambda () x)) (x 1)) (return1))
  1

This needlessly complicated piece of work shows that the lambda bound to
``return1`` can access the name x, if it accesses it *after* x is bound.

Higher Order Functions
----------------------



@@ 229,6 288,55 @@ list in pairs:
  > (reduce + '(1 2 3))
  6

Macros + Advanced Quoting
-------------------------

Funlisp provisionally supports some more powerful features of lisp: macros and
quoting. Macros are similar to functions which take un-evaluated code
(s-expressions), and return new code. Since code is represented as lists of
symbols internally, it can be manipulated quite nicely with lisp code as well.
The result is capable of defining syntatic shortcuts and other niceties. Here is
an example that takes the common ``(define function-name (lambda (args) ...))``
pattern and shortens it into a more convenient construct: ``(defun name (args)
...)``.

.. code:: lisp

  (define defun (macro (name args code)
    (list 'define name (list 'lambda args code))))

This uses the ``(list)`` builtin which constructs a list from evaluated
expressions. The first argument, ``name`` is a symbol representing the name of
the function. It gets substituted after the ``define`` symbol. The remaining
arguments are part of the lambda declaration and get substituted later. The
result is a macro that you can use to define functions like this:

.. code:: lisp

  (defun +1 (n) (+ n 1))

However, you can see that it would get a bit cumbersome to use the ``list``
builtin everywhere, so a more advanced quoting system exists. In this
"quasiquoting" system allows you to quote most of the data using a backtick, but
"turn off" quoting for certain parts using a comma. Here is the same macro
rewritten:

.. code:: lisp

  (define defun (macro (name args code)
    `(define ,name (lambda ,args ,code))))

You can see this is shorter and less error-prone. Simply write the code the way
you'd like to see it, but use commas to substitute evaluated values.

.. warning::

  While macros are usually evaluated at compile/parse time, funlisp currently
  evaluates them after the fact -- just before the code is about to be run.
  Further, funlisp evaluates the macros *each time* they are used, rather than
  once only. The result is that macros are slightly less efficient than one
  might expect. But, you're not using funlisp for its efficiency, right?

The End
-------