Class: Ambit::Generator

Inherits:
Object
  • Object
show all
Defined in:
lib/ambit.rb

Instance Method Summary collapse

Constructor Details

#initializeGenerator

Allocate a new private Generator. Usually not needed – use Ambit::choose et al, instead.

See “Private Generators” in the README for details



21
22
23
24
# File 'lib/ambit.rb', line 21

def initialize
  @paths = []
  @trace = 0
end

Instance Method Details

#assert(cond) ⇒ Object Also known as: require

Fail unless a condition holds.



89
90
91
# File 'lib/ambit.rb', line 89

def assert cond
  fail! unless cond
end

#choose(choices = []) ⇒ Object Also known as: amb

Given an enumerator, begin a generate-and-test process.

Returns with the first member of the enumerator. A later call to #fail! on the same generator will backtrack and try the next value in the enumerator, continuing from the point of this #choose as if that value had been chosen originally.

Multiple calls to #choose will nest, so that backtracking forms a tree-like execution path

calling #choose with no argument or an empty iterator is equivalent to calling #fail!



63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/ambit.rb', line 63

def choose choices = []
  ch = choices.clone          # clone it in case it's modified by the caller
  ch.each do |choice|
    callcc do |cc|
      STDERR.print "choosing from " + choices.inspect + ": " if @trace > 0
      @paths.unshift cc
      STDERR.puts choice.inspect if @trace > 0
      return choice
    end
  end
  self.fail!                  # if we get here, we've exhausted the choices
end

#clear!Object

Clear all outstanding choices registered with this generator.

Returns the generator to the state it was in before all choices were made. Does not rewind execution.



47
48
49
# File 'lib/ambit.rb', line 47

def clear!
  @paths = []
end

#cut!Object

Commit to all choices since the last #mark operation.

See “Marking and Cutting” in README for details



124
125
126
127
128
129
130
131
# File 'lib/ambit.rb', line 124

def cut!
  STDERR.puts "cut!" if @trace > 0
  return if @paths.empty?
  # rewind paths back to the last mark
  @paths = @paths.drop_while {|x| x.instance_of? Continuation}
  # drop up to one mark
  @paths = @paths.drop(1) unless @paths.empty?
end

#fail!Object

Indicate that the current combination of choices has failed, and roll execution back to the last #choose, continuing with the next choice.

Raises:



80
81
82
83
84
85
86
# File 'lib/ambit.rb', line 80

def fail!
  raise ChoicesExhausted.new if @paths.empty?
  cc = @paths.shift
  # if it quacks (or can be called) like a duck, call it -- it's either a Proc
  # from #mark or a Continuation from #choose
  cc.call
end

#markObject

Begin a mark/cut pair to commit to one branch of the current #choose operation.

See “Marking and Cutting” in README for details



98
99
100
# File 'lib/ambit.rb', line 98

def mark 
  @paths.unshift Proc.new {self.fail!}
end

#trace(lvl = false) ⇒ Object

Turn on tracing (to standard error) of Ambit operations

The optional level argument sets the verbosity – if not passed, each call to this method increases verbosity



30
31
32
33
34
35
36
# File 'lib/ambit.rb', line 30

def trace lvl=false
  if lvl
    @trace = lvl
  else 
    @trace = @trace + 1
  end
end

#unmark!Object

Remove the most recent mark

See “Marking and Cutting” in README for details



105
106
107
108
109
110
# File 'lib/ambit.rb', line 105

def unmark!
  STDERR.puts "unmark!" if @trace > 0
  return if @paths.empty?
  n = @paths.rindex {|x| x.instance_of? Proc}
  n and @paths.delete_at(n)
end

#unmark_all!Object

Remove all marks

See “Marking and Cutting” in README for details



115
116
117
118
119
# File 'lib/ambit.rb', line 115

def unmark_all!
  STDERR.puts "unmark_all!" if @trace > 0
  return if @paths.empty?
  @paths = @paths.reject {|x| x.instance_of? Proc}
end

#untraceObject

Turn off tracing (to standard error) of Ambit operations



39
40
41
# File 'lib/ambit.rb', line 39

def untrace
  @trace = 0
end