| Register | FAQ | Calendar | Search | Today's Posts | Mark Forums Read |
|
#1
| |||
| |||
| 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 |
|
#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 |
|
#3
| |||
| |||
| 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 |
|
#4
| |||
| |||
| 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. |
![]() |
| Thread Tools | |
| Display Modes | |
In an effort to better serve ads to our visitors, cookies are used on objectmix.com. For more information, check out our Privacy Policy.