From: William James
Subject: Alternatives 2
Date: 
Message-ID: <e5ed16d8-2351-4fe1-a219-792de840876a@v16g2000prc.googlegroups.com>
More fun with On Lisp by Paul Graham and Ruby.


=begin

We can't use a function defined elsewhere with defun, because we
need bindings from the local environment. And we can't use
lambda to define a recursive function, because the function will
have no way of referring to itself.

Common Lisp gives us labels as a way out of this dilemma.

Using labels we can write a function analogous to list+, but in
which the first argument to mapcar is a recursive function:

	(defun count-instances (obj lsts)
  (labels ((instances-in (lst)
			 (if (consp lst)
			     (+ (if (eq (car lst) obj) 1 0)
              (instances-in (cdr lst)))
        0)
     ))
    (mapcar #'instances-in lsts)))

This function takes an object and a list, and returns a list of
the number of occurrences of the object in each element:

> (count-instances 'a '((a b c) (d a r p a) (d a r) (a a)))
(1 2 1 2)

=end

# The Graham way.
def count_instances obj, lists
  instances_in = proc{|list|
    if list.empty?
      0
    else
      ( list[0]==obj ? 1 : 0 ) + instances_in[list[1..-1]]
    end }
  lists.map{|x| instances_in[ x ]}
end
p count_instances( "a",
  [ %w(a b c), %w(d a r p a), %w(d a r), %w(a a)] )

# The smart way.
def count_instances obj, lists
  lists.map{|x| x.grep(obj).size }
end

p count_instances( "a",
  [ %w(a b c), %w(d a r p a), %w(d a r), %w(a a)] )


=begin

3.1 Functional Design

(defun good-reverse (lst)
  (labels ((rev (lst acc)
		(if (null lst)
		    acc
		  (rev (cdr lst) (cons (car lst) acc)))))
    (rev lst nil)))

=end

def good_reverse list
  acc = []
  list.reverse_each{|x| acc << x }
  acc
end

p good_reverse( [2,3,5,8] )


=begin

Finally, to return multiple values, we use the values operator:

> (defun powers (x)
(values x (sqrt x) (expt x 2)))
POWERS
> (multiple-value-bind (base root square) (powers 4)
(list base root square))
(4 2.0 16)

=end

def powers x
  [ x, Math.sqrt(x), x ** 2 ]
end

base, root, square = powers( 4 )

p base, root, square

From: ·············@gmail.com
Subject: Re: Alternatives 2
Date: 
Message-ID: <e90be745-3116-4bbd-bd50-4bb19857bfc3@p10g2000prf.googlegroups.com>
On Nov 4, 10:47 pm, William James <·········@yahoo.com> wrote:
> More fun with On Lisp by Paul Graham and Ruby.
>
> =begin
>
> We can't use a function defined elsewhere with defun, because we
> need bindings from the local environment. And we can't use
> lambda to define a recursive function, because the function will
> have no way of referring to itself.
>
> Common Lisp gives us labels as a way out of this dilemma.
>
> Using labels we can write a function analogous to list+, but in
> which the first argument to mapcar is a recursive function:
>
>         (defun count-instances (obj lsts)
>   (labels ((instances-in (lst)
>                          (if (consp lst)
>                              (+ (if (eq (car lst) obj) 1 0)
>               (instances-in (cdr lst)))
>         0)
>      ))
>     (mapcar #'instances-in lsts)))
>
> This function takes an object and a list, and returns a list of
> the number of occurrences of the object in each element:
>
> > (count-instances 'a '((a b c) (d a r p a) (d a r) (a a)))
>
> (1 2 1 2)
>
> =end
>
> # The Graham way.
> def count_instances obj, lists
>   instances_in = proc{|list|
>     if list.empty?
>       0
>     else
>       ( list[0]==obj ? 1 : 0 ) + instances_in[list[1..-1]]
>     end }
>   lists.map{|x| instances_in[ x ]}
> end
> p count_instances( "a",
>   [ %w(a b c), %w(d a r p a), %w(d a r), %w(a a)] )
>
> # The smart way.
> def count_instances obj, lists
>   lists.map{|x| x.grep(obj).size }
> end
>
> p count_instances( "a",
>   [ %w(a b c), %w(d a r p a), %w(d a r), %w(a a)] )
>
> =begin
>

I think your comparison is incomplete.  Fur a full comparison of lisp
with the `smart way', you should consider the `count' function:
(defun count-instances (obj lists)
	   (map 'list #'(lambda (arg) (count obj arg)) lists))

Now, if some hardy soul would do a useful benchmark :-)

... stuff deleted

Mirko
From: William James
Subject: Re: Alternatives 2
Date: 
Message-ID: <gevaur$goc$1@aioe.org>
William James wrote:

> 
> # The smart way.
> def count_instances obj, lists
>   lists.map{|x| x.grep(obj).size }
> end

If you have Ruby 1.8.7 or higher:

def count_instances obj, lists
  lists.map{|x| x.count(obj) }
end 
From: Kaz Kylheku
Subject: Re: Alternatives 2
Date: 
Message-ID: <20081106104926.122@gmail.com>
On 2008-11-05, William James <·········@yahoo.com> wrote:
> More fun with On Lisp by Paul Graham and Ruby.

We can estimate a programmer's depth by what he finds interesting.
> # The Graham way.
> def count_instances obj, lists
>   instances_in = proc{|list|
>     if list.empty?
>       0
>     else
>       ( list[0]==obj ? 1 : 0 ) + instances_in[list[1..-1]]
>     end }
>   lists.map{|x| instances_in[ x ]}
> end
> p count_instances( "a",
>   [ %w(a b c), %w(d a r p a), %w(d a r), %w(a a)] )
>
> # The smart way.
> def count_instances obj, lists
>   lists.map{|x| x.grep(obj).size }
> end

Common Lisp:

 (mapcar (lambda (list) (count obj list)) lists)

Look, only letters, spaces and parentheses. A non-computer-programmer
could grok the syntax of this.

The new count method in Ruby 1.8.7 still misses the fact that objects
can be equal in more than one way:

 (def count-into-lists (obj lists &key (test #'eql))
   (mapcar (lambda (list) (count obj list :test test)) lists))

 (count-into-lists "abc" '(("ABC" "abc") ("foo"))) -> (0 0)

 (count-into-lists "abc" '(("ABC" "abc") ("foo")) :test #'equal) -> (1 0)

 (count-into-lists "abc" '(("ABC" "abc") ("foo")) :test #'equalp) -> (2 0)

A smart Lisper would never write an extension to the sequences library that
didn't properly support KEY or TEST parameters.

> Finally, to return multiple values, we use the values operator:
>
>> (defun powers (x)
> (values x (sqrt x) (expt x 2)))
> POWERS
>> (multiple-value-bind (base root square) (powers 4)
> (list base root square))
> (4 2.0 16)
>
>=end
>
> def powers x
>   [ x, Math.sqrt(x), x ** 2 ]
> end
>
> base, root, square = powers( 4 )

An array isn't multiple values. The difference becomes obvious when
you have a compiler.

Multiple values can be compiled such that they use the stack or registers,
similarly to arguments.

What you're doing here is returning an array to /emulate/ multiple return
values. This could still be compiled efficiently in some cases, but it's more
difficult, because you need to be ale to compile the callee and caller in
isolation, and they have to be binary compatible. You don't have
statically typed information about the return value, like for struct
returns in C.  For the callee, you don't know whether or not the caller will be
using the result as an array or as multiple values. What you can do is allocate
it on the stack or in multiple registers, and let the caller deal with it.
But the caller likewise doesn't know whether the called function will just be
an ordinary array-returning function, or whether it's an optimized one that is
returning the array in a stack area. Code has to be generated to check some
flag and handle either type.

Returning lists is what Lisp programs had to do before multiple value support
was properly added to the language.

Even Schemers recognized the importance of proper multiple values, and added
it. And consider that their goal is to keep the set of special forms to a
minimum; a new operator is added to Scheme casually.