require 'forwardable' require 'monitor' require 'hamster/tuple' require 'hamster/set' module Hamster class << self extend Forwardable def list(*items) items.reverse.reduce(EmptyList) { |list, item| list.cons(item) } end def stream(&block) return EmptyList unless block_given? Stream.new { Sequence.new(yield, stream(&block)) } end def interval(from, to) return EmptyList if from > to Stream.new { Sequence.new(from, interval(from.succ, to)) } end def_delegator :self, :interval, :range def repeat(item) Stream.new { Sequence.new(item, repeat(item)) } end def replicate(number, item) repeat(item).take(number) end def iterate(item, &block) Stream.new { Sequence.new(item, iterate(yield(item), &block)) } end end module List extend Forwardable def_delegator :self, :head, :first def_delegator :self, :empty?, :null? def size reduce(0) { |memo, item| memo.succ } end def_delegator :self, :size, :length def cons(item) Sequence.new(item, self) end def_delegator :self, :cons, :>> def each # return nil if empty? # yield(head) # tail.each(&block) return self unless block_given? list = self while !list.empty? yield(list.head) list = list.tail end end def_delegator :self, :each, :foreach def map(&block) return self unless block_given? Stream.new do if empty? self else Sequence.new(yield(head), tail.map(&block)) end end end def_delegator :self, :map, :collect def reduce(memo = Undefined, &block) # return memo if empty? # return memo unless block_given? # return tail.reduce(head, &block) if memo.equal?(Undefined) # tail.reduce(yield(memo, head), &block) return tail.reduce(head, &block) if memo.equal?(Undefined) return memo unless block_given? each { |item| memo = yield(memo, item) } memo end def_delegator :self, :reduce, :inject def_delegator :self, :reduce, :fold def filter(&block) return self unless block_given? Stream.new do if empty? self elsif yield(head) Sequence.new(head, tail.filter(&block)) else tail.filter(&block) end end end def_delegator :self, :filter, :select def_delegator :self, :filter, :find_all def remove(&block) return self unless block_given? filter { |item| !yield(item) } end def_delegator :self, :remove, :reject def_delegator :self, :remove, :delete_if def take_while(&block) return self unless block_given? Stream.new do if empty? self elsif yield(head) Sequence.new(head, tail.take_while(&block)) else EmptyList end end end def drop_while(&block) return self unless block_given? Stream.new do if empty? self elsif yield(head) tail.drop_while(&block) else self end end end def take(number) Stream.new do if empty? self elsif number > 0 Sequence.new(head, tail.take(number - 1)) else EmptyList end end end def drop(number) Stream.new do if empty? self elsif number > 0 tail.drop(number - 1) else self end end end def include?(object) any? { |item| item == object } end def_delegator :self, :include?, :member? def_delegator :self, :include?, :contains? def_delegator :self, :include?, :elem? def any? # return false if empty? # return any? { |item| item } unless block_given? # !! yield(head) || tail.any?(&block) return any? { |item| item } unless block_given? each { |item| return true if yield(item) } false end def_delegator :self, :any?, :exist? def_delegator :self, :any?, :exists? def all? # return true if empty? # return all? { |item| item } unless block_given? # !! yield(head) && tail.all?(&block) return all? { |item| item } unless block_given? each { |item| return false unless yield(item) } true end def_delegator :self, :all?, :forall? def none? # return true if empty? # return none? { |item| item } unless block_given? # !yield(head) && tail.none?(&block) return none? { |item| item } unless block_given? each { |item| return false if yield(item) } true end def one?(&block) # return true if empty? # return none? { |item| item } unless block_given? # !yield(head) && tail.none?(&block) return one? { |item| item } unless block_given? list = self while !list.empty? return list.tail.none?(&block) if yield(list.head) list = list.tail end false end def find # return nil if empty? # return nil unless block_given? # return head if yield(head) # tail.find(&block) return nil unless block_given? each { |item| return item if yield(item) } end def_delegator :self, :find, :detect def partition(&block) return self unless block_given? Tuple.new(filter(&block), remove(&block)) end def append(other) Stream.new do if empty? other else Sequence.new(head, tail.append(other)) end end end def_delegator :self, :append, :concat def_delegator :self, :append, :cat def_delegator :self, :append, :+ def reverse reduce(EmptyList) { |list, item| list.cons(item) } end def minimum(&block) return minimum { |minimum, item| item <=> minimum } unless block_given? reduce { |minimum, item| yield(minimum, item) < 0 ? item : minimum } end def_delegator :self, :minimum, :min def maximum(&block) return maximum { |maximum, item| item <=> maximum } unless block_given? reduce { |maximum, item| yield(maximum, item) > 0 ? item : maximum } end def_delegator :self, :maximum, :max def grep(pattern, &block) filter { |item| pattern === item }.map(&block) end def zip(other) Stream.new do if empty? && other.empty? self else Sequence.new(Sequence.new(head, Sequence.new(other.head)), tail.zip(other.tail)) end end end def cycle Stream.new do if empty? self else Sequence.new(head, tail.append(self.cycle)) end end end def split_at(number) Tuple.new(take(number), drop(number)) end def span(&block) return Tuple.new(self, EmptyList) unless block_given? Tuple.new(take_while(&block), drop_while(&block)) end def break(&block) return Tuple.new(self, EmptyList) unless block_given? span { |item| !yield(item) } end def count(&block) filter(&block).size end def clear EmptyList end def sort(&block) Stream.new do Hamster.list(*to_a.sort(&block)) end end def sort_by(&block) return sort unless block_given? Stream.new do Hamster.list(*to_a.sort_by(&block)) end end def join(sep = "") return "" if empty? sep = sep.to_s tail.reduce(head.to_s) { |string, item| string << sep << item.to_s } end def intersperse(sep) Stream.new do if tail.empty? self else Sequence.new(head, Sequence.new(sep, tail.intersperse(sep))) end end end def uniq(items = Set.new) Stream.new do if empty? self elsif items.include?(head) tail.uniq(items) else Sequence.new(head, tail.uniq(items.add(head))) end end end def_delegator :self, :uniq, :nub def_delegator :self, :uniq, :remove_duplicates def union(other) self.append(other).uniq end def_delegator :self, :union, :| def init return EmptyList if tail.empty? Stream.new { Sequence.new(head, tail.init) } end def last list = self while !list.tail.empty? list = list.tail end list.head end def product reduce(1, &:*) end def sum reduce(0, &:+) end def tails Stream.new do if empty? Sequence.new(self) else Sequence.new(self, tail.tails) end end end def inits Stream.new do if empty? Sequence.new(self) else Sequence.new(EmptyList, tail.inits.map { |list| list.cons(head) }) end end end def combinations(number) return Sequence.new(EmptyList) if number == 0 Stream.new do if empty? self else tail.combinations(number - 1).map { |list| list.cons(head) }.append(tail.combinations(number)) end end end def_delegator :self, :combinations, :combination def compact remove(&:nil?) end def chunk(number) Stream.new do if empty? self else first, remainder = split_at(number) Sequence.new(first, remainder.chunk(number)) end end end def each_chunk(number, &block) chunk(number).each(&block) end def_delegator :self, :each_chunk, :each_slice def flatten Stream.new do if empty? self elsif head.is_a?(List) head.append(tail.flatten) else Sequence.new(head, tail.flatten) end end end def eql?(other) # return true if other.equal?(self) # return false unless other.is_a?(List) # return other.empty? if empty? # return empty? if other.empty? # other.head.eql?(head) && other.tail.eql?(tail) return false unless other.is_a?(List) list = self while !list.empty? && !other.empty? return true if other.equal?(list) return false unless other.is_a?(List) return false unless other.head.eql?(list.head) list = list.tail other = other.tail end other.empty? && list.empty? end def_delegator :self, :eql?, :== def dup self end def_delegator :self, :dup, :clone def to_a reduce([]) { |a, item| a << item } end def_delegator :self, :to_a, :entries def_delegator :self, :to_a, :to_ary def to_list self end def inspect to_a.inspect end def respond_to?(name, include_private = false) super || CADR === name end private Undefined = Object.new CADR = /^c([ad]+)r$/ def method_missing(name, *args, &block) if CADR === name accessor($1) else super end end # Perform compositions of car and cdr operations. Their names consist of a 'c', followed by at # 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 # identify the series of car and cdr operations that is performed by the function. The order in which the 'a's and # 'd's appear is the inverse of the order in which the corresponding operations are performed. 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 end class Sequence include List attr_reader :head, :tail def initialize(head, tail = EmptyList) @head = head @tail = tail end def empty? false end end class Stream include List def initialize(&block) @block = block @mutex = Mutex.new end def head target.head end def tail target.tail end def empty? list = target while list.is_a?(Stream) list = list.target end list.empty? end protected def target @mutex.synchronize do unless defined?(@target) @target = @block.call @block = nil end end @target end end module EmptyList class << self include List def head nil end def tail self end def empty? true end end end end