Courses/CS 460/Fall 2005/SolveAll

From CSWiki

Jump to: navigation, search

Revised from the original SolveAll in Chapter 12 of CTM.


declare

% This version of SolveAll will do a depth-first or breadth-first 
% traversal of the search space depending on the WhichFirst parameter.
fun {SolveAll WhichFirst Script} 
   {TouchAll {Solve WhichFirst Script}} 
end
fun {TouchAll L}
   case L of
      nil then skip
   [] _ | Rest then {TouchAll Rest _}
   end
   L
end
% Returns a lazy list of solutions for Script.
% The list is ordered depth-first or breadth-first
% depending on the WhichFirst parameter.
% The allowable values are depth and breadth.
fun {Solve WhichFirst Script}
% All of the subsidiary functions are declared within Solve so
% that we won't have to pass WhichFirst around.
% The body of Solve is at the bottom.
   % Each of the elements in Ss is either a Space or a 
   % commitTo(<Space> <Int>) record. A commitTo(<Space> <Int>) 
   % record identifies a Space that is ready to commit to
   % the Ith choice at a choice point.
   % Returns all solutions using either depth-first or
   % breadth-first depending on the value of WhichFirst.
   fun lazy {SolveSpaces Ss}
      case Ss of
         nil then nil
      [] S | SRest then
         % S is either a Space or a commitTo(<Space> <Int>) record.
         case S of
	     commitTo(S I) then
	     Clone = {Space.clone S} 
         in
	     % Start the Ith branch in the clone of S.
	     {Space.commit Clone I}
	     {SolveSpaces Clone|SRest}
         else % S is a Space.
             {SolveSpace {Space.ask S} S SRest}
         end
      end
   end
   % Deal with Space S, which is in state SpaceState
   fun {SolveSpace SpaceState S SRest}
      case SpaceState of
         failed then {SolveSpaces SRest}  
      [] succeeded then {Space.merge S}|{SolveSpaces SRest}  
      [] alternatives(N) then
         {SolveSpaces {NewSpaceList {Choices S N} SRest}}
      end
   end
   % The choices are commitTo(<Space> <Int>) records. They
   % keep track of the branch to which to commit.
   fun {Choices S N}
      {List.mapInd
       {List.make N} % Generates N elements for Map to use.
       % Keep track of which branch to commit to.
       fun {$ I _} commitTo(S I) end}
   end
   % Put the Choices at the front or back of the existing list
   % of pending Spaces depending on WhichFirst.  For efficiency 
   % the lists could be replaced with difference lists.
   fun {NewSpaceList Choices Ss}

      % This is the only place where WhichFirst matters.

      % In depth-first search, the list of pending spaces is a stack.
      if WhichFirst == depth then {Append Choices Ss}

      % In breadth-first search, the list of pending spaces is a queue.
      elseif WhichFirst == breadth then {Append Ss Choices}

      else {Raise traversalSpecificationError(WhichFirst)} nil
      end
   end
in
% The body of Solve
   {SolveSpaces [{Space.new Script}]} 
end
% ==============================================================
% Example to illustrate depth-first vs. breadth-first
fun {ABC} choice a [] b [] c end end

% The "problem" looks at all lists of length =< 3.
% The "Show" documents the order in which the lists
% are generated.
fun {Problem List}
   if {Length List} > 3 then fail end
   {Show List}
   {Problem {Append List [{ABC}]}}
end

{Browse {SolveAll breadth fun {$} {Problem nil} end}}
Personal tools