module Hamster::List
def accessor(sequence)
identify the series of car and cdr operations that is performed by the function. The order in which the 'a's and
least one 'a' or 'd', and finally an 'r'. The series of 'a's and 'd's in each function's name is chosen to
Perform compositions of car and cdr operations. Their names consist of a 'c', followed by at
def accessor(sequence) sequence.reverse.each_char.reduce(self) do |memo, char| case char when "a" then memo.head when "d" then memo.tail end end end
def add(item)
def add(item) append(Hamster.list(item)) end
def append(other)
def append(other) Stream.new do next other if empty? Sequence.new(head, tail.append(other)) end end
def at(index)
def at(index) drop(index).head end
def break(&block)
def break(&block) return span unless block_given? span { |item| !yield(item) } end
def chunk(number)
def chunk(number) Stream.new do next self if empty? first, remainder = split_at(number) Sequence.new(first, remainder.chunk(number)) end end
def clear
def clear EmptyList end
def combinations(number)
def combinations(number) return Sequence.new(EmptyList) if number == 0 Stream.new do next self if empty? tail.combinations(number - 1).map { |list| list.cons(head) }.append(tail.combinations(number)) end end
def cons(item)
def cons(item) Sequence.new(item, self) end
def cycle
def cycle Stream.new do next self if empty? Sequence.new(head, tail.append(cycle)) end end
def drop(number)
def drop(number) Stream.new do list = self while !list.empty? && number > 0 number -= 1 list = list.tail end list end end
def drop_while(&block)
def drop_while(&block) return self unless block_given? Stream.new do list = self list = list.tail while !list.empty? && yield(list.head) list end end
def dup
def dup self end
def each
def each return self unless block_given? list = self until list.empty? yield(list.head) list = list.tail end end
def each_chunk(number, &block)
def each_chunk(number, &block) chunk(number).each(&block) end
def elem_index(object)
def elem_index(object) find_index { |item| item == object } end
def elem_indices(object)
def elem_indices(object) find_indices { |item| item == object } end
def eql?(other)
def eql?(other) list = self loop do return true if other.equal?(list) return false unless other.is_a?(List) return other.empty? if list.empty? return false if other.empty? return false unless other.head.eql?(list.head) list = list.tail other = other.tail end end
def filter(&block)
def filter(&block) return self unless block_given? Stream.new do next self if empty? next Sequence.new(head, tail.filter(&block)) if yield(head) tail.filter(&block) end end
def find_index
def find_index return nil unless block_given? i = 0 list = self loop do return nil if list.empty? return i if yield(list.head) i += 1 list = list.tail end end
def find_indices(i = 0, &block)
def find_indices(i = 0, &block) return EmptyList unless block_given? Stream.new do next EmptyList if empty? next Sequence.new(i, tail.find_indices(i + 1, &block)) if yield(head) tail.find_indices(i + 1, &block) end end
def flat_map(&block)
def flat_map(&block) return self unless block_given? Stream.new do next self if empty? head_list = Hamster.list(*yield(head)) next tail.flat_map(&block) if head_list.empty? Sequence.new(head_list.first, head_list.drop(1).append(tail.flat_map(&block))) end end
def flatten
def flatten Stream.new do next self if empty? next head.append(tail.flatten) if head.is_a?(List) Sequence.new(head, tail.flatten) end end
def group_by(&block)
def group_by(&block) return group_by { |item| item } unless block_given? reduce(EmptyHash) do |hash, item| key = yield(item) hash.put(key, (hash.get(key) || EmptyList).cons(item)) end end
def hash
def hash reduce(0) { |hash, item| (hash << 5) - hash + item.hash } end
def index(object = Undefined, &block)
def index(object = Undefined, &block) return elem_index(object) unless object.equal?(Undefined) find_index(&block) end
def indices(object = Undefined, &block)
def indices(object = Undefined, &block) return elem_indices(object) unless object.equal?(Undefined) find_indices(&block) end
def init
def init return EmptyList if tail.empty? Stream.new { Sequence.new(head, tail.init) } end
def inits
def inits Stream.new do next Sequence.new(self) if empty? Sequence.new(EmptyList, tail.inits.map { |list| list.cons(head) }) end end
def inspect
def inspect to_a.inspect end
def intersperse(sep)
def intersperse(sep) Stream.new do next self if tail.empty? Sequence.new(head, Sequence.new(sep, tail.intersperse(sep))) end end
def join(sep = "")
def join(sep = "") return "" if empty? sep = sep.to_s tail.reduce(head.to_s.dup) { |result, item| result << sep << item.to_s } end
def last
def last list = self list = list.tail until list.tail.empty? list.head end
def map(&block)
def map(&block) return self unless block_given? Stream.new do next self if empty? Sequence.new(yield(head), tail.map(&block)) end end
def merge(&comparator)
def merge(&comparator) return merge_by unless block_given? Stream.new do sorted = remove(&:empty?).sort do |a, b| yield(a.head, b.head) end next EmptyList if sorted.empty? Sequence.new(sorted.head.head, sorted.tail.cons(sorted.head.tail).merge(&comparator)) end end
def merge_by(&transformer)
def merge_by(&transformer) return merge_by { |item| item } unless block_given? Stream.new do sorted = remove(&:empty?).sort_by do |list| yield(list.head) end next EmptyList if sorted.empty? Sequence.new(sorted.head.head, sorted.tail.cons(sorted.head.tail).merge_by(&transformer)) end end
def method_missing(name, *args, &block)
def method_missing(name, *args, &block) return accessor(Regexp.last_match[1]) if name.to_s.match(CADR) super end
def pop
def pop Stream.new do next self if empty? new_size = size - 1 next Sequence.new(head, tail.take(new_size - 1)) if new_size >= 1 EmptyList end end
def respond_to?(name, include_private = false)
def respond_to?(name, include_private = false) super || !!name.to_s.match(CADR) end
def reverse
def reverse Stream.new { reduce(EmptyList) { |list, item| list.cons(item) } } end
def size
def size reduce(0) { |memo, item| memo.next } end
def slice(from, length = Undefined)
def slice(from, length = Undefined) return at(from) if length.equal?(Undefined) drop(from).take(length) end
def sort(&comparator)
def sort(&comparator) Stream.new { Sorter.new(self).sort(&comparator) } end
def sort_by(&transformer)
def sort_by(&transformer) return sort unless block_given? Stream.new { Sorter.new(self).sort_by(&transformer) } end
def span(&block)
def span(&block) return Tuple.new(self, EmptyList) unless block_given? Tuple.new(take_while(&block), drop_while(&block)) end
def split_at(number)
def split_at(number) Tuple.new(take(number), drop(number)) end
def tails
def tails Stream.new do next Sequence.new(self) if empty? Sequence.new(self, tail.tails) end end
def take(number)
def take(number) Stream.new do next self if empty? next Sequence.new(head, tail.take(number - 1)) if number > 0 EmptyList end end
def take_while(&block)
def take_while(&block) return self unless block_given? Stream.new do next self if empty? next Sequence.new(head, tail.take_while(&block)) if yield(head) EmptyList end end
def to_list
def to_list self end
def to_set
def to_set reduce(EmptySet) { |set, item| set.add(item) } end
def union(other)
def union(other) append(other).uniq end
def uniq(items = EmptySet)
def uniq(items = EmptySet) Stream.new do next self if empty? next tail.uniq(items) if items.include?(head) Sequence.new(head, tail.uniq(items.add(head))) end end
def zip(other)
def zip(other) Stream.new do next self if empty? && other.empty? Sequence.new(Sequence.new(head, Sequence.new(other.head)), tail.zip(other.tail)) end end