Newbie questions 
Author Message
 Newbie questions

Quote:

> Here in Israel , we have thousands of C\C++ programmers and so the
> newspapers want ads are filled with requests for this kind of programmers ,
> BUT never did I see a CLOS \ Lisp programmer want ad .!!!

> If CLOS is so powerfull and (I read that) P Graham sold his software (in
> CLOS) to Yahoo in 49 Million U$, How come CLOS is so obscure in the
> programming community ?

I think you've answered your own question in a way. Newspaper
advertising is a mass medium. It is appropriate to reach mass
audiences. The Lisp programming community is not that large and so job
announcements get distributed through other channels. I have
personally had job announcements through email, by friends or people
who get asked by their management to search for additional Lisp
programmers.

I've never seen newspaper ads for brain surgeons but I'm fairly
certain that a competent brain surgeon has no trouble finding a job.

--

If there are aliens, they play Go. -- Lasker



Fri, 19 Oct 2001 03:00:00 GMT  
 Newbie questions
On 03 May 1999 09:21:05 -0400, Johan Kullstam

Quote:

>lisp macros let you inspect and digest the arguments and do different
>things depending on circumstances.  if an algorithm shares 99% (or 1%)
>of the same stuff, you can make a macro to share what you can and
>special case what you cannot.

I'm new to Lisp but am interested in macros.  I'm wondering
if Lisp macros can be invoked by code that is in a
non-standard syntax, such that the macro processes the
syntax to make it work.  For example, can a macro be called
by its name followed by a sequence of whitespace delimited
arguments with some defined pattern to end the list of
arguments, and the number of arguments found would
determine the macro processing?  Or can a macro be
invoked by an arbitrary expression in an arbitrary syntax,
such that the parts of the expression would be the macro
arguments?  The macro definition would have to define the
syntax, and there would have to be some way for the compiler
to recognize that syntax from knowledge of that macro.

And can you do things like rename the parenthesis characters
so some other character or symbol would represent them in
ordinary Lisp syntax?

Or if not that kind of stuff, what kind of stuff can you do
with Lisp macros?



Fri, 19 Oct 2001 03:00:00 GMT  
 Newbie questions

Quote:

>I'm new to Lisp but am interested in macros.  I'm wondering
>if Lisp macros can be invoked by code that is in a
>non-standard syntax, such that the macro processes the
>syntax to make it work.  For example, can a macro be called
>by its name followed by a sequence of whitespace delimited
>arguments with some defined pattern to end the list of
>arguments, and the number of arguments found would
>determine the macro processing?  Or can a macro be
>invoked by an arbitrary expression in an arbitrary syntax,
>such that the parts of the expression would be the macro
>arguments?  The macro definition would have to define the
>syntax, and there would have to be some way for the compiler
>to recognize that syntax from knowledge of that macro.

A macro's parameters are the subexpressions of the expression of which it's
the head.  For instance, in the expression (push <expression> <place>), the
PUSH macro will be given the unevaluated expressions <expression> and
<place> as its parameter.  Since the function definition containing the
macro invocation will already have been processed lexically by the reader,
all the objects will have been read into internal data types.

This means that a macro can define arbitrary semantics to its syntax, but
it can't change the lexical nature of the language.  For an example of a
macro that defines a pretty complex syntax of its own, see LOOP.

Quote:
>And can you do things like rename the parenthesis characters
>so some other character or symbol would represent them in
>ordinary Lisp syntax?

These things can be done using reader macros.  These are functions that are
invoked by the reader when it encounters a specific character during
lexical analysis.  See the I/O chapter of CltL or the CLHS for details.

--

GTE Internetworking, Powered by BBN, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.



Fri, 19 Oct 2001 03:00:00 GMT  
 Newbie questions

: | LISP was interesting, but ultimately impractical.  The left and right
: | parenthesis keys wore out on my keyboard before I finished my second
: | program.  Give me C++ any day.  This sensible language spreads the load
: | out much more evenly across _all_ the number-keys in the top row of my
: | keyboard.

:   I'm truly relieved.  I actually appreciate it when the people who hate me
:   are certified nut cases.

It is actually important to me that I believe Philip was joking when he
wrote this.  Despite all the evidence to the contrary, I've managed to
convince myself that no-one in the world is that clueless.  It will
destroy my world construct if people I respect take the above comments
by Philip seriously.

Erik, please don't take him seriously.

--

"It is amazing how complete is the delusion that beauty is goodness."
                                                 -- Leo Tolstoy



Fri, 19 Oct 2001 03:00:00 GMT  
 Newbie questions

Quote:

>> I still don't see the difference between closures and objects.  A
>> closure is just a function or set of functions with some trapped
>> variables, right?

>        The Devil is in the details... In Common Lisp you can easily
>define a closure that contains(?) two or more functions that access
>a set of values. To do the same in C++, you have to

>        1) define a struct/class to hold the closure data
>        2) define classes for each of the functions in the closure
>        3) instantiate an object for the closure data (from [1])
>        4) instantiate objects for each of the classes from [2]. Each
>           of these objects need a reference to the closure object,
>           passed via the constructor.

>        Note that the classes defined in [1] and [2] are named
>classes; in Common Lisp, there is no need to introduce classes for the
>functions, and the closure itself is anonymous.

>        Compare the following:
>        (defun f(a)
>               (cons
>                  (lambda () (setq a (1+ a)))
>                  (lambda () (setq a (+ a a)))))

>        (setq g (f 2))
>        (funcall (car g))
>        (funcall (car g))
>        (funcall (cdr g))
>        (funcall (cdr g))
>        (setq h (f 2))
>        (funcall (car h))
>        (funcall (car h))
>        (funcall (cdr h))
>        (funcall (cdr h))

You're thinking in LISP.  

There are lots of ways of doing this stuff in C++, none of which take
the 30 line to define that you took.  When we really want all the
generality of a closure (which we rarely do) we use a template class
that will combine any function pointer with an object pointer to make
a closure that contains both and, (since all such templates are
derived from a single root), they can be passed around like anonymous
functions.

In any case, no matter what you do, the simple mapping from a closure
is one object = one activation record.  

class f
{
    int a;
public:
    f(int _a):a(_a){}
    int operator++() { return ++a; }
    int Times2() { return a*=2; }

Quote:
};

void main()
{
  f g(2);

//when you really want all the generality of a closure

  IntClosure<f> car(g, &f::operator ++);
  IntClosure<f> cdr(g, &f::Times2);

  cout << car() << endl;
  cout << cdr() << endl;

//Note that the type isn't stuck being specific to this template
//instantiation

IntClosureBase *anyClosure = &car;

  cout << (*anyClosure)() << endl;

//but most of the time you just want functions
  cout << ++g << endl;
  cout << ++g << endl;
  cout << g.Times2() << endl;
  cout << g.Times2() << endl;

//sometimes just having the function pointers is enough
  int (f::*fn)();

  fn = &f::operator ++();
  cout << (g.*fn)() << endl;
  fn = &f::Times2();
  cout << (g.*fn)() << endl;  

Quote:
}

Off the top of my head, the template for closures of this type
signature would look like this:

class IntClosureBase
{
public:
  virtual int operator() = 0;

Quote:
};

template <class T> IntClosure : public IntClosureBase
{
    T *object;
    int (T::*function)();  
public:
  IntClosure(T* _o,(T::*_f)()):object(_o),function(_f){}

  virtual int operator() { return (object->*function)(); }

Quote:
};

We don't really call our template "Closures" but I'm being LISP
friendly.

Josh Scholar



Fri, 19 Oct 2001 03:00:00 GMT  
 Newbie questions

Quote:

> I'm new to Lisp but am interested in macros.  I'm wondering if Lisp
> macros can be invoked by code that is in a non-standard syntax, such
> that the macro processes the syntax to make it work.

[My answer is about Common Lisp, not Lisp in general]

A macro cannot change the basic syntax of parentesis, whitespace etc.
It is still damn powerful and very, very useful.

A macro _character_ on the other hand, can change anything.

So you cannot say
(with-angle-brackets  <+ 2 <* 3 4>>)

But you _can_ say
?<+ 2 <* 3 4>>
by properly defining the meaning of "?"

For example, I have defined
?(func-name arg1 arg2)
to mean
(my-funcall #'func-name arg1 arg2)

Stig Hemmer,
Jack of a Few Trades.



Fri, 19 Oct 2001 03:00:00 GMT  
 Newbie questions

| It is actually important to me that I believe Philip was joking when he
| wrote this.  Despite all the evidence to the contrary, I've managed to
| convince myself that no-one in the world is that clueless.

  the evidence to the contrary is overwhelming: there is no limit to
  cluelessness, and no reason to presume cluelessness is a joke: failing to
  realize that the clueless aren't joking is how most politicians manage to
  pull their tricks on all of us.

| It will destroy my world construct if people I respect take the above
| comments by Philip seriously.

  that's harsh, but I think you should just convince yourself otherwise.

#:Erik



Sat, 20 Oct 2001 03:00:00 GMT  
 Newbie questions

Quote:

> There are lots of ways of doing this stuff in C++, none of which take
> the 30 line to define that you took.  

> [... example snipped... ]

One problem with your approach is returning the closure objects you
created:

IntClosure< afunc()
{
   f g(2);

   IntClosure<f> car(g, &f::operator ++);
   return car;

Quote:
}

This would result in a dangling reference to the destructed 'g' object
- as 'g' would have gone out of scope.

I miss closures and lambda functions the most when using some of the
stl algorithms. For example:

class Person
{
  string getName();

Quote:
};

vector<Person*> people = ...;

// Find a person with the name 'John':
vector<Person*>::iterator it = find_if(
  people.begin(),
  people.end(),
  compose(
    bind2nd(equal_to<string>(), string("John")).
    mem_fun(&Person::getName)));

I would much prefer writing an anonymous function inline:

vector<Person*>::iterator it = find_if(
  people.begin(),
  people.end(),
  method(Person* p) { return p->getName() == "John"; } );

Excuse the ugly syntax.

The main problem with closure simulators in C++ is the memory
management and providing access to the local variables without having
to create a class which copies and stores them.

Chris.



Sat, 20 Oct 2001 03:00:00 GMT  
 Newbie questions

Quote:
> You should swap "( )" and "[ ]", even if you are not a Lisp
> programmer, since the parenthesis keys are used far more.

My norwegian keyboard favours lisp over the C-syntax family of
languages, since {[]} are almost ultimately unaccessible ;-)

Having to type shift-8 and shift-9 isn't a big deal though, I
think my stiff left arm is caused by EscapeMetaAltControlShifts
- ingenious ideas for remapping emacs control combinations are
very welcome (is it possible, on a sun keyboard, to use the
caps lock as an ordinary modifier?).

--

  espen



Sat, 20 Oct 2001 03:00:00 GMT  
 Newbie questions

Quote:


> >        Compare the following:
> >        (defun f(a)
> >               (cons
> >                  (lambda () (setq a (1+ a)))
> >                  (lambda () (setq a (+ a a)))))

        [ ... ]

Quote:
> There are lots of ways of doing this stuff in C++, none of which take
> the 30 line to define that you took.  When we really want all the
> generality of a closure (which we rarely do) we use a template class
> that will combine any function pointer with an object pointer to make
> a closure that contains both and, (since all such templates are
> derived from a single root), they can be passed around like anonymous
> functions.

> In any case, no matter what you do, the simple mapping from a closure
> is one object = one activation record.  

> class f
> {
>     int a;
> public:
>     f(int _a):a(_a){}
>     int operator++() { return ++a; }
>     int Times2() { return a*=2; }
> };

> void main()
> {
>   f g(2);

> //when you really want all the generality of a closure

>   IntClosure<f> car(g, &f::operator ++);
>   IntClosure<f> cdr(g, &f::Times2);

        As somebody else already noted, this may give you a dangling
reference if you allow g to go out of scope. My version had the same
problem, so I won't stress this (although it *obviously* means that
in the general case, you have to build some sort of memory management
into your closure classes.)

- Show quoted text -

Quote:

>   cout << car() << endl;
>   cout << cdr() << endl;

> //Note that the type isn't stuck being specific to this template
> //instantiation

> IntClosureBase *anyClosure = &car;

>   cout << (*anyClosure)() << endl;

> //but most of the time you just want functions
>   cout << ++g << endl;
>   cout << ++g << endl;
>   cout << g.Times2() << endl;
>   cout << g.Times2() << endl;

> //sometimes just having the function pointers is enough
>   int (f::*fn)();

>   fn = &f::operator ++();
>   cout << (g.*fn)() << endl;
>   fn = &f::Times2();
>   cout << (g.*fn)() << endl;  
> }

> Off the top of my head, the template for closures of this type
> signature would look like this:

> class IntClosureBase
> {
> public:
>   virtual int operator() = 0;
> };

> template <class T> IntClosure : public IntClosureBase
> {
>     T *object;
>     int (T::*function)();  
> public:
>   IntClosure(T* _o,(T::*_f)()):object(_o),function(_f){}

>   virtual int operator() { return (object->*function)(); }
> };

        Hum. If you count parentheses in the IntClosure* classes and
class f, you actually get a larger number than the 11 in my (borrowed)
Lisp example. There goes another argument against Lisp :-)

        Also keep in mind that IntClosure is not sufficient; you have
to add similar classes if you want closures with other/different data
than just a single int, and also if you want "enclosed" functions with
other operation signatures.

--
Raymond Wiker, Orion Systems AS
+47 370 61150



Sat, 20 Oct 2001 03:00:00 GMT  
 Newbie questions

Quote:

>> There are lots of ways of doing this stuff in C++, none of which take
>> the 30 line to define that you took.  

>> [... example snipped... ]

>One problem with your approach is returning the closure objects you
>created:

>IntClosure< afunc()
>{
>   f g(2);

>   IntClosure<f> car(g, &f::operator ++);
>   return car;
>}

>This would result in a dangling reference to the destructed 'g' object
>- as 'g' would have gone out of scope.

I know that, I was just simplifying the model.  Most problems seem to
have fairly simple lifetimes, but I have templates that help me with
the ones that don't.  My most common use for counted pointers, by the
way, is sharing an object between threads (I made the counting
atomic).

I've have yet to have a problem where I had to put all of these
templates together, but if you wanted all of the flexibility of gd
here it would be:

class IntClosureBase : public Counted
{
public:
  virtual int operator() = 0;

Quote:
};

template <class T> IntClosure : public IntClosureBase
{
    CountedPtr<T> object;
    int (T::*function)();  
public:
  IntClosure(CountedPtr<T> _o,(T::*_f)()):object(_o),function(_f){}

  virtual int operator() { return ((*object).*function)(); }

Quote:
};

class f : public Counted
{
    int a;
public:
    f(int _a):a(_a){}
    int operator++() { return ++a; }

Quote:
};

CountedPtr<IntClosureBase> foo()
{
    CountedPtr<IntClosureBase> car =
        (IntClosureBase *)new IntClosure<f>(new f(2),
                                            &f::operator ++);
    cout << ++ *car << endl;
    return car;

Quote:
}
>...  compose(
>    bind2nd(equal_to<string>(), string("John")).
>    mem_fun(&Person::getName)) ..

I've never seen an expression like this.  Perhaps I misunderstand, but
it looks to me like you're fighting the language in order to get
anonymous functions, FORGET ANONYMITY!  You're sacrificing readable
syntax just in order to not name something - that's a rip off.  So the
function needs a name, so what?

Josh Scholar

P.S In case it helps, here is the counted pointer classes and
templates (specialized for windows multitasking):

struct Counted
{
    LONG refCount;
    Counted():refCount(0){}

Quote:
};

template <class T> class CountedPtr
{

  protected:
      T *letter;

  public:
      void decRefCount()
      {
          if (letter)
          {
              if ( InterlockedDecrement(&letter->refCount) <= 0)
              {
                  delete letter;
                  letter = NULL;
              }
          }
      }

      void incRefCount()
      {
          if (letter)
          {
              InterlockedIncrement(&letter->refCount);
          }
      }

      CountedPtr():letter(NULL){}
      CountedPtr(const CountedPtr<T> &w);
      CountedPtr(const T *w);

      operator T *(){ return letter; }
      operator const T *()const{ return letter; }

      CountedPtr<T> & operator=(const T *w);        
      CountedPtr<T> & operator=(const CountedPtr<T> &w);        

      operator bool() const
      { return letter!=NULL; }

      int operator !() const
      { return letter==NULL; }

      int operator==(const CountedPtr&r)
      { return letter == r.letter; }

      const T & operator*() const
      { return *letter; }

      T & operator*()
      { return *letter; }

      T * operator->()
      { assert(letter); return letter; }
      T * operator->()const
      { assert(letter); return letter; }

      ~CountedPtr();

Quote:
};

template <class T> CountedPtr<T> & CountedPtr<T>::operator=(const T
*w)
{
    if (w) InterlockedIncrement(& (const_cast<T *>(w)->refCount));
    decRefCount();
    letter= const_cast<T *>(w);
    return *this;
Quote:
}

template <class T> CountedPtr<T> & CountedPtr<T>::operator=(const
CountedPtr<T> &w)
{
    return *this = (const T *)w;

Quote:
}

template <class T> CountedPtr<T>::CountedPtr(const CountedPtr<T> &w)
:letter(const_cast<T *>(w.letter))
{  incRefCount(); }

template <class T> CountedPtr<T>::CountedPtr(const T *w):letter((T
*)w)
{  incRefCount(); }

template <class T> CountedPtr<T>::~CountedPtr()
{  decRefCount(); }



Sat, 20 Oct 2001 03:00:00 GMT  
 Newbie questions

Quote:
>        Also keep in mind that IntClosure is not sufficient; you have
>to add similar classes if you want closures with other/different data
>than just a single int, and also if you want "enclosed" functions with
>other operation signatures.

Which is an advantage if you believe in type checking!!!!

I WANT the compiler to make sure that every function is only used with
compatable parameters!

Joshua Scholar



Sat, 20 Oct 2001 03:00:00 GMT  
 Newbie questions

Quote:


> >        Also keep in mind that IntClosure is not sufficient; you have
> >to add similar classes if you want closures with other/different data
> >than just a single int, and also if you want "enclosed" functions with
> >other operation signatures.

> Which is an advantage if you believe in type checking!!!!

> I WANT the compiler to make sure that every function is only used with
> compatable parameters!

        This is probably not very helpful, but anyway... Simple type
compatibility is the only C++ can check statically - for example, you
can have a function that expects as an argument a value from {1, 2,
5}. There's no way you can check this statically, which means that you
ultimately have to resort to run-time checking, which (as with
closures) is more painful to do in C++ than in Common Lisp.

        My point? I do not think that the advantages of a dynamic type
system are worth trading in for a flawed static type system.

--
Raymond Wiker, Orion Systems AS
+47 370 61150



Sat, 20 Oct 2001 03:00:00 GMT  
 
 [ 350 post ]  Go to page: [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] [14] [15] [16] [17] [18] [19] [20] [21] [22] [23] [24]

 Relevant Pages 
 

 
Powered by phpBB® Forum Software