# --------------------------------------------------------------------------- #
# LazySequence Class
# --------------------------------------------------------------------------- #
# - An Lazy Immutable Sequence class
# --------------------------------------------------------------------------- #
^LazySequence := ^Class.new({});
^LazySequence.set_name('LazySequence');
^LazySequence.set_version('0.0.1');
^LazySequence.set_authority('url:pugscode.org');
^LazySequence.set_roles([ ^Seq ]);
^LazySequence.set_superclasses([ ^Object ]);
^LazySequence.add_attribute('$!current', nil);
^LazySequence.add_attribute('&generator', nil);
^LazySequence.add_method('BUILD', -> %params {
# cache the current (head) element
# at instance creation time :)
self`set_attr('$!current', self`get_attr('&generator')`());
});
# --------------------------------------------------------------------------- #
# Methods dependent upon the repr type
^LazySequence.add_method('head', -> { self`get_attr('$!current') });
^LazySequence.add_method('tail', -> {
# create a new instance, which then forces the
# current element to be generated (see BUILD above)
$?CLASS.new({ '&generator' => self`get_attr('&generator') });
});
# these two need to be re-implemented to return LazySequences
^LazySequence.add_method('apply', -> &code {
&old_generator := self`get_attr('&generator');
$?CLASS.new({ '&generator' => -> { &code`(&old_generator`()) } });
});
^LazySequence.add_method('filter', -> &code {
&old_generator := self`get_attr('&generator');
$?CLASS.new({ '&generator' => -> {
&redo := &?SUB;
my $value = &old_generator`();
&code`($value)`as_bit()`if_else(
-> { $value },
-> { &redo`() }
);
}
});
});
# NOTE:
# ideally this would not need to be re-implemented
# here just so that I could return a non-lazy Sequence
# but I see no other way currently.
^LazySequence.add_method('reverse', -> {
-> $list, @acc {
&redo := &?SUB;
$list.is_empty()`if_else(
-> { ^Sequence.new(@acc) }, # << Must return a regular Sequcene type
-> { &redo`($list.tail(), [ $list.head() ]`concat(@acc)) }
);
}`(self.tail(), [ self.head() ]);
});