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_evaluator
Regards,
Dan
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_evaluator
Regards,
Dan
In article <1111806229.622292.217680@l41g2000cwc.googlegroups.com>,
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_evaluator
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
Daniel Berger <djberg96@hotmail.com> wrote:
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_evaluator
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
"Phil Tomson" <ptkwt@aracnet.com> schrieb im Newsbeitrag news:d22ob001uag@enews1.newsguy.com...
In article <1111806229.622292.217680@l41g2000cwc.googlegroups.com>,
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_evaluator
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
endi = 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 fNow, 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
Daniel Berger <djberg96@hotmail.com> wrote:
In article <3alo9bF6d2vo8U1@individual.net>,
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
end0
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
Robert Klemme <bob.news@gmx.net> wrote:
In article <3alo9bF6d2vo8U1@individual.net>,
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
end0
1
2
3
4
5
6
7
8
9
LocalJumpError: unexpected break
from (irb):2:in `my_while'
from (irb):7def 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
Robert Klemme <bob.news@gmx.net> wrote:
In data 3/26/2005, "(Phil Tomson)" <ptkwt@aracnet.com> ha scritto:
In article <3alo9bF6d2vo8U1@individual.net>,
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
end0
1
2
3
4
5
6
7
8
9
LocalJumpError: unexpected break
from (irb):2:in `my_while'
from (irb):7Hmmm... 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
Robert Klemme <bob.news@gmx.net> wrote:
"Phil Tomson" <ptkwt@aracnet.com> schrieb im Newsbeitrag news:d24b8d02fq1@enews4.newsguy.com...
In article <3alo9bF6d2vo8U1@individual.net>,
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
end0
1
2
3
4
5
6
7
8
9
LocalJumpError: unexpected break
from (irb):2:in `my_while'
from (irb):7Hmmm... 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 <bob.news@gmx.net> wrote:
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>,
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
end0
1
2
3
4
5
6
7
8
9
LocalJumpError: unexpected break
from (irb):2:in `my_while'
from (irb):7Hmmm... 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 <bob.news@gmx.net> wrote:
In article <9uuQtIOA.1111864906.5153320.ruerue@bidwell.textdrive.com>,
In data 3/26/2005, "(Phil Tomson)" <ptkwt@aracnet.com> ha scritto:
In article <3alo9bF6d2vo8U1@individual.net>,
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
end0
1
2
3
4
5
6
7
8
9
LocalJumpError: unexpected break
from (irb):2:in `my_while'
from (irb):7Hmmm... 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
Saynatkari <ruby-ml@magical-cat.org> wrote:
Robert Klemme <bob.news@gmx.net> wrote:
In article <3anjpeF6d91alU1@individual.net>,
"Phil Tomson" <ptkwt@aracnet.com> schrieb im Newsbeitrag
news:d24b8d02fq1@enews4.newsguy.com...In article <3alo9bF6d2vo8U1@individual.net>,
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
end0
1
2
3
4
5
6
7
8
9
LocalJumpError: unexpected break
from (irb):2:in `my_while'
from (irb):7Hmmm... 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
endNot thread safe. And I think also not nesting safe.
Yes, I know. Did you see my later post? I don't think it made it from
the newsgroup to the mailing list.
Here's the code:
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
A bit cumbersome, perhaps, but it is definately nestable and should be
threadsafe as well.
Phil
Robert Klemme <bob.news@gmx.net> wrote:
Robert Klemme <bob.news@gmx.net> wrote:
"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>,
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
end0
1
2
3
4
5
6
7
8
9
LocalJumpError: unexpected break
from (irb):2:in `my_while'
from (irb):7Hmmm... 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
Robert Klemme <bob.news@gmx.net> wrote:
We've been having this discussion about defining your own while loop in a
thread about Haskell and I thought I'd change the subject in case people
who had no interest in Haskell were avoiding it
In article <d26sfn01vqs@enews3.newsguy.com>,
In article <3anjpeF6d91alU1@individual.net>,
"Phil Tomson" <ptkwt@aracnet.com> schrieb im Newsbeitrag
news:d24b8d02fq1@enews4.newsguy.com...In article <3alo9bF6d2vo8U1@individual.net>,
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
end0
1
2
3
4
5
6
7
8
9
LocalJumpError: unexpected break
from (irb):2:in `my_while'
from (irb):7Hmmm... 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
endNot thread safe. And I think also not nesting safe.
Yes, I know. Did you see my later post? I don't think it made it from
the newsgroup to the mailing list.Here's the code to make it nestable and threadsafe:
class Whiler
def initialize
@ret = nil
enddef while(cond)
break @ret unless cond
@ret = yield
retry
end
endouter = Whiler.new
inner = Whiler.newi=0
outer.while i<5 do
puts "i: #{i}"
j=0
inner.while j<5 do
puts " j: #{j}"
j+=1
end
i+=1
endA bit cumbersome, perhaps, but it is definately nestable and should be
threadsafe as well.
Actually, I figured out a way to make it much more natural:
Change Whiler to accept an optional condition in it's constructor like
so:
class Whiler
def initialize(cond=nil)
@ret = nil
@cond = cond
end
def while(cond=@cond)
break @ret unless cond
@ret = yield
retry
end
end
Define the my_while top-level method like so:
def my_while(cond,&block)
Whiler.new(cond).method(:while).call(&block)
end
Now the user of my_while doesn't need to know that a Whiler class even
exists. Usage example:
i = 0
my_while(i<10) do
puts i
j=0
my_while(j<10) do
puts " j: #{j}"
j+=1
end
i+=1
end
I think there are some implications for DSLs (Domain Specific Languages)
in this example.
The my_while method as defined above (the last one) hides some Ruby
language details from the user of my_while so that my_while can appear like a
natural looping construct. I've created DSLs for people who had
no idea they were using Ruby underneath; this sort of thing is
necessary so they don't feel as though they are obliged to learn
Ruby to use the DSL.
Another example of why Ruby is so good for creating DSLs.
Phil
Phil Tomson <ptkwt@aracnet.com> wrote:
Robert Klemme <bob.news@gmx.net> wrote:
Robert Klemme <bob.news@gmx.net> wrote:
"Phil Tomson" <ptkwt@aracnet.com> schrieb im Newsbeitrag news:d26uh30st5@enews1.newsguy.com...
We've been having this discussion about defining your own while loop in a
thread about Haskell and I thought I'd change the subject in case people
who had no interest in Haskell were avoiding itIn article <d26sfn01vqs@enews3.newsguy.com>,
In article <3anjpeF6d91alU1@individual.net>,
"Phil Tomson" <ptkwt@aracnet.com> schrieb im Newsbeitrag
news:d24b8d02fq1@enews4.newsguy.com...In article <3alo9bF6d2vo8U1@individual.net>,
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
end0
1
2
3
4
5
6
7
8
9
LocalJumpError: unexpected break
from (irb):2:in `my_while'
from (irb):7Hmmm... 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
endNot thread safe. And I think also not nesting safe.
Yes, I know. Did you see my later post? I don't think it made it from
the newsgroup to the mailing list.
Yes, I saw it - but too late.
Here's the code to make it nestable and threadsafe:
class Whiler
def initialize
@ret = nil
enddef while(cond)
break @ret unless cond
@ret = yield
retry
end
endouter = Whiler.new
inner = Whiler.newi=0
outer.while i<5 do
puts "i: #{i}"
j=0
inner.while j<5 do
puts " j: #{j}"
j+=1
end
i+=1
endA bit cumbersome, perhaps, but it is definately nestable and should be
threadsafe as well.Actually, I figured out a way to make it much more natural:
Change Whiler to accept an optional condition in it's constructor like
so:class Whiler
def initialize(cond=nil)
@ret = nil
@cond = cond
end
def while(cond=@cond)
break @ret unless cond
@ret = yield
retry
end
endDefine the my_while top-level method like so:
def my_while(cond,&block)
Whiler.new(cond).method(:while).call(&block)
endNow the user of my_while doesn't need to know that a Whiler class even
exists. Usage example:i = 0
my_while(i<10) do
puts i
j=0
my_while(j<10) do
puts " j: #{j}"
j+=1
end
i+=1
end
This is nice!
I think there are some implications for DSLs (Domain Specific Languages)
in this example.
The my_while method as defined above (the last one) hides some Ruby
language details from the user of my_while so that my_while can appear like a
natural looping construct. I've created DSLs for people who had
no idea they were using Ruby underneath; this sort of thing is
necessary so they don't feel as though they are obliged to learn
Ruby to use the DSL.Another example of why Ruby is so good for creating DSLs.
+2
Kind regards
robert
Phil Tomson <ptkwt@aracnet.com> wrote:
Robert Klemme <bob.news@gmx.net> wrote:
Robert Klemme <bob.news@gmx.net> wrote:
This new my_while doesn't seem to return the last block. The following
snippet outputs nil values instead of "outer" and "inner":
i = 0
x = nil
y = nil
x = my_while(i<10) do
j=0
y = my_while(j<10) do
j+=1
"inner"
end
i+=1
"outer"
end
puts x
puts y
This makes your original my_while thread-safe. It was already safe for
nesting.
def my_while(cond)
@ret ||= {}
key = Thread.current
return @ret.delete(key) unless cond
@ret[key] = yield
retry
end
On Mon, 28 Mar 2005, Phil Tomson wrote:
Actually, I figured out a way to make it much more natural:
Change Whiler to accept an optional condition in it's constructor like
so:class Whiler
def initialize(cond=nil)
@ret = nil
@cond = cond
end
def while(cond=@cond)
break @ret unless cond
@ret = yield
retry
end
endDefine the my_while top-level method like so:
def my_while(cond,&block)
Whiler.new(cond).method(:while).call(&block)
end
--
Relm
In article <Pine.LNX.4.21.0503280111230.10981-100000@frieza>,
Actually, I figured out a way to make it much more natural:
Change Whiler to accept an optional condition in it's constructor like
so:class Whiler
def initialize(cond=nil)
@ret = nil
@cond = cond
end
def while(cond=@cond)
break @ret unless cond
@ret = yield
retry
end
endDefine the my_while top-level method like so:
def my_while(cond,&block)
Whiler.new(cond).method(:while).call(&block)
endThis new my_while doesn't seem to return the last block. The following
snippet outputs nil values instead of "outer" and "inner":i = 0
x = nil
y = nilx = my_while(i<10) do
j=0
y = my_while(j<10) do
j+=1
"inner"
end
i+=1
"outer"
endputs x
puts y
Hmmm... I'm seeing the same thing you are, but I'm not sure why.
Anyone got any ideas?
This makes your original my_while thread-safe. It was already safe for
nesting.def my_while(cond)
@ret ||= {}
key = Thread.current
return @ret.delete(key) unless cond
@ret[key] = yield
retry
end
That'll work.
Phil
Relm <relm@3tlk.net> wrote:
On Mon, 28 Mar 2005, Phil Tomson wrote:
In article <d29fv40210q@enews4.newsguy.com>,
In article <Pine.LNX.4.21.0503280111230.10981-100000@frieza>,
Actually, I figured out a way to make it much more natural:
Change Whiler to accept an optional condition in it's constructor like
so:class Whiler
def initialize(cond=nil)
@ret = nil
@cond = cond
end
def while(cond=@cond)
break @ret unless cond
@ret = yield
retry
end
endDefine the my_while top-level method like so:
def my_while(cond,&block)
Whiler.new(cond).method(:while).call(&block)
endThis new my_while doesn't seem to return the last block. The following
snippet outputs nil values instead of "outer" and "inner":i = 0
x = nil
y = nilx = my_while(i<10) do
j=0
y = my_while(j<10) do
j+=1
"inner"
end
i+=1
"outer"
endputs x
puts yHmmm... I'm seeing the same thing you are, but I'm not sure why.
Anyone got any ideas?
Ah, I see the problem now. my_while calls Whiler.new every time it is
called of course, thus creating a new Whiler object each time. The last
time through each loop, the condition is false when Whiler.new is
called and thus @ret is nil because my_while returns before getting to
the '@ret = yield'. Definately problematic. You can see the problem by
adding a 'puts' to the Whiler constructor like so:
class Whiler
def initialize(cond=nil)
puts "Whiler::new(#{cond})"
@ret = nil
@cond = cond
end
end
This makes your original my_while thread-safe. It was already safe for
nesting.def my_while(cond)
@ret ||= {}
key = Thread.current
return @ret.delete(key) unless cond
@ret[key] = yield
retry
end
This is probably the best bet for being both threadsafe and nestable.
Phil
Phil Tomson <ptkwt@aracnet.com> wrote:
Relm <relm@3tlk.net> wrote:
On Mon, 28 Mar 2005, Phil Tomson wrote: