Skip to content

Instantly share code, notes, and snippets.

@lbarasti
Created November 15, 2015 23:44
Show Gist options
  • Select an option

  • Save lbarasti/c35359ea3f8b946c6a5b to your computer and use it in GitHub Desktop.

Select an option

Save lbarasti/c35359ea3f8b946c6a5b to your computer and use it in GitHub Desktop.
Implements a stack as an immutable data structure using a functional approach
module Stack
include Enumerable
class EmptyStack
include Stack
def empty?; true; end
def pop; raise 'Cannot pop empty stack'; end
def peek; raise 'Cannot peek empty stack' end
alias_method :head, :peek
alias_method :tail, :pop
end
class NonEmptyStack
include Stack
attr_reader :head, :tail
def initialize head, tail
@head, @tail = head, tail
end
def empty?; false; end
alias_method :peek, :head
alias_method :pop, :tail
end
def self.empty
@@emptyStack ||= EmptyStack.new
end
def self.new *args
args.reverse.inject(self.empty) { |stack, element|
stack.push(element)
}
end
def push(item)
NonEmptyStack.new(item, self)
end
alias_method :<<, :push
def each &block
block or return enum_for(__method__)
unless self.empty?
block.call self.head
self.tail.each &block
end
self
end
def replace_at index, value
l_reversed, r = (0...index).inject([Stack.empty, self]){|pair, idx|
left, right = pair
[left.push(right.head), right.pop]
}
l_reversed.inject(r.pop.push(value)) {|stack, el| NonEmptyStack.new(el, stack)}
end
end
# Stack.new(1,2,3).replace_at(0,0).replace_at(2,-1).push(5).pop.pop.map.to_a
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment