Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

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?


Update 1

Based on the answer of @chenyf, I developed the following span subroutine (additional later update reflects negated predicate within span required to remain faithful to the positive logic of Haskell's span function) …

sub span( &predicate, @numberList )
  {
  my &negatedPredicate = { ! &predicate($^x) } ;
  my $idx = @numberList.first(&negatedPredicate):k ;
  my @lst is Array[List] = @numberList[0..$idx-1], @numberList[$idx..*] ;
  @lst ;
  } # end sub span

sub MAIN()
  {
  my &myPredicate = { $_ <= 10 } ;
  my @myNumberList is Array[Int] = [2, 2, 2, 5, 5, 7, 13, 9, 6, 2, 20, 4] ;
  my @result is Array[List] = span( &myPredicate, @myNumberList ) ;

  say '@result is ...' ;
  say @result ;
  say '@result[0] is ...' ;
  say @result[0] ;
  say @result[0].WHAT ;
  say '@result[1] is ...' ;
  say @result[1] ;
  say @result[1].WHAT ;
  } # end sub MAIN

Program output is …

@result is ...
[(2 2 2 5 5 7) (13 9 6 2 20 4)]
@result[0] is ...
(2 2 2 5 5 7)
(List)
@result[1] is ...
(13 9 6 2 20 4)
(List)

Update 2

Utilizing information posted to StackOverflow concerning Raku's Nil, the following updated draft of subroutine span is …

sub span( &predicate, @numberList )
  {
  my &negatedPredicate = { ! &predicate($^x) } ;
  my $idx = @numberList.first( &negatedPredicate ):k ;
  if Nil ~~ any($idx) { $idx = @numberList.elems ; }
  my List $returnList = (@numberList[0..$idx-1], @numberList[$idx..*]) ;
  $returnList ;
  } # end sub span

sub MAIN()
  {
  say span( { $_ == 0 }, [2, 2, 5, 7, 4, 0] ) ;  #  (() (2 2 5 7 4 0))
  say span( { $_ <  6 }, (2, 2, 5, 7, 4, 0) ) ;  #  ((2 2 5) (7 4 0))
  say span( { $_ != 9 }, [2, 2, 5, 7, 4, 0] ) ;  #  ((2 2 5 7 4 0) ())
  } # end sub MAIN

like image 841
user3134725 Avatar asked Dec 07 '25 09:12

user3134725


1 Answers

I use first method and :k adverb, like this:

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..*];
like image 115
chenyf Avatar answered Dec 08 '25 22:12

chenyf