Alternatives 2

This is a discussion on Alternatives 2 within the lisp forums in Programming Languages category; 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 ...

Go Back   Application Development Forum > Programming Languages > lisp

Object Mix

Register FAQ Calendar Search Today's Posts Mark Forums Read
  #1  
Old 11-04-2008, 10:47 PM
William James
Guest
 
Default Alternatives 2

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
Reply With Quote
  #2  
Old 11-05-2008, 08:19 AM
Mirko.Vukovic@gmail.com
Guest
 
Default Re: Alternatives 2

On Nov 4, 10:47*pm, William James <w_a_x_...@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
Reply With Quote
  #3  
Old 11-06-2008, 12:53 PM
William James
Guest
 
Default Re: Alternatives 2

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

Reply With Quote
  #4  
Old 11-06-2008, 02:33 PM
Kaz Kylheku
Guest
 
Default Re: Alternatives 2

On 2008-11-05, William James <w_a_x_man@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.
Reply With Quote
Reply


Thread Tools
Display Modes


All times are GMT -5. The time now is 11:54 PM.


Powered by vBulletin® Version 3.7.2
Copyright ©2000 - 2009, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.2.0
vB Ad Management by =RedTyger=

In an effort to better serve ads to our visitors, cookies are used on objectmix.com. For more information, check out our Privacy Policy.