Mechanical

Pleasant pre-Christmas Evenings

So I started writing a post about my "fantasy" Christmas list. One idea was the idea of buying a bottle of cheap whiskey and a pack of fags for the elderly mother of my long long adopted brother and sister. However, my present list got offensive enough that it offended even me! So I'll just say that after wrapping a few presents for family members, I am having a thoroughly pleasant evening drinking rum and Coke and working on Perl 6. All I can say is that Perl 6 rocks!

  # P12 (**) Decode a run-length encoded list.
  #
  #     Given a run-length code list generated as specified in problem P11.
  #     Construct its uncompressed version.
 
  sub decode(*@list) returns Array {
      gather {
          for @list -> $elem {
              take $elem.isa(Array) ?? $elem[1] xx $elem[0] !! item $elem;
          }
      }
  }
  decode( [4, "a"], "b", [2, "c"], [2, "a"], "d", [4, "e"] ).perl.say;

And if you don't think I'm totally cool, just check out my "current music".

In other news, why the hell do I feel so guilty for not doing more to promote Perl 6?

  • Current Mood: drunk drunk
  • Current Music: Massive Retaliation | Sigue Sigue Sputnik
I used to have a Sigue Sigue Sputnik CD that someone burned for me a few years ago, and it was lost in a move. It was very crushing.
I can't recall how I stumbled across them, but they're frickin' awesome. Many people dismiss them as 'glam rock', but they're so much better than that.
Eeeeee! I haven't listened to Sigue Sigue Sputnik in YEARS...! Thanks for bringing back good memories.
I take it 'gather' is an accumulator in Perl 6?

Anyway, here's one way to do it in Ruby, if you care:
def decode(array)
   array.inject([]){ |list, elem|
      elem.is_a?(Array) ? elem[0].times{ list << elem[1] } : list << elem
      list
   }
end

Also, does 'xx' do some kind of auto-flattening? Otherwise, it looks like you'll end up with ['aaaa', 'b', 'cc', 'd', 'eeee'] instead of the expected result. That, or I've misunderstood what the result should be.

Not so. xx is the Perl 6 list-repeat operator, distinct from the Perl 6 string-repeat operator called x. That is, 2 xx 4 will give you ( 2, 2, 2, 2 ).

Actually, I do care about Ruby. It gives me new ways of thinking about things and it's a super-cool language.

Using gather/take here strikes me as a disadvantageous gimmick. Then again, I have no idea what the .perl method call is doing in there, and I don’t know what item means or why it is necessary, so I could well be completely wrong. But I’d write this as a straight map instead (in Perl 5, since I don’t know Perl 6 beyond a few tidbits):

sub decode { map { ref $_ ? ( $_->[1] ) x $_->[0] : $_ } @_ }

The only things that strike me as inferior about that are the forced use of the default variable and the forced use of parens caused by the conflation of the list- and string-repeat operators in Perl 5.

Is there something clever about the Perl 6 version that I’m missing?

No, you're not missing anything. Your map solution is clean and probably better. I've just been playing with the gather/take syntax and discovering on #perl6 that it's still in flux. It's a fairly readable syntax, though I do confess I've not found any constructs it makes particularly shorter.

Oh, and the "item" I had in the original code was a workaround for a Pugs bug. Without that, single elements were returned as references for some strange reason. The ".perl" forces a data structure to be represented as valid Perl (sort of like a simplistic Data::Dumper).

I suppose it’s more about readability. maps with relatively large blocks (more than 3-4 lines or so), particularly when nested, tend to be disorienting. And over large code blocks, the relative verbosity of the gather/take construct is lost in the sheer amount of code.

The “.perl” forces a data structure to be represented as valid Perl (sort of like a simplistic Data::Dumper).

Ah – cool!! Finally, part of the language core. That’s one little thing I quite liked about Python and Ruby and even, I barely dare say it, PHP.

Oh, one thing I forgot to mention. Larry states that gather/take is not a loop and order is not guaranteed. I believe this means is that multiple "takings" could occur simultaneously, taking advantage of multiple processors and the like. (Actually, that would be multiple gather/takes, not multiple takes).
Oh, I should have known there was a map solution:
def decode(array)
   array.map{ |e| e.is_a?(Array) ? [e[1]] * e[0] : e }.flatten
end

Much nicer. The other version with the array.inject([]) thing and the emulation of gather by iteratively shifting onto an array is quite… unpretty.