Class: Ambit::Generator

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

Constant Summary collapse

@@trace =
0

Class Method Summary collapse

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



24
25
26
27
# File 'lib/ambit.rb', line 24

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

Class Method Details

.trace(lvl = false) ⇒ Object

Turn on tracing (to standard error) of Ambit operations

intended for use by Ambit::trace

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



35
36
37
38
39
40
41
# File 'lib/ambit.rb', line 35

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

.untraceObject

Turn off tracing (to standard error) of Ambit operations

intended for use by Ambit::untrace



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

def self.untrace
  @@trace = 0
end

Instance Method Details

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

Fail unless a condition holds.



96
97
98
# File 'lib/ambit.rb', line 96

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!



70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/ambit.rb', line 70

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.



54
55
56
# File 'lib/ambit.rb', line 54

def clear!
  @paths = []
end

#cut!Object

Commit to all choices since the last #mark operation.

See “Marking and Cutting” in README for details



131
132
133
134
135
136
137
138
# File 'lib/ambit.rb', line 131

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:



87
88
89
90
91
92
93
# File 'lib/ambit.rb', line 87

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



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

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

#unmark!Object

Remove the most recent mark

See “Marking and Cutting” in README for details



112
113
114
115
116
117
# File 'lib/ambit.rb', line 112

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



122
123
124
125
126
# File 'lib/ambit.rb', line 122

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