this morning I stumbled across the Autrijus Tang journal[1],
which was showing this nifty piece of code:
say [~] (-> @c is copy {gather {
while @c[0] { for @c ->
{take(.shift)} } }
}(['Joec','utrk','shle','te6r',' r .','a h.','nPa.'].map:{[split "",$_]}));
in perl6 the [<something>] is the reduce metaoperator, and -> is the
equivalent of "proc".
The hard thing was understanding what gather/take are supposed to do.
A little investigation yielded explanation[2], they seem to be some kind
of accumulating construct a-la inject. In the tradition of the
perl6->ruby port such as junctions, .= operator and so on I tried
implement it.
Oh, and here is the translated JAPRH
proc{|c|p gather{c.each{|x|take x.shift}while
c[0][0]}.join}.call ['Joedh','utr a','shlRc',
'te6uk',' r be','a ayr.','nPn .' ].map{|x|x.split ''}
And down is the implementation[3]
[1] http://use.perl.org/~autrijus/journal/24919
[2] http://search.cpan.org/~dconway/Perl6-Gather-0.04/Gather.pm
[3]
class Gatherer
attr :gathered
def take(arg)
@gathered||=[]
@gathered<< arg
end
end
def gather &blk
c=Gatherer.new
c.instance_eval &blk
c.gathered
end
if __FILE__ == $0
require 'test/unit'
class TestGatherer < Test::Unit::TestCase
def ok(x, y)
assert_equal x.to_a,y
end
def test_take
l= gather { for i in 1..10: take i end}
ok 1..10, l
end
def test_take2
l= gather { for i in 1..10: take i end; take 99}
assert_equal (1..10).to_a+[99],l
end
def test_gathered
l= gather {for i in 1..10: take i end; take 99 unless gathered}
ok 1..10,l
end
def test_gathered_empty
l= gather {take 99 unless gathered}
ok 99,l
end
def test_gathered_pop
l= gather {for i in 1..10: take i end; gathered.pop }
ok 1..9,l
end
end
end
> Hi gurus and nubys,
>
> this morning I stumbled across the Autrijus Tang journal[1],
> which was showing this nifty piece of code:
>
>
> say [~] (-> @c is copy {gather {
> while @c[0] { for @c ->
> {take(.shift)} } }
> }(['Joec','utrk','shle','te6r',' r .','a h.','nPa.'].map:{[split "",$_]}));
>
> in perl6 the [<something>] is the reduce metaoperator, and -> is the
> equivalent of "proc".
> The hard thing was understanding what gather/take are supposed to do.
> A little investigation yielded explanation[2], they seem to be some
> kind of accumulating construct a-la inject. In the tradition of the
> perl6->ruby port such as junctions, .= operator and so on I tried
> implement it.
That's very nice and useful (I often wished for it), but goo already
had it for a long time. :-) It is called "packing" there, see
http://people.csail.mit.edu/jrb/goo/manual.46/goomanual_29.html
I think the implementation with instance_eval can be a bit surprising,
maybe [Dynamic Variables][1] could do that better.
[1]: http://chneukirchen.org/blog/archive/2005/04/dynamic-variables-in-ruby.html
--
Christian Neukirchen <chneuk...@gmail.com> http://chneukirchen.org
wow, I always thought GOO was cool, it seem I need to investigate it
more deeply :)
> I think the implementation with instance_eval can be a bit surprising,
> maybe [Dynamic Variables][1] could do that better.
yup, instance_eval is an hack, but I liked the idea of just allowing
#take inside #gather, which I don't have Idea how to reproduce withouth
it. Using DynaVars seem definitely a cool hack, anyway :)
> Christian Neukirchen ha scritto:
> <snip>
>> That's very nice and useful (I often wished for it), but goo already
>> had it for a long time. :-) It is called "packing" there, see
>> http://people.csail.mit.edu/jrb/goo/manual.46/goomanual_29.html
>
> wow, I always thought GOO was cool, it seem I need to investigate it
> more deeply :)
If it was alive, it would be even nicer... so many good ideas but
noone pushing them.
>> I think the implementation with instance_eval can be a bit surprising,
>> maybe [Dynamic Variables][1] could do that better.
>
> yup, instance_eval is an hack, but I liked the idea of just allowing
> #take inside #gather, which I don't have Idea how to reproduce
> withouth it. Using DynaVars seem definitely a cool hack, anyway :)
I'd just make it raise a RuntimeError if you're not inside a
gathering. Esp. in method definitions, how would you reach for "the
outer self"?
class Array
def add
yield self
self
end
end
# simple
a = [].add do |a|
a << 1
a << 2
a << 3
end
p a
# Fibonacci
b = [1,1].add do |a|
15.times { a << a[-1] + a[-2] }
end
p b
Array#inject may do as well.
I think the nice thing about packings is that they don't need to
reference the array variable... your code is no improvement to just
appending to the array directly, IMHO.
> I think the nice thing about packings is that they don't need to
> reference the array variable... your code is no improvement to just
> appending to the array directly, IMHO.
In that case, how are gather/packing an improvement? They require
more typing than just appending to an Array.
I guess I just don't "get it". <shrugs>
James Edward Gray II
For example, you could write methods that can add to any object
responding to "<<", just whatever it is.
It's mostly convenience, I'd say. It can make the code more elegant,
e.g. if you would have used #map, but sometimes need to map to several
values...
> James Edward Gray II