Subject: Re: low quality lisp books
From: Erik Naggum <erik@naggum.net>
Date: Wed, 19 Sep 2001 02:01:38 GMT
Newsgroups: comp.lang.lisp
Message-ID: <3209853697331820@naggum.net>

* p-m@yahoo.com (Philip)
> Lately I've been thinking of buying a lisp book. I was thinking of Paul
> graham's book, but my friend pointed out that its not very good. He had a
> problem with the guy lying on the first page.  What do you guys think?

  That your friend is a stupid liar who missed the point entirely.

  A lexical closure is a function-callable structure with local data.  You
  construct a new such structure by capturing the values of all variables
  bindings that close over the function.  However, this structure can be
  called directly with language primitives and it looks no different than
  normal functions.

(defun addn (n)
  (lambda (x)
    (+ x n)))

  amd you call this with

(funcall (addn 1) 2)

  Now, there are several interesting problems with this solution from a C
  point of view.  The first and foremost is that writing a function that
  can call an arbitrary function or function-like object in C with an
  arbitrary number of arguments is _really_ hard.  Thefore, you typically
  write a specialized function in C.  This is the first case of cheating.
  You see, the lexical closure support in Common Lisp is _general_.

struct closure {
  int (*body) (int, struct closure *, ...);
  int args;
];

/* This would be done with classes and inheritance in C++.  */
struct addn_closure {
  int (*body) (int, struct closure *, ...);
  int args;
  int n;
}

int addn_lambda (int count, struct closure *closure, va_list arg_list)
{
  int argument;
  argument = va_arg (arg_list, int)
  return (argument + (struct addn_closure *)closure->n);
}

struct addn_closure * addn (int n)
{
  /* This would be done with class initialization in C++.  */
  struct addn_closure *new_closure = malloc (sizeof (struct addn_closure));
  new_closure->body = addn_lambda;
  new_closure->n = n;
  return new_closure;
}

int funcall_closure (int count, struct closure *closure, ...)
{
  int result;
  va_list arg_list;
  /* This would be done with exceptions in C++.  */
  if (count != closure->args)
    exit (1);
  va_start (arg_list, closure);
  result +> closure->body (count, closure, arg_list);
  va_end (arg_list);
  return result;
}

  Now we can do this, more or less, but you may have to engage in casting
  to get the stupid static typing cruft in the compiler to agree with you,
  which also screwed up our ability to use any other argument type than
  int, which is really, really painful.  (So maybe it should have used
  pointers to various object types, and passed void* around instead, but
  then you could not have passed integer constants directly, but would have
  had to make up some objects to hold such values.)

funcall_closure (1, addn (1), 2);

  If you think all of this supports your (friend's) view that Paul Graham
  is a liar and that you _can_ do lexical closures in C, you are actually
  gravely mistaken.  We are cheating and limiting the functionality all
  over the place.  More than half of what cannot be done in C is precisely
  the generality of the solution.

  It is perhaps possible to do lexical closures in C++, with support for
  overloading and lots and lots of heavy-duty features, but even with STL
  and all kinds of "foundation classes" and shit, it is not actually done.
  There has to be a good reason for this, considering how tremendously
  useful lexical closures are when passing functions around, and the reason
  is two-fold: (1) Since it is so incredibly hard to do this in C/C++, it
  is not done, and (2) since it is not done, the kinds of solutions that
  benefit from it are not done in C/C++.  Therefore, a C/C++ programmer,
  like your friend, will have absolutely no use for lexical closures and
  neither will will he understand how he missed the point, because the
  whole concept is _actually_ outside the reach of the C/C++ mindset.

  I suggest you get smarter friends who do not keep you down by confusing
  you with negative bullshit when you clearly should spend your time
  reading and understanding books that open your mind instead of closing
  them down.  You might then learn something and be able to tell your
  friend that he is a liar in terms he can understand, although it is
  highly doubtful that he will grow a clue considering this insistence that
  he need not understand what he argues against.  This seems to happen to
  C/C++ people a lot, and it is part of the survival tactics of those
  language to keep people from discovering that their languages are
  limiting them to that which is easy to do in thelr languages.  Common
  Lisp makes a lot of simple things in those languages a little harder, but
  the things that are _really_ hard in C/C++ is no harder than the rest,
  and when you run out of hard things to do in C/C++, the complex stuff you
  work with in Common Lisp is still going to be equally hard to what you
  have been used to.  This is where higher-level languages beat lower-level
  languages.  Incidentally, it is far easier to do lexical closures at the
  assembly level than at the C level.  This is an indication that C/C++ is
  a step up from assembly, but in the wrong direction, such that you cannot
  get any further, and your friend hit the C level from _below_ (and lots
  of other C/C++ people react the same way), and cannot get anywhere.  This
  is the _real_ tragedy of C/C++ and the people who think they do not need
  what these languages cannot provide (easily) are so pathetic it hurts to
  watch them make fools of themselves.

  Incidentally, there are not enough high-quality Common Lisp books that
  explain things to people who have been used to working with the machine
  at the C level.  I may think a book like that would have worked better
  for you, too, but the only one I can think of is "Anatomy of Lisp", which
  is out of print and hard to come by.

///