Why don't people like lisp?

Joe Marshall jrm at ccs.neu.edu
Thu Oct 23 12:11:30 EDT 2003


"Andrew Dalke" <adalke at mindspring.com> writes:

> As an example, here's a quick hack of a way to parse a simple
> stack-based language and make a native Python function out
> of it....

[code elided]

Let's take on something more complicated.  A lot more complicated.

Suppose I am solving problems that are best expressed
non-deterministically, and I need a domain language that has the
following non-deterministic constructs:

EITHER --
        Used as a mechanism to combine expressions
        non-deterministically as in

        (either <expr1> <expr2> <expr3> ...)

           or, if you prefer infix

        <expr1> either <expr2> either <expr3>

           or possibly

        either:
            <expr1>
            <expr2>
            <expr3>

        Whatever the syntax, EITHER introduces a choice-point.  It
        begins by attempting evaluation of the first subexpression.
        If that subexpression returns a value, EITHER returns that
        value.  If the subexpression `fails', EITHER attempts to
        evaluate the next subexpression.  The first subexpression
        to produce a value is the value of the whole expression.
        If all subexpressions `fail', then the EITHER form itself
        `fails'.

FAIL  --
        Causes an expression to `fail'.  This means that control is
        immediately returned to the nearest enclosing EITHER form
        (backtracking) which will then proceed to attempt to evaluate
        the next subexpression.  If the current subexpression is the
        last form in the enclosing EITHER, the EITHER form propagates
        the failure up to the next enclosing EITHER.
 
ALL-VALUES --
        Used to collect all possible values returned by a
        non-deterministic expression.  If all possible choice-points
        in the expression yield failure, then ALL-VALUES
        deterministically returns an empty collection.  Thus failures
        cannot propagate past an ALL-VALUES form.

        Syntax could be something like
        (all-values <expr>)

               or
 
        all-values <expr>

               or

        all-values { <expr> }


ONE-VALUE --
        Returns the first possible value returned by a non-deterministic
        expression, or some sort of distinguished token if no value
        can be found.  Also blocks propagation of `failure'.


Since I am unsure of the entire details of the problem I am solving, I
also wish to have these forms integrated into a reasonably complete
computer language.  Obviously this new language will have syntactic
differences from anything other language (via the introduction of
these forms), but by and large, the subexpressions of this new
language ought to be something familiar.

So if we extended Lisp, for example, I could write:

(defun an-integer-between (low high)
  (if (> low high)
      (fail)
      (either low (an-integer-between (+ low 1) high))))

(defun pythagorean-triples (n)
  (all-values
    (let ((opposite (an-integer-between 1 n))
          (adjacent (an-integer-between 1 n))
          (hypotenuse (an-integer-between 1 n)))
      (if (= (+ (* opposite opposite)
                (* adjacent adjacent))
             (* hypotenuse hypotenuse))
          (list opposite adjacent hypotenuse)
          (fail)))))

and (pythagorean-triples 10)
would return ((3 4 5) (4 3 5) (6 8 10) (8 6 10))


on the other hand, if we extended Python, I could write:

def anIntegerBetween(low, high):
    if(low > high):
        fail
    either:
        return low
        return anIntegerBetween(low + 1, high)

def pythagoreanTriples(n):
    all-values:
        opposite = anIntegerBetween(1, n)
        adjacent = anIntegerBetween(1, n)
        hypotenuse = anIntegerBetween(1, n)
        if(hypotenuse * hypotenuse == opposite * opposite + adjacent * adjacent):
            return [opposite, adjacent, hypotenuse]
        fail

and I'd get back something like
[[3, 4, 5], [4, 3, 5], [6, 8, 10], [8, 6, 10]]

-----------------

This is a tricky problem, but one approach in Lisp is to make
ALL-VALUES and EITHER be rather complicated macros.

The advantage of doing this is that the rest of the language, LET,
DEFUN, *, +, conditionals, strings, CLOS, i.e. everything, is pretty
much intact.  Since I know that Lisp is a `reasonably complete'
substrate, I don't have to worry about designing and parsing an entire
non-deterministic language.  I can just graft my extension on to
something people will be familiar with.

Yes, I know that adding non-determinism to the language is going to
mean a change in how people would program (how could it not?!) but
I'm attempting to *minimize* the intellectual burden by making the
non-deterministic language very similar to one that already exists.


How would one approach this in Python?  If Python had macros, then
one could take exactly the same approach as Lisp.  What does a Pythonista
do when encountering a problem like this?  (I'm actually curious,
not raising rhetorical questions.  I assume that there is *something*
one would do, but not being a python hacker, I don't know what it is.)







More information about the Python-list mailing list