Home > Back-end >  In Raku, how does one write the equivalent of Haskell's span function?
In Raku, how does one write the equivalent of Haskell's span function?

Time:06-30


In Raku, how does one write the equivalent of Haskell's span function?

In Haskell, given a predicate and a list, one can split the list into two parts:

  • the longest prefix of elements satisfying the predicate
  • the remainder of the list

For example, the Haskell expression …

span (< 10) [2, 2, 2, 5, 5, 7, 13, 9, 6, 2, 20, 4]

… evaluates to …

([2,2,2,5,5,7],[13,9,6,2,20,4])

How does one write the Raku equivalent of Haskell's span function?


CodePudding user response:

I use first method and :k adverb:

my @num  = [2, 2, 2, 5, 5, 7, 13, 9, 6, 2, 20, 4];
my $idx = @num.first(* > 10):k;

@num[0..$idx-1], @num[$idx..*];

CodePudding user response:

A completely naive take on this:

sub split_on(@arr, &pred) {
  my @arr1;
  my @arr2 = @arr;

  loop {
    if not &pred(@arr2.first) {
      last;
    } 

    push @arr1: @arr2.shift
  }

  (@arr1, @arr2);
}

Create a new @arr1 and copy the array into @arr2. Loop, and if the predicate is not met for the first element in the array, it's the last time through. Otherwise, shift the first element off from @arr2 and push it onto @arr1.

When testing this:

my @a = [2, 2, 2, 5, 5, 7, 13, 9, 6, 2, 20, 4];
my @b = split_on @a, -> $x { $x < 10 };

say @b;

The output is:

[[2 2 2 5 5 7] [13 9 6 2 20 4]]

Only problem here is... what if the predicate isn't met? Well, let's check if the list is empty or the predicate isn't met to terminate the loop.

sub split_on(@arr, &pred) {
  my @arr1;
  my @arr2 = @arr;

  loop {
    if !@arr2 || not &pred(@arr2.first) {
      last;
    } 

    push @arr1: @arr2.shift;
  }

  (@arr1, @arr2);
}
  • Related