1/*  Part of Optic Planner interface for SWI-Prolog
    2
    3    Author:        Andrew Dougherty, Douglas Miles
    4    E-mail:        andrewdo@frdcsa.org, logicmoo@gmail.com
    5    WWW:           https://github.com/TeamSPoon/planner_external_api
    6    Copyright (C): 2017, Process Design Center, Breda, The Netherlands.
    7    All rights reserved.
    8
    9    Redistribution and use in source and binary forms, with or without
   10    modification, are permitted provided that the following conditions
   11    are met:
   12
   13    1. Redistributions of source code must retain the above copyright
   14       notice, this list of conditions and the following disclaimer.
   15
   16    2. Redistributions in binary form must reproduce the above copyright
   17       notice, this list of conditions and the following disclaimer in
   18       the documentation and/or other materials provided with the
   19       distribution.
   20
   21    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   22    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   23    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
   24    FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
   25    COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
   26    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   27    BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   28    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
   29    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   30    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
   31    ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   32    POSSIBILITY OF SUCH DAMAGE.
   33*/

   34
   35/*
   36":typing" | ":strips" | ":equality" | ":fluents" | ":durative-actions" | ":duration-inequalities" | ":numeric-fluents" | ":action-costs" | ":adl" | ":negative-preconditions" | ":disjunctive-preconditions" | ":existential-preconditions" | "universal-preconditions" | "quantified-preconditions" | ":conditional-effects" | ":timed-initial-literals" | ":preferences" | ":constraints"
   37
   38":domain-axioms" | ":derived-predicates" ":action-expansions" | ":foreach-expansions" | ":dag-expansions" | ":subgoal-through-axioms" | ":safety-constraints" | ":expression-evaluation" | ":open-world" | ":true-negation" | ":ucpop"
   39
   40*/

   41
   42:- module(planner_external_interface, [
   43          planner_program/2,   % planner_program(Program)
   44          planner_workspace/2,   % planner_workspace(Opr,W)
   45          planner_workspace_program/3, % planner_workspace_program(Opr,W,Program)
   46          planner_requirement/3,   % planner_requirement(Opr,W,Require)
   47          planner_init/3, % planner_init(Opr,W,Fact)
   48          planner_predicate/3, % planner_predicate(Opr,W,Predicate)
   49          planner_function/3, % planner_function(Opr,W,Function)
   50          planner_type/3, % planner_type(Opr,W,Sort)
   51          planner_object/3, % planner_object(Opr,W,Object)
   52          planner_derived/4, % planner_derived(Opr,W,Fact,Condition) 
   53          planner_axiom/3, % planner_axiom(Opr,W,Axiom)
   54          planner_action/4, % planner_action(Opr,W,Action,Info)
   55          planner_copy_workspace/2, % planner_copy_workspace(+W,?NewWorkspace)
   56          planner_load_file/2, % planner_load_file(+W,+FileName)
   57  planner_current_program/1,
   58  planner_add_program/1,
   59  planner_remove_program/1,
   60  planner_current_workspace/1,
   61  planner_add_workspace/1,
   62  planner_remove_workspace/1,
   63  planner_current_workspace_program/2,
   64  planner_add_workspace_program/2,
   65  planner_remove_workspace_program/2,
   66  planner_current_requirement/2,
   67  planner_add_requirement/2,
   68  planner_remove_requirement/2,
   69  planner_current_init/2,
   70  planner_add_init/2,
   71  planner_remove_init/2,
   72  planner_current_predicate/2,
   73  planner_add_predicate/2,
   74  planner_remove_predicate/2,
   75  planner_current_function/2,
   76  planner_add_function/2,
   77  planner_remove_function/2,
   78  planner_current_type/2,
   79  planner_add_type/2,
   80  planner_remove_type/2,
   81  planner_current_object/2,
   82  planner_add_object/2,
   83  planner_remove_object/2,
   84  planner_current_derived/3,
   85  planner_add_derived/3,
   86  planner_remove_derived/3,
   87  planner_current_axiom/2,
   88  planner_add_axiom/2,
   89  planner_remove_axiom/2,
   90  planner_current_action/3,
   91  planner_add_action/3,
   92  planner_remove_action/3,
   93   planner_get_plan/3, % planner_get_plan(+W,+Goal,-Plan)
   94   planner_get_plan/4, % planner_get_plan(+W,+Planner,+Goal,-Plan)
   95   planner_apply_step/3, % planner_apply_step(+W,+Step,-NewWorkspace)
   96   planner_apply_step/4, % planner_apply_step(+W,+Planner,+Step,-NewWorkspace)
   97   ensure_external_planners/0,
   98   planner_debug/1,
   99   make_api/0
  100
  101  ]).
  102
  103make_api:-
  104 maplist(make_one_api,
  105   [program/2,   % program(Program)
  106   workspace/2,   % workspace(Opr,W)
  107   workspace_program/3, % workspace_program(Opr,W,Program)
  108   requirement/3,   % requirement(Opr,W,Require)
  109   init/3, % init(Opr,W,Fact)
  110   predicate/3, % predicate(Opr,W,Predicate)
  111   function/3, % function(Opr,W,Function)
  112   type/3, % type(Opr,W,Sort)
  113   object/3, % object(Opr,W,Object)
  114   derived/4, % derived(Opr,W,Fact,Conditions) 
  115   axiom/3, % axiom(Opr,W,Axiom)
  116   action/4]). % action(Opr,W,Action,Info)
  117make_exports:-
  118 maplist(make_one_export,
  119   [program/2,   % program(Program)
  120   workspace/2,   % workspace(Opr,W)
  121   workspace_program/3, % workspace_program(Opr,W,Program)
  122   requirement/3,   % requirement(Opr,W,Require)
  123   init/3, % init(Opr,W,Fact)
  124   predicate/3, % predicate(Opr,W,Predicate)
  125   function/3, % function(Opr,W,Function)
  126   type/3, % type(Opr,W,Sort)
  127   object/3, % object(Opr,W,Object)
  128   derived/4, % derived(Opr,W,Fact,Conditions) 
  129   axiom/3, % axiom(Opr,W,Axiom)
  130   action/4]). % action(Opr,W,Action,Info)
  131
  132make_one_export(F/Am1):- A is Am1-1,
  133  make_one_export_fa(current,F,A),
  134  make_one_export_fa(add,F,A),
  135  make_one_export_fa(remove,F,A),!.
  136
  137make_one_export_fa(C,F,A):- format('\n  planner_~w_~w/~w, ',[C,F,A]).
  138           
  139make_one_api(F/4):- !,  
  140  make_one_api_34(current,"+Workspace, ?",F,nondet,"Gets each",?,", Conds"),
  141  make_one_api_34(add,"+Workspace, +",F,det,"Adds one",+,", Conds"),
  142  make_one_api_34(remove,"+Workspace, +",F,det,"Removes one",-,", Conds"),!.
  143
  144make_one_api(F/3):- !,  
  145  make_one_api_34(current,"+Workspace, ?",F,nondet,"Gets each",?,""),
  146  make_one_api_34(add,"+Workspace, +",F,det,"Adds one",+,""),
  147  make_one_api_34(remove,"+Workspace, +",F,det,"Removes one",-,""),!.
  148
  149make_one_api(F/2):- !,  
  150  make_one_api_2(current,"?",F,nondet,"Gets each",?,""),
  151  make_one_api_2(add,"+",F,det,"Adds one",+,""),
  152  make_one_api_2(remove,"+",F,det,"Removes one",-,""),!.
  153
  154make_one_api_2(Current,Mode,F,Det,String,Quest,ExtraArgs):-
  155  make_one_api_234(Current,Mode,F,Det,String,Quest,"",ExtraArgs).
  156make_one_api_34(Current,Mode,F,Det,String,Quest,ExtraArgs):-
  157make_one_api_234(Current,Mode,F,Det,String,Quest,"Workspace, ",ExtraArgs).
  158  
  159
  160make_one_api_234(Current,Mode,F,Det,String,Quest,WSC,ExtraArgs):-
  161 toPropercase(F,CapsF), 
  162 (Quest=='?' -> From = "contained in";
  163 Quest=='+' -> From = "into";
  164 Quest=='-' -> From = "from"),
  165 upcase_atom(F,UP),
  166  format('
  167%! planner_~w_~w(~w~w~w) is ~w.
  168% 
  169%   ~w ~w ~w the Workspace. 
  170%
  171%      (PDDL''s :~w directive)
  172%
  173planner_~w_~w(~w~w~w):- 
  174      planner_~w(~w, ~w~w~w).
  175
  176',[Current,F,Mode,CapsF,ExtraArgs,Det,
  177  String,CapsF,From,
  178  UP,
  179  Current,F,WSC,CapsF,ExtraArgs,
  180  F,Quest,WSC,CapsF,ExtraArgs]).
 planner_current_program(?Program) is nondet
Gets each Program contained in the Workspace.

(PDDL's :PROGRAM directive)

  189planner_current_program(Program):-
  190      planner_program(?, Program).
 planner_add_program(+Program) is det
Adds one Program into the Workspace.

(PDDL's :PROGRAM directive)

  199planner_add_program(Program):-
  200      planner_program(+, Program).
 planner_remove_program(+Program) is det
Removes one Program from the Workspace.

(PDDL's :PROGRAM directive)

  209planner_remove_program(Program):-
  210      planner_program(-, Program).
 planner_current_workspace(?Workspace) is nondet
Gets each Workspace contained in the Workspace.

(PDDL's :WORKSPACE directive)

  219planner_current_workspace(Workspace):-
  220      planner_workspace(?, Workspace).
 planner_add_workspace(+Workspace) is det
Adds one Workspace into the Workspace.

(PDDL's :WORKSPACE directive)

  229planner_add_workspace(Workspace):-
  230      planner_workspace(+, Workspace).
 planner_remove_workspace(+Workspace) is det
Removes one Workspace from the Workspace.

(PDDL's :WORKSPACE directive)

  239planner_remove_workspace(Workspace):-
  240      planner_workspace(-, Workspace).
 planner_current_workspace_program(+Workspace, ?Workspace_Program) is nondet
Gets each Workspace_Program contained in the Workspace.

(PDDL's :WORKSPACE_PROGRAM directive)

  249planner_current_workspace_program(Workspace, Workspace_Program):-
  250      planner_workspace_program(?, Workspace, Workspace_Program).
 planner_add_workspace_program(+Workspace, +Workspace_Program) is det
Adds one Workspace_Program into the Workspace.

(PDDL's :WORKSPACE_PROGRAM directive)

  259planner_add_workspace_program(Workspace, Workspace_Program):-
  260      planner_workspace_program(+, Workspace, Workspace_Program).
 planner_remove_workspace_program(+Workspace, +Workspace_Program) is det
Removes one Workspace_Program from the Workspace.

(PDDL's :WORKSPACE_PROGRAM directive)

  269planner_remove_workspace_program(Workspace, Workspace_Program):-
  270      planner_workspace_program(-, Workspace, Workspace_Program).
 planner_current_requirement(+Workspace, ?Requirement) is nondet
Gets each Requirement contained in the Workspace.

(PDDL's :REQUIREMENT directive)

  279planner_current_requirement(Workspace, Requirement):-
  280      planner_requirement(?, Workspace, Requirement).
 planner_add_requirement(+Workspace, +Requirement) is det
Adds one Requirement into the Workspace.

(PDDL's :REQUIREMENT directive)

  289planner_add_requirement(Workspace, Requirement):-
  290      planner_requirement(+, Workspace, Requirement).
 planner_remove_requirement(+Workspace, +Requirement) is det
Removes one Requirement from the Workspace.

(PDDL's :REQUIREMENT directive)

  299planner_remove_requirement(Workspace, Requirement):-
  300      planner_requirement(-, Workspace, Requirement).
 planner_current_init(+Workspace, ?Init) is nondet
Gets each Init contained in the Workspace.

(PDDL's :INIT directive)

  309planner_current_init(Workspace, Init):-
  310      planner_init(?, Workspace, Init).
 planner_add_init(+Workspace, +Init) is det
Adds one Init into the Workspace.

(PDDL's :INIT directive)

  319planner_add_init(Workspace, Init):-
  320      planner_init(+, Workspace, Init).
 planner_remove_init(+Workspace, +Init) is det
Removes one Init from the Workspace.

(PDDL's :INIT directive)

  329planner_remove_init(Workspace, Init):-
  330      planner_init(-, Workspace, Init).
 planner_current_predicate(+Workspace, ?Predicate) is nondet
Gets each Predicate contained in the Workspace.

(PDDL's :PREDICATE directive)

  339planner_current_predicate(Workspace, Predicate):-
  340      planner_predicate(?, Workspace, Predicate).
 planner_add_predicate(+Workspace, +Predicate) is det
Adds one Predicate into the Workspace.

(PDDL's :PREDICATE directive)

  349planner_add_predicate(Workspace, Predicate):-
  350      planner_predicate(+, Workspace, Predicate).
 planner_remove_predicate(+Workspace, +Predicate) is det
Removes one Predicate from the Workspace.

(PDDL's :PREDICATE directive)

  359planner_remove_predicate(Workspace, Predicate):-
  360      planner_predicate(-, Workspace, Predicate).
 planner_current_function(+Workspace, ?Function) is nondet
Gets each Function contained in the Workspace.

(PDDL's :FUNCTION directive)

  369planner_current_function(Workspace, Function):-
  370      planner_function(?, Workspace, Function).
 planner_add_function(+Workspace, +Function) is det
Adds one Function into the Workspace.

(PDDL's :FUNCTION directive)

  379planner_add_function(Workspace, Function):-
  380      planner_function(+, Workspace, Function).
 planner_remove_function(+Workspace, +Function) is det
Removes one Function from the Workspace.

(PDDL's :FUNCTION directive)

  389planner_remove_function(Workspace, Function):-
  390      planner_function(-, Workspace, Function).
 planner_current_type(+Workspace, ?Type) is nondet
Gets each Type contained in the Workspace.

(PDDL's :TYPE directive)

  399planner_current_type(Workspace, Type):-
  400      planner_type(?, Workspace, Type).
 planner_add_type(+Workspace, +Type) is det
Adds one Type into the Workspace.

(PDDL's :TYPE directive)

  409planner_add_type(Workspace, Type):-
  410      planner_type(+, Workspace, Type).
 planner_remove_type(+Workspace, +Type) is det
Removes one Type from the Workspace.

(PDDL's :TYPE directive)

  419planner_remove_type(Workspace, Type):-
  420      planner_type(-, Workspace, Type).
 planner_current_object(+Workspace, ?Object) is nondet
Gets each Object contained in the Workspace.

(PDDL's :OBJECT directive)

  429planner_current_object(Workspace, Object):-
  430      planner_object(?, Workspace, Object).
 planner_add_object(+Workspace, +Object) is det
Adds one Object into the Workspace.

(PDDL's :OBJECT directive)

  439planner_add_object(Workspace, Object):-
  440      planner_object(+, Workspace, Object).
 planner_remove_object(+Workspace, +Object) is det
Removes one Object from the Workspace.

(PDDL's :OBJECT directive)

  449planner_remove_object(Workspace, Object):-
  450      planner_object(-, Workspace, Object).
 planner_current_derived(+Workspace, ?Derived, ?Conds) is nondet
Gets each Derived contained in the Workspace.

(PDDL's :DERIVED directive)

  459planner_current_derived(Workspace, Derived, Conds):-
  460      planner_derived(?, Workspace, Derived, Conds).
 planner_add_derived(+Workspace, +Derived, +Conds) is det
Adds one Derived into the Workspace.

(PDDL's :DERIVED directive)

  469planner_add_derived(Workspace, Derived, Conds):-
  470      planner_derived(+, Workspace, Derived, Conds).
 planner_remove_derived(+Workspace, +Derived, +Conds) is det
Removes one Derived from the Workspace.

(PDDL's :DERIVED directive)

  479planner_remove_derived(Workspace, Derived, Conds):-
  480      planner_derived(-, Workspace, Derived, Conds).
 planner_current_axiom(+Workspace, ?Axiom) is nondet
Gets each Axiom contained in the Workspace.

(PDDL's :AXIOM directive)

  489planner_current_axiom(Workspace, Axiom):-
  490      planner_axiom(?, Workspace, Axiom).
 planner_add_axiom(+Workspace, +Axiom) is det
Adds one Axiom into the Workspace.

(PDDL's :AXIOM directive)

  499planner_add_axiom(Workspace, Axiom):-
  500      planner_axiom(+, Workspace, Axiom).
 planner_remove_axiom(+Workspace, +Axiom) is det
Removes one Axiom from the Workspace.

(PDDL's :AXIOM directive)

  509planner_remove_axiom(Workspace, Axiom):-
  510      planner_axiom(-, Workspace, Axiom).
 planner_current_action(+Workspace, ?Action, ?Conds) is nondet
Gets each Action contained in the Workspace.

(PDDL's :ACTION directive)

  519planner_current_action(Workspace, Action, Conds):-
  520      planner_action(?, Workspace, Action, Conds).
 planner_add_action(+Workspace, +Action, +Conds) is det
Adds one Action into the Workspace.

(PDDL's :ACTION directive)

  529planner_add_action(Workspace, Action, Conds):-
  530      planner_action(+, Workspace, Action, Conds).
 planner_remove_action(+Workspace, +Action, +Conds) is det
Removes one Action from the Workspace.

(PDDL's :ACTION directive)

  539planner_remove_action(Workspace, Action, Conds):-
  540      planner_action(-, Workspace, Action, Conds).
  541
  542
  543planner_copy_workspace(Workspace,NewWorkspace):- 
  544   (var(NewWorkspace)->gensym(Workspace,NewWorkspace);true),
  545   forall(mdata:ws_data(Workspace,P,V),call_ws_data_hook(+,NewWorkspace,P,V)).
  546
  547planner_load_file(W,FileName):- planner_missing(planner_load_file(W,FileName)).
+ = Adds a workspace name
  557planner_workspace(Opr,Workspace):- 
  558  call_settings_data(Opr,ws_data(Workspace,isa,tWorkspace)).
+ = Adds a planner program name
  569planner_program(Opr,Program):- call_settings_data(Opr,current_planner_program(Program)).
  570
  571
  572planner_data_template(current_planner_program(_Program)).
  573planner_data_template(ws_data(_W,_P,_D)).
  574
  575pre_existing_clause(MData,R):- strip_module(MData,M,Data),
  576  clause(M:Data,true,R),clause(MCData,true,R),strip_module(MCData,_,CData),Data=@=CData,!.
  577
  578:- dynamic(mdata:current_planner_program/1).
  579:- dynamic(mdata:ws_data/3).
  580
  581to_mdata(Data,mdata:BData):- strip_module(Data,_,BData).
  582
  583call_ws_data_hook(Opr,W,Prop,DataL):- 
  584  check_opr(W,Opr),
  585  forall(delistify_data(DataL,Data),
  586       call_settings_data(Opr,ws_data(W,Prop,Data))).
  587
  588call_settings_data(Opr,Data):- to_mdata(Data,MData), call_settings_mdata(Opr,MData).
  589call_settings_mdata(?,MData):- !, call(MData).
  590call_settings_mdata(+,MData):-  !, (pre_existing_clause(MData,_R)->true;
  591   (asserta(MData),planner_debug(asserta(MData)))).
  592call_settings_mdata(-,MData):- ignore(call(MData)),retractall(MData).
  593
  594delistify_data(DataL,Data):- is_list(DataL),!,member(Data,DataL).
  595delistify_data(Data,Data).
  596
  597% Manipulate PDDL Workspace Dfault Planner Program
  598planner_workspace_program(Opr,W,Program):- 
  599  (call_settings_data(Opr,ws_data(W,program,Program))
  600   *->true;
  601   call_settings_data(Opr,current_planner_program(Program))).
  602  
  603
  604% Manipulate PDDL Workspace Problem/Domains (:Requirements ...)
  605planner_requirement(Opr,W,Require):- call_ws_data_hook(Opr,W,requirement,Require).
  606
  607% Manipulate PDDL Workspace Problem/Domains (:Init ...)
  608planner_init(Opr,W,Fact):- 
  609  glean_objs(Opr,W,Fact),
  610  call_ws_data_hook(Opr,W,init,Fact).
  611
  612% Manipulate PDDL Workspace Problem/Domains (:Predicates ...)
  613planner_predicate(Opr,W,Predicate):- 
  614  glean_types(Opr,W,Predicate),
  615  call_ws_data_hook(Opr,W,predicate,Predicate).
  616
  617% Manipulate PDDL Workspace Problem/Domains (:Functions ...)
  618planner_function(Opr,W,Function):- 
  619  glean_types(Opr,W,Function),
  620  call_ws_data_hook(Opr,W,function,Function).
  621
  622% Manipulate PDDL Workspace Problem/Domains (:TYPE ...)
  623planner_type(Opr,W,Type):-
  624  glean_types(Opr,W,Type),
  625  call_ws_data_hook(Opr,W,type,Type).
  626
  627% Manipulate PDDL Workspace Problem/Domains (:OBJECTS ...)
  628planner_object(Opr,W,Object):- 
  629  glean_types(Opr,W,Object),
  630  call_ws_data_hook(Opr,W,object,Object).
  631
  632% Manipulate a PDDL Workspace Problem/Domains (:derived-predicates ...)
  633planner_derived(Opr,W,Fact,Cond) :- Cond==[], !, planner_init(Opr,W,Fact).
  634planner_derived(Opr,W,Fact,Condition) :- 
  635  FULL= derived(Fact,Condition),
  636  numbervars(FULL),
  637  call_ws_data_hook(Opr,W,derived,FULL).
  638
  639
  640% Manipulate a PDDL Workspace Problem/Domains (:axiom ...)
  641planner_axiom(Opr,W,Axiom):- call_ws_data_hook(Opr,W,axiom,Axiom).
  642
  643% Manipulate a PDDL Workspace Problem/Domains (:action Action (...Info...))
  644planner_action(Opr,W,Action,InfoList):- glean_types(Opr,W,Action),   
  645   numbervars(InfoList),
  646   planner_action_info(Opr,W,Action,InfoList),
  647   !. % call_ws_data_hook(Opr,W,action,act_info(Action,InfoList)).
  648
  649planner_action_info(Opr,W,Action,InfoList):- 
  650  is_list(InfoList),!,maplist(planner_action(Opr,W,Action),InfoList).
  651planner_action_info(Opr,W,Action,Type:Info):-!,
  652   call_ws_data_hook(Opr,W,action,act_inf(Action,Type,Info)).
  653planner_action_info(Opr,W,Action,Info):-
  654   call_ws_data_hook(Opr,W,action,act_inf(Action,meta,Info)).
 planner_get_plan(+W, +Goal, -Plan) is nondet
  658planner_get_plan(W,Goal,Plan):-
  659  planner_workspace_program(?,W,Planner),
  660  planner_get_plan(Planner,W,Goal,Plan).
 planner_get_plan(+Planner, +W, +Goal, -Plan) is nondet
  663planner_get_plan(Planner,W,Goal,Plan):-   
  664  check_workspace(W),
  665  ignore(Plan=[s1,s2,s3]),
  666  planner_missing(planner_get_plan(Planner,W,Goal,Plan)).
 planner_apply_step(+W, +Step, -NewWorkspace) is det
  669planner_apply_step(W,Step,NewWorkspace):-
  670  planner_workspace_program(?,W,Planner),
  671  planner_apply_step(Planner,W,Step,NewWorkspace).
 planner_apply_step(+Planner, +W, +Step, -NewWorkspace) is det
  674planner_apply_step(Planner,W,Step,NewWorkspace):-
  675 check_workspace(W),
  676 (var(NewWorkspace)->gensym(W,NewWorkspace);true),
  677 check_workspace(NewWorkspace),
  678 planner_missing(planner_apply_step(Planner,W,Step,NewWorkspace)).
  679
  680
  681ensure_external_planners.
  682
  683glean_types(Opr,W,Any):- Opr == +,!,
  684  check_opr(W,Opr),
  685  forall((sub_term(Sub,Any),
  686  compound(Sub),member(Sub,[_-Type, Type:_])),
  687  planner_type(Opr,W,Type)).
  688glean_types(_,_,_).   
  689
  690
  691glean_objs(Opr,W,Any):- Opr == +,!,
  692  forall((sub_term(Sub,Any),
  693   compound(Sub),member(Sub,[Obj-_])),
  694   planner_object(Opr,W,Obj)),
  695  forall((sub_term(Obj,Any),
  696  atom(Obj)),planner_object(Opr,W,Obj)).
  697glean_objs(_,_,_).   
  698
  699check_opr(W,+):- check_workspace(W).
  700check_opr(W,del):- check_workspace(W).
  701check_opr(W,?):- check_workspace(W).
  702check_opr(_Workspace,Opr):- throw(opr_missing(Opr)).
  703
  704check_workspace(W):- mdata:ws_data(W,isa,tWorkspace),!.
  705check_workspace(W):- asserta(mdata:ws_data(W,isa,tWorkspace)).
  706
  707planner_debug(Info):- format('~N% ~q.~n',[Info]).
  708
  709planner_missing(Goal):- !,planner_debug(g(Goal)).
  710planner_missing(Goal):- throw(planner_missing(Goal)).
  711
  712
  713
  714%e_member([L|ST],E):- nonvar(L),!,member(E,[L|ST]).
  715%e_member(E,E).