#!/usr/bin/perl

package Stream;

sub new {
  my ($p,$h,$t) = @_;
  bless { h => $h, t => $t } => $p;
}

sub head { $_[0]{h} }

sub tail {
  my $tail = $_[0]{t};
  if (ref $tail eq CODE) {
    $_[0]{t} = $tail->();
  }
  $_[0]{t};
}

sub empty {
  my $p = ref(shift) || Stream;
  bless { e => 'Estoy vacio' } => $p;
}

sub is_empty {
  exists $_[0]{e}
}

sub scale {
  my $self = shift;
  my $n    = shift;
  return empty() if $self->is_empty;
  Stream->new($self->head * $n, sub { $self->tail->scale($n) });
}

sub filter {
  my $self = shift;
  my $predicate = shift;

  while (! $self->is_empty && ! $predicate->($self->head) ) {
    $self = $self->tail;
  }
  return empty() if $self->is_empty;
  Stream->new($self->head, sub { $self->tail->filter($predicate) } );
}

sub show {
  my $self = shift;
  my $n = shift || 10;

  while ($n--) {
    print $self->head, ", ";
    $self = $self->tail;
  }
  print "...\n";
}

42;
