Lazy evaluation

Y

Yukihiro Matsumoto

Hi,

In message "Re: Lazy evaluation (evil)"

|From a conceptual point of view is callcc very important.
|It is not just added because it may seem like a good feature,
|but because it makes Ruby a real functional language (like scheme).
|In functional languages can continuations be seen as a
|functions-calls.

I have to mention callcc was added not because to make Ruby a real
functional language, but because we happened to succeed to implement
it, and there was no reason to remove.

matz.
 
J

Jean-Hugues ROBERT

Hi,

In message "Re: Lazy evaluation (evil)"

|From a conceptual point of view is callcc very important.
|It is not just added because it may seem like a good feature,
|but because it makes Ruby a real functional language (like scheme).
|In functional languages can continuations be seen as a
|functions-calls.

I have to mention callcc was added not because to make Ruby a real
functional language, but because we happened to succeed to implement
it, and there was no reason to remove.

matz.

I guess this really deserved to be called "pragmatism" ;-)

Yours,

Jean-Hugues
 
K

Kristof Bastiaensen

I guess this really deserved to be called "pragmatism" ;-)

This surprises me quite a bit, because I wouldn't think implementing
callcc is an easy thing. But I am sure it is great way to
attract scheme programmers to Ruby.

"What is this 'Ruby' beast you are talking about? Oh, it
has call/cc, then I must surely give it a try!"

Kristof
 
Y

Yukihiro Matsumoto

Hi,

In message "Re: Lazy evaluation (evil)"

|This surprises me quite a bit, because I wouldn't think implementing
|callcc is an easy thing.

I didn't implement, my colleague did. I'm proud of working with such
a smart person.

matz.
 
N

Niklas Frykholm

I'd say lambda expressions are more of a defining characteristic of functional
languages.

I think that the distinction between procedural and functional languages
has become less important than it used to be. Procedural
languages/programmers used to depend heavily on global variables and
gotos. Some languages didn't even support recursion. Today, through the
evolution of languages and "good programming style" the procedural
languages have become "more functional", to the extent where it even may
be hard to tell whether a language is functional or not.

I would say the two remaining distinguishing characterstics for a
functional language are:

(1) discourage side effects

No feature complete language is really free from side effects,
since you can't do I/O or draw to the screen without them. (Unless
you employ a contorted definition of what a "side effect" is.) But
functional languages try to keep their side effects in check and not
letting them roam free.

(2) functions as first class values

You can write a function that takes a function and returns a new
modified function with reasonable syntax.

C fails on both accounts. In C++ you can sort of do (2) with templates,
but that fails the "reasonable syntax" test.

Ruby, and indeed all object-oriented languages, fail (1) since the main
thing they do is to pass around mutable objects. (2) is a bit harder to
call. But I would say Ruby fails this too. Mainly because of the fact
that "methods" have a different calling syntax than "method objects" and
"procs".

So I wouldn't say that Ruby is a functional language.

// Niklas
 
K

Kristof Bastiaensen

(2) functions as first class values

You can write a function that takes a function and returns a new
modified function with reasonable syntax.
C fails on both accounts.

In C you can return a pointer to a function. Of course it
totally fails the "reasonable syntax".
In C++ you can sort of do (2) with templates,
but that fails the "reasonable syntax" test.

Ruby, and indeed all object-oriented languages, fail (1) since the main
thing they do is to pass around mutable objects. (2) is a bit harder to
call. But I would say Ruby fails this too. Mainly because of the fact
that "methods" have a different calling syntax than "method objects" and
"procs".

So I wouldn't say that Ruby is a functional language.

I agree on everything except point (2). Just because there are
also methods, which are different things as procs, doesn't mean
that there are no first class functions. Take the following code:
add = lambda { |x| lambda { |y| y + x }}
add2 = add.call(2)
add2.call(5)
=> 7
add2.call(7)
=> 9

This works just like it does in scheme. I would say it fits
very nicely in (2). The "reasonable syntax" is a bit subjective,
and I admit there is an extra level of indirection. But this is
just the way in Ruby to perform an action on an object, so that's
rather a confirmation of the fact that functions (proc objects)
have an equal status as all other values (objects).

Kristof
 
G

gabriele renzi

il Mon, 03 May 2004 12:30:53 +0200, Kristof Bastiaensen
I agree on everything except point (2). Just because there are
also methods, which are different things as procs, doesn't mean
that there are no first class functions. Take the following code:
add = lambda { |x| lambda { |y| y + x }}
add2 = add.call(2)
add2.call(5)
=> 7
add2.call(7)
=> 9

a little cosmethic change:
add = lambda { |x| lambda { |y| y + x }}
=> # said:
add7= add[7]
=> # said:
add7[5] => 12

you can use var[args] with callable objects (continuations, methods,
procs)
This works just like it does in scheme.

I'm not an expert, but ruby models should be closer to LISP than
scheme, cause function/methods are not in the same 'namespace', wich
is true in scheme. I mean, we have method() and LISP has the
sharp-quote notation. But I may be cmpletely wrong.
 
R

Robert Feldt

Michael said:
I am currently hacking a Packrat parser just for fun. I need to mix
values (like numbers, strings etc.) together with lazy values. I want to
make processing these values as transparent as possible.
I guess this is beside the point but are you sure you really need an
explicit way to encapsulate lazy values to implement packrat parsing? I
did a packrat parser some time back but it was more like "memoize for
later"; maybe I didn't read the packrat papers enough... ;)

Can you comment on how you use the lazy values and how they help you
write the packrat parser? From my reading of the papers he presents it
in a lazy framework but you can unroll the laziness by memoization of
the partial results of a recursive decent parser.

Regards,

Robert Feldt
 
J

Jean-Hugues ROBERT

I would say the two remaining distinguishing characterstics for a
functional language are:
(1) discourage side effects
(2) functions as first class values
You can write a function that takes a function and returns a new
modified function with reasonable syntax.
Ruby, and indeed all object-oriented languages, fail (1) since the main
thing they do is to pass around mutable objects. (2) is a bit harder to
call. But I would say Ruby fails this too. Mainly because of the fact that
"methods" have a different calling syntax than "method objects" and "procs".

Would the last one succeed if there was something like a Lvalue class,
with auto dereferencing by the interpretor ?
f = ref proc { |*args| p args } # or f = ref method :p, "ref" creates a
Lvalue instance.
f( "hello") # => ["hello"], proc/meth's getter() invoked, alias for []()
p f # => [], proc's proc/meth's getter() invoked, alias for []()
f = "world" # => ["world"], proc/meth's setter(x) invoked, alias for
something like []=() ?
getter/setter are bad names, I hope to find better ones by
the time I issue the "match, assign & Lvalue" RCR.

EOM
Yours,
Jean-Hugues
 
M

Michael Neumann

I guess this is beside the point but are you sure you really need an
explicit way to encapsulate lazy values to implement packrat parsing? I
did a packrat parser some time back but it was more like "memoize for
later"; maybe I didn't read the packrat papers enough... ;)

Hm, it's probably me who didn't read the papers enough :)
Can you comment on how you use the lazy values and how they help you
write the packrat parser? From my reading of the papers he presents it
in a lazy framework but you can unroll the laziness by memoization of
the partial results of a recursive decent parser.

I am currently using lazy values for actions that return semantic
values. But I am not sure whether I need this or not. I'll have to
rewrite it a bit... you can have a look at it soon (the sources are not
yet there, but I'll try to upload them this evening):

http://rubyforge.org/projects/packrat

What I am really looking for is a easy scannerless (I don't like tokens :)
parser generator for Ruby. I know your Rockit parser, but I've admit
that I didn't tried it too much as it seems to be a bit outdated.
Speed is not a big deal for me, just ease of use.

Regards,

Michael
 
P

Paul Brannan

Any comments or suggestions?

I'm not suggesting that anyone actually do this, but I have a lazily-
evaluated object that looks something like this:

class LazyFoo
def method_missing(*args, &block)
$foo = Foo.new
$foo.__send__(*args, &block)
end

Kernel.instance_methods.each do |m|
next if m == '__send__'
next if m == '__id__'
eval <<-END
def #{m}(*args, &block)
method_missing:)#{m}, *args, &block)
end
END
end
end

$foo = LazyFoo.new

Obviously this only works with global variables, and it doesn't work if
you pass the variable around. IMO Object#become is a much cleaner
solution, and while there are some limitations with every Object#become
I've seen thus far for Ruby 1.6 and 1.8, I hope that we will have a
clean implementation of Object#become in a future version of Ruby, so
that we can have nice lazy evaluation without using delegates.

Paul
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,043
Latest member
CannalabsCBDReview

Latest Threads

Top