[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Evaluator for a mini-Ruby in Haskell

djberg96

3/26/2005 3:04:00 AM

Maybe I need to rethink my view of Haskell after all:

http://community.moertel.com/ss/space/start/2005-03-25/1#Writing_a_simple_Ruby...

Regards,

Dan

17 Answers

ptkwt

3/26/2005 4:27:00 AM

0

In article <1111806229.622292.217680@l41g2000cwc.googlegroups.com>,
Daniel Berger <djberg96@hotmail.com> wrote:
>Maybe I need to rethink my view of Haskell after all:
>
>http://community.moertel.com/ss/space/start/2005-03-25/1#Writing_a_simple_Ruby...
>

Interesting.

Anyone care to comment on the analysis of 'retry' there? He presents the
following code for a do-it-yourself while loop:

def my_while(cond)
break unless cond
yield
retry
end

i = 0 my_while i < 10 do print i i += 1 end

# output: 0123456789


And offers this analysis:

"This is where the Pickaxe II let me down. It said, "retry will
reevaluate
any arguments to the iterator before restarting it." Yes, clearly, that
is what is happening. But how is it happening and what exactly does that
simple English statement really mean?

So, after thinking about it, I concluded that what is going on is that a
function call in Ruby works like this. Given a function f, a block b, and
arguments xs, the call f(xs){b} means this:

1. let k be the current continuation (i.e., just before the call)
2. bind xs to f's formal arguments
3. bind b internally to the current block
4. evaluate the body of f

Now, if inside of f's body we encounter a retry, the evaluator basically
calls k (with a nil argument, I expect). This jumps back to step 2, from
which evaluation continues. Any side effects up to this point are
retained (so we could have previously incremented i, for example), which
is what allows the code within the function body eventually to choose an
execution path which does not contain a retry expression, and thus avoid
looping forever."


Phil

gabriele renzi

3/26/2005 9:30:00 AM

0

Daniel Berger ha scritto:
> Maybe I need to rethink my view of Haskell after all:
>
> http://community.moertel.com/ss/space/start/2005-03-25/1#Writing_a_simple_Ruby...
>

yeah, i was surprised too from:
"I must say that I really like Ruby's semantics. So far, I find it to be
a seriously cool programming language."
I would'nt expect this static functional guys to like ruby ;)

Robert Klemme

3/26/2005 6:34:00 PM

0


"Phil Tomson" <ptkwt@aracnet.com> schrieb im Newsbeitrag
news:d22ob001uag@enews1.newsguy.com...
> In article <1111806229.622292.217680@l41g2000cwc.googlegroups.com>,
> Daniel Berger <djberg96@hotmail.com> wrote:
>>Maybe I need to rethink my view of Haskell after all:
>>
>>http://community.moertel.com/ss/space/start/2005-03-25/1#Writing_a_simple_Ruby...
>>
>
> Interesting.
>
> Anyone care to comment on the analysis of 'retry' there? He presents the
> following code for a do-it-yourself while loop:
>
> def my_while(cond)
> break unless cond
> yield
> retry
> end
>
> i = 0 my_while i < 10 do print i i += 1 end
>
> # output: 0123456789
>
>
> And offers this analysis:
>
> "This is where the Pickaxe II let me down. It said, "retry will
> reevaluate
> any arguments to the iterator before restarting it." Yes, clearly, that
> is what is happening. But how is it happening and what exactly does that
> simple English statement really mean?
>
> So, after thinking about it, I concluded that what is going on is that a
> function call in Ruby works like this. Given a function f, a block b, and
> arguments xs, the call f(xs){b} means this:
>
> 1. let k be the current continuation (i.e., just before the call)
> 2. bind xs to f's formal arguments
> 3. bind b internally to the current block
> 4. evaluate the body of f
>
> Now, if inside of f's body we encounter a retry, the evaluator basically
> calls k (with a nil argument, I expect). This jumps back to step 2, from
> which evaluation continues. Any side effects up to this point are
> retained (so we could have previously incremented i, for example), which
> is what allows the code within the function body eventually to choose an
> execution path which does not contain a retry expression, and thus avoid
> looping forever."

I'm surprised about "retry", too. His analysis sounds all very resonable -
only that "break" does not work for me but "return" does:

>> def my_while(cond)
>> break unless cond
>> yield
>> retry
>> end
=> nil
>> i = 0
=> 0
>> my_while i < 10 do
?> puts i
>> i += 1
>> end
0
1
2
3
4
5
6
7
8
9
LocalJumpError: unexpected break
from (irb):2:in `my_while'
from (irb):7
>> def my_while(cond)
>> return unless cond
>> yield
>> retry
>> end
=> nil
>> i = 0
=> 0
>> my_while i < 10 do
?> puts i
>> i += 1
>> end
0
1
2
3
4
5
6
7
8
9
=> nil

ruby 1.8.1

Btw, can anybody think of a way to make my_while return the result of the
last block evaluation? It seems impossible because the return occurs before
the yield...

Kind regards

robert

ptkwt

3/26/2005 6:56:00 PM

0

In article <3alo9bF6d2vo8U1@individual.net>,
Robert Klemme <bob.news@gmx.net> wrote:
>
>
>I'm surprised about "retry", too. His analysis sounds all very resonable -
>only that "break" does not work for me but "return" does:
>
>>> def my_while(cond)
>>> break unless cond
>>> yield
>>> retry
>>> end
>=> nil
>>> i = 0
>=> 0
>>> my_while i < 10 do
>?> puts i
>>> i += 1
>>> end
>0
>1
>2
>3
>4
>5
>6
>7
>8
>9
>LocalJumpError: unexpected break
> from (irb):2:in `my_while'
> from (irb):7


Hmmm... break works find for me in 1.8.2. Time to upgrade?


>
>Btw, can anybody think of a way to make my_while return the result of the
>last block evaluation? It seems impossible because the return occurs before
>the yield...
>


How about:

def my_while(cond)
return @ret unless cond
@ret = yield
retry
end


Phil

ES

3/26/2005 7:22:00 PM

0


In data 3/26/2005, "(Phil Tomson)" <ptkwt@aracnet.com> ha scritto:

>In article <3alo9bF6d2vo8U1@individual.net>,
>Robert Klemme <bob.news@gmx.net> wrote:
>>
>>
>>I'm surprised about "retry", too. His analysis sounds all very resonable -
>>only that "break" does not work for me but "return" does:
>>
>>>> def my_while(cond)
>>>> break unless cond
>>>> yield
>>>> retry
>>>> end
>>=> nil
>>>> i = 0
>>=> 0
>>>> my_while i < 10 do
>>?> puts i
>>>> i += 1
>>>> end
>>0
>>1
>>2
>>3
>>4
>>5
>>6
>>7
>>8
>>9
>>LocalJumpError: unexpected break
>> from (irb):2:in `my_while'
>> from (irb):7
>
>
>Hmmm... break works find for me in 1.8.2. Time to upgrade?
>
>
>>
>>Btw, can anybody think of a way to make my_while return the result of the
>>last block evaluation? It seems impossible because the return occurs before
>>the yield...
>>
>
>
>How about:
>
> def my_while(cond)
> return @ret unless cond
> @ret = yield
> retry
> end

@ret may not be defined at that point of evaluation.

>Phil

E



ptkwt

3/26/2005 7:26:00 PM

0

In article <3alo9bF6d2vo8U1@individual.net>,
Robert Klemme <bob.news@gmx.net> wrote:
>
>
>I'm surprised about "retry", too. His analysis sounds all very resonable -
>only that "break" does not work for me but "return" does:
>
>>> def my_while(cond)
>>> break unless cond
>>> yield
>>> retry
>>> end
>=> nil
>>> i = 0
>=> 0
>>> my_while i < 10 do
>?> puts i
>>> i += 1
>>> end
>0
>1
>2
>3
>4
>5
>6
>7
>8
>9
>LocalJumpError: unexpected break
> from (irb):2:in `my_while'
> from (irb):7
>>> def my_while(cond)
>>> return unless cond
>>> yield
>>> retry
>>> end
>=> nil
>>> i = 0
>=> 0
>>> my_while i < 10 do
>?> puts i
>>> i += 1
>>> end

I tried to do nested my_while's using the my_while with return instead
of break. It doesn't work; it endlessly loops. Using break it works
correctly:

i=0
my_while i<5 do
puts "i: #{i}"
j = 0
my_while j<5 do
puts " j: #{j}"
j+=1
end
i+=1
end

prints:

i: 0
j: 0
j: 1
j: 2
j: 3
j: 4
i: 1
j: 0
j: 1
j: 2
j: 3
j: 4
i: 2
j: 0
j: 1
j: 2
j: 3
j: 4
i: 3
j: 0
j: 1
j: 2
j: 3
j: 4
i: 4
j: 0
j: 1
j: 2
j: 3
j: 4
=> nil


Oh, and my proposed my_while that returns the last block evaluation:

def my_while(cond)
break @ret unless cond #NOTE: break can return a value
@ret = yield
retry
end

wouldn't work if you have nested my_while's. You would have to create
some kind of class that contains a while method in order for nesting
to be handled correctly.

something like:

class Whiler
def initialize
@ret = nil
end

def while(cond)
break @ret unless cond
@ret = yield
retry
end
end

outer = Whiler.new
inner = Whiler.new

i=0
outer.while i<5 do
puts "i: #{i}"
j=0
inner.while j<5 do
puts " j: #{j}"
j+=1
end
i+=1
end

perhaps a bit cumbersome, though.


Phil

ptkwt

3/26/2005 7:31:00 PM

0

In article <9uuQtIOA.1111864906.5153320.ruerue@bidwell.textdrive.com>,
Saynatkari <ruby-ml@magical-cat.org> wrote:
>
>In data 3/26/2005, "(Phil Tomson)" <ptkwt@aracnet.com> ha scritto:
>
>>In article <3alo9bF6d2vo8U1@individual.net>,
>>Robert Klemme <bob.news@gmx.net> wrote:
>>>
>>>
>>>I'm surprised about "retry", too. His analysis sounds all very resonable -
>>>only that "break" does not work for me but "return" does:
>>>
>>>>> def my_while(cond)
>>>>> break unless cond
>>>>> yield
>>>>> retry
>>>>> end
>>>=> nil
>>>>> i = 0
>>>=> 0
>>>>> my_while i < 10 do
>>>?> puts i
>>>>> i += 1
>>>>> end
>>>0
>>>1
>>>2
>>>3
>>>4
>>>5
>>>6
>>>7
>>>8
>>>9
>>>LocalJumpError: unexpected break
>>> from (irb):2:in `my_while'
>>> from (irb):7
>>
>>
>>Hmmm... break works find for me in 1.8.2. Time to upgrade?
>>
>>
>>>
>>>Btw, can anybody think of a way to make my_while return the result of the
>>>last block evaluation? It seems impossible because the return occurs before
>>>the yield...
>>>
>>
>>
>>How about:
>>
>> def my_while(cond)
>> return @ret unless cond
>> @ret = yield
>> retry
>> end
>
>@ret may not be defined at that point of evaluation.
>

Ah, true. If you did something like:

my_while false do
#foo
end

it would return nil, since @ret never got defined. Maybe that wouldn't
be too bad, though.

what would you want returned in this case:

i = 10
my_while i<10 do
puts i
i+=1
end

?

Phil


ES

3/26/2005 7:36:00 PM

0


In data 3/26/2005, "Saynatkari" <ruby-ml@magical-cat.org> ha scritto:

>
>In data 3/26/2005, "(Phil Tomson)" <ptkwt@aracnet.com> ha scritto:
>
>>In article <3alo9bF6d2vo8U1@individual.net>,
>>Robert Klemme <bob.news@gmx.net> wrote:
>>>
>>>
>>>I'm surprised about "retry", too. His analysis sounds all very resonable -
>>>only that "break" does not work for me but "return" does:
>>>
>>>>> def my_while(cond)
>>>>> break unless cond
>>>>> yield
>>>>> retry
>>>>> end
>>>=> nil
>>>>> i = 0
>>>=> 0
>>>>> my_while i < 10 do
>>>?> puts i
>>>>> i += 1
>>>>> end
>>>0
>>>1
>>>2
>>>3
>>>4
>>>5
>>>6
>>>7
>>>8
>>>9
>>>LocalJumpError: unexpected break
>>> from (irb):2:in `my_while'
>>> from (irb):7
>>
>>
>>Hmmm... break works find for me in 1.8.2. Time to upgrade?
>>
>>
>>>
>>>Btw, can anybody think of a way to make my_while return the result of the
>>>last block evaluation? It seems impossible because the return occurs before
>>>the yield...
>>>
>>
>>
>>How about:
>>
>> def my_while(cond)
>> return @ret unless cond
>> @ret = yield
>> retry
>> end
>
>@ret may not be defined at that point of evaluation.

Er, defined 'correctly', that is. It'll just be the
current value of i. Otherwise a novel approach!

>>Phil
>
>E

E



Robert Klemme

3/27/2005 11:29:00 AM

0


"Phil Tomson" <ptkwt@aracnet.com> schrieb im Newsbeitrag
news:d24b8d02fq1@enews4.newsguy.com...
> In article <3alo9bF6d2vo8U1@individual.net>,
> Robert Klemme <bob.news@gmx.net> wrote:
>>
>>
>>I'm surprised about "retry", too. His analysis sounds all very
>>resonable -
>>only that "break" does not work for me but "return" does:
>>
>>>> def my_while(cond)
>>>> break unless cond
>>>> yield
>>>> retry
>>>> end
>>=> nil
>>>> i = 0
>>=> 0
>>>> my_while i < 10 do
>>?> puts i
>>>> i += 1
>>>> end
>>0
>>1
>>2
>>3
>>4
>>5
>>6
>>7
>>8
>>9
>>LocalJumpError: unexpected break
>> from (irb):2:in `my_while'
>> from (irb):7
>
>
> Hmmm... break works find for me in 1.8.2. Time to upgrade?

Yeah, maybe.

>>Btw, can anybody think of a way to make my_while return the result of the
>>last block evaluation? It seems impossible because the return occurs
>>before
>>the yield...
>>
>
>
> How about:
>
> def my_while(cond)
> return @ret unless cond
> @ret = yield
> retry
> end

Not thread safe. And I think also not nesting safe.

Cheers

robert

Robert Klemme

3/27/2005 11:33:00 AM

0


"Saynatkari" <ruby-ml@magical-cat.org> schrieb im Newsbeitrag
news:cqCUhZUI.1111865719.6056510.ruerue@bidwell.textdrive.com...
>
> In data 3/26/2005, "Saynatkari" <ruby-ml@magical-cat.org> ha scritto:
>
>>
>>In data 3/26/2005, "(Phil Tomson)" <ptkwt@aracnet.com> ha scritto:
>>
>>>In article <3alo9bF6d2vo8U1@individual.net>,
>>>Robert Klemme <bob.news@gmx.net> wrote:
>>>>
>>>>
>>>>I'm surprised about "retry", too. His analysis sounds all very
>>>>resonable -
>>>>only that "break" does not work for me but "return" does:
>>>>
>>>>>> def my_while(cond)
>>>>>> break unless cond
>>>>>> yield
>>>>>> retry
>>>>>> end
>>>>=> nil
>>>>>> i = 0
>>>>=> 0
>>>>>> my_while i < 10 do
>>>>?> puts i
>>>>>> i += 1
>>>>>> end
>>>>0
>>>>1
>>>>2
>>>>3
>>>>4
>>>>5
>>>>6
>>>>7
>>>>8
>>>>9
>>>>LocalJumpError: unexpected break
>>>> from (irb):2:in `my_while'
>>>> from (irb):7
>>>
>>>
>>>Hmmm... break works find for me in 1.8.2. Time to upgrade?
>>>
>>>
>>>>
>>>>Btw, can anybody think of a way to make my_while return the result of
>>>>the
>>>>last block evaluation? It seems impossible because the return occurs
>>>>before
>>>>the yield...
>>>>
>>>
>>>
>>>How about:
>>>
>>> def my_while(cond)
>>> return @ret unless cond
>>> @ret = yield
>>> retry
>>> end
>>
>>@ret may not be defined at that point of evaluation.
>
> Er, defined 'correctly', that is. It'll just be the
> current value of i. Otherwise a novel approach!

What do you mean by "correctly"? If there's no value you'll get nil which
is ok if the condition evaluates to false right from the start IMHO. The
problem I see with this is rather thread safety (which could be handled by
thread local variables) and nesting (which is a bit more difficult to cope
with IMHO; I guess you'll need a stack of values as thread local or such).

Kind regards

robert