One could generalize that solution:
class Symbol
def to_proc
lambda { |a,*b| a.send(self,*b) }
end
end
[1,2,3].inject(&:+)
(For some reason, irb complained unless I put parens around it.)
For an even shorter version, here's my APL subset for Ruby:
class Symbol
def *(ary)
ary.inject {|a,b| a.send(self, b)}
end
def [](*ary)
self * ary
end
end
class Array
def +@
:+*self
end
def -@
:-*self
end
end
Now, :+*[1,2,3], :+[1,2,3], and +[1,2,3] are all valid. (Not that I
actually use this libary; just came up with it to make a point about
Ruby to somebody. :P)
(I would've overloaded /, but Ruby kept thinking I was trying to
construct a regular expression.)
And here's a vaguely neat extension of that idea:
class Symbol
def **(ary)
ary.inject { |a,b| a.send(self, *b) }
end
end
:gsub ** ["Hello!",
[/Hell/,"Good"]
[/o!/,"bye.]]
Talk about reducing duplication. :)
Devin
Daniel Brockman wrote:
>Hi Joe,
>
>
>
>>Sorry, please bear with me... the Lisp I had in mind was
>>more like:
>>
>> (setf a #'length)
>> (funcall a "foo")
>>
>>(Hard to make an exact parallel because Ruby has methods
>>not functions, and Lisp AFAIK has functions not
>>methods...?)
>>
>>
>
>Ruby has both methods and functions, but methods are more
>primitive than functions. In particular, functions are
>objects and thus have methods. Methods, on the other hand,
>are not objects (and they are not functions). So functions
>are implemented using methods, not the other way around.
>
>As for the example code, the closest Ruby equivalent would
>have to be something like the following:
>
> a = :length
> "foo".send(a)
>
>This is because in Ruby, polymorphism is implemented by
>having different ¡Ælength¡Ç methods for different objects,
>whereas in Lisp, there is just one function ¡Ælength¡Ç that
>handles all types of objects. (Of course, CLOS simplifies
>the task of adding new clauses by way of defmethod, but a
>generic function is still just one function.)
>
>
>
>>Setting a variable to the function itself seems pretty
>>different than wrapping a call to the function in a lambda,
>>
>>
>
>Again, there is not just a single ¡Ælength¡Ç method in Ruby,
>so you can't ¡Èset a variable to the function itself.¡É The
>closest analogy to the ¡Èfunction itself¡É is the method name.
>
>
>
>>but honestly, now I can't think of what the actual
>>implications would be... other than a little bit of
>>additional terseness in calls like
>>
>>(reduce #'+ '(1 2 3))
>>vs.
>>[1, 2, 3].inject {|a,b|a+b}
>>
>>
>
>You could actually define the equivalent of Lisp's ¡Æ+¡Ç
>function in Ruby, by doing this:
>
> module Kernel
> def +(a, b) a + b end
> end
>
>Then the example with inject could be written like this:
>
> [1,2,3].inject &method(:+)
>
>But this will fail when someone overrides the ¡Æ+¡Ç operator,
>in which case you need to do something like this:
>
> [1,2,3].inject &Object.new.method(:+)
>
>Much cleaner would be to define the function in a separate
>namespace so that name clashes are avoided:
>
> Function = Object.new
> class << Function
> alias [] method
> def +(*terms) terms.inject(0) { |a, b| a + b } end
> end
>
>Now the example looks like this:
>
> [1,2,3].inject &Function[:+]
>
>You could go one step further:
>
> class Symbol
> def to_proc
> Function[self].to_proc
> end
> end
>
>Note that if you take the Kernel#+ approach, the above
>implementation needs to be much hairier:
>
> class Symbol
> def to_proc
> Binding.of_caller do |boc|
> eval(%{method(:#{self})}, boc).to_proc
> end
> end
> end
>
>Now you can reduce the original example (no pun intended)
>to the following,
>
> [1,2,3].inject &:+
>
>which is actually *shorter* than the equivalent Lisp code.
>
>By the way, a more popular definition of Symbol#to_proc is
>to have ¡Æfoo.each &:bar¡Ç equal ¡Æfoo.each { |x| x.bar }¡Ç.
>This won't work in the above example because we cannot use
>the Fixnum#+ method to fold an array of integers (since it
>only takes one argument!).
>
>(If you want both variants of Symbol#to_proc, I guess you
>could use a unary plus or minus operator to disambiguate.
>However, ¡Æ[1,2,3].inject &-:+¡Ç is starting to look rather
>much like line noise.)
>
>
>