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 =3D :length
"foo".send(a)
This is because in Ruby, polymorphism is implemented by
having different =E2=80=98length=E2=80=99 methods for different objects,
whereas in Lisp, there is just one function =E2=80=98length=E2=80=99 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 =E2=80=98length=E2=80=99 method in Ruby=
,
so you can't =E2=80=9Cset a variable to the function itself.=E2=80=9D Th=
e
closest analogy to the =E2=80=9Cfunction itself=E2=80=9D is the method na=
me.
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 =E2=80=98+=E2=80=99
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 =E2=80=98+=E2=80=99 operato=
r,
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:
=20
Function =3D 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 =E2=80=98foo.each &:bar=E2=80=99 equal =E2=80=98foo.each { |x| x.=
bar }=E2=80=99.
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, =E2=80=98[1,2,3].inject &-:+=E2=80=99 is starting to look rather
much like line noise.)
--=20
Daniel Brockman <
[email protected]>
So really, we all have to ask ourselves:
Am I waiting for RMS to do this? --TTN.